From b0f6d07b0b85489c5c956f145522ba1b7d4d5d01 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Tue, 21 Dec 2021 22:47:29 -0800 Subject: [PATCH] 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 --- .../backend/instancing/BatchExecutor.java | 15 +- .../backend/instancing/InstanceWorld.java | 2 +- .../backend/instancing/RenderDispatcher.java | 3 +- .../instancing/batching/BatchedMaterial.java | 4 +- .../batching/BatchedMaterialGroup.java | 39 ++- .../instancing/batching/BatchingEngine.java | 24 +- .../instancing/batching/CPUInstancer.java | 41 +-- .../instancing/batching/FormatContext.java | 8 - .../instancing/InstancedMaterial.java | 4 +- .../instancing/InstancingEngine.java | 2 +- .../flywheel/backend/model/BufferedModel.java | 2 +- .../backend/model/DirectBufferBuilder.java | 14 + .../backend/model/DirectVertexConsumer.java | 15 +- .../flywheel/backend/model/ModelPool.java | 37 ++- .../com/jozufozu/flywheel/core/Formats.java | 2 +- .../core/crumbling/CrumblingRenderer.java | 2 +- .../flywheel/core/model/BlockModel.java | 33 +- .../flywheel/core/model/BlockType.java | 71 ++++ .../jozufozu/flywheel/core/model/Model.java | 22 +- .../flywheel/core/model/ModelPart.java | 132 ++------ .../flywheel/core/model/ModelTransformer.java | 187 +++++------ .../flywheel/core/model/PartBuilder.java | 14 +- .../flywheel/core/model/WorldModel.java | 36 +- .../core/vertex/PosNormalTexReader.java | 97 ++++++ .../core/vertex/PosNormalTexType.java | 38 +++ .../core/vertex/PosTexNormalWriter.java | 36 ++ .../flywheel/core/vertex/VertexType.java | 17 + .../flywheel/mixin/BufferBuilderMixin.java | 7 +- ...lderReader.java => BlockFormatReader.java} | 27 +- .../com/jozufozu/flywheel/util/Color.java | 309 ++++++++++++++++++ .../util/UnsafeBlockFormatReader.java | 103 ++++++ .../flywheel/shaders/data/modelvertex.glsl | 2 +- 32 files changed, 948 insertions(+), 397 deletions(-) delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/batching/FormatContext.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/model/BlockType.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/vertex/PosNormalTexReader.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/vertex/PosNormalTexType.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalWriter.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/vertex/VertexType.java rename src/main/java/com/jozufozu/flywheel/util/{BufferBuilderReader.java => BlockFormatReader.java} (70%) create mode 100644 src/main/java/com/jozufozu/flywheel/util/Color.java create mode 100644 src/main/java/com/jozufozu/flywheel/util/UnsafeBlockFormatReader.java diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/BatchExecutor.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/BatchExecutor.java index f3da663c0..da856e57c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/BatchExecutor.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/BatchExecutor.java @@ -11,6 +11,7 @@ import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.backend.instancing.batching.WaitGroup; import net.minecraft.util.Mth; @@ -104,7 +105,7 @@ public class BatchExecutor implements TaskEngine { Runnable job; // Finish everyone else's work... - while ((job = getNextTask(false)) != null) { + while ((job = this.jobQueue.pollLast()) != null) { processTask(job); } @@ -116,10 +117,10 @@ public class BatchExecutor implements TaskEngine { } @Nullable - private Runnable getNextTask(boolean block) { - Runnable job = this.jobQueue.poll(); + private Runnable getNextTask() { + Runnable job = this.jobQueue.pollFirst(); - if (job == null && block) { + if (job == null) { synchronized (BatchExecutor.this.jobNotifier) { try { BatchExecutor.this.jobNotifier.wait(); @@ -134,6 +135,8 @@ public class BatchExecutor implements TaskEngine { private void processTask(Runnable job) { try { job.run(); + } catch (Exception e) { + Flywheel.log.error(e); } finally { BatchExecutor.this.wg.done(); } @@ -158,13 +161,13 @@ public class BatchExecutor implements TaskEngine { public void run() { // Run until the chunk builder shuts down while (this.running.get()) { - Runnable job = BatchExecutor.this.getNextTask(true); + Runnable job = BatchExecutor.this.getNextTask(); if (job == null) { continue; } - processTask(job); + BatchExecutor.this.processTask(job); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java index 10862c154..1b85c8ed6 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java @@ -116,7 +116,7 @@ public class InstanceWorld { */ public void renderLayer(RenderLayerEvent event) { taskEngine.syncPoint(); - engine.render(event, event.buffers.bufferSource()); + engine.render(event); } /** diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/RenderDispatcher.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/RenderDispatcher.java index c54d60205..ae9ccf88f 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/RenderDispatcher.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/RenderDispatcher.java @@ -10,9 +10,8 @@ public interface RenderDispatcher { * Render every model for every material. * * @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. diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedMaterial.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedMaterial.java index 1b314a10a..cf97a5b1b 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedMaterial.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedMaterial.java @@ -28,9 +28,9 @@ public class BatchedMaterial implements Material { 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 instancer : models.values()) { - instancer.setup(context); + instancer.setup(); instancer.drawAll(stack, buffer); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedMaterialGroup.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedMaterialGroup.java index 1dd50c414..ba5d71105 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedMaterialGroup.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedMaterialGroup.java @@ -42,41 +42,44 @@ public class BatchedMaterialGroup implements MaterialGroup { if (buffer instanceof DirectBufferBuilder direct) { renderParallel(stack, pool, direct); } else { - renderSerial(stack, buffer, FormatContext.defaultContext()); + renderSerial(stack, buffer); } } 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); - 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 (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); } } } - private void renderSerial(PoseStack stack, VertexConsumer consumer, FormatContext context) { + private void renderSerial(PoseStack stack, VertexConsumer consumer) { 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() { materials.values().forEach(BatchedMaterial::clear); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java index 1d49062c9..7af1eb14a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java @@ -9,7 +9,9 @@ import com.jozufozu.flywheel.backend.RenderLayer; import com.jozufozu.flywheel.backend.instancing.TaskEngine; import com.jozufozu.flywheel.backend.instancing.Engine; import com.jozufozu.flywheel.event.RenderLayerEvent; +import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; import net.minecraft.client.Camera; 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.Vec3i; -public class BatchingEngine implements Engine { +public class BatchingEngine implements Engine, MultiBufferSource { + protected final Map buffers = new HashMap<>(); protected final Map> layers; protected final TaskEngine taskEngine; @@ -42,7 +45,7 @@ public class BatchingEngine implements Engine { } @Override - public void render(RenderLayerEvent event, MultiBufferSource buffers) { + public void render(RenderLayerEvent event) { PoseStack stack = event.stack; stack.pushPose(); @@ -50,14 +53,27 @@ public class BatchingEngine implements Engine { stack.translate(-event.camX, -event.camY, -event.camZ); for (BatchedMaterialGroup group : layers.get(event.getLayer()).values()) { - group.render(stack, buffers, taskEngine); + group.render(stack, this, taskEngine); } taskEngine.syncPoint(); 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 diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java index 1c39a076d..1486ef14e 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java @@ -2,12 +2,12 @@ package com.jozufozu.flywheel.backend.instancing.batching; import com.jozufozu.flywheel.api.InstanceData; 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.TaskEngine; import com.jozufozu.flywheel.backend.model.DirectVertexConsumer; import com.jozufozu.flywheel.core.model.Model; import com.jozufozu.flywheel.core.model.ModelTransformer; +import com.jozufozu.flywheel.util.Color; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; @@ -15,15 +15,14 @@ public class CPUInstancer extends AbstractInstancer { private final Batched batchingType; - private final ModelTransformer sbb; - private final ModelTransformer.Params defaultParams; + final ModelTransformer sbb; public CPUInstancer(Batched type, Model modelData) { super(type::create, modelData); batchingType = type; sbb = new ModelTransformer(modelData); - defaultParams = ModelTransformer.Params.defaultParams(); + modelData.configure(sbb.context); } void submitTasks(PoseStack stack, TaskEngine pool, DirectVertexConsumer consumer) { @@ -42,43 +41,47 @@ public class CPUInstancer extends AbstractInstancer { } } - @Override - public void notifyDirty() { - // noop - } - 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)) { + params.loadDefault(); + 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) { - ModelTransformer.Params params = defaultParams.copy(); + ModelTransformer.Params params = new ModelTransformer.Params(); for (D d : data) { + params.loadDefault(); + batchingType.transform(d, params); sbb.renderInto(params, stack, buffer); - - params.load(defaultParams); } } - void setup(FormatContext context) { + void setup() { if (anyToRemove) { - removeDeletedInstances(); + data.removeIf(InstanceData::isRemoved); anyToRemove = false; } - if (context.usesOverlay()) { - defaultParams.overlay(); + if (false) { + this.sbb.context.outputColorDiffuse = false; + this.sbb.context.fullNormalTransform = false; } } + @Override + public void notifyDirty() { + // noop + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/FormatContext.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/FormatContext.java deleted file mode 100644 index bb0bbd41e..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/FormatContext.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.jozufozu.flywheel.backend.instancing.batching; - -public record FormatContext(boolean usesOverlay) { - - public static FormatContext defaultContext() { - return new FormatContext(false); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterial.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterial.java index a8229424b..d60a18926 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterial.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterial.java @@ -14,8 +14,8 @@ import com.jozufozu.flywheel.backend.RenderWork; import com.jozufozu.flywheel.backend.model.ImmediateAllocator; import com.jozufozu.flywheel.backend.model.ModelAllocator; 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.vertex.PosNormalTexType; /** * A collection of Instancers that all have the same format. @@ -33,7 +33,7 @@ public class InstancedMaterial implements Material { if (Backend.getInstance().compat.onAMDWindows()) { allocator = ImmediateAllocator.INSTANCE; } else { - allocator = new ModelPool(Formats.UNLIT_MODEL, 64); + allocator = new ModelPool(PosNormalTexType.INSTANCE, 64); } this.models = CacheBuilder.newBuilder() .removalListener(notification -> { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java index af045697a..63015b349 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java @@ -82,7 +82,7 @@ public class InstancingEngine

implements Engine { * Render every model for every material. */ @Override - public void render(RenderLayerEvent event, MultiBufferSource buffers) { + public void render(RenderLayerEvent event) { double camX; double camY; double camZ; diff --git a/src/main/java/com/jozufozu/flywheel/backend/model/BufferedModel.java b/src/main/java/com/jozufozu/flywheel/backend/model/BufferedModel.java index 98d2ef6dc..9ec3effcd 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/model/BufferedModel.java +++ b/src/main/java/com/jozufozu/flywheel/backend/model/BufferedModel.java @@ -34,7 +34,7 @@ public class BufferedModel implements IBufferedModel { // mirror it in system memory so we can write to it, and upload our model. try (MappedBuffer buffer = vbo.getBuffer(0, model.size())) { - model.buffer(new VecBufferWriter(buffer)); + model.getType().copyInto(buffer.unwrap(), model.getReader()); } catch (Exception e) { Flywheel.log.error(String.format("Error uploading model '%s':", model.name()), e); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/model/DirectBufferBuilder.java b/src/main/java/com/jozufozu/flywheel/backend/model/DirectBufferBuilder.java index 98449155a..c157aed9b 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/model/DirectBufferBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/backend/model/DirectBufferBuilder.java @@ -1,6 +1,20 @@ 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 { + /** + * Create a DirectVertexConsumer from this BufferBuilder. + * + *

+ * 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. + *

+ */ DirectVertexConsumer intoDirectConsumer(int vertexCount); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/model/DirectVertexConsumer.java b/src/main/java/com/jozufozu/flywheel/backend/model/DirectVertexConsumer.java index 0286083f6..781ad8693 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/model/DirectVertexConsumer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/model/DirectVertexConsumer.java @@ -10,6 +10,11 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexFormat; 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 final VertexFormat format; private final int stride; @@ -68,12 +73,16 @@ public class DirectVertexConsumer implements VertexConsumer { this.end = parent.vertexBase + (long) maxVertices * this.stride; } + public void memSetZero() { + MemoryUtil.memSet(vertexBase, 0, end - vertexBase); + } + public boolean hasOverlay() { 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. * @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) { if (color < 0) return this; long base = vertexBase + color; - int color = ((r & 0xFF)) | ((g & 0xFF) << 8) | ((b & 0xFF) << 16) | ((a & 0xFF) << 24); - //MemoryUtil.memPutInt(base, color); +// int color = ((r & 0xFF)) | ((g & 0xFF) << 8) | ((b & 0xFF) << 16) | ((a & 0xFF) << 24); +// MemoryUtil.memPutInt(base, color); MemoryUtil.memPutByte(base, (byte) r); MemoryUtil.memPutByte(base + 1, (byte) g); MemoryUtil.memPutByte(base + 2, (byte) b); diff --git a/src/main/java/com/jozufozu/flywheel/backend/model/ModelPool.java b/src/main/java/com/jozufozu/flywheel/backend/model/ModelPool.java index 72f7973e2..9d26f2abb 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/model/ModelPool.java +++ b/src/main/java/com/jozufozu/flywheel/backend/model/ModelPool.java @@ -1,5 +1,6 @@ package com.jozufozu.flywheel.backend.model; +import java.nio.ByteBuffer; import java.util.ArrayList; 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.MappedGlBuffer; 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; public class ModelPool implements ModelAllocator { - protected final VertexFormat format; + protected final VertexType vertexType; private final List models = new ArrayList<>(); @@ -32,9 +33,9 @@ public class ModelPool implements ModelAllocator { private boolean dirty; private boolean anyToRemove; - public ModelPool(VertexFormat format, int initialSize) { - this.format = format; - bufferSize = format.getStride() * initialSize; + public ModelPool(VertexType vertexType, int initialSize) { + this.vertexType = vertexType; + bufferSize = vertexType.getStride() * initialSize; vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER); @@ -104,7 +105,7 @@ public class ModelPool implements ModelAllocator { * @return true if the buffer was reallocated */ private boolean realloc() { - int neededSize = vertices * format.getStride(); + int neededSize = vertices * vertexType.getStride(); if (neededSize > bufferSize) { bufferSize = neededSize + 128; vbo.alloc(bufferSize); @@ -117,14 +118,14 @@ public class ModelPool implements ModelAllocator { private void uploadAll() { try (MappedBuffer buffer = vbo.getBuffer(0, bufferSize)) { - - VecBufferWriter consumer = new VecBufferWriter(buffer); + ByteBuffer buf = buffer.unwrap(); int vertices = 0; for (PooledModel model : models) { model.first = vertices; - model.model.buffer(consumer); - if (model.callback != null) model.callback.onAlloc(model); + + buffer(buf, model); + vertices += model.getVertexCount(); } @@ -135,14 +136,9 @@ public class ModelPool implements ModelAllocator { private void uploadPending() { try (MappedBuffer buffer = vbo.getBuffer(0, bufferSize)) { - VecBufferWriter consumer = new VecBufferWriter(buffer); - - int stride = format.getStride(); + ByteBuffer buf = buffer.unwrap(); for (PooledModel model : pendingUpload) { - int pos = model.first * stride; - buffer.position(pos); - model.model.buffer(consumer); - if (model.callback != null) model.callback.onAlloc(model); + buffer(buf, model); } pendingUpload.clear(); } 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() { dirty = true; } diff --git a/src/main/java/com/jozufozu/flywheel/core/Formats.java b/src/main/java/com/jozufozu/flywheel/core/Formats.java index 6632c2117..fcd25a452 100644 --- a/src/main/java/com/jozufozu/flywheel/core/Formats.java +++ b/src/main/java/com/jozufozu/flywheel/core/Formats.java @@ -6,7 +6,7 @@ import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat; public class Formats { public static final VertexFormat UNLIT_MODEL = VertexFormat.builder() - .addAttributes(CommonAttributes.VEC3, CommonAttributes.NORMAL, CommonAttributes.UV) + .addAttributes(CommonAttributes.VEC3, CommonAttributes.UV, CommonAttributes.NORMAL) .build(); public static final VertexFormat COLORED_LIT_MODEL = VertexFormat.builder() diff --git a/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingRenderer.java b/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingRenderer.java index f15d3ea91..57f75d84f 100644 --- a/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingRenderer.java +++ b/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingRenderer.java @@ -77,7 +77,7 @@ public class CrumblingRenderer { instanceManager.beginFrame(info); - materials.render(event, null); + materials.render(event); instanceManager.invalidate(); } diff --git a/src/main/java/com/jozufozu/flywheel/core/model/BlockModel.java b/src/main/java/com/jozufozu/flywheel/core/model/BlockModel.java index 172cf217a..c33013ed3 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/BlockModel.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/BlockModel.java @@ -1,12 +1,8 @@ package com.jozufozu.flywheel.core.model; -import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat; -import com.jozufozu.flywheel.core.Formats; -import com.jozufozu.flywheel.util.BufferBuilderReader; +import com.jozufozu.flywheel.util.UnsafeBlockFormatReader; import com.jozufozu.flywheel.util.ModelReader; -import com.jozufozu.flywheel.util.RenderMath; import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; import net.minecraft.client.Minecraft; import net.minecraft.client.resources.model.BakedModel; @@ -33,38 +29,27 @@ public class BlockModel implements Model { } 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(); } + @Override + public void configure(ModelTransformer.Context ctx) { + ctx.inputHasDiffuse = true; + } + @Override public String name() { return name; } - @Override - public VertexFormat format() { - return Formats.UNLIT_MODEL; - } - @Override public int vertexCount() { return reader.getVertexCount(); } @Override - public void buffer(VertexConsumer buffer) { - - 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(); - } + public ModelReader getReader() { + return reader; } } diff --git a/src/main/java/com/jozufozu/flywheel/core/model/BlockType.java b/src/main/java/com/jozufozu/flywheel/core/model/BlockType.java new file mode 100644 index 000000000..c766c89d3 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/model/BlockType.java @@ -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; + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/model/Model.java b/src/main/java/com/jozufozu/flywheel/core/model/Model.java index 863cef816..631cb2362 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/Model.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/Model.java @@ -3,8 +3,9 @@ package com.jozufozu.flywheel.core.model; import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat; import com.jozufozu.flywheel.backend.model.ElementBuffer; 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.mojang.blaze3d.vertex.VertexConsumer; /** * A model that can be rendered by flywheel. @@ -33,20 +34,27 @@ public interface Model { */ String name(); - /** - * Copy this model into the given buffer. - */ - void buffer(VertexConsumer buffer); + ModelReader getReader(); /** * @return The number of vertices the model has. */ int vertexCount(); + default void configure(ModelTransformer.Context ctx) { + + } + + default VertexType getType() { + return PosNormalTexType.INSTANCE; + } + /** * @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. @@ -77,6 +85,4 @@ public interface Model { default boolean empty() { return vertexCount() == 0; } - - ModelReader getReader(); } diff --git a/src/main/java/com/jozufozu/flywheel/core/model/ModelPart.java b/src/main/java/com/jozufozu/flywheel/core/model/ModelPart.java index 0b87087fb..854779e69 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/ModelPart.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/ModelPart.java @@ -3,29 +3,35 @@ package com.jozufozu.flywheel.core.model; import java.nio.ByteBuffer; import java.util.List; -import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat; -import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer; -import com.jozufozu.flywheel.core.Formats; +import com.jozufozu.flywheel.core.vertex.PosNormalTexReader; +import com.jozufozu.flywheel.core.vertex.PosTexNormalWriter; import com.jozufozu.flywheel.util.ModelReader; -import com.jozufozu.flywheel.util.RenderMath; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.math.Vector3f; +import com.mojang.blaze3d.platform.MemoryTracker; public class ModelPart implements Model { - private final List cuboids; - private int vertices; + private final int vertices; private final String name; + private final PosNormalTexReader reader; public ModelPart(List cuboids, String name) { - this.cuboids = cuboids; this.name = name; - vertices = 0; - - for (PartBuilder.CuboidBuilder cuboid : cuboids) { - vertices += cuboid.vertices(); + { + int vertices = 0; + for (PartBuilder.CuboidBuilder cuboid : cuboids) { + 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) { @@ -37,111 +43,13 @@ public class ModelPart implements Model { return name; } - @Override - public void buffer(VertexConsumer buffer) { - for (PartBuilder.CuboidBuilder cuboid : cuboids) { - cuboid.buffer(buffer); - } - } - @Override public int vertexCount() { return vertices; } - @Override - public VertexFormat format() { - return Formats.UNLIT_MODEL; - } - @Override public ModelReader getReader() { - return new PartReader(this); - } - - 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; - } + return reader; } } diff --git a/src/main/java/com/jozufozu/flywheel/core/model/ModelTransformer.java b/src/main/java/com/jozufozu/flywheel/core/model/ModelTransformer.java index 4a8b6bf72..d5e1dbcab 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/ModelTransformer.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/ModelTransformer.java @@ -1,6 +1,7 @@ package com.jozufozu.flywheel.core.model; import com.jozufozu.flywheel.util.ModelReader; +import com.jozufozu.flywheel.util.RenderMath; import com.jozufozu.flywheel.util.transform.Transform; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; @@ -16,6 +17,8 @@ public class ModelTransformer { private final Model model; private final ModelReader reader; + public final Context context = new Context(); + public ModelTransformer(Model model) { this.model = model; reader = model.getReader(); @@ -34,7 +37,7 @@ public class ModelTransformer { modelMat.multiply(params.model); Matrix3f normalMat; - if (params.fullNormalTransform) { + if (context.fullNormalTransform) { normalMat = input.last().normal().copy(); normalMat.mul(params.normal); } else { @@ -61,42 +64,46 @@ public class ModelTransformer { float ny = normal.y(); float nz = normal.z(); - float instanceDiffuse = LightUtil.diffuseLight(nx, ny, nz); - - switch (params.colorMode) { - 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 { + if (params.useParamColor) { + if (context.outputColorDiffuse) { + float instanceDiffuse = LightUtil.diffuseLight(nx, ny, nz); int colorR = transformColor(params.r, instanceDiffuse); int colorG = transformColor(params.g, instanceDiffuse); int colorB = transformColor(params.b, instanceDiffuse); 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); @@ -110,11 +117,10 @@ public class ModelTransformer { builder.uv(u, v); } - if (params.hasOverlay) { - builder.overlayCoords(params.overlay); - } + // not always used, but will be ignored by formats that don't use it + 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); @@ -128,7 +134,7 @@ public class ModelTransformer { @Override public String toString() { - return "SuperByteBuffer[" + model + ']'; + return "ModelTransformer[" + model + ']'; } public static int transformColor(int component, float scale) { @@ -140,28 +146,32 @@ public class ModelTransformer { void shift(VertexConsumer builder, float u, float v); } - public enum ColorMode { - MODEL_ONLY, - MODEL_DIFFUSE, - DIFFUSE_ONLY, - RECOLOR - } + public static class Context { + /** + * Do we need to include the PoseStack transforms in our transformation of the normal? + */ + 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 { - // Vertex Position + + // Transform public final Matrix4f model; public final Matrix3f normal; // Vertex Coloring - public ColorMode colorMode; - public DiffuseMode diffuseMode; + public boolean useParamColor; public int r; public int g; public int b; @@ -171,46 +181,47 @@ public class ModelTransformer { public SpriteShiftFunc spriteShiftFunc; // Vertex Overlay Color - public boolean hasOverlay; public int overlay; // Vertex Lighting - public boolean hasCustomLight; + public boolean useParamLight; public int packedLightCoords; - // Vertex Normals - public boolean fullNormalTransform; - public Params() { model = new Matrix4f(); 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) { model.load(from.model); normal.load(from.normal); - colorMode = from.colorMode; - diffuseMode = from.diffuseMode; + useParamColor = from.useParamColor; r = from.r; g = from.g; b = from.b; a = from.a; spriteShiftFunc = from.spriteShiftFunc; - hasOverlay = from.hasOverlay; overlay = from.overlay; - hasCustomLight = from.hasCustomLight; + useParamLight = from.useParamLight; 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) { - this.colorMode = ColorMode.RECOLOR; + this.useParamColor = true; this.r = r; this.g = g; this.b = b; @@ -219,7 +230,7 @@ public class ModelTransformer { } public Params color(byte r, byte g, byte b, byte a) { - this.colorMode = ColorMode.RECOLOR; + this.useParamColor = true; this.r = Byte.toUnsignedInt(r); this.g = Byte.toUnsignedInt(g); this.b = Byte.toUnsignedInt(b); @@ -228,7 +239,7 @@ public class ModelTransformer { } public Params color(int color) { - this.colorMode = ColorMode.RECOLOR; + this.useParamColor = true; this.r = ((color >> 16) & 0xFF); this.g = ((color >> 8) & 0xFF); this.b = (color & 0xFF); @@ -241,29 +252,13 @@ public class ModelTransformer { return this; } - public Params overlay() { - this.hasOverlay = true; - return this; - } - public Params overlay(int overlay) { - this.hasOverlay = true; this.overlay = overlay; 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) { - this.hasCustomLight = true; + this.useParamLight = true; this.packedLightCoords = packedLightCoords; return this; } @@ -313,23 +308,5 @@ public class ModelTransformer { 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; - } } } diff --git a/src/main/java/com/jozufozu/flywheel/core/model/PartBuilder.java b/src/main/java/com/jozufozu/flywheel/core/model/PartBuilder.java index 0fb6f2383..f96ba4cab 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/PartBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/PartBuilder.java @@ -5,7 +5,7 @@ import java.util.EnumSet; import java.util.List; 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.Quaternion; import com.mojang.math.Vector3f; @@ -160,7 +160,7 @@ public class PartBuilder { return visibleFaces.size() * 4; } - public void buffer(VertexConsumer buffer) { + public void buffer(PosTexNormalWriter buffer) { float sizeX = posX2 - posX1; 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) { - buffer.vertex(vertices[0].x(), vertices[0].y(), vertices[0].z()).normal(normal.x(), normal.y(), normal.z()).uv(maxU, minV).endVertex(); - buffer.vertex(vertices[1].x(), vertices[1].y(), vertices[1].z()).normal(normal.x(), normal.y(), normal.z()).uv(minU, minV).endVertex(); - buffer.vertex(vertices[2].x(), vertices[2].y(), vertices[2].z()).normal(normal.x(), normal.y(), normal.z()).uv(minU, maxV).endVertex(); - buffer.vertex(vertices[3].x(), vertices[3].y(), vertices[3].z()).normal(normal.x(), normal.y(), normal.z()).uv(maxU, maxV).endVertex(); + public void quad(PosTexNormalWriter buffer, Vector3f[] vertices, float minU, float minV, float maxU, float maxV, Vector3f normal) { + buffer.putVertex(vertices[0].x(), vertices[0].y(), vertices[0].z(), normal.x(), normal.y(), normal.z(), maxU, minV); + buffer.putVertex(vertices[1].x(), vertices[1].y(), vertices[1].z(), normal.x(), normal.y(), normal.z(), minU, minV); + buffer.putVertex(vertices[2].x(), vertices[2].y(), vertices[2].z(), normal.x(), normal.y(), normal.z(), minU, maxV); + buffer.putVertex(vertices[3].x(), vertices[3].y(), vertices[3].z(), normal.x(), normal.y(), normal.z(), maxU, maxV); } diff --git a/src/main/java/com/jozufozu/flywheel/core/model/WorldModel.java b/src/main/java/com/jozufozu/flywheel/core/model/WorldModel.java index c5f5dff2e..4d61f4c80 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/WorldModel.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/WorldModel.java @@ -2,14 +2,10 @@ package com.jozufozu.flywheel.core.model; import java.util.Collection; -import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat; -import com.jozufozu.flywheel.core.Formats; -import com.jozufozu.flywheel.util.BufferBuilderReader; +import com.jozufozu.flywheel.core.vertex.VertexType; +import com.jozufozu.flywheel.util.UnsafeBlockFormatReader; 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.world.level.BlockAndTintGetter; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; @@ -20,7 +16,7 @@ public class WorldModel implements Model { private final String name; public WorldModel(BlockAndTintGetter renderWorld, RenderType layer, Collection blocks, String name) { - reader = new BufferBuilderReader(ModelUtil.getBufferBuilderFromTemplate(renderWorld, layer, blocks)); + reader = new UnsafeBlockFormatReader(ModelUtil.getBufferBuilderFromTemplate(renderWorld, layer, blocks)); this.name = name; } @@ -30,25 +26,8 @@ public class WorldModel implements Model { } @Override - public void buffer(VertexConsumer vertices) { - for (int i = 0; i < vertexCount(); i++) { - 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(); - } + public VertexType getType() { + return BlockType.INSTANCE; } @Override @@ -56,11 +35,6 @@ public class WorldModel implements Model { return reader.getVertexCount(); } - @Override - public VertexFormat format() { - return Formats.COLORED_LIT_MODEL; - } - @Override public ModelReader getReader() { return reader; diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/PosNormalTexReader.java b/src/main/java/com/jozufozu/flywheel/core/vertex/PosNormalTexReader.java new file mode 100644 index 000000000..f5c745148 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/PosNormalTexReader.java @@ -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; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/PosNormalTexType.java b/src/main/java/com/jozufozu/flywheel/core/vertex/PosNormalTexType.java new file mode 100644 index 000000000..eb2396848 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/PosNormalTexType.java @@ -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); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalWriter.java b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalWriter.java new file mode 100644 index 000000000..a0a7aa1f7 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalWriter.java @@ -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; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/VertexType.java b/src/main/java/com/jozufozu/flywheel/core/vertex/VertexType.java new file mode 100644 index 000000000..24fd80ba1 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/VertexType.java @@ -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(); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/mixin/BufferBuilderMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/BufferBuilderMixin.java index 76dd7f129..66c29bfd4 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/BufferBuilderMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/BufferBuilderMixin.java @@ -2,6 +2,7 @@ package com.jozufozu.flywheel.mixin; import java.nio.ByteBuffer; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.spongepowered.asm.mixin.Mixin; @@ -38,9 +39,11 @@ public abstract class BufferBuilderMixin implements DirectBufferBuilder { private int nextElementByte; @Override + @Nonnull public DirectVertexConsumer intoDirectConsumer(int vertexCount) { 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); @@ -49,7 +52,7 @@ public abstract class BufferBuilderMixin implements DirectBufferBuilder { .get(0); this.elementIndex = 0; this.nextElementByte += bytes; - this.buffer.position(consumer.startPos + bytes); + this.buffer.position(this.buffer.position() + bytes); return consumer; } diff --git a/src/main/java/com/jozufozu/flywheel/util/BufferBuilderReader.java b/src/main/java/com/jozufozu/flywheel/util/BlockFormatReader.java similarity index 70% rename from src/main/java/com/jozufozu/flywheel/util/BufferBuilderReader.java rename to src/main/java/com/jozufozu/flywheel/util/BlockFormatReader.java index eecf24e1b..2372d0036 100644 --- a/src/main/java/com/jozufozu/flywheel/util/BufferBuilderReader.java +++ b/src/main/java/com/jozufozu/flywheel/util/BlockFormatReader.java @@ -3,36 +3,24 @@ package com.jozufozu.flywheel.util; import java.nio.ByteBuffer; import com.mojang.blaze3d.vertex.BufferBuilder; -import com.mojang.blaze3d.vertex.VertexFormat; import com.mojang.datafixers.util.Pair; -public class BufferBuilderReader implements ModelReader { +public class BlockFormatReader implements ModelReader { private final ByteBuffer buffer; private final int vertexCount; - private final int formatSize; - private final int size; + private final int stride; - public BufferBuilderReader(BufferBuilder builder) { - VertexFormat vertexFormat = builder.getVertexFormat(); + public BlockFormatReader(BufferBuilder builder) { Pair data = builder.popNextBuffer(); buffer = data.getSecond(); - formatSize = vertexFormat.getVertexSize(); + stride = builder.getVertexFormat() + .getVertexSize(); vertexCount = data.getFirst() .vertexCount(); - size = vertexCount * formatSize; - - // TODO: adjust the getters based on the input format - // ImmutableList 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 @@ -41,7 +29,7 @@ public class BufferBuilderReader implements ModelReader { } private int vertIdx(int vertexIndex) { - return vertexIndex * formatSize; + return vertexIndex * stride; } @Override @@ -114,7 +102,4 @@ public class BufferBuilderReader implements ModelReader { return vertexCount; } - public int getSize() { - return size; - } } diff --git a/src/main/java/com/jozufozu/flywheel/util/Color.java b/src/main/java/com/jozufozu/flywheel/util/Color.java new file mode 100644 index 000000000..0a21b84bd --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/util/Color.java @@ -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 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); + } + +} diff --git a/src/main/java/com/jozufozu/flywheel/util/UnsafeBlockFormatReader.java b/src/main/java/com/jozufozu/flywheel/util/UnsafeBlockFormatReader.java new file mode 100644 index 000000000..a81ca4205 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/util/UnsafeBlockFormatReader.java @@ -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 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; + } +} diff --git a/src/main/resources/assets/flywheel/flywheel/shaders/data/modelvertex.glsl b/src/main/resources/assets/flywheel/flywheel/shaders/data/modelvertex.glsl index ae77b9b68..48e713b43 100644 --- a/src/main/resources/assets/flywheel/flywheel/shaders/data/modelvertex.glsl +++ b/src/main/resources/assets/flywheel/flywheel/shaders/data/modelvertex.glsl @@ -1,5 +1,5 @@ struct Vertex { vec3 pos; - vec3 normal; vec2 texCoords; + vec3 normal; };