mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-15 00:36:08 +01:00
Make the BatchingEngine not jittery
- Stop having threads compete for a single BufferBuilder - ...by skirting around minecraft's BufferSource - Begin work on making vertex writing sane
This commit is contained in:
parent
831f990153
commit
b0f6d07b0b
32 changed files with 948 additions and 397 deletions
|
@ -11,6 +11,7 @@ import org.apache.logging.log4j.Logger;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.Flywheel;
|
||||||
import com.jozufozu.flywheel.backend.instancing.batching.WaitGroup;
|
import com.jozufozu.flywheel.backend.instancing.batching.WaitGroup;
|
||||||
|
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
|
@ -104,7 +105,7 @@ public class BatchExecutor implements TaskEngine {
|
||||||
Runnable job;
|
Runnable job;
|
||||||
|
|
||||||
// Finish everyone else's work...
|
// Finish everyone else's work...
|
||||||
while ((job = getNextTask(false)) != null) {
|
while ((job = this.jobQueue.pollLast()) != null) {
|
||||||
processTask(job);
|
processTask(job);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,10 +117,10 @@ public class BatchExecutor implements TaskEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Runnable getNextTask(boolean block) {
|
private Runnable getNextTask() {
|
||||||
Runnable job = this.jobQueue.poll();
|
Runnable job = this.jobQueue.pollFirst();
|
||||||
|
|
||||||
if (job == null && block) {
|
if (job == null) {
|
||||||
synchronized (BatchExecutor.this.jobNotifier) {
|
synchronized (BatchExecutor.this.jobNotifier) {
|
||||||
try {
|
try {
|
||||||
BatchExecutor.this.jobNotifier.wait();
|
BatchExecutor.this.jobNotifier.wait();
|
||||||
|
@ -134,6 +135,8 @@ public class BatchExecutor implements TaskEngine {
|
||||||
private void processTask(Runnable job) {
|
private void processTask(Runnable job) {
|
||||||
try {
|
try {
|
||||||
job.run();
|
job.run();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Flywheel.log.error(e);
|
||||||
} finally {
|
} finally {
|
||||||
BatchExecutor.this.wg.done();
|
BatchExecutor.this.wg.done();
|
||||||
}
|
}
|
||||||
|
@ -158,13 +161,13 @@ public class BatchExecutor implements TaskEngine {
|
||||||
public void run() {
|
public void run() {
|
||||||
// Run until the chunk builder shuts down
|
// Run until the chunk builder shuts down
|
||||||
while (this.running.get()) {
|
while (this.running.get()) {
|
||||||
Runnable job = BatchExecutor.this.getNextTask(true);
|
Runnable job = BatchExecutor.this.getNextTask();
|
||||||
|
|
||||||
if (job == null) {
|
if (job == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
processTask(job);
|
BatchExecutor.this.processTask(job);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,7 @@ public class InstanceWorld {
|
||||||
*/
|
*/
|
||||||
public void renderLayer(RenderLayerEvent event) {
|
public void renderLayer(RenderLayerEvent event) {
|
||||||
taskEngine.syncPoint();
|
taskEngine.syncPoint();
|
||||||
engine.render(event, event.buffers.bufferSource());
|
engine.render(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,9 +10,8 @@ public interface RenderDispatcher {
|
||||||
* Render every model for every material.
|
* Render every model for every material.
|
||||||
*
|
*
|
||||||
* @param event Context for rendering.
|
* @param event Context for rendering.
|
||||||
* @param buffers The buffer source for which batched rendering should happen.
|
|
||||||
*/
|
*/
|
||||||
void render(RenderLayerEvent event, MultiBufferSource buffers);
|
void render(RenderLayerEvent event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maintain the integer origin coordinate to be within a certain distance from the camera in all directions.
|
* Maintain the integer origin coordinate to be within a certain distance from the camera in all directions.
|
||||||
|
|
|
@ -28,9 +28,9 @@ public class BatchedMaterial<D extends InstanceData> implements Material<D> {
|
||||||
return models.computeIfAbsent(key, $ -> new CPUInstancer<>(type, modelSupplier.get()));
|
return models.computeIfAbsent(key, $ -> new CPUInstancer<>(type, modelSupplier.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void render(PoseStack stack, VertexConsumer buffer, FormatContext context) {
|
public void setupAndRenderInto(PoseStack stack, VertexConsumer buffer) {
|
||||||
for (CPUInstancer<D> instancer : models.values()) {
|
for (CPUInstancer<D> instancer : models.values()) {
|
||||||
instancer.setup(context);
|
instancer.setup();
|
||||||
instancer.drawAll(stack, buffer);
|
instancer.drawAll(stack, buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,41 +42,44 @@ public class BatchedMaterialGroup implements MaterialGroup {
|
||||||
if (buffer instanceof DirectBufferBuilder direct) {
|
if (buffer instanceof DirectBufferBuilder direct) {
|
||||||
renderParallel(stack, pool, direct);
|
renderParallel(stack, pool, direct);
|
||||||
} else {
|
} else {
|
||||||
renderSerial(stack, buffer, FormatContext.defaultContext());
|
renderSerial(stack, buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderParallel(PoseStack stack, TaskEngine pool, DirectBufferBuilder direct) {
|
private void renderParallel(PoseStack stack, TaskEngine pool, DirectBufferBuilder direct) {
|
||||||
int vertexCount = calculateNeededVertices();
|
int vertexCount = 0;
|
||||||
|
for (BatchedMaterial<?> material : materials.values()) {
|
||||||
|
for (CPUInstancer<?> instancer : material.models.values()) {
|
||||||
|
instancer.setup();
|
||||||
|
vertexCount += instancer.getTotalVertexCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DirectVertexConsumer consumer = direct.intoDirectConsumer(vertexCount);
|
DirectVertexConsumer consumer = direct.intoDirectConsumer(vertexCount);
|
||||||
FormatContext context = new FormatContext(consumer.hasOverlay());
|
|
||||||
|
// avoids rendering garbage, but doesn't fix the issue of some instances not being buffered
|
||||||
|
consumer.memSetZero();
|
||||||
|
|
||||||
for (BatchedMaterial<?> material : materials.values()) {
|
for (BatchedMaterial<?> material : materials.values()) {
|
||||||
for (CPUInstancer<?> instancer : material.models.values()) {
|
for (CPUInstancer<?> instancer : material.models.values()) {
|
||||||
instancer.setup(context);
|
if (consumer.hasOverlay()) {
|
||||||
|
instancer.sbb.context.fullNormalTransform = false;
|
||||||
|
instancer.sbb.context.outputColorDiffuse = false;
|
||||||
|
} else {
|
||||||
|
instancer.sbb.context.fullNormalTransform = false;
|
||||||
|
instancer.sbb.context.outputColorDiffuse = true;
|
||||||
|
}
|
||||||
instancer.submitTasks(stack, pool, consumer);
|
instancer.submitTasks(stack, pool, consumer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderSerial(PoseStack stack, VertexConsumer consumer, FormatContext context) {
|
private void renderSerial(PoseStack stack, VertexConsumer consumer) {
|
||||||
for (BatchedMaterial<?> value : materials.values()) {
|
for (BatchedMaterial<?> value : materials.values()) {
|
||||||
value.render(stack, consumer, context);
|
value.setupAndRenderInto(stack, consumer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int calculateNeededVertices() {
|
|
||||||
int total = 0;
|
|
||||||
for (BatchedMaterial<?> material : materials.values()) {
|
|
||||||
for (CPUInstancer<?> instancer : material.models.values()) {
|
|
||||||
total += instancer.getTotalVertexCount();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
materials.values().forEach(BatchedMaterial::clear);
|
materials.values().forEach(BatchedMaterial::clear);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,9 @@ import com.jozufozu.flywheel.backend.RenderLayer;
|
||||||
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
||||||
import com.jozufozu.flywheel.backend.instancing.Engine;
|
import com.jozufozu.flywheel.backend.instancing.Engine;
|
||||||
import com.jozufozu.flywheel.event.RenderLayerEvent;
|
import com.jozufozu.flywheel.event.RenderLayerEvent;
|
||||||
|
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
|
|
||||||
import net.minecraft.client.Camera;
|
import net.minecraft.client.Camera;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
@ -17,8 +19,9 @@ import net.minecraft.client.renderer.RenderType;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Vec3i;
|
import net.minecraft.core.Vec3i;
|
||||||
|
|
||||||
public class BatchingEngine implements Engine {
|
public class BatchingEngine implements Engine, MultiBufferSource {
|
||||||
|
|
||||||
|
protected final Map<RenderType, BufferBuilder> buffers = new HashMap<>();
|
||||||
protected final Map<RenderLayer, Map<RenderType, BatchedMaterialGroup>> layers;
|
protected final Map<RenderLayer, Map<RenderType, BatchedMaterialGroup>> layers;
|
||||||
protected final TaskEngine taskEngine;
|
protected final TaskEngine taskEngine;
|
||||||
|
|
||||||
|
@ -42,7 +45,7 @@ public class BatchingEngine implements Engine {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(RenderLayerEvent event, MultiBufferSource buffers) {
|
public void render(RenderLayerEvent event) {
|
||||||
PoseStack stack = event.stack;
|
PoseStack stack = event.stack;
|
||||||
|
|
||||||
stack.pushPose();
|
stack.pushPose();
|
||||||
|
@ -50,14 +53,27 @@ public class BatchingEngine implements Engine {
|
||||||
stack.translate(-event.camX, -event.camY, -event.camZ);
|
stack.translate(-event.camX, -event.camY, -event.camZ);
|
||||||
|
|
||||||
for (BatchedMaterialGroup group : layers.get(event.getLayer()).values()) {
|
for (BatchedMaterialGroup group : layers.get(event.getLayer()).values()) {
|
||||||
group.render(stack, buffers, taskEngine);
|
group.render(stack, this, taskEngine);
|
||||||
}
|
}
|
||||||
|
|
||||||
taskEngine.syncPoint();
|
taskEngine.syncPoint();
|
||||||
|
|
||||||
stack.popPose();
|
stack.popPose();
|
||||||
|
|
||||||
event.buffers.bufferSource().endBatch();
|
// TODO: when/if this causes trouble with shaders, try to inject our BufferBuilders
|
||||||
|
// into the RenderBuffers from context.
|
||||||
|
buffers.forEach((type, builder) -> type.end(builder, 0, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VertexConsumer getBuffer(RenderType renderType) {
|
||||||
|
BufferBuilder builder = buffers.computeIfAbsent(renderType, type -> new BufferBuilder(type.bufferSize()));
|
||||||
|
|
||||||
|
if (!builder.building()) {
|
||||||
|
builder.begin(renderType.mode(), renderType.format());
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -2,12 +2,12 @@ package com.jozufozu.flywheel.backend.instancing.batching;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.InstanceData;
|
import com.jozufozu.flywheel.api.InstanceData;
|
||||||
import com.jozufozu.flywheel.api.struct.Batched;
|
import com.jozufozu.flywheel.api.struct.Batched;
|
||||||
import com.jozufozu.flywheel.api.struct.StructType;
|
|
||||||
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
|
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
|
||||||
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
||||||
import com.jozufozu.flywheel.backend.model.DirectVertexConsumer;
|
import com.jozufozu.flywheel.backend.model.DirectVertexConsumer;
|
||||||
import com.jozufozu.flywheel.core.model.Model;
|
import com.jozufozu.flywheel.core.model.Model;
|
||||||
import com.jozufozu.flywheel.core.model.ModelTransformer;
|
import com.jozufozu.flywheel.core.model.ModelTransformer;
|
||||||
|
import com.jozufozu.flywheel.util.Color;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
|
|
||||||
|
@ -15,15 +15,14 @@ public class CPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
||||||
|
|
||||||
private final Batched<D> batchingType;
|
private final Batched<D> batchingType;
|
||||||
|
|
||||||
private final ModelTransformer sbb;
|
final ModelTransformer sbb;
|
||||||
private final ModelTransformer.Params defaultParams;
|
|
||||||
|
|
||||||
public CPUInstancer(Batched<D> type, Model modelData) {
|
public CPUInstancer(Batched<D> type, Model modelData) {
|
||||||
super(type::create, modelData);
|
super(type::create, modelData);
|
||||||
batchingType = type;
|
batchingType = type;
|
||||||
|
|
||||||
sbb = new ModelTransformer(modelData);
|
sbb = new ModelTransformer(modelData);
|
||||||
defaultParams = ModelTransformer.Params.defaultParams();
|
modelData.configure(sbb.context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void submitTasks(PoseStack stack, TaskEngine pool, DirectVertexConsumer consumer) {
|
void submitTasks(PoseStack stack, TaskEngine pool, DirectVertexConsumer consumer) {
|
||||||
|
@ -42,43 +41,47 @@ public class CPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void notifyDirty() {
|
|
||||||
// noop
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawRange(PoseStack stack, VertexConsumer buffer, int from, int to) {
|
private void drawRange(PoseStack stack, VertexConsumer buffer, int from, int to) {
|
||||||
ModelTransformer.Params params = defaultParams.copy();
|
ModelTransformer.Params params = new ModelTransformer.Params();
|
||||||
|
|
||||||
|
// Color color = Color.generateFromLong(from);
|
||||||
|
|
||||||
for (D d : data.subList(from, to)) {
|
for (D d : data.subList(from, to)) {
|
||||||
|
params.loadDefault();
|
||||||
|
|
||||||
batchingType.transform(d, params);
|
batchingType.transform(d, params);
|
||||||
|
|
||||||
sbb.renderInto(params, stack, buffer);
|
//params.color(color.getRGB());
|
||||||
|
|
||||||
params.load(defaultParams);
|
sbb.renderInto(params, stack, buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawAll(PoseStack stack, VertexConsumer buffer) {
|
void drawAll(PoseStack stack, VertexConsumer buffer) {
|
||||||
ModelTransformer.Params params = defaultParams.copy();
|
ModelTransformer.Params params = new ModelTransformer.Params();
|
||||||
for (D d : data) {
|
for (D d : data) {
|
||||||
|
params.loadDefault();
|
||||||
|
|
||||||
batchingType.transform(d, params);
|
batchingType.transform(d, params);
|
||||||
|
|
||||||
sbb.renderInto(params, stack, buffer);
|
sbb.renderInto(params, stack, buffer);
|
||||||
|
|
||||||
params.load(defaultParams);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup(FormatContext context) {
|
void setup() {
|
||||||
if (anyToRemove) {
|
if (anyToRemove) {
|
||||||
removeDeletedInstances();
|
data.removeIf(InstanceData::isRemoved);
|
||||||
anyToRemove = false;
|
anyToRemove = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.usesOverlay()) {
|
if (false) {
|
||||||
defaultParams.overlay();
|
this.sbb.context.outputColorDiffuse = false;
|
||||||
|
this.sbb.context.fullNormalTransform = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyDirty() {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
package com.jozufozu.flywheel.backend.instancing.batching;
|
|
||||||
|
|
||||||
public record FormatContext(boolean usesOverlay) {
|
|
||||||
|
|
||||||
public static FormatContext defaultContext() {
|
|
||||||
return new FormatContext(false);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -14,8 +14,8 @@ import com.jozufozu.flywheel.backend.RenderWork;
|
||||||
import com.jozufozu.flywheel.backend.model.ImmediateAllocator;
|
import com.jozufozu.flywheel.backend.model.ImmediateAllocator;
|
||||||
import com.jozufozu.flywheel.backend.model.ModelAllocator;
|
import com.jozufozu.flywheel.backend.model.ModelAllocator;
|
||||||
import com.jozufozu.flywheel.backend.model.ModelPool;
|
import com.jozufozu.flywheel.backend.model.ModelPool;
|
||||||
import com.jozufozu.flywheel.core.Formats;
|
|
||||||
import com.jozufozu.flywheel.core.model.Model;
|
import com.jozufozu.flywheel.core.model.Model;
|
||||||
|
import com.jozufozu.flywheel.core.vertex.PosNormalTexType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A collection of Instancers that all have the same format.
|
* A collection of Instancers that all have the same format.
|
||||||
|
@ -33,7 +33,7 @@ public class InstancedMaterial<D extends InstanceData> implements Material<D> {
|
||||||
if (Backend.getInstance().compat.onAMDWindows()) {
|
if (Backend.getInstance().compat.onAMDWindows()) {
|
||||||
allocator = ImmediateAllocator.INSTANCE;
|
allocator = ImmediateAllocator.INSTANCE;
|
||||||
} else {
|
} else {
|
||||||
allocator = new ModelPool(Formats.UNLIT_MODEL, 64);
|
allocator = new ModelPool(PosNormalTexType.INSTANCE, 64);
|
||||||
}
|
}
|
||||||
this.models = CacheBuilder.newBuilder()
|
this.models = CacheBuilder.newBuilder()
|
||||||
.removalListener(notification -> {
|
.removalListener(notification -> {
|
||||||
|
|
|
@ -82,7 +82,7 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
||||||
* Render every model for every material.
|
* Render every model for every material.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void render(RenderLayerEvent event, MultiBufferSource buffers) {
|
public void render(RenderLayerEvent event) {
|
||||||
double camX;
|
double camX;
|
||||||
double camY;
|
double camY;
|
||||||
double camZ;
|
double camZ;
|
||||||
|
|
|
@ -34,7 +34,7 @@ public class BufferedModel implements IBufferedModel {
|
||||||
|
|
||||||
// mirror it in system memory so we can write to it, and upload our model.
|
// mirror it in system memory so we can write to it, and upload our model.
|
||||||
try (MappedBuffer buffer = vbo.getBuffer(0, model.size())) {
|
try (MappedBuffer buffer = vbo.getBuffer(0, model.size())) {
|
||||||
model.buffer(new VecBufferWriter(buffer));
|
model.getType().copyInto(buffer.unwrap(), model.getReader());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Flywheel.log.error(String.format("Error uploading model '%s':", model.name()), e);
|
Flywheel.log.error(String.format("Error uploading model '%s':", model.name()), e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,20 @@
|
||||||
package com.jozufozu.flywheel.backend.model;
|
package com.jozufozu.flywheel.backend.model;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Duck interface used on {@link BufferBuilder} to provide lower level access to the backing memory.
|
||||||
|
*/
|
||||||
public interface DirectBufferBuilder {
|
public interface DirectBufferBuilder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a DirectVertexConsumer from this BufferBuilder.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* After this function returns, the internal state of the BufferBuilder will be as if
|
||||||
|
* {@link BufferBuilder#endVertex()} was called vertexCount times. It is up to the callee
|
||||||
|
* to actually populate the BufferBuilder with vertices using the returned value.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
DirectVertexConsumer intoDirectConsumer(int vertexCount);
|
DirectVertexConsumer intoDirectConsumer(int vertexCount);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,11 @@ import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
import com.mojang.blaze3d.vertex.VertexFormatElement;
|
import com.mojang.blaze3d.vertex.VertexFormatElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An unsafe vertex consumer allowing for unchecked writes into a ByteBuffer.
|
||||||
|
*
|
||||||
|
* @see DirectBufferBuilder
|
||||||
|
*/
|
||||||
public class DirectVertexConsumer implements VertexConsumer {
|
public class DirectVertexConsumer implements VertexConsumer {
|
||||||
public final VertexFormat format;
|
public final VertexFormat format;
|
||||||
private final int stride;
|
private final int stride;
|
||||||
|
@ -68,12 +73,16 @@ public class DirectVertexConsumer implements VertexConsumer {
|
||||||
this.end = parent.vertexBase + (long) maxVertices * this.stride;
|
this.end = parent.vertexBase + (long) maxVertices * this.stride;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void memSetZero() {
|
||||||
|
MemoryUtil.memSet(vertexBase, 0, end - vertexBase);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasOverlay() {
|
public boolean hasOverlay() {
|
||||||
return uv1 >= 0;
|
return uv1 >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Split off the head of this consumer into a new object and advance our write-pointer.
|
* Split off the head of this consumer into a new object and advance this object's write-pointer.
|
||||||
* @param vertexCount The number of vertices that must be written to the head.
|
* @param vertexCount The number of vertices that must be written to the head.
|
||||||
* @return The head of this consumer.
|
* @return The head of this consumer.
|
||||||
*/
|
*/
|
||||||
|
@ -102,8 +111,8 @@ public class DirectVertexConsumer implements VertexConsumer {
|
||||||
public VertexConsumer color(int r, int g, int b, int a) {
|
public VertexConsumer color(int r, int g, int b, int a) {
|
||||||
if (color < 0) return this;
|
if (color < 0) return this;
|
||||||
long base = vertexBase + color;
|
long base = vertexBase + color;
|
||||||
int color = ((r & 0xFF)) | ((g & 0xFF) << 8) | ((b & 0xFF) << 16) | ((a & 0xFF) << 24);
|
// int color = ((r & 0xFF)) | ((g & 0xFF) << 8) | ((b & 0xFF) << 16) | ((a & 0xFF) << 24);
|
||||||
//MemoryUtil.memPutInt(base, color);
|
// MemoryUtil.memPutInt(base, color);
|
||||||
MemoryUtil.memPutByte(base, (byte) r);
|
MemoryUtil.memPutByte(base, (byte) r);
|
||||||
MemoryUtil.memPutByte(base + 1, (byte) g);
|
MemoryUtil.memPutByte(base + 1, (byte) g);
|
||||||
MemoryUtil.memPutByte(base + 2, (byte) b);
|
MemoryUtil.memPutByte(base + 2, (byte) b);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.jozufozu.flywheel.backend.model;
|
package com.jozufozu.flywheel.backend.model;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -13,12 +14,12 @@ import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
|
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
|
||||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedGlBuffer;
|
import com.jozufozu.flywheel.backend.gl.buffer.MappedGlBuffer;
|
||||||
import com.jozufozu.flywheel.core.model.Model;
|
import com.jozufozu.flywheel.core.model.Model;
|
||||||
import com.jozufozu.flywheel.core.model.VecBufferWriter;
|
import com.jozufozu.flywheel.core.vertex.VertexType;
|
||||||
import com.jozufozu.flywheel.util.AttribUtil;
|
import com.jozufozu.flywheel.util.AttribUtil;
|
||||||
|
|
||||||
public class ModelPool implements ModelAllocator {
|
public class ModelPool implements ModelAllocator {
|
||||||
|
|
||||||
protected final VertexFormat format;
|
protected final VertexType vertexType;
|
||||||
|
|
||||||
private final List<PooledModel> models = new ArrayList<>();
|
private final List<PooledModel> models = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -32,9 +33,9 @@ public class ModelPool implements ModelAllocator {
|
||||||
private boolean dirty;
|
private boolean dirty;
|
||||||
private boolean anyToRemove;
|
private boolean anyToRemove;
|
||||||
|
|
||||||
public ModelPool(VertexFormat format, int initialSize) {
|
public ModelPool(VertexType vertexType, int initialSize) {
|
||||||
this.format = format;
|
this.vertexType = vertexType;
|
||||||
bufferSize = format.getStride() * initialSize;
|
bufferSize = vertexType.getStride() * initialSize;
|
||||||
|
|
||||||
vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER);
|
vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER);
|
||||||
|
|
||||||
|
@ -104,7 +105,7 @@ public class ModelPool implements ModelAllocator {
|
||||||
* @return true if the buffer was reallocated
|
* @return true if the buffer was reallocated
|
||||||
*/
|
*/
|
||||||
private boolean realloc() {
|
private boolean realloc() {
|
||||||
int neededSize = vertices * format.getStride();
|
int neededSize = vertices * vertexType.getStride();
|
||||||
if (neededSize > bufferSize) {
|
if (neededSize > bufferSize) {
|
||||||
bufferSize = neededSize + 128;
|
bufferSize = neededSize + 128;
|
||||||
vbo.alloc(bufferSize);
|
vbo.alloc(bufferSize);
|
||||||
|
@ -117,14 +118,14 @@ public class ModelPool implements ModelAllocator {
|
||||||
|
|
||||||
private void uploadAll() {
|
private void uploadAll() {
|
||||||
try (MappedBuffer buffer = vbo.getBuffer(0, bufferSize)) {
|
try (MappedBuffer buffer = vbo.getBuffer(0, bufferSize)) {
|
||||||
|
ByteBuffer buf = buffer.unwrap();
|
||||||
VecBufferWriter consumer = new VecBufferWriter(buffer);
|
|
||||||
|
|
||||||
int vertices = 0;
|
int vertices = 0;
|
||||||
for (PooledModel model : models) {
|
for (PooledModel model : models) {
|
||||||
model.first = vertices;
|
model.first = vertices;
|
||||||
model.model.buffer(consumer);
|
|
||||||
if (model.callback != null) model.callback.onAlloc(model);
|
buffer(buf, model);
|
||||||
|
|
||||||
vertices += model.getVertexCount();
|
vertices += model.getVertexCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,14 +136,9 @@ public class ModelPool implements ModelAllocator {
|
||||||
|
|
||||||
private void uploadPending() {
|
private void uploadPending() {
|
||||||
try (MappedBuffer buffer = vbo.getBuffer(0, bufferSize)) {
|
try (MappedBuffer buffer = vbo.getBuffer(0, bufferSize)) {
|
||||||
VecBufferWriter consumer = new VecBufferWriter(buffer);
|
ByteBuffer buf = buffer.unwrap();
|
||||||
|
|
||||||
int stride = format.getStride();
|
|
||||||
for (PooledModel model : pendingUpload) {
|
for (PooledModel model : pendingUpload) {
|
||||||
int pos = model.first * stride;
|
buffer(buf, model);
|
||||||
buffer.position(pos);
|
|
||||||
model.model.buffer(consumer);
|
|
||||||
if (model.callback != null) model.callback.onAlloc(model);
|
|
||||||
}
|
}
|
||||||
pendingUpload.clear();
|
pendingUpload.clear();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -150,6 +146,13 @@ public class ModelPool implements ModelAllocator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void buffer(ByteBuffer buf, PooledModel model) {
|
||||||
|
int pos = model.first * vertexType.getStride();
|
||||||
|
buf.position(pos);
|
||||||
|
vertexType.copyInto(buf, model.model.getReader());
|
||||||
|
if (model.callback != null) model.callback.onAlloc(model);
|
||||||
|
}
|
||||||
|
|
||||||
private void setDirty() {
|
private void setDirty() {
|
||||||
dirty = true;
|
dirty = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
||||||
|
|
||||||
public class Formats {
|
public class Formats {
|
||||||
public static final VertexFormat UNLIT_MODEL = VertexFormat.builder()
|
public static final VertexFormat UNLIT_MODEL = VertexFormat.builder()
|
||||||
.addAttributes(CommonAttributes.VEC3, CommonAttributes.NORMAL, CommonAttributes.UV)
|
.addAttributes(CommonAttributes.VEC3, CommonAttributes.UV, CommonAttributes.NORMAL)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
public static final VertexFormat COLORED_LIT_MODEL = VertexFormat.builder()
|
public static final VertexFormat COLORED_LIT_MODEL = VertexFormat.builder()
|
||||||
|
|
|
@ -77,7 +77,7 @@ public class CrumblingRenderer {
|
||||||
|
|
||||||
instanceManager.beginFrame(info);
|
instanceManager.beginFrame(info);
|
||||||
|
|
||||||
materials.render(event, null);
|
materials.render(event);
|
||||||
|
|
||||||
instanceManager.invalidate();
|
instanceManager.invalidate();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
package com.jozufozu.flywheel.core.model;
|
package com.jozufozu.flywheel.core.model;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
import com.jozufozu.flywheel.util.UnsafeBlockFormatReader;
|
||||||
import com.jozufozu.flywheel.core.Formats;
|
|
||||||
import com.jozufozu.flywheel.util.BufferBuilderReader;
|
|
||||||
import com.jozufozu.flywheel.util.ModelReader;
|
import com.jozufozu.flywheel.util.ModelReader;
|
||||||
import com.jozufozu.flywheel.util.RenderMath;
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.resources.model.BakedModel;
|
import net.minecraft.client.resources.model.BakedModel;
|
||||||
|
@ -33,38 +29,27 @@ public class BlockModel implements Model {
|
||||||
}
|
}
|
||||||
|
|
||||||
public BlockModel(BakedModel model, BlockState referenceState, PoseStack ms) {
|
public BlockModel(BakedModel model, BlockState referenceState, PoseStack ms) {
|
||||||
reader = new BufferBuilderReader(ModelUtil.getBufferBuilder(model, referenceState, ms));
|
reader = new UnsafeBlockFormatReader(ModelUtil.getBufferBuilder(model, referenceState, ms));
|
||||||
name = referenceState.toString();
|
name = referenceState.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configure(ModelTransformer.Context ctx) {
|
||||||
|
ctx.inputHasDiffuse = true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String name() {
|
public String name() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public VertexFormat format() {
|
|
||||||
return Formats.UNLIT_MODEL;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int vertexCount() {
|
public int vertexCount() {
|
||||||
return reader.getVertexCount();
|
return reader.getVertexCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void buffer(VertexConsumer buffer) {
|
public ModelReader getReader() {
|
||||||
|
return reader;
|
||||||
int vertexCount = vertexCount();
|
|
||||||
|
|
||||||
for (int i = 0; i < vertexCount; i++) {
|
|
||||||
buffer.vertex(reader.getX(i), reader.getY(i), reader.getZ(i));
|
|
||||||
|
|
||||||
buffer.normal(reader.getNX(i), reader.getNY(i), reader.getNZ(i));
|
|
||||||
|
|
||||||
buffer.uv(reader.getU(i), reader.getV(i));
|
|
||||||
|
|
||||||
buffer.endVertex();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
package com.jozufozu.flywheel.core.model;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
||||||
|
import com.jozufozu.flywheel.core.Formats;
|
||||||
|
import com.jozufozu.flywheel.core.vertex.VertexType;
|
||||||
|
import com.jozufozu.flywheel.util.ModelReader;
|
||||||
|
import com.jozufozu.flywheel.util.RenderMath;
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.LightTexture;
|
||||||
|
|
||||||
|
public class BlockType implements VertexType {
|
||||||
|
|
||||||
|
public static final BlockType INSTANCE = new BlockType();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VertexFormat getFormat() {
|
||||||
|
return Formats.COLORED_LIT_MODEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copyInto(ByteBuffer buffer, ModelReader reader) {
|
||||||
|
int stride = getStride();
|
||||||
|
long addr = MemoryUtil.memAddress(buffer);
|
||||||
|
|
||||||
|
int vertexCount = reader.getVertexCount();
|
||||||
|
for (int i = 0; i < vertexCount; i++) {
|
||||||
|
float x = reader.getX(i);
|
||||||
|
float y = reader.getY(i);
|
||||||
|
float z = reader.getZ(i);
|
||||||
|
|
||||||
|
float xN = reader.getNX(i);
|
||||||
|
float yN = reader.getNY(i);
|
||||||
|
float zN = reader.getNZ(i);
|
||||||
|
|
||||||
|
float u = reader.getU(i);
|
||||||
|
float v = reader.getV(i);
|
||||||
|
|
||||||
|
byte r = reader.getR(i);
|
||||||
|
byte g = reader.getG(i);
|
||||||
|
byte b = reader.getB(i);
|
||||||
|
byte a = reader.getA(i);
|
||||||
|
|
||||||
|
int light = reader.getLight(i);
|
||||||
|
|
||||||
|
MemoryUtil.memPutFloat(addr, x);
|
||||||
|
MemoryUtil.memPutFloat(addr + 4, y);
|
||||||
|
MemoryUtil.memPutFloat(addr + 8, z);
|
||||||
|
MemoryUtil.memPutByte(addr + 12, RenderMath.nb(xN));
|
||||||
|
MemoryUtil.memPutByte(addr + 13, RenderMath.nb(yN));
|
||||||
|
MemoryUtil.memPutByte(addr + 14, RenderMath.nb(zN));
|
||||||
|
MemoryUtil.memPutFloat(addr + 15, u);
|
||||||
|
MemoryUtil.memPutFloat(addr + 19, v);
|
||||||
|
MemoryUtil.memPutByte(addr + 23, r);
|
||||||
|
MemoryUtil.memPutByte(addr + 24, g);
|
||||||
|
MemoryUtil.memPutByte(addr + 25, b);
|
||||||
|
MemoryUtil.memPutByte(addr + 26, a);
|
||||||
|
|
||||||
|
byte block = (byte) (LightTexture.block(light) << 4);
|
||||||
|
byte sky = (byte) (LightTexture.sky(light) << 4);
|
||||||
|
|
||||||
|
MemoryUtil.memPutByte(addr + 27, block);
|
||||||
|
MemoryUtil.memPutByte(addr + 28, sky);
|
||||||
|
|
||||||
|
addr += stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,8 +3,9 @@ package com.jozufozu.flywheel.core.model;
|
||||||
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
||||||
import com.jozufozu.flywheel.backend.model.ElementBuffer;
|
import com.jozufozu.flywheel.backend.model.ElementBuffer;
|
||||||
import com.jozufozu.flywheel.core.QuadConverter;
|
import com.jozufozu.flywheel.core.QuadConverter;
|
||||||
|
import com.jozufozu.flywheel.core.vertex.PosNormalTexType;
|
||||||
|
import com.jozufozu.flywheel.core.vertex.VertexType;
|
||||||
import com.jozufozu.flywheel.util.ModelReader;
|
import com.jozufozu.flywheel.util.ModelReader;
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A model that can be rendered by flywheel.
|
* A model that can be rendered by flywheel.
|
||||||
|
@ -33,20 +34,27 @@ public interface Model {
|
||||||
*/
|
*/
|
||||||
String name();
|
String name();
|
||||||
|
|
||||||
/**
|
ModelReader getReader();
|
||||||
* Copy this model into the given buffer.
|
|
||||||
*/
|
|
||||||
void buffer(VertexConsumer buffer);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The number of vertices the model has.
|
* @return The number of vertices the model has.
|
||||||
*/
|
*/
|
||||||
int vertexCount();
|
int vertexCount();
|
||||||
|
|
||||||
|
default void configure(ModelTransformer.Context ctx) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
default VertexType getType() {
|
||||||
|
return PosNormalTexType.INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The format of this model's vertices
|
* @return The format of this model's vertices
|
||||||
*/
|
*/
|
||||||
VertexFormat format();
|
default VertexFormat format() {
|
||||||
|
return getType().getFormat();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an element buffer object that indexes the vertices of this model.
|
* Create an element buffer object that indexes the vertices of this model.
|
||||||
|
@ -77,6 +85,4 @@ public interface Model {
|
||||||
default boolean empty() {
|
default boolean empty() {
|
||||||
return vertexCount() == 0;
|
return vertexCount() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelReader getReader();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,29 +3,35 @@ package com.jozufozu.flywheel.core.model;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
import com.jozufozu.flywheel.core.vertex.PosNormalTexReader;
|
||||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
import com.jozufozu.flywheel.core.vertex.PosTexNormalWriter;
|
||||||
import com.jozufozu.flywheel.core.Formats;
|
|
||||||
import com.jozufozu.flywheel.util.ModelReader;
|
import com.jozufozu.flywheel.util.ModelReader;
|
||||||
import com.jozufozu.flywheel.util.RenderMath;
|
import com.mojang.blaze3d.platform.MemoryTracker;
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
|
||||||
import com.mojang.math.Vector3f;
|
|
||||||
|
|
||||||
public class ModelPart implements Model {
|
public class ModelPart implements Model {
|
||||||
|
|
||||||
private final List<PartBuilder.CuboidBuilder> cuboids;
|
private final int vertices;
|
||||||
private int vertices;
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
private final PosNormalTexReader reader;
|
||||||
|
|
||||||
public ModelPart(List<PartBuilder.CuboidBuilder> cuboids, String name) {
|
public ModelPart(List<PartBuilder.CuboidBuilder> cuboids, String name) {
|
||||||
this.cuboids = cuboids;
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
|
||||||
vertices = 0;
|
{
|
||||||
|
int vertices = 0;
|
||||||
for (PartBuilder.CuboidBuilder cuboid : cuboids) {
|
for (PartBuilder.CuboidBuilder cuboid : cuboids) {
|
||||||
vertices += cuboid.vertices();
|
vertices += cuboid.vertices();
|
||||||
|
}
|
||||||
|
this.vertices = vertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ByteBuffer buffer = MemoryTracker.create(size());
|
||||||
|
PosTexNormalWriter writer = new PosTexNormalWriter(buffer);
|
||||||
|
for (PartBuilder.CuboidBuilder cuboid : cuboids) {
|
||||||
|
cuboid.buffer(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
reader = new PosNormalTexReader(buffer, vertices);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PartBuilder builder(String name, int sizeU, int sizeV) {
|
public static PartBuilder builder(String name, int sizeU, int sizeV) {
|
||||||
|
@ -37,111 +43,13 @@ public class ModelPart implements Model {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void buffer(VertexConsumer buffer) {
|
|
||||||
for (PartBuilder.CuboidBuilder cuboid : cuboids) {
|
|
||||||
cuboid.buffer(buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int vertexCount() {
|
public int vertexCount() {
|
||||||
return vertices;
|
return vertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public VertexFormat format() {
|
|
||||||
return Formats.UNLIT_MODEL;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ModelReader getReader() {
|
public ModelReader getReader() {
|
||||||
return new PartReader(this);
|
return reader;
|
||||||
}
|
|
||||||
|
|
||||||
private class PartReader implements ModelReader {
|
|
||||||
|
|
||||||
private final ByteBuffer buffer;
|
|
||||||
|
|
||||||
private PartReader(ModelPart part) {
|
|
||||||
this.buffer = ByteBuffer.allocate(part.size());
|
|
||||||
VecBufferWriter writer = new VecBufferWriter(this.buffer);
|
|
||||||
|
|
||||||
buffer(writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int vertIdx(int vertexIndex) {
|
|
||||||
return vertexIndex * format().getStride();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float getX(int index) {
|
|
||||||
return buffer.getFloat(vertIdx(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float getY(int index) {
|
|
||||||
return buffer.getFloat(vertIdx(index) + 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float getZ(int index) {
|
|
||||||
return buffer.getFloat(vertIdx(index) + 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte getR(int index) {
|
|
||||||
return (byte) 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte getG(int index) {
|
|
||||||
return (byte) 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte getB(int index) {
|
|
||||||
return (byte) 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte getA(int index) {
|
|
||||||
return (byte) 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float getU(int index) {
|
|
||||||
return buffer.getFloat(vertIdx(index) + 15);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float getV(int index) {
|
|
||||||
return buffer.getFloat(vertIdx(index) + 19);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getLight(int index) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float getNX(int index) {
|
|
||||||
return RenderMath.f(buffer.get(vertIdx(index) + 12));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float getNY(int index) {
|
|
||||||
return RenderMath.f(buffer.get(vertIdx(index) + 13));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float getNZ(int index) {
|
|
||||||
return RenderMath.f(buffer.get(vertIdx(index) + 14));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getVertexCount() {
|
|
||||||
return vertices;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.jozufozu.flywheel.core.model;
|
package com.jozufozu.flywheel.core.model;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.util.ModelReader;
|
import com.jozufozu.flywheel.util.ModelReader;
|
||||||
|
import com.jozufozu.flywheel.util.RenderMath;
|
||||||
import com.jozufozu.flywheel.util.transform.Transform;
|
import com.jozufozu.flywheel.util.transform.Transform;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
|
@ -16,6 +17,8 @@ public class ModelTransformer {
|
||||||
private final Model model;
|
private final Model model;
|
||||||
private final ModelReader reader;
|
private final ModelReader reader;
|
||||||
|
|
||||||
|
public final Context context = new Context();
|
||||||
|
|
||||||
public ModelTransformer(Model model) {
|
public ModelTransformer(Model model) {
|
||||||
this.model = model;
|
this.model = model;
|
||||||
reader = model.getReader();
|
reader = model.getReader();
|
||||||
|
@ -34,7 +37,7 @@ public class ModelTransformer {
|
||||||
modelMat.multiply(params.model);
|
modelMat.multiply(params.model);
|
||||||
|
|
||||||
Matrix3f normalMat;
|
Matrix3f normalMat;
|
||||||
if (params.fullNormalTransform) {
|
if (context.fullNormalTransform) {
|
||||||
normalMat = input.last().normal().copy();
|
normalMat = input.last().normal().copy();
|
||||||
normalMat.mul(params.normal);
|
normalMat.mul(params.normal);
|
||||||
} else {
|
} else {
|
||||||
|
@ -61,42 +64,46 @@ public class ModelTransformer {
|
||||||
float ny = normal.y();
|
float ny = normal.y();
|
||||||
float nz = normal.z();
|
float nz = normal.z();
|
||||||
|
|
||||||
float instanceDiffuse = LightUtil.diffuseLight(nx, ny, nz);
|
if (params.useParamColor) {
|
||||||
|
if (context.outputColorDiffuse) {
|
||||||
switch (params.colorMode) {
|
float instanceDiffuse = LightUtil.diffuseLight(nx, ny, nz);
|
||||||
case MODEL_ONLY -> builder.color(reader.getR(i), reader.getG(i), reader.getB(i), reader.getA(i));
|
|
||||||
case DIFFUSE_ONLY -> builder.color(instanceDiffuse, instanceDiffuse, instanceDiffuse, 1f);
|
|
||||||
case MODEL_DIFFUSE -> {
|
|
||||||
int r = Byte.toUnsignedInt(reader.getR(i));
|
|
||||||
int g = Byte.toUnsignedInt(reader.getG(i));
|
|
||||||
int b = Byte.toUnsignedInt(reader.getB(i));
|
|
||||||
int a = Byte.toUnsignedInt(reader.getA(i));
|
|
||||||
|
|
||||||
float diffuse = switch (params.diffuseMode) {
|
|
||||||
case NONE -> 1f;
|
|
||||||
case INSTANCE -> instanceDiffuse;
|
|
||||||
case ONE_OVER_STATIC -> 1 / LightUtil.diffuseLight(normalX, normalY, normalZ);
|
|
||||||
case INSTANCE_OVER_STATIC -> instanceDiffuse / LightUtil.diffuseLight(normalX, normalY, normalZ);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (diffuse != 1) {
|
|
||||||
r = transformColor(r, diffuse);
|
|
||||||
g = transformColor(g, diffuse);
|
|
||||||
b = transformColor(b, diffuse);
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.color(r, g, b, a);
|
|
||||||
}
|
|
||||||
case RECOLOR -> {
|
|
||||||
if (params.diffuseMode == DiffuseMode.NONE) {
|
|
||||||
builder.color(params.r, params.g, params.b, params.a);
|
|
||||||
} else {
|
|
||||||
int colorR = transformColor(params.r, instanceDiffuse);
|
int colorR = transformColor(params.r, instanceDiffuse);
|
||||||
int colorG = transformColor(params.g, instanceDiffuse);
|
int colorG = transformColor(params.g, instanceDiffuse);
|
||||||
int colorB = transformColor(params.b, instanceDiffuse);
|
int colorB = transformColor(params.b, instanceDiffuse);
|
||||||
builder.color(colorR, colorG, colorB, params.a);
|
builder.color(colorR, colorG, colorB, params.a);
|
||||||
|
} else {
|
||||||
|
builder.color(params.r, params.g, params.b, params.a);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (context.inputHasDiffuse) {
|
||||||
|
int r = Byte.toUnsignedInt(reader.getR(i));
|
||||||
|
int g = Byte.toUnsignedInt(reader.getG(i));
|
||||||
|
int b = Byte.toUnsignedInt(reader.getB(i));
|
||||||
|
int a = Byte.toUnsignedInt(reader.getA(i));
|
||||||
|
|
||||||
|
float undoStaticDiffuse = 1 / LightUtil.diffuseLight(normalX, normalY, normalZ);
|
||||||
|
float diffuse;
|
||||||
|
if (context.outputColorDiffuse) {
|
||||||
|
diffuse = LightUtil.diffuseLight(nx, ny, nz) * undoStaticDiffuse;
|
||||||
|
} else {
|
||||||
|
diffuse = undoStaticDiffuse;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diffuse != 1) {
|
||||||
|
r = transformColor(r, diffuse);
|
||||||
|
g = transformColor(g, diffuse);
|
||||||
|
b = transformColor(b, diffuse);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.color(r, g, b, a);
|
||||||
|
} else {
|
||||||
|
if (context.outputColorDiffuse) {
|
||||||
|
int d = RenderMath.unb(LightUtil.diffuseLight(nx, ny, nz));
|
||||||
|
builder.color(d, d, d, 0xFF);
|
||||||
|
} else {
|
||||||
|
builder.color(reader.getR(i), reader.getG(i), reader.getB(i), reader.getA(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//builder.color(Math.max(0, (int) (nx * 255)), Math.max(0, (int) (ny * 255)), Math.max(0, (int) (nz * 255)), 0xFF);
|
//builder.color(Math.max(0, (int) (nx * 255)), Math.max(0, (int) (ny * 255)), Math.max(0, (int) (nz * 255)), 0xFF);
|
||||||
|
@ -110,11 +117,10 @@ public class ModelTransformer {
|
||||||
builder.uv(u, v);
|
builder.uv(u, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.hasOverlay) {
|
// not always used, but will be ignored by formats that don't use it
|
||||||
builder.overlayCoords(params.overlay);
|
builder.overlayCoords(params.overlay);
|
||||||
}
|
|
||||||
|
|
||||||
builder.uv2(params.hasCustomLight ? params.packedLightCoords : reader.getLight(i));
|
builder.uv2(params.useParamLight ? params.packedLightCoords : reader.getLight(i));
|
||||||
|
|
||||||
builder.normal(nx, ny, nz);
|
builder.normal(nx, ny, nz);
|
||||||
|
|
||||||
|
@ -128,7 +134,7 @@ public class ModelTransformer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "SuperByteBuffer[" + model + ']';
|
return "ModelTransformer[" + model + ']';
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int transformColor(int component, float scale) {
|
public static int transformColor(int component, float scale) {
|
||||||
|
@ -140,28 +146,32 @@ public class ModelTransformer {
|
||||||
void shift(VertexConsumer builder, float u, float v);
|
void shift(VertexConsumer builder, float u, float v);
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ColorMode {
|
public static class Context {
|
||||||
MODEL_ONLY,
|
/**
|
||||||
MODEL_DIFFUSE,
|
* Do we need to include the PoseStack transforms in our transformation of the normal?
|
||||||
DIFFUSE_ONLY,
|
*/
|
||||||
RECOLOR
|
public boolean fullNormalTransform = false;
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* Does the model we're transforming have diffuse light baked into its colors?
|
||||||
|
*/
|
||||||
|
public boolean inputHasDiffuse = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do we need to bake diffuse lighting into the output colors?
|
||||||
|
*/
|
||||||
|
public boolean outputColorDiffuse = true;
|
||||||
|
|
||||||
public enum DiffuseMode {
|
|
||||||
NONE,
|
|
||||||
INSTANCE,
|
|
||||||
ONE_OVER_STATIC,
|
|
||||||
INSTANCE_OVER_STATIC,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Params implements Transform<Params> {
|
public static class Params implements Transform<Params> {
|
||||||
// Vertex Position
|
|
||||||
|
// Transform
|
||||||
public final Matrix4f model;
|
public final Matrix4f model;
|
||||||
public final Matrix3f normal;
|
public final Matrix3f normal;
|
||||||
|
|
||||||
// Vertex Coloring
|
// Vertex Coloring
|
||||||
public ColorMode colorMode;
|
public boolean useParamColor;
|
||||||
public DiffuseMode diffuseMode;
|
|
||||||
public int r;
|
public int r;
|
||||||
public int g;
|
public int g;
|
||||||
public int b;
|
public int b;
|
||||||
|
@ -171,46 +181,47 @@ public class ModelTransformer {
|
||||||
public SpriteShiftFunc spriteShiftFunc;
|
public SpriteShiftFunc spriteShiftFunc;
|
||||||
|
|
||||||
// Vertex Overlay Color
|
// Vertex Overlay Color
|
||||||
public boolean hasOverlay;
|
|
||||||
public int overlay;
|
public int overlay;
|
||||||
|
|
||||||
// Vertex Lighting
|
// Vertex Lighting
|
||||||
public boolean hasCustomLight;
|
public boolean useParamLight;
|
||||||
public int packedLightCoords;
|
public int packedLightCoords;
|
||||||
|
|
||||||
// Vertex Normals
|
|
||||||
public boolean fullNormalTransform;
|
|
||||||
|
|
||||||
public Params() {
|
public Params() {
|
||||||
model = new Matrix4f();
|
model = new Matrix4f();
|
||||||
normal = new Matrix3f();
|
normal = new Matrix3f();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void loadDefault() {
|
||||||
|
model.setIdentity();
|
||||||
|
normal.setIdentity();
|
||||||
|
useParamColor = true;
|
||||||
|
r = 0xFF;
|
||||||
|
g = 0xFF;
|
||||||
|
b = 0xFF;
|
||||||
|
a = 0xFF;
|
||||||
|
spriteShiftFunc = null;
|
||||||
|
overlay = OverlayTexture.NO_OVERLAY;
|
||||||
|
useParamLight = false;
|
||||||
|
packedLightCoords = LightTexture.FULL_BRIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
public void load(Params from) {
|
public void load(Params from) {
|
||||||
model.load(from.model);
|
model.load(from.model);
|
||||||
normal.load(from.normal);
|
normal.load(from.normal);
|
||||||
colorMode = from.colorMode;
|
useParamColor = from.useParamColor;
|
||||||
diffuseMode = from.diffuseMode;
|
|
||||||
r = from.r;
|
r = from.r;
|
||||||
g = from.g;
|
g = from.g;
|
||||||
b = from.b;
|
b = from.b;
|
||||||
a = from.a;
|
a = from.a;
|
||||||
spriteShiftFunc = from.spriteShiftFunc;
|
spriteShiftFunc = from.spriteShiftFunc;
|
||||||
hasOverlay = from.hasOverlay;
|
|
||||||
overlay = from.overlay;
|
overlay = from.overlay;
|
||||||
hasCustomLight = from.hasCustomLight;
|
useParamLight = from.useParamLight;
|
||||||
packedLightCoords = from.packedLightCoords;
|
packedLightCoords = from.packedLightCoords;
|
||||||
fullNormalTransform = from.fullNormalTransform;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Params copy() {
|
|
||||||
Params params = new Params();
|
|
||||||
params.load(this);
|
|
||||||
return params;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Params color(int r, int g, int b, int a) {
|
public Params color(int r, int g, int b, int a) {
|
||||||
this.colorMode = ColorMode.RECOLOR;
|
this.useParamColor = true;
|
||||||
this.r = r;
|
this.r = r;
|
||||||
this.g = g;
|
this.g = g;
|
||||||
this.b = b;
|
this.b = b;
|
||||||
|
@ -219,7 +230,7 @@ public class ModelTransformer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Params color(byte r, byte g, byte b, byte a) {
|
public Params color(byte r, byte g, byte b, byte a) {
|
||||||
this.colorMode = ColorMode.RECOLOR;
|
this.useParamColor = true;
|
||||||
this.r = Byte.toUnsignedInt(r);
|
this.r = Byte.toUnsignedInt(r);
|
||||||
this.g = Byte.toUnsignedInt(g);
|
this.g = Byte.toUnsignedInt(g);
|
||||||
this.b = Byte.toUnsignedInt(b);
|
this.b = Byte.toUnsignedInt(b);
|
||||||
|
@ -228,7 +239,7 @@ public class ModelTransformer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Params color(int color) {
|
public Params color(int color) {
|
||||||
this.colorMode = ColorMode.RECOLOR;
|
this.useParamColor = true;
|
||||||
this.r = ((color >> 16) & 0xFF);
|
this.r = ((color >> 16) & 0xFF);
|
||||||
this.g = ((color >> 8) & 0xFF);
|
this.g = ((color >> 8) & 0xFF);
|
||||||
this.b = (color & 0xFF);
|
this.b = (color & 0xFF);
|
||||||
|
@ -241,29 +252,13 @@ public class ModelTransformer {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Params overlay() {
|
|
||||||
this.hasOverlay = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Params overlay(int overlay) {
|
public Params overlay(int overlay) {
|
||||||
this.hasOverlay = true;
|
|
||||||
this.overlay = overlay;
|
this.overlay = overlay;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Transforms normals not only by the local matrix stack, but also by the passed matrix stack.
|
|
||||||
*/
|
|
||||||
public void entityMode() {
|
|
||||||
this.hasOverlay = true;
|
|
||||||
this.fullNormalTransform = true;
|
|
||||||
this.diffuseMode = DiffuseMode.NONE;
|
|
||||||
this.colorMode = ColorMode.RECOLOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Params light(int packedLightCoords) {
|
public Params light(int packedLightCoords) {
|
||||||
this.hasCustomLight = true;
|
this.useParamLight = true;
|
||||||
this.packedLightCoords = packedLightCoords;
|
this.packedLightCoords = packedLightCoords;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -313,23 +308,5 @@ public class ModelTransformer {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Params defaultParams() {
|
|
||||||
Params out = new Params();
|
|
||||||
out.model.setIdentity();
|
|
||||||
out.normal.setIdentity();
|
|
||||||
out.colorMode = ColorMode.DIFFUSE_ONLY;
|
|
||||||
out.diffuseMode = DiffuseMode.INSTANCE;
|
|
||||||
out.r = 0xFF;
|
|
||||||
out.g = 0xFF;
|
|
||||||
out.b = 0xFF;
|
|
||||||
out.a = 0xFF;
|
|
||||||
out.spriteShiftFunc = null;
|
|
||||||
out.hasOverlay = false;
|
|
||||||
out.overlay = OverlayTexture.NO_OVERLAY;
|
|
||||||
out.hasCustomLight = false;
|
|
||||||
out.packedLightCoords = LightTexture.FULL_BRIGHT;
|
|
||||||
out.fullNormalTransform = false;
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
import com.jozufozu.flywheel.core.vertex.PosTexNormalWriter;
|
||||||
import com.mojang.math.Matrix3f;
|
import com.mojang.math.Matrix3f;
|
||||||
import com.mojang.math.Quaternion;
|
import com.mojang.math.Quaternion;
|
||||||
import com.mojang.math.Vector3f;
|
import com.mojang.math.Vector3f;
|
||||||
|
@ -160,7 +160,7 @@ public class PartBuilder {
|
||||||
return visibleFaces.size() * 4;
|
return visibleFaces.size() * 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void buffer(VertexConsumer buffer) {
|
public void buffer(PosTexNormalWriter buffer) {
|
||||||
|
|
||||||
float sizeX = posX2 - posX1;
|
float sizeX = posX2 - posX1;
|
||||||
float sizeY = posY2 - posY1;
|
float sizeY = posY2 - posY1;
|
||||||
|
@ -235,11 +235,11 @@ public class PartBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void quad(VertexConsumer buffer, Vector3f[] vertices, float minU, float minV, float maxU, float maxV, Vector3f normal) {
|
public void quad(PosTexNormalWriter buffer, Vector3f[] vertices, float minU, float minV, float maxU, float maxV, Vector3f normal) {
|
||||||
buffer.vertex(vertices[0].x(), vertices[0].y(), vertices[0].z()).normal(normal.x(), normal.y(), normal.z()).uv(maxU, minV).endVertex();
|
buffer.putVertex(vertices[0].x(), vertices[0].y(), vertices[0].z(), normal.x(), normal.y(), normal.z(), maxU, minV);
|
||||||
buffer.vertex(vertices[1].x(), vertices[1].y(), vertices[1].z()).normal(normal.x(), normal.y(), normal.z()).uv(minU, minV).endVertex();
|
buffer.putVertex(vertices[1].x(), vertices[1].y(), vertices[1].z(), normal.x(), normal.y(), normal.z(), minU, minV);
|
||||||
buffer.vertex(vertices[2].x(), vertices[2].y(), vertices[2].z()).normal(normal.x(), normal.y(), normal.z()).uv(minU, maxV).endVertex();
|
buffer.putVertex(vertices[2].x(), vertices[2].y(), vertices[2].z(), normal.x(), normal.y(), normal.z(), minU, maxV);
|
||||||
buffer.vertex(vertices[3].x(), vertices[3].y(), vertices[3].z()).normal(normal.x(), normal.y(), normal.z()).uv(maxU, maxV).endVertex();
|
buffer.putVertex(vertices[3].x(), vertices[3].y(), vertices[3].z(), normal.x(), normal.y(), normal.z(), maxU, maxV);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,10 @@ package com.jozufozu.flywheel.core.model;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
import com.jozufozu.flywheel.core.vertex.VertexType;
|
||||||
import com.jozufozu.flywheel.core.Formats;
|
import com.jozufozu.flywheel.util.UnsafeBlockFormatReader;
|
||||||
import com.jozufozu.flywheel.util.BufferBuilderReader;
|
|
||||||
import com.jozufozu.flywheel.util.ModelReader;
|
import com.jozufozu.flywheel.util.ModelReader;
|
||||||
import com.jozufozu.flywheel.util.RenderMath;
|
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
|
||||||
|
|
||||||
import net.minecraft.client.renderer.LightTexture;
|
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
import net.minecraft.world.level.BlockAndTintGetter;
|
import net.minecraft.world.level.BlockAndTintGetter;
|
||||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
|
||||||
|
@ -20,7 +16,7 @@ public class WorldModel implements Model {
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
public WorldModel(BlockAndTintGetter renderWorld, RenderType layer, Collection<StructureTemplate.StructureBlockInfo> blocks, String name) {
|
public WorldModel(BlockAndTintGetter renderWorld, RenderType layer, Collection<StructureTemplate.StructureBlockInfo> blocks, String name) {
|
||||||
reader = new BufferBuilderReader(ModelUtil.getBufferBuilderFromTemplate(renderWorld, layer, blocks));
|
reader = new UnsafeBlockFormatReader(ModelUtil.getBufferBuilderFromTemplate(renderWorld, layer, blocks));
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,25 +26,8 @@ public class WorldModel implements Model {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void buffer(VertexConsumer vertices) {
|
public VertexType getType() {
|
||||||
for (int i = 0; i < vertexCount(); i++) {
|
return BlockType.INSTANCE;
|
||||||
vertices.vertex(reader.getX(i), reader.getY(i), reader.getZ(i));
|
|
||||||
|
|
||||||
vertices.normal(reader.getNX(i), reader.getNY(i), reader.getNZ(i));
|
|
||||||
|
|
||||||
vertices.uv(reader.getU(i), reader.getV(i));
|
|
||||||
|
|
||||||
vertices.color(reader.getR(i), reader.getG(i), reader.getB(i), reader.getA(i));
|
|
||||||
|
|
||||||
int light = reader.getLight(i);
|
|
||||||
|
|
||||||
byte block = (byte) (LightTexture.block(light) << 4);
|
|
||||||
byte sky = (byte) (LightTexture.sky(light) << 4);
|
|
||||||
|
|
||||||
vertices.uv2(block, sky);
|
|
||||||
|
|
||||||
vertices.endVertex();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -56,11 +35,6 @@ public class WorldModel implements Model {
|
||||||
return reader.getVertexCount();
|
return reader.getVertexCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public VertexFormat format() {
|
|
||||||
return Formats.COLORED_LIT_MODEL;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ModelReader getReader() {
|
public ModelReader getReader() {
|
||||||
return reader;
|
return reader;
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
package com.jozufozu.flywheel.core.vertex;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.util.ModelReader;
|
||||||
|
import com.jozufozu.flywheel.util.RenderMath;
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.LightTexture;
|
||||||
|
|
||||||
|
public class PosNormalTexReader implements ModelReader {
|
||||||
|
|
||||||
|
private final ByteBuffer buffer;
|
||||||
|
private final int vertexCount;
|
||||||
|
private final long base;
|
||||||
|
|
||||||
|
public PosNormalTexReader(ByteBuffer buffer, int vertexCount) {
|
||||||
|
this.buffer = buffer;
|
||||||
|
this.vertexCount = vertexCount;
|
||||||
|
this.base = MemoryUtil.memAddress(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private long ptr(long idx) {
|
||||||
|
return base + idx * 23;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getX(int index) {
|
||||||
|
return MemoryUtil.memGetFloat(ptr(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getY(int index) {
|
||||||
|
return MemoryUtil.memGetFloat(ptr(index) + 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getZ(int index) {
|
||||||
|
return MemoryUtil.memGetFloat(ptr(index) + 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getR(int index) {
|
||||||
|
return (byte) 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getG(int index) {
|
||||||
|
return (byte) 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getB(int index) {
|
||||||
|
return (byte) 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getA(int index) {
|
||||||
|
return (byte) 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getU(int index) {
|
||||||
|
return MemoryUtil.memGetFloat(ptr(index) + 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getV(int index) {
|
||||||
|
return MemoryUtil.memGetFloat(ptr(index) + 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLight(int index) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getNX(int index) {
|
||||||
|
return RenderMath.f(MemoryUtil.memGetByte(ptr(index) + 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getNY(int index) {
|
||||||
|
return RenderMath.f(MemoryUtil.memGetByte(ptr(index) + 21));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getNZ(int index) {
|
||||||
|
return RenderMath.f(MemoryUtil.memGetByte(ptr(index) + 22));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getVertexCount() {
|
||||||
|
return vertexCount;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package com.jozufozu.flywheel.core.vertex;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
||||||
|
import com.jozufozu.flywheel.core.Formats;
|
||||||
|
import com.jozufozu.flywheel.util.ModelReader;
|
||||||
|
|
||||||
|
public class PosNormalTexType implements VertexType {
|
||||||
|
|
||||||
|
public static final PosNormalTexType INSTANCE = new PosNormalTexType();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VertexFormat getFormat() {
|
||||||
|
return Formats.UNLIT_MODEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copyInto(ByteBuffer buffer, ModelReader reader) {
|
||||||
|
PosTexNormalWriter writer = new PosTexNormalWriter(buffer);
|
||||||
|
|
||||||
|
int vertexCount = reader.getVertexCount();
|
||||||
|
for (int i = 0; i < vertexCount; i++) {
|
||||||
|
float x = reader.getX(i);
|
||||||
|
float y = reader.getY(i);
|
||||||
|
float z = reader.getZ(i);
|
||||||
|
|
||||||
|
float u = reader.getU(i);
|
||||||
|
float v = reader.getV(i);
|
||||||
|
|
||||||
|
float xN = reader.getNX(i);
|
||||||
|
float yN = reader.getNY(i);
|
||||||
|
float zN = reader.getNZ(i);
|
||||||
|
|
||||||
|
writer.putVertex(x, y, z, xN, yN, zN, u, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.jozufozu.flywheel.core.vertex;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.util.RenderMath;
|
||||||
|
|
||||||
|
public class PosTexNormalWriter {
|
||||||
|
|
||||||
|
private long addr;
|
||||||
|
|
||||||
|
private int vertexCount;
|
||||||
|
|
||||||
|
public PosTexNormalWriter(ByteBuffer buffer) {
|
||||||
|
addr = MemoryUtil.memAddress(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void putVertex(float x, float y, float z, float nX, float nY, float nZ, float u, float v) {
|
||||||
|
MemoryUtil.memPutFloat(addr, x);
|
||||||
|
MemoryUtil.memPutFloat(addr + 4, y);
|
||||||
|
MemoryUtil.memPutFloat(addr + 8, z);
|
||||||
|
MemoryUtil.memPutFloat(addr + 12, u);
|
||||||
|
MemoryUtil.memPutFloat(addr + 16, v);
|
||||||
|
MemoryUtil.memPutByte(addr + 20, RenderMath.nb(nX));
|
||||||
|
MemoryUtil.memPutByte(addr + 21, RenderMath.nb(nY));
|
||||||
|
MemoryUtil.memPutByte(addr + 22, RenderMath.nb(nZ));
|
||||||
|
|
||||||
|
addr += 23;
|
||||||
|
vertexCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getVertexCount() {
|
||||||
|
return vertexCount;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.jozufozu.flywheel.core.vertex;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
||||||
|
import com.jozufozu.flywheel.util.ModelReader;
|
||||||
|
|
||||||
|
public interface VertexType {
|
||||||
|
|
||||||
|
VertexFormat getFormat();
|
||||||
|
|
||||||
|
void copyInto(ByteBuffer buffer, ModelReader reader);
|
||||||
|
|
||||||
|
default int getStride() {
|
||||||
|
return getFormat().getStride();
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package com.jozufozu.flywheel.mixin;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
@ -38,9 +39,11 @@ public abstract class BufferBuilderMixin implements DirectBufferBuilder {
|
||||||
private int nextElementByte;
|
private int nextElementByte;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nonnull
|
||||||
public DirectVertexConsumer intoDirectConsumer(int vertexCount) {
|
public DirectVertexConsumer intoDirectConsumer(int vertexCount) {
|
||||||
int bytes = vertexCount * format.getVertexSize();
|
int bytes = vertexCount * format.getVertexSize();
|
||||||
ensureCapacity(bytes);
|
// ensure we have capacity for one extra vertex, BufferBuilder does this on #endVertex
|
||||||
|
ensureCapacity(bytes + format.getVertexSize());
|
||||||
|
|
||||||
DirectVertexConsumer consumer = new DirectVertexConsumer(this.buffer, this.format, vertexCount);
|
DirectVertexConsumer consumer = new DirectVertexConsumer(this.buffer, this.format, vertexCount);
|
||||||
|
|
||||||
|
@ -49,7 +52,7 @@ public abstract class BufferBuilderMixin implements DirectBufferBuilder {
|
||||||
.get(0);
|
.get(0);
|
||||||
this.elementIndex = 0;
|
this.elementIndex = 0;
|
||||||
this.nextElementByte += bytes;
|
this.nextElementByte += bytes;
|
||||||
this.buffer.position(consumer.startPos + bytes);
|
this.buffer.position(this.buffer.position() + bytes);
|
||||||
|
|
||||||
return consumer;
|
return consumer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,36 +3,24 @@ package com.jozufozu.flywheel.util;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.BufferBuilder;
|
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
|
||||||
import com.mojang.datafixers.util.Pair;
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
|
||||||
public class BufferBuilderReader implements ModelReader {
|
public class BlockFormatReader implements ModelReader {
|
||||||
|
|
||||||
private final ByteBuffer buffer;
|
private final ByteBuffer buffer;
|
||||||
private final int vertexCount;
|
private final int vertexCount;
|
||||||
private final int formatSize;
|
private final int stride;
|
||||||
private final int size;
|
|
||||||
|
|
||||||
public BufferBuilderReader(BufferBuilder builder) {
|
public BlockFormatReader(BufferBuilder builder) {
|
||||||
VertexFormat vertexFormat = builder.getVertexFormat();
|
|
||||||
Pair<BufferBuilder.DrawState, ByteBuffer> data = builder.popNextBuffer();
|
Pair<BufferBuilder.DrawState, ByteBuffer> data = builder.popNextBuffer();
|
||||||
buffer = data.getSecond();
|
buffer = data.getSecond();
|
||||||
|
|
||||||
formatSize = vertexFormat.getVertexSize();
|
stride = builder.getVertexFormat()
|
||||||
|
.getVertexSize();
|
||||||
|
|
||||||
vertexCount = data.getFirst()
|
vertexCount = data.getFirst()
|
||||||
.vertexCount();
|
.vertexCount();
|
||||||
|
|
||||||
size = vertexCount * formatSize;
|
|
||||||
|
|
||||||
// TODO: adjust the getters based on the input format
|
|
||||||
// ImmutableList<VertexFormatElement> elements = vertexFormat.getElements();
|
|
||||||
// for (int i = 0, size = elements.size(); i < size; i++) {
|
|
||||||
// VertexFormatElement element = elements.get(i);
|
|
||||||
// int offset = vertexFormat.getOffset(i);
|
|
||||||
//
|
|
||||||
// element.getUsage()
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -41,7 +29,7 @@ public class BufferBuilderReader implements ModelReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
private int vertIdx(int vertexIndex) {
|
private int vertIdx(int vertexIndex) {
|
||||||
return vertexIndex * formatSize;
|
return vertexIndex * stride;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -114,7 +102,4 @@ public class BufferBuilderReader implements ModelReader {
|
||||||
return vertexCount;
|
return vertexCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize() {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
}
|
}
|
309
src/main/java/com/jozufozu/flywheel/util/Color.java
Normal file
309
src/main/java/com/jozufozu/flywheel/util/Color.java
Normal file
|
@ -0,0 +1,309 @@
|
||||||
|
package com.jozufozu.flywheel.util;
|
||||||
|
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import com.google.common.hash.Hashing;
|
||||||
|
import com.mojang.math.Vector3f;
|
||||||
|
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
@SuppressWarnings("PointlessBitwiseExpression")
|
||||||
|
public class Color {
|
||||||
|
public final static Color TRANSPARENT_BLACK = new Color(0, 0, 0, 0).setImmutable();
|
||||||
|
public final static Color BLACK = new Color(0, 0, 0).setImmutable();
|
||||||
|
public final static Color WHITE = new Color(255, 255, 255).setImmutable();
|
||||||
|
public final static Color RED = new Color(255, 0, 0).setImmutable();
|
||||||
|
public final static Color GREEN = new Color(0, 255, 0).setImmutable();
|
||||||
|
public final static Color SPRING_GREEN = new Color(0, 255, 187).setImmutable();
|
||||||
|
|
||||||
|
protected boolean mutable = true;
|
||||||
|
protected int value;
|
||||||
|
|
||||||
|
public Color(int r, int g, int b) {
|
||||||
|
this(r, g, b, 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color(int r, int g, int b, int a) {
|
||||||
|
value = ((a & 0xff) << 24) |
|
||||||
|
((r & 0xff) << 16) |
|
||||||
|
((g & 0xff) << 8) |
|
||||||
|
((b & 0xff) << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color(float r, float g, float b, float a) {
|
||||||
|
this(
|
||||||
|
(int) (0.5 + 0xff * Mth.clamp(r, 0, 1)),
|
||||||
|
(int) (0.5 + 0xff * Mth.clamp(g, 0, 1)),
|
||||||
|
(int) (0.5 + 0xff * Mth.clamp(b, 0, 1)),
|
||||||
|
(int) (0.5 + 0xff * Mth.clamp(a, 0, 1))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color(int rgba) {
|
||||||
|
value = rgba;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color(int rgb, boolean hasAlpha) {
|
||||||
|
if (hasAlpha) {
|
||||||
|
value = rgb;
|
||||||
|
} else {
|
||||||
|
value = rgb | 0xff_000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color copy() {
|
||||||
|
return copy(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color copy(boolean mutable) {
|
||||||
|
if (mutable)
|
||||||
|
return new Color(value);
|
||||||
|
else
|
||||||
|
return new Color(value).setImmutable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark this color as immutable. Attempting to mutate this color in the future
|
||||||
|
* will instead cause a copy to be created that can me modified.
|
||||||
|
*/
|
||||||
|
public Color setImmutable() {
|
||||||
|
this.mutable = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the red component in the range 0-255.
|
||||||
|
* @see #getRGB
|
||||||
|
*/
|
||||||
|
public int getRed() {
|
||||||
|
return (getRGB() >> 16) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the green component in the range 0-255.
|
||||||
|
* @see #getRGB
|
||||||
|
*/
|
||||||
|
public int getGreen() {
|
||||||
|
return (getRGB() >> 8) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the blue component in the range 0-255.
|
||||||
|
* @see #getRGB
|
||||||
|
*/
|
||||||
|
public int getBlue() {
|
||||||
|
return (getRGB() >> 0) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the alpha component in the range 0-255.
|
||||||
|
* @see #getRGB
|
||||||
|
*/
|
||||||
|
public int getAlpha() {
|
||||||
|
return (getRGB() >> 24) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the red component in the range 0-1f.
|
||||||
|
*/
|
||||||
|
public float getRedAsFloat() {
|
||||||
|
return getRed() / 255f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the green component in the range 0-1f.
|
||||||
|
*/
|
||||||
|
public float getGreenAsFloat() {
|
||||||
|
return getGreen() / 255f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the blue component in the range 0-1f.
|
||||||
|
*/
|
||||||
|
public float getBlueAsFloat() {
|
||||||
|
return getBlue() / 255f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the alpha component in the range 0-1f.
|
||||||
|
*/
|
||||||
|
public float getAlphaAsFloat() {
|
||||||
|
return getAlpha() / 255f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the RGB value representing this color
|
||||||
|
* (Bits 24-31 are alpha, 16-23 are red, 8-15 are green, 0-7 are blue).
|
||||||
|
* @return the RGB value of the color
|
||||||
|
*/
|
||||||
|
public int getRGB() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3 asVector() {
|
||||||
|
return new Vec3(getRedAsFloat(), getGreenAsFloat(), getBlueAsFloat());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3f asVectorF() {
|
||||||
|
return new Vector3f(getRedAsFloat(), getGreenAsFloat(), getBlueAsFloat());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color setRed(int r) {
|
||||||
|
return ensureMutable().setRedUnchecked(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color setGreen(int g) {
|
||||||
|
return ensureMutable().setGreenUnchecked(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color setBlue(int b) {
|
||||||
|
return ensureMutable().setBlueUnchecked(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color setAlpha(int a) {
|
||||||
|
return ensureMutable().setAlphaUnchecked(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color setRed(float r) {
|
||||||
|
return ensureMutable().setRedUnchecked((int) (0xff * Mth.clamp(r, 0, 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color setGreen(float g) {
|
||||||
|
return ensureMutable().setGreenUnchecked((int) (0xff * Mth.clamp(g, 0, 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color setBlue(float b) {
|
||||||
|
return ensureMutable().setBlueUnchecked((int) (0xff * Mth.clamp(b, 0, 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color setAlpha(float a) {
|
||||||
|
return ensureMutable().setAlphaUnchecked((int) (0xff * Mth.clamp(a, 0, 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color scaleAlpha(float factor) {
|
||||||
|
return ensureMutable().setAlphaUnchecked((int) (getAlpha() * Mth.clamp(factor, 0, 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color mixWith(Color other, float weight) {
|
||||||
|
return ensureMutable()
|
||||||
|
.setRedUnchecked((int) (getRed() + (other.getRed() - getRed()) * weight))
|
||||||
|
.setGreenUnchecked((int) (getGreen() + (other.getGreen() - getGreen()) * weight))
|
||||||
|
.setBlueUnchecked((int) (getBlue() + (other.getBlue() - getBlue()) * weight))
|
||||||
|
.setAlphaUnchecked((int) (getAlpha() + (other.getAlpha() - getAlpha()) * weight));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color darker() {
|
||||||
|
int a = getAlpha();
|
||||||
|
return ensureMutable().mixWith(BLACK, .25f).setAlphaUnchecked(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color brighter() {
|
||||||
|
int a = getAlpha();
|
||||||
|
return ensureMutable().mixWith(WHITE, .25f).setAlphaUnchecked(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color setValue(int value) {
|
||||||
|
return ensureMutable().setValueUnchecked(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color modifyValue(UnaryOperator<Integer> function) {
|
||||||
|
int newValue = function.apply(value);
|
||||||
|
if (newValue == value)
|
||||||
|
return this;
|
||||||
|
|
||||||
|
return ensureMutable().setValueUnchecked(newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ********* //
|
||||||
|
|
||||||
|
protected Color ensureMutable() {
|
||||||
|
if (this.mutable)
|
||||||
|
return this;
|
||||||
|
|
||||||
|
return new Color(this.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Color setRedUnchecked(int r) {
|
||||||
|
this.value = (this.value & 0xff_00ffff) | ((r & 0xff) << 16);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Color setGreenUnchecked(int g) {
|
||||||
|
this.value = (this.value & 0xff_ff00ff) | ((g & 0xff) << 8);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Color setBlueUnchecked(int b) {
|
||||||
|
this.value = (this.value & 0xff_ffff00) | ((b & 0xff) << 0);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Color setAlphaUnchecked(int a) {
|
||||||
|
this.value = (this.value & 0x00_ffffff) | ((a & 0xff) << 24);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Color setValueUnchecked(int value) {
|
||||||
|
this.value = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ********* //
|
||||||
|
|
||||||
|
public static Color mixColors(@Nonnull Color c1, @Nonnull Color c2, float w) {
|
||||||
|
return new Color(
|
||||||
|
(int) (c1.getRed() + (c2.getRed() - c1.getRed()) * w),
|
||||||
|
(int) (c1.getGreen() + (c2.getGreen() - c1.getGreen()) * w),
|
||||||
|
(int) (c1.getBlue() + (c2.getBlue() - c1.getBlue()) * w),
|
||||||
|
(int) (c1.getAlpha() + (c2.getAlpha() - c1.getAlpha()) * w)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int mixColors(int color1, int color2, float w) {
|
||||||
|
int a1 = (color1 >> 24);
|
||||||
|
int r1 = (color1 >> 16) & 0xFF;
|
||||||
|
int g1 = (color1 >> 8) & 0xFF;
|
||||||
|
int b1 = color1 & 0xFF;
|
||||||
|
int a2 = (color2 >> 24);
|
||||||
|
int r2 = (color2 >> 16) & 0xFF;
|
||||||
|
int g2 = (color2 >> 8) & 0xFF;
|
||||||
|
int b2 = color2 & 0xFF;
|
||||||
|
|
||||||
|
return
|
||||||
|
((int) (a1 + (a2 - a1) * w) << 24) +
|
||||||
|
((int) (r1 + (r2 - r1) * w) << 16) +
|
||||||
|
((int) (g1 + (g2 - g1) * w) << 8) +
|
||||||
|
((int) (b1 + (b2 - b1) * w) << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Color rainbowColor(int timeStep) {
|
||||||
|
int localTimeStep = Math.abs(timeStep) % 1536;
|
||||||
|
int timeStepInPhase = localTimeStep % 256;
|
||||||
|
int phaseBlue = localTimeStep / 256;
|
||||||
|
int red = colorInPhase(phaseBlue + 4, timeStepInPhase);
|
||||||
|
int green = colorInPhase(phaseBlue + 2, timeStepInPhase);
|
||||||
|
int blue = colorInPhase(phaseBlue, timeStepInPhase);
|
||||||
|
return new Color(red, green, blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int colorInPhase(int phase, int progress) {
|
||||||
|
phase = phase % 6;
|
||||||
|
if (phase <= 1)
|
||||||
|
return 0;
|
||||||
|
if (phase == 2)
|
||||||
|
return progress;
|
||||||
|
if (phase <= 4)
|
||||||
|
return 255;
|
||||||
|
else
|
||||||
|
return 255 - progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Color generateFromLong(long l) {
|
||||||
|
return rainbowColor(Hashing.crc32().hashLong(l).asInt())
|
||||||
|
.mixWith(WHITE, 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
package com.jozufozu.flywheel.util;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
|
||||||
|
public class UnsafeBlockFormatReader implements ModelReader {
|
||||||
|
|
||||||
|
private final int vertexCount;
|
||||||
|
private final int stride;
|
||||||
|
private final long base;
|
||||||
|
|
||||||
|
public UnsafeBlockFormatReader(BufferBuilder builder) {
|
||||||
|
VertexFormat vertexFormat = builder.getVertexFormat();
|
||||||
|
Pair<BufferBuilder.DrawState, ByteBuffer> data = builder.popNextBuffer();
|
||||||
|
this.base = MemoryUtil.memAddress(data.getSecond());
|
||||||
|
this.vertexCount = data.getFirst().vertexCount();
|
||||||
|
this.stride = vertexFormat.getVertexSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private long ptr(long index) {
|
||||||
|
return base + index * stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return vertexCount == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getX(int index) {
|
||||||
|
return MemoryUtil.memGetFloat(ptr(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getY(int index) {
|
||||||
|
return MemoryUtil.memGetFloat(ptr(index) + 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getZ(int index) {
|
||||||
|
return MemoryUtil.memGetFloat(ptr(index) + 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getR(int index) {
|
||||||
|
return MemoryUtil.memGetByte(ptr(index) + 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getG(int index) {
|
||||||
|
return MemoryUtil.memGetByte(ptr(index) + 13);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getB(int index) {
|
||||||
|
return MemoryUtil.memGetByte(ptr(index) + 14);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getA(int index) {
|
||||||
|
return MemoryUtil.memGetByte(ptr(index) + 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getU(int index) {
|
||||||
|
return MemoryUtil.memGetFloat(ptr(index) + 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getV(int index) {
|
||||||
|
return MemoryUtil.memGetFloat(ptr(index) + 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLight(int index) {
|
||||||
|
return MemoryUtil.memGetInt(ptr(index) + 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getNX(int index) {
|
||||||
|
return RenderMath.f(MemoryUtil.memGetByte(ptr(index) + 28));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getNY(int index) {
|
||||||
|
return RenderMath.f(MemoryUtil.memGetByte(ptr(index) + 29));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getNZ(int index) {
|
||||||
|
return RenderMath.f(MemoryUtil.memGetByte(ptr(index) + 30));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getVertexCount() {
|
||||||
|
return vertexCount;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
vec3 pos;
|
vec3 pos;
|
||||||
vec3 normal;
|
|
||||||
vec2 texCoords;
|
vec2 texCoords;
|
||||||
|
vec3 normal;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue