From 83f4aaa4db0b7405b817b4122fc339f257b240ce Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Fri, 29 Jul 2022 15:58:34 -0700 Subject: [PATCH] A fresh batch of refactoring - Replace ModelTransformer with modular pipeline that closely resembles the instancing pipeline - StructTypes and Materials now provide a VertexTransformer that mutates a MutableVertexList - Rewrite all model building to make it cleaner, more flexible, and easier to use - Add SimpleMaterial.GlStateShard for easier control over GL state - Rename and move some classes --- .../java/com/jozufozu/flywheel/Flywheel.java | 4 +- .../api/instancer/InstancerFactory.java | 4 +- .../flywheel/api/material/Material.java | 13 +- .../flywheel/api/struct/StructType.java | 10 +- .../api/vertex/MutableVertexList.java | 38 +++ .../flywheel/api/vertex/ShadedVertexList.java | 5 - .../flywheel/api/vertex/VertexList.java | 34 +- .../backend/instancing/One2OneStorage.java | 5 - .../backend/instancing/SadCrumbling.java | 6 +- .../{ => batching}/BatchDrawingTracker.java | 15 +- .../instancing/batching/BatchLists.java | 12 +- .../instancing/batching/BatchedModel.java | 20 +- .../instancing/batching/BatchingEngine.java | 21 +- .../batching}/BufferBuilderExtension.java | 12 +- .../batching/CPUInstancerFactory.java | 10 +- .../instancing/{ => batching}/DrawBuffer.java | 40 ++- .../batching/MutableVertexListImpl.java | 206 ++++++++++++ .../instancing/batching/TransformSet.java | 135 ++++++-- .../instancing/batching/VertexFormatInfo.java | 64 ++++ .../effect/EffectInstanceManager.java | 5 - .../instancing/instancing/DrawCall.java | 3 +- .../instancing}/ElementBuffer.java | 2 +- .../instancing/GPUInstancerFactory.java | 8 +- .../instancing/instancing/InstancedModel.java | 20 +- .../instancing/InstancingEngine.java | 1 - .../instancing}/MeshPool.java | 6 +- .../backend/model/ArrayModelRenderer.java | 29 -- .../backend/model/DirectVertexConsumer.java | 180 ----------- .../flywheel/backend/model/package-info.java | 6 - .../com/jozufozu/flywheel/core/Materials.java | 171 +++++++++- .../com/jozufozu/flywheel/core/Models.java | 43 --- .../jozufozu/flywheel/core/QuadConverter.java | 2 +- .../core/crumbling/CrumblingRenderer.java | 3 - .../flywheel/core/hardcoded/ModelPart.java | 4 +- .../flywheel/core/layout/BufferLayout.java | 1 - .../core/material/SimpleMaterial.java | 116 ++++--- .../core/model/BakedModelBuilder.java | 47 --- .../flywheel/core/model/BlockMesh.java | 70 ---- .../flywheel/core/model/Bufferable.java | 18 -- .../jozufozu/flywheel/core/model/Mesh.java | 44 ++- .../jozufozu/flywheel/core/model/Model.java | 17 + .../flywheel/core/model/ModelSupplier.java | 11 - .../flywheel/core/model/ModelTransformer.java | 305 ------------------ .../flywheel/core/model/ModelUtil.java | 99 ++---- .../jozufozu/flywheel/core/model/Models.java | 48 +++ .../model/SeparatedWorldModelBuilder.java | 117 ------- .../model/ShadeSeparatedBufferBuilder.java | 25 -- .../model/ShadeSeparatingVertexConsumer.java | 84 ----- .../SimpleLazyModel.java} | 12 +- .../flywheel/core/model/SimpleMesh.java | 36 +++ .../flywheel/core/model/TessellatedModel.java | 25 ++ .../core/model/WorldModelBuilder.java | 86 ----- .../model/buffering/BakedModelBuilder.java | 136 ++++++++ .../model/buffering/BlockModelBuilder.java | 125 +++++++ .../LazyDelegatingVertexConsumer.java | 65 ++++ .../buffering/ModelBufferingObjects.java | 18 ++ .../model/buffering/ModelBufferingUtil.java | 283 ++++++++++++++++ .../buffering/MultiBlockModelBuilder.java | 128 ++++++++ .../ShadeSeparatingVertexConsumer.java | 75 +++++ .../core/structs/model/TransformedType.java | 43 ++- .../core/structs/oriented/OrientedType.java | 57 +++- .../flywheel/core/vertex/BlockVertex.java | 25 -- .../flywheel/core/vertex/BlockVertexList.java | 57 ++-- .../core/vertex/BlockVertexListUnsafe.java | 56 ++-- .../core/vertex/BlockWriterUnsafe.java | 26 +- .../vertex/PosTexNormalVertexListUnsafe.java | 39 +-- .../core/vertex/PosTexNormalWriterUnsafe.java | 16 +- .../flywheel/mixin/BufferBuilderMixin.java | 32 +- .../flywheel/mixin/RenderTypeMixin.java | 13 +- .../flywheel/util/DiffuseLightCalculator.java | 5 - .../flywheel/util/RenderTypeExtension.java | 2 +- .../flywheel/vanilla/BellInstance.java | 4 +- .../flywheel/vanilla/ChestInstance.java | 6 +- .../flywheel/vanilla/MinecartInstance.java | 6 +- .../flywheel/vanilla/ShulkerBoxInstance.java | 6 +- .../vanilla/effect/ExampleEffect.java | 2 +- 76 files changed, 1974 insertions(+), 1549 deletions(-) create mode 100644 src/main/java/com/jozufozu/flywheel/api/vertex/MutableVertexList.java delete mode 100644 src/main/java/com/jozufozu/flywheel/api/vertex/ShadedVertexList.java rename src/main/java/com/jozufozu/flywheel/backend/instancing/{ => batching}/BatchDrawingTracker.java (72%) rename src/main/java/com/jozufozu/flywheel/backend/{model => instancing/batching}/BufferBuilderExtension.java (60%) rename src/main/java/com/jozufozu/flywheel/backend/instancing/{ => batching}/DrawBuffer.java (54%) create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/batching/MutableVertexListImpl.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/batching/VertexFormatInfo.java rename src/main/java/com/jozufozu/flywheel/backend/{model => instancing/instancing}/ElementBuffer.java (87%) rename src/main/java/com/jozufozu/flywheel/backend/{model => instancing/instancing}/MeshPool.java (97%) delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/model/ArrayModelRenderer.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/model/DirectVertexConsumer.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/model/package-info.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/Models.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/model/BakedModelBuilder.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/model/BlockMesh.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/model/Bufferable.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/model/Model.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/model/ModelSupplier.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/model/ModelTransformer.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/model/Models.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/model/SeparatedWorldModelBuilder.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/model/ShadeSeparatedBufferBuilder.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/model/ShadeSeparatingVertexConsumer.java rename src/main/java/com/jozufozu/flywheel/core/{BasicModelSupplier.java => model/SimpleLazyModel.java} (65%) create mode 100644 src/main/java/com/jozufozu/flywheel/core/model/SimpleMesh.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/model/TessellatedModel.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/model/WorldModelBuilder.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/model/buffering/BakedModelBuilder.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/model/buffering/BlockModelBuilder.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/model/buffering/LazyDelegatingVertexConsumer.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/model/buffering/ModelBufferingObjects.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/model/buffering/ModelBufferingUtil.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/model/buffering/MultiBlockModelBuilder.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/model/buffering/ShadeSeparatingVertexConsumer.java diff --git a/src/main/java/com/jozufozu/flywheel/Flywheel.java b/src/main/java/com/jozufozu/flywheel/Flywheel.java index a36335422..7aaa6a7f6 100644 --- a/src/main/java/com/jozufozu/flywheel/Flywheel.java +++ b/src/main/java/com/jozufozu/flywheel/Flywheel.java @@ -7,17 +7,17 @@ import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.RenderWork; import com.jozufozu.flywheel.backend.ShadersModHandler; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; -import com.jozufozu.flywheel.backend.model.MeshPool; +import com.jozufozu.flywheel.backend.instancing.instancing.MeshPool; import com.jozufozu.flywheel.config.BackendTypeArgument; import com.jozufozu.flywheel.config.FlwCommands; import com.jozufozu.flywheel.config.FlwConfig; import com.jozufozu.flywheel.core.Components; -import com.jozufozu.flywheel.core.Models; import com.jozufozu.flywheel.core.PartialModel; import com.jozufozu.flywheel.core.QuadConverter; import com.jozufozu.flywheel.core.StitchedSprite; import com.jozufozu.flywheel.core.compile.ProgramCompiler; import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer; +import com.jozufozu.flywheel.core.model.Models; import com.jozufozu.flywheel.event.EntityWorldHandler; import com.jozufozu.flywheel.event.ForgeEvents; import com.jozufozu.flywheel.event.ReloadRenderersEvent; diff --git a/src/main/java/com/jozufozu/flywheel/api/instancer/InstancerFactory.java b/src/main/java/com/jozufozu/flywheel/api/instancer/InstancerFactory.java index 85ac11cea..d1005a207 100644 --- a/src/main/java/com/jozufozu/flywheel/api/instancer/InstancerFactory.java +++ b/src/main/java/com/jozufozu/flywheel/api/instancer/InstancerFactory.java @@ -1,6 +1,6 @@ package com.jozufozu.flywheel.api.instancer; -import com.jozufozu.flywheel.core.model.ModelSupplier; +import com.jozufozu.flywheel.core.model.Model; public interface InstancerFactory { @@ -10,6 +10,6 @@ public interface InstancerFactory { * @param modelKey An object that uniquely identifies and provides the model. * @return An instancer for the given model, capable of rendering many copies for little cost. */ - Instancer model(ModelSupplier modelKey); + Instancer model(Model modelKey); } diff --git a/src/main/java/com/jozufozu/flywheel/api/material/Material.java b/src/main/java/com/jozufozu/flywheel/api/material/Material.java index 5db75cb12..a93091d89 100644 --- a/src/main/java/com/jozufozu/flywheel/api/material/Material.java +++ b/src/main/java/com/jozufozu/flywheel/api/material/Material.java @@ -1,16 +1,15 @@ package com.jozufozu.flywheel.api.material; import com.jozufozu.flywheel.api.RenderStage; +import com.jozufozu.flywheel.api.vertex.MutableVertexList; import com.jozufozu.flywheel.core.source.FileResolution; +import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.renderer.RenderType; -import net.minecraft.resources.ResourceLocation; public interface Material { RenderStage getRenderStage(); - RenderType getBatchingRenderType(); - FileResolution getVertexShader(); FileResolution getFragmentShader(); @@ -18,4 +17,12 @@ public interface Material { void setup(); void clear(); + + RenderType getBatchingRenderType(); + + VertexTransformer getVertexTransformer(); + + public interface VertexTransformer { + void transform(MutableVertexList vertexList, ClientLevel level); + } } diff --git a/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java b/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java index 12bb3f1e5..7841f92de 100644 --- a/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java +++ b/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java @@ -3,10 +3,12 @@ package com.jozufozu.flywheel.api.struct; import java.nio.ByteBuffer; import com.jozufozu.flywheel.api.instancer.InstancedPart; +import com.jozufozu.flywheel.api.vertex.MutableVertexList; import com.jozufozu.flywheel.core.layout.BufferLayout; -import com.jozufozu.flywheel.core.model.ModelTransformer; import com.jozufozu.flywheel.core.source.FileResolution; +import net.minecraft.client.multiplayer.ClientLevel; + /** * A StructType contains metadata for a specific instance struct that Flywheel can interface with. * @param The java representation of the instance struct. @@ -32,6 +34,10 @@ public interface StructType { FileResolution getInstanceShader(); - void transform(S d, ModelTransformer.Params b); + VertexTransformer getVertexTransformer(); + + public interface VertexTransformer { + void transform(MutableVertexList vertexList, S struct, ClientLevel level); + } } diff --git a/src/main/java/com/jozufozu/flywheel/api/vertex/MutableVertexList.java b/src/main/java/com/jozufozu/flywheel/api/vertex/MutableVertexList.java new file mode 100644 index 000000000..e4796c038 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/vertex/MutableVertexList.java @@ -0,0 +1,38 @@ +package com.jozufozu.flywheel.api.vertex; + +public interface MutableVertexList extends VertexList { + void x(int index, float x); + + void y(int index, float y); + + void z(int index, float z); + + void r(int index, byte r); + + void g(int index, byte g); + + void b(int index, byte b); + + void a(int index, byte a); + + default void color(int index, int color) { + a(index, (byte) (color >> 24 & 0xFF)); + r(index, (byte) (color >> 16 & 0xFF)); + g(index, (byte) (color >> 8 & 0xFF)); + b(index, (byte) (color & 0xFF)); + } + + void u(int index, float u); + + void v(int index, float v); + + void overlay(int index, int overlay); + + void light(int index, int light); + + void normalX(int index, float normalX); + + void normalY(int index, float normalY); + + void normalZ(int index, float normalZ); +} diff --git a/src/main/java/com/jozufozu/flywheel/api/vertex/ShadedVertexList.java b/src/main/java/com/jozufozu/flywheel/api/vertex/ShadedVertexList.java deleted file mode 100644 index 227879b3a..000000000 --- a/src/main/java/com/jozufozu/flywheel/api/vertex/ShadedVertexList.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.jozufozu.flywheel.api.vertex; - -public interface ShadedVertexList extends VertexList { - boolean isShaded(int index); -} diff --git a/src/main/java/com/jozufozu/flywheel/api/vertex/VertexList.java b/src/main/java/com/jozufozu/flywheel/api/vertex/VertexList.java index 46edc536d..519ef671f 100644 --- a/src/main/java/com/jozufozu/flywheel/api/vertex/VertexList.java +++ b/src/main/java/com/jozufozu/flywheel/api/vertex/VertexList.java @@ -10,36 +10,40 @@ package com.jozufozu.flywheel.api.vertex; * TODO: more flexible elements? */ public interface VertexList { - float getX(int index); + float x(int index); - float getY(int index); + float y(int index); - float getZ(int index); + float z(int index); - byte getR(int index); + byte r(int index); - byte getG(int index); + byte g(int index); - byte getB(int index); + byte b(int index); - byte getA(int index); + byte a(int index); - float getU(int index); + default int color(int index) { + return a(index) << 24 | r(index) << 16 | g(index) << 8 | b(index); + } - float getV(int index); + float u(int index); - int getLight(int index); + float v(int index); - float getNX(int index); + int overlay(int index); - float getNY(int index); + int light(int index); - float getNZ(int index); + float normalX(int index); + + float normalY(int index); + + float normalZ(int index); int getVertexCount(); - VertexType getVertexType(); - default boolean isEmpty() { return getVertexCount() == 0; } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/One2OneStorage.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/One2OneStorage.java index d82858ad6..a58860944 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/One2OneStorage.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/One2OneStorage.java @@ -1,15 +1,10 @@ package com.jozufozu.flywheel.backend.instancing; -import java.util.ArrayList; import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; import java.util.Map; import org.jetbrains.annotations.Nullable; -import com.jozufozu.flywheel.api.instance.DynamicInstance; -import com.jozufozu.flywheel.api.instance.TickableInstance; import com.jozufozu.flywheel.api.instancer.InstancerManager; import com.jozufozu.flywheel.light.LightUpdater; diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/SadCrumbling.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/SadCrumbling.java index 497dce5a3..296544423 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/SadCrumbling.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/SadCrumbling.java @@ -14,7 +14,7 @@ import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstanceManager; import com.jozufozu.flywheel.backend.instancing.instancing.GPUInstancer; -import com.jozufozu.flywheel.core.model.ModelSupplier; +import com.jozufozu.flywheel.core.model.Model; import com.jozufozu.flywheel.mixin.LevelRendererAccessor; import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; @@ -94,8 +94,8 @@ public class SadCrumbling { // } @NotNull - private Map> modelsToParts(Int2ObjectMap>> dataByStage) { - var map = new HashMap>(); + private Map> modelsToParts(Int2ObjectMap>> dataByStage) { + var map = new HashMap>(); for (var entry : dataByStage.int2ObjectEntrySet()) { RenderType currentLayer = ModelBakery.DESTROY_TYPES.get(entry.getIntKey()); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/BatchDrawingTracker.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchDrawingTracker.java similarity index 72% rename from src/main/java/com/jozufozu/flywheel/backend/instancing/BatchDrawingTracker.java rename to src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchDrawingTracker.java index e3de27024..25ce1b86a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/BatchDrawingTracker.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchDrawingTracker.java @@ -1,10 +1,8 @@ -package com.jozufozu.flywheel.backend.instancing; +package com.jozufozu.flywheel.backend.instancing.batching; import java.util.HashSet; import java.util.Set; -import com.jozufozu.flywheel.backend.model.BufferBuilderExtension; -import com.jozufozu.flywheel.backend.model.DirectVertexConsumer; import com.jozufozu.flywheel.util.RenderTypeExtension; import com.mojang.blaze3d.vertex.BufferBuilder; @@ -21,16 +19,9 @@ public class BatchDrawingTracker { ((BufferBuilderExtension) scratch).flywheel$freeBuffer(); } - /** - * Get a direct vertex consumer for drawing the given number of vertices to the given RenderType. - * @param renderType The RenderType to draw to. - * @param vertexCount The number of vertices that will be drawn. - * @return A direct vertex consumer. - */ - public DirectVertexConsumer getDirectConsumer(RenderType renderType, int vertexCount) { + public DrawBuffer getBuffer(RenderType renderType) { activeTypes.add(renderType); - return RenderTypeExtension.getDrawBuffer(renderType) - .begin(vertexCount); + return RenderTypeExtension.getDrawBuffer(renderType); } /** diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchLists.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchLists.java index 3d3be00b2..615047612 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchLists.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchLists.java @@ -1,18 +1,14 @@ package com.jozufozu.flywheel.backend.instancing.batching; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; import net.minecraft.client.renderer.RenderType; public class BatchLists { - - public final Map>> renderLists = new HashMap<>(); + public final Multimap> renderLists = ArrayListMultimap.create(); public void add(TransformSet set) { - renderLists.computeIfAbsent(set.material.getBatchingRenderType(), k -> new ArrayList<>()) - .add(set); + renderLists.put(set.getMaterial().getBatchingRenderType(), set); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedModel.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedModel.java index 61a7bd048..6b0a56f34 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedModel.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedModel.java @@ -4,23 +4,23 @@ import java.util.List; import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.core.model.ModelSupplier; +import com.jozufozu.flywheel.core.model.Model; public class BatchedModel { - CPUInstancer instancer; - ModelSupplier model; - StructType type; + private final StructType type; + private final Model model; + private final CPUInstancer instancer; private List> layers; - public BatchedModel(StructType type, ModelSupplier model) { + public BatchedModel(StructType type, Model model) { this.type = type; this.model = model; this.instancer = new CPUInstancer<>(type); } public void init(BatchLists batchLists) { - layers = model.get() + layers = model.getMeshes() .entrySet() .stream() .map(entry -> new TransformSet<>(instancer, entry.getKey(), entry.getValue())) @@ -31,6 +31,14 @@ public class BatchedModel { } } + public Model getModel() { + return model; + } + + public CPUInstancer getInstancer() { + return instancer; + } + public void clear() { instancer.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 c12a67431..00fb68cd6 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 @@ -8,8 +8,6 @@ import java.util.Map; import com.jozufozu.flywheel.api.RenderStage; import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.backend.ShadersModHandler; -import com.jozufozu.flywheel.backend.instancing.BatchDrawingTracker; import com.jozufozu.flywheel.backend.instancing.Engine; import com.jozufozu.flywheel.backend.instancing.InstanceManager; import com.jozufozu.flywheel.backend.instancing.TaskEngine; @@ -20,6 +18,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Matrix4f; import net.minecraft.client.Camera; +import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.core.BlockPos; import net.minecraft.core.Vec3i; import net.minecraft.world.phys.Vec3; @@ -48,21 +47,20 @@ public class BatchingEngine implements Engine { return BlockPos.ZERO; } - public void submitTasks(PoseStack stack, TaskEngine taskEngine) { - batchLists.renderLists.forEach((renderType, renderList) -> { + public void submitTasks(TaskEngine taskEngine, PoseStack stack, ClientLevel level) { + batchLists.renderLists.asMap().forEach((renderType, renderList) -> { int vertices = 0; for (var transformSet : renderList) { vertices += transformSet.getTotalVertexCount(); } - var consumer = batchTracker.getDirectConsumer(renderType, vertices); - consumer.memSetZero(); - - var outputColorDiffuse = !consumer.hasOverlay() && !ShadersModHandler.isShaderPackInUse(); + DrawBuffer buffer = batchTracker.getBuffer(renderType); + buffer.prepare(vertices); + int startVertex = 0; for (var transformSet : renderList) { - transformSet.setOutputColorDiffuse(outputColorDiffuse); - transformSet.submitTasks(stack, taskEngine, consumer); + transformSet.submitTasks(taskEngine, buffer, startVertex, stack, level); + startVertex += transformSet.getTotalVertexCount(); } }); } @@ -83,7 +81,6 @@ public class BatchingEngine implements Engine { Lighting.setupLevel(mat); } - taskEngine.syncPoint(); batchTracker.endBatch(); } @@ -109,7 +106,7 @@ public class BatchingEngine implements Engine { var stack = FlwUtil.copyPoseStack(context.stack()); stack.translate(-cameraPos.x, -cameraPos.y, -cameraPos.z); - submitTasks(stack, taskEngine); + submitTasks(taskEngine, stack, context.level()); } @Override diff --git a/src/main/java/com/jozufozu/flywheel/backend/model/BufferBuilderExtension.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BufferBuilderExtension.java similarity index 60% rename from src/main/java/com/jozufozu/flywheel/backend/model/BufferBuilderExtension.java rename to src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BufferBuilderExtension.java index 4aec62268..f1dfe2388 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/model/BufferBuilderExtension.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BufferBuilderExtension.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.model; +package com.jozufozu.flywheel.backend.instancing.batching; import java.nio.ByteBuffer; @@ -12,8 +12,6 @@ import com.mojang.blaze3d.vertex.VertexFormat; */ public interface BufferBuilderExtension { - int flywheel$getVertices(); - /** * Frees the internal ByteBuffer, if it exists. */ @@ -26,12 +24,4 @@ public interface BufferBuilderExtension { * @param vertexCount The number of vertices in the buffer. */ void flywheel$injectForRender(ByteBuffer buffer, VertexFormat format, int vertexCount); - - /** - * Appends the remaining bytes from the given buffer to this BufferBuilder. - * @param buffer The buffer from which to copy bytes. - * @throws IllegalStateException If this BufferBuilder is not started or is the process of writing a vertex - * @throws IllegalArgumentException If the given buffer does not contain a whole number of vertices - */ - void flywheel$appendBufferUnsafe(ByteBuffer buffer); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancerFactory.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancerFactory.java index f24bbccaa..a8a09fd79 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancerFactory.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancerFactory.java @@ -8,11 +8,11 @@ import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.instancer.Instancer; import com.jozufozu.flywheel.api.instancer.InstancerFactory; import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.core.model.ModelSupplier; +import com.jozufozu.flywheel.core.model.Model; public class CPUInstancerFactory implements InstancerFactory { - protected final Map> models; + protected final Map> models; private final StructType type; private final Consumer> creationListener; @@ -25,8 +25,8 @@ public class CPUInstancerFactory implements InstancerFa } @Override - public Instancer model(ModelSupplier modelKey) { - return models.computeIfAbsent(modelKey, this::createModel).instancer; + public Instancer model(Model modelKey) { + return models.computeIfAbsent(modelKey, this::createModel).getInstancer(); } /** @@ -37,7 +37,7 @@ public class CPUInstancerFactory implements InstancerFa .forEach(BatchedModel::clear); } - private BatchedModel createModel(ModelSupplier k) { + private BatchedModel createModel(Model k) { var out = new BatchedModel<>(type, k); creationListener.accept(out); return out; diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/DrawBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/DrawBuffer.java similarity index 54% rename from src/main/java/com/jozufozu/flywheel/backend/instancing/DrawBuffer.java rename to src/main/java/com/jozufozu/flywheel/backend/instancing/batching/DrawBuffer.java index 8ba605f23..e583f85e1 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/DrawBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/DrawBuffer.java @@ -1,45 +1,47 @@ -package com.jozufozu.flywheel.backend.instancing; +package com.jozufozu.flywheel.backend.instancing.batching; import java.nio.ByteBuffer; -import com.jozufozu.flywheel.backend.model.BufferBuilderExtension; -import com.jozufozu.flywheel.backend.model.DirectVertexConsumer; +import org.lwjgl.system.MemoryUtil; + import com.mojang.blaze3d.platform.MemoryTracker; -import com.mojang.blaze3d.vertex.VertexFormat; import net.minecraft.client.renderer.RenderType; /** - * A byte buffer that can be used to draw vertices through a {@link DirectVertexConsumer}. + * A byte buffer that can be used to draw vertices through multiple {@link MutableVertexListImpl}s. * * The number of vertices needs to be known ahead of time. */ public class DrawBuffer { - private final RenderType parent; + private final VertexFormatInfo formatInfo; + private ByteBuffer backingBuffer; private int expectedVertices; + private long ptr; public DrawBuffer(RenderType parent) { this.parent = parent; + formatInfo = new VertexFormatInfo(parent.format()); } /** - * Creates a direct vertex consumer that can be used to write vertices into this buffer. + * Prepares this buffer by initializing a block of memory. * @param vertexCount The number of vertices to reserve memory for. - * @return A direct vertex consumer. * @throws IllegalStateException If the buffer is already in use. */ - public DirectVertexConsumer begin(int vertexCount) { + public void prepare(int vertexCount) { if (expectedVertices != 0) { throw new IllegalStateException("Already drawing"); } this.expectedVertices = vertexCount; - VertexFormat format = parent.format(); - - int byteSize = format.getVertexSize() * vertexCount; + // Add one extra vertex to uphold the vanilla assumption that BufferBuilders have at least + // enough buffer space for one more vertex. Sodium checks for this extra space when popNextBuffer + // is called and reallocates the buffer if there is not space for one more vertex. + int byteSize = formatInfo.stride * (vertexCount + 1); if (backingBuffer == null) { backingBuffer = MemoryTracker.create(byteSize); @@ -47,7 +49,13 @@ public class DrawBuffer { backingBuffer = MemoryTracker.resize(backingBuffer, byteSize); } - return new DirectVertexConsumer(backingBuffer, format, vertexCount); + backingBuffer.clear(); + ptr = MemoryUtil.memAddress(backingBuffer); + MemoryUtil.memSet(ptr, 0, byteSize); + } + + public MutableVertexListImpl slice(int startVertex, int vertexCount) { + return new MutableVertexListImpl(ptr + startVertex * formatInfo.stride, formatInfo, vertexCount); } /** @@ -55,7 +63,11 @@ public class DrawBuffer { * @param bufferBuilder The buffer builder to inject into. */ public void inject(BufferBuilderExtension bufferBuilder) { - bufferBuilder.flywheel$injectForRender(backingBuffer, parent.format(), expectedVertices); + bufferBuilder.flywheel$injectForRender(backingBuffer, formatInfo.format, expectedVertices); + } + + public int getVertexCount() { + return expectedVertices; } /** diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/MutableVertexListImpl.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/MutableVertexListImpl.java new file mode 100644 index 000000000..410da67af --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/MutableVertexListImpl.java @@ -0,0 +1,206 @@ +package com.jozufozu.flywheel.backend.instancing.batching; + +import org.lwjgl.system.MemoryUtil; + +import com.jozufozu.flywheel.api.vertex.MutableVertexList; +import com.jozufozu.flywheel.util.RenderMath; + +public class MutableVertexListImpl extends VertexFormatInfo implements MutableVertexList { + private final long anchorPtr; + private final int totalVertexCount; + + private long ptr; + private int vertexCount; + + public MutableVertexListImpl(long ptr, VertexFormatInfo formatInfo, int vertexCount) { + super(formatInfo); + + anchorPtr = ptr; + totalVertexCount = vertexCount; + + setFullRange(); + } + + public void setRange(int startVertex, int vertexCount) { + ptr = anchorPtr + startVertex * stride; + this.vertexCount = vertexCount; + } + + public void setFullRange() { + ptr = anchorPtr; + vertexCount = totalVertexCount; + } + + @Override + public float x(int index) { + if (positionOffset < 0) return 0; + return MemoryUtil.memGetFloat(ptr + index * stride + positionOffset); + } + + @Override + public float y(int index) { + if (positionOffset < 0) return 0; + return MemoryUtil.memGetFloat(ptr + index * stride + positionOffset + 4); + } + + @Override + public float z(int index) { + if (positionOffset < 0) return 0; + return MemoryUtil.memGetFloat(ptr + index * stride + positionOffset + 8); + } + + @Override + public byte r(int index) { + if (colorOffset < 0) return 0; + return MemoryUtil.memGetByte(ptr + index * stride + colorOffset); + } + + @Override + public byte g(int index) { + if (colorOffset < 0) return 0; + return MemoryUtil.memGetByte(ptr + index * stride + colorOffset + 1); + } + + @Override + public byte b(int index) { + if (colorOffset < 0) return 0; + return MemoryUtil.memGetByte(ptr + index * stride + colorOffset + 2); + } + + @Override + public byte a(int index) { + if (colorOffset < 0) return 0; + return MemoryUtil.memGetByte(ptr + index * stride + colorOffset + 3); + } + + @Override + public float u(int index) { + if (textureOffset < 0) return 0; + return MemoryUtil.memGetFloat(ptr + index * stride + textureOffset); + } + + @Override + public float v(int index) { + if (textureOffset < 0) return 0; + return MemoryUtil.memGetFloat(ptr + index * stride + textureOffset + 4); + } + + @Override + public int overlay(int index) { + if (overlayOffset < 0) return 0; + return MemoryUtil.memGetInt(ptr + index * stride + overlayOffset); + } + + @Override + public int light(int index) { + if (lightOffset < 0) return 0; + return MemoryUtil.memGetInt(ptr + index * stride + lightOffset); + } + + @Override + public float normalX(int index) { + if (normalOffset < 0) return 0; + return RenderMath.f(MemoryUtil.memGetByte(ptr + index * stride + normalOffset)); + } + + @Override + public float normalY(int index) { + if (normalOffset < 0) return 0; + return RenderMath.f(MemoryUtil.memGetByte(ptr + index * stride + normalOffset + 1)); + } + + @Override + public float normalZ(int index) { + if (normalOffset < 0) return 0; + return RenderMath.f(MemoryUtil.memGetByte(ptr + index * stride + normalOffset + 2)); + } + + @Override + public int getVertexCount() { + return vertexCount; + } + + @Override + public void x(int index, float x) { + if (positionOffset < 0) return; + MemoryUtil.memPutFloat(ptr + index * stride + positionOffset, x); + } + + @Override + public void y(int index, float y) { + if (positionOffset < 0) return; + MemoryUtil.memPutFloat(ptr + index * stride + positionOffset + 4, y); + } + + @Override + public void z(int index, float z) { + if (positionOffset < 0) return; + MemoryUtil.memPutFloat(ptr + index * stride + positionOffset + 8, z); + } + + @Override + public void r(int index, byte r) { + if (colorOffset < 0) return; + MemoryUtil.memPutByte(ptr + index * stride + colorOffset, r); + } + + @Override + public void g(int index, byte g) { + if (colorOffset < 0) return; + MemoryUtil.memPutByte(ptr + index * stride + colorOffset + 1, g); + } + + @Override + public void b(int index, byte b) { + if (colorOffset < 0) return; + MemoryUtil.memPutByte(ptr + index * stride + colorOffset + 2, b); + } + + @Override + public void a(int index, byte a) { + if (colorOffset < 0) return; + MemoryUtil.memPutByte(ptr + index * stride + colorOffset + 3, a); + } + + @Override + public void u(int index, float u) { + if (textureOffset < 0) return; + MemoryUtil.memPutFloat(ptr + index * stride + textureOffset, u); + } + + @Override + public void v(int index, float v) { + if (textureOffset < 0) return; + MemoryUtil.memPutFloat(ptr + index * stride + textureOffset + 4, v); + } + + @Override + public void overlay(int index, int overlay) { + if (overlayOffset < 0) return; + MemoryUtil.memPutInt(ptr + index * stride + overlayOffset, overlay); + } + + @Override + public void light(int index, int light) { + if (lightOffset < 0) return; + MemoryUtil.memPutInt(ptr + index * stride + lightOffset, light); + } + + @Override + public void normalX(int index, float normalX) { + if (normalOffset < 0) return; + MemoryUtil.memPutByte(ptr + index * stride + normalOffset, RenderMath.nb(normalX)); + } + + @Override + public void normalY(int index, float normalY) { + if (normalOffset < 0) return; + MemoryUtil.memPutByte(ptr + index * stride + normalOffset + 1, RenderMath.nb(normalY)); + } + + @Override + public void normalZ(int index, float normalZ) { + if (normalOffset < 0) return; + MemoryUtil.memPutByte(ptr + index * stride + normalOffset + 2, RenderMath.nb(normalZ)); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/TransformSet.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/TransformSet.java index 3fc42e21e..642fea29f 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/TransformSet.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/TransformSet.java @@ -4,29 +4,41 @@ import java.util.List; import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.material.Material; +import com.jozufozu.flywheel.api.struct.StructType; +import com.jozufozu.flywheel.api.struct.StructType.VertexTransformer; +import com.jozufozu.flywheel.api.vertex.MutableVertexList; +import com.jozufozu.flywheel.api.vertex.VertexList; import com.jozufozu.flywheel.backend.instancing.TaskEngine; -import com.jozufozu.flywheel.backend.model.DirectVertexConsumer; import com.jozufozu.flywheel.core.model.Mesh; -import com.jozufozu.flywheel.core.model.ModelTransformer; import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Matrix3f; +import com.mojang.math.Matrix4f; +import com.mojang.math.Vector3f; +import com.mojang.math.Vector4f; + +import net.minecraft.client.multiplayer.ClientLevel; public class TransformSet { - public final Material material; - public final Mesh mesh; private final CPUInstancer instancer; - private final ModelTransformer modelTransformer; + private final Material material; + private final Mesh mesh; public TransformSet(CPUInstancer instancer, Material material, Mesh mesh) { this.instancer = instancer; this.material = material; this.mesh = mesh; - - modelTransformer = new ModelTransformer(mesh); } - void submitTasks(PoseStack stack, TaskEngine pool, DirectVertexConsumer consumer) { + public Material getMaterial() { + return material; + } + + public Mesh getMesh() { + return mesh; + } + + void submitTasks(TaskEngine pool, DrawBuffer buffer, int startVertex, PoseStack stack, ClientLevel level) { instancer.setup(); int instances = instancer.getInstanceCount(); @@ -36,39 +48,110 @@ public class TransformSet { instances -= 512; int start = Math.max(instances, 0); - int verts = mesh.getVertexCount() * (end - start); + int vertexCount = mesh.getVertexCount() * (end - start); + MutableVertexListImpl sub = buffer.slice(startVertex, vertexCount); + startVertex += vertexCount; - DirectVertexConsumer sub = consumer.split(verts); - - pool.submit(() -> drawRange(stack, sub, start, end)); + pool.submit(() -> drawRange(sub, start, end, stack, level)); } } - private void drawRange(PoseStack stack, VertexConsumer buffer, int from, int to) { - drawList(stack, buffer, instancer.getRange(from, to)); + private void drawRange(MutableVertexListImpl vertexList, int from, int to, PoseStack stack, ClientLevel level) { + drawList(vertexList, instancer.getRange(from, to), stack, level); } - void drawAll(PoseStack stack, VertexConsumer buffer) { - drawList(stack, buffer, instancer.getAll()); + void drawAll(MutableVertexListImpl vertexList, PoseStack stack, ClientLevel level) { + drawList(vertexList, instancer.getAll(), stack, level); } - private void drawList(PoseStack stack, VertexConsumer buffer, List list) { - ModelTransformer.Params params = new ModelTransformer.Params(); + private void drawList(MutableVertexListImpl vertexList, List list, PoseStack stack, ClientLevel level) { + int startVertex = 0; + int meshVertexCount = mesh.getVertexCount(); + + VertexList meshReader = mesh.getReader(); + @SuppressWarnings("unchecked") + StructType.VertexTransformer structVertexTransformer = (VertexTransformer) instancer.type.getVertexTransformer(); for (D d : list) { - params.loadDefault(); + vertexList.setRange(startVertex, meshVertexCount); - instancer.type.transform(d, params); + writeMesh(vertexList, meshReader); - modelTransformer.renderInto(params, stack, buffer); + structVertexTransformer.transform(vertexList, d, level); + + startVertex += meshVertexCount; + } + + vertexList.setFullRange(); + material.getVertexTransformer().transform(vertexList, level); + applyPoseStack(vertexList, stack, false); + } + + // TODO: remove this + // The VertexWriter API and VertexFormat conversion needs to be rewritten to make this unnecessary + private static void writeMesh(MutableVertexList vertexList, VertexList meshReader) { + for (int i = 0; i < meshReader.getVertexCount(); i++) { + vertexList.x(i, meshReader.x(i)); + vertexList.y(i, meshReader.y(i)); + vertexList.z(i, meshReader.z(i)); + + vertexList.r(i, meshReader.r(i)); + vertexList.g(i, meshReader.g(i)); + vertexList.b(i, meshReader.b(i)); + vertexList.a(i, meshReader.a(i)); + + vertexList.u(i, meshReader.u(i)); + vertexList.v(i, meshReader.v(i)); + + vertexList.overlay(i, meshReader.overlay(i)); + vertexList.light(i, meshReader.light(i)); + + vertexList.normalX(i, meshReader.normalX(i)); + vertexList.normalY(i, meshReader.normalY(i)); + vertexList.normalZ(i, meshReader.normalZ(i)); + } + } + + private static void applyPoseStack(MutableVertexList vertexList, PoseStack stack, boolean applyNormalMatrix) { + Vector4f pos = new Vector4f(); + Vector3f normal = new Vector3f(); + + Matrix4f modelMatrix = stack.last().pose(); + Matrix3f normalMatrix; + if (applyNormalMatrix) { + normalMatrix = stack.last().normal(); + } else { + normalMatrix = null; + } + + for (int i = 0; i < vertexList.getVertexCount(); i++) { + pos.set( + vertexList.x(i), + vertexList.y(i), + vertexList.z(i), + 1f + ); + pos.transform(modelMatrix); + vertexList.x(i, pos.x()); + vertexList.y(i, pos.y()); + vertexList.z(i, pos.z()); + + if (applyNormalMatrix) { + normal.set( + vertexList.normalX(i), + vertexList.normalY(i), + vertexList.normalZ(i) + ); + normal.transform(normalMatrix); + normal.normalize(); + vertexList.normalX(i, normal.x()); + vertexList.normalY(i, normal.y()); + vertexList.normalZ(i, normal.z()); + } } } public int getTotalVertexCount() { return mesh.getVertexCount() * instancer.getInstanceCount(); } - - public void setOutputColorDiffuse(boolean outputColorDiffuse) { - modelTransformer.context.outputColorDiffuse = outputColorDiffuse; - } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/VertexFormatInfo.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/VertexFormatInfo.java new file mode 100644 index 000000000..35f273508 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/VertexFormatInfo.java @@ -0,0 +1,64 @@ +package com.jozufozu.flywheel.backend.instancing.batching; + +import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.blaze3d.vertex.VertexFormatElement; + +public class VertexFormatInfo { + public final VertexFormat format; + public final int stride; + + public final int positionOffset; + public final int colorOffset; + public final int textureOffset; + public final int overlayOffset; + public final int lightOffset; + public final int normalOffset; + + public VertexFormatInfo(VertexFormat format) { + this.format = format; + stride = format.getVertexSize(); + + int positionOffset = -1; + int colorOffset = -1; + int textureOffset = -1; + int overlayOffset = -1; + int lightOffset = -1; + int normalOffset = -1; + + int offset = 0; + for (VertexFormatElement element : format.getElements()) { + switch (element.getUsage()) { + case POSITION -> positionOffset = offset; + case NORMAL -> normalOffset = offset; + case COLOR -> colorOffset = offset; + case UV -> { + switch (element.getIndex()) { + case 0 -> textureOffset = offset; + case 1 -> overlayOffset = offset; + case 2 -> lightOffset = offset; + } + } + } + + offset += element.getByteSize(); + } + + this.positionOffset = positionOffset; + this.colorOffset = colorOffset; + this.textureOffset = textureOffset; + this.overlayOffset = overlayOffset; + this.lightOffset = lightOffset; + this.normalOffset = normalOffset; + } + + protected VertexFormatInfo(VertexFormatInfo formatInfo) { + format = formatInfo.format; + stride = formatInfo.stride; + positionOffset = formatInfo.positionOffset; + colorOffset = formatInfo.colorOffset; + textureOffset = formatInfo.textureOffset; + overlayOffset = formatInfo.overlayOffset; + lightOffset = formatInfo.lightOffset; + normalOffset = formatInfo.normalOffset; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/effect/EffectInstanceManager.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/effect/EffectInstanceManager.java index efff6bd4e..3a57e6673 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/effect/EffectInstanceManager.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/effect/EffectInstanceManager.java @@ -1,14 +1,9 @@ package com.jozufozu.flywheel.backend.instancing.effect; import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; -import com.jozufozu.flywheel.api.instance.DynamicInstance; -import com.jozufozu.flywheel.api.instance.TickableInstance; import com.jozufozu.flywheel.api.instancer.InstancerManager; import com.jozufozu.flywheel.backend.instancing.AbstractInstance; import com.jozufozu.flywheel.backend.instancing.AbstractStorage; diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/DrawCall.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/DrawCall.java index a8f09ff28..334a42770 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/DrawCall.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/DrawCall.java @@ -4,13 +4,12 @@ import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.gl.GlStateTracker; import com.jozufozu.flywheel.backend.gl.array.GlVertexArray; -import com.jozufozu.flywheel.backend.model.MeshPool; import com.jozufozu.flywheel.core.model.Mesh; public class DrawCall { - final Material material; private final GPUInstancer instancer; + private final Material material; MeshPool.BufferedMesh bufferedMesh; GlVertexArray vao; diff --git a/src/main/java/com/jozufozu/flywheel/backend/model/ElementBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/ElementBuffer.java similarity index 87% rename from src/main/java/com/jozufozu/flywheel/backend/model/ElementBuffer.java rename to src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/ElementBuffer.java index 0eb07f21d..4164b6261 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/model/ElementBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/ElementBuffer.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.model; +package com.jozufozu.flywheel.backend.instancing.instancing; import com.jozufozu.flywheel.backend.gl.GlNumericType; import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer; diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancerFactory.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancerFactory.java index c209a5f7d..bae60adbc 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancerFactory.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancerFactory.java @@ -9,7 +9,7 @@ import com.jozufozu.flywheel.api.instancer.Instancer; import com.jozufozu.flywheel.api.instancer.InstancerFactory; import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.backend.instancing.AbstractInstancer; -import com.jozufozu.flywheel.core.model.ModelSupplier; +import com.jozufozu.flywheel.core.model.Model; /** * A collection of Instancers that all have the same format. @@ -17,7 +17,7 @@ import com.jozufozu.flywheel.core.model.ModelSupplier; */ public class GPUInstancerFactory implements InstancerFactory { - protected final Map> models = new HashMap<>(); + protected final Map> models = new HashMap<>(); protected final StructType type; private final Consumer> creationListener; @@ -27,7 +27,7 @@ public class GPUInstancerFactory implements InstancerFa } @Override - public Instancer model(ModelSupplier modelKey) { + public Instancer model(Model modelKey) { return models.computeIfAbsent(modelKey, this::createInstancer).getInstancer(); } @@ -61,7 +61,7 @@ public class GPUInstancerFactory implements InstancerFa .forEach(AbstractInstancer::clear); } - private InstancedModel createInstancer(ModelSupplier model) { + private InstancedModel createInstancer(Model model) { var instancer = new InstancedModel<>(type, model); this.creationListener.accept(instancer); return instancer; diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedModel.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedModel.java index 854ca0fac..0f67e625a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedModel.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedModel.java @@ -4,43 +4,43 @@ import java.util.List; import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.core.model.ModelSupplier; +import com.jozufozu.flywheel.core.model.Model; public class InstancedModel { - private final ModelSupplier model; private final StructType type; + private final Model model; private final GPUInstancer instancer; private List layers; - public InstancedModel(StructType type, ModelSupplier model) { + public InstancedModel(StructType type, Model model) { + this.type = type; this.model = model; this.instancer = new GPUInstancer<>(this, type); - this.type = type; } public void init(RenderLists renderLists) { instancer.init(); - layers = model.get() + layers = model.getMeshes() .entrySet() .stream() .map(entry -> new DrawCall(instancer, entry.getKey(), entry.getValue())) .toList(); for (DrawCall layer : layers) { - renderLists.add(new ShaderState(layer.material, layer.getVertexType(), type), layer); + renderLists.add(new ShaderState(layer.getMaterial(), layer.getVertexType(), type), layer); } } + public Model getModel() { + return model; + } + public GPUInstancer getInstancer() { return instancer; } - public ModelSupplier getModel() { - return model; - } - public int getVertexCount() { return model.getVertexCount() * instancer.glInstanceCount; } 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 b59aa562a..43d1acd41 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 @@ -18,7 +18,6 @@ import com.jozufozu.flywheel.backend.gl.GlTextureUnit; import com.jozufozu.flywheel.backend.instancing.Engine; import com.jozufozu.flywheel.backend.instancing.InstanceManager; import com.jozufozu.flywheel.backend.instancing.TaskEngine; -import com.jozufozu.flywheel.backend.model.MeshPool; import com.jozufozu.flywheel.core.RenderContext; import com.jozufozu.flywheel.core.compile.ContextShader; import com.jozufozu.flywheel.core.compile.ProgramCompiler; diff --git a/src/main/java/com/jozufozu/flywheel/backend/model/MeshPool.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/MeshPool.java similarity index 97% rename from src/main/java/com/jozufozu/flywheel/backend/model/MeshPool.java rename to src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/MeshPool.java index 171ea5abf..145f90ec3 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/model/MeshPool.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/MeshPool.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.model; +package com.jozufozu.flywheel.backend.instancing.instancing; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -192,7 +192,7 @@ public class MeshPool { this.mesh = mesh; this.byteIndex = byteIndex; this.ebo = mesh.createEBO(); - this.layout = mesh.getType() + this.layout = mesh.getVertexType() .getLayout(); } @@ -255,7 +255,7 @@ public class MeshPool { } public VertexType getVertexType() { - return this.mesh.getType(); + return this.mesh.getVertexType(); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/model/ArrayModelRenderer.java b/src/main/java/com/jozufozu/flywheel/backend/model/ArrayModelRenderer.java deleted file mode 100644 index f8e41586f..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/model/ArrayModelRenderer.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.jozufozu.flywheel.backend.model; - -import com.jozufozu.flywheel.backend.gl.array.GlVertexArray; -import com.jozufozu.flywheel.core.model.BlockMesh; - -public class ArrayModelRenderer { - - protected final GlVertexArray vao; - protected final MeshPool.BufferedMesh mesh; - - public ArrayModelRenderer(BlockMesh mesh, MeshPool meshPool) { - this.vao = new GlVertexArray(); - this.mesh = meshPool.alloc(mesh); - } - - /** - * Renders this model, checking first if there is anything to render. - */ - public void draw() { - if (mesh.isDeleted()) return; - - mesh.drawCall(vao); - } - - public void delete() { - mesh.delete(); - } - -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/model/DirectVertexConsumer.java b/src/main/java/com/jozufozu/flywheel/backend/model/DirectVertexConsumer.java deleted file mode 100644 index 3461e65e1..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/model/DirectVertexConsumer.java +++ /dev/null @@ -1,180 +0,0 @@ -package com.jozufozu.flywheel.backend.model; - -import java.nio.BufferOverflowException; -import java.nio.ByteBuffer; - -import org.lwjgl.system.MemoryUtil; - -import com.jozufozu.flywheel.util.RenderMath; -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 BufferBuilderExtension - */ -public class DirectVertexConsumer implements VertexConsumer { - public final VertexFormat format; - private final int stride; - public final int startPos; - - private int position = -1; - private int normal = -1; - private int color = -1; - private int uv = -1; - private int uv1 = -1; - private int uv2 = -1; - - private long vertexBase; - private final long end; - - public DirectVertexConsumer(ByteBuffer buffer, VertexFormat format, int maxVertices) { - this.format = format; - startPos = buffer.position(); - stride = format.getVertexSize(); - - int offset = 0; - - for (VertexFormatElement element : format.getElements()) { - switch (element.getUsage()) { - case POSITION -> this.position = offset; - case NORMAL -> this.normal = offset; - case COLOR -> this.color = offset; - case UV -> { - switch (element.getIndex()) { - case 0 -> this.uv = offset; - case 1 -> this.uv1 = offset; - case 2 -> this.uv2 = offset; - } - } - } - - offset += element.getByteSize(); - } - - this.vertexBase = MemoryUtil.memAddress(buffer, startPos); - this.end = vertexBase + (long) maxVertices * stride; - } - - private DirectVertexConsumer(DirectVertexConsumer parent, int maxVertices) { - this.format = parent.format; - this.stride = parent.stride; - this.startPos = parent.startPos; - this.position = parent.position; - this.normal = parent.normal; - this.color = parent.color; - this.uv = parent.uv; - this.uv1 = parent.uv1; - this.uv2 = parent.uv2; - - this.vertexBase = parent.vertexBase; - 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 this object's write-pointer. - * @param vertexCount The number of vertices that must be written to the head. - * @return The head of this consumer. - */ - public DirectVertexConsumer split(int vertexCount) { - int bytes = vertexCount * stride; - - DirectVertexConsumer head = new DirectVertexConsumer(this, vertexCount); - - this.vertexBase += bytes; - - return head; - } - - @Override - public VertexConsumer vertex(double x, double y, double z) { - checkOverflow(); - if (position < 0) return this; - long base = vertexBase + position; - MemoryUtil.memPutFloat(base, (float) x); - MemoryUtil.memPutFloat(base + 4, (float) y); - MemoryUtil.memPutFloat(base + 8, (float) z); - return this; - } - - @Override - 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); - MemoryUtil.memPutByte(base, (byte) r); - MemoryUtil.memPutByte(base + 1, (byte) g); - MemoryUtil.memPutByte(base + 2, (byte) b); - MemoryUtil.memPutByte(base + 3, (byte) a); - return this; - } - - @Override - public VertexConsumer uv(float u, float v) { - if (uv < 0) return this; - long base = vertexBase + uv; - MemoryUtil.memPutFloat(base, u); - MemoryUtil.memPutFloat(base + 4, v); - return this; - } - - @Override - public VertexConsumer overlayCoords(int u, int v) { - if (uv1 < 0) return this; - long base = vertexBase + uv1; - MemoryUtil.memPutShort(base, (short) u); - MemoryUtil.memPutShort(base + 2, (short) v); - return this; - } - - @Override - public VertexConsumer uv2(int u, int v) { - if (uv2 < 0) return this; - long base = vertexBase + uv2; - MemoryUtil.memPutShort(base, (short) u); - MemoryUtil.memPutShort(base + 2, (short) v); - return this; - } - - @Override - public VertexConsumer normal(float x, float y, float z) { - if (normal < 0) return this; - long base = vertexBase + normal; - MemoryUtil.memPutByte(base, RenderMath.nb(x)); - MemoryUtil.memPutByte(base + 1, RenderMath.nb(y)); - MemoryUtil.memPutByte(base + 2, RenderMath.nb(z)); - return this; - } - - @Override - public void endVertex() { - vertexBase += stride; - } - - @Override - public void defaultColor(int r, int g, int b, int a) { - - } - - @Override - public void unsetDefaultColor() { - - } - - private void checkOverflow() { - if (vertexBase >= end) { - throw new BufferOverflowException(); - } - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/model/package-info.java b/src/main/java/com/jozufozu/flywheel/backend/model/package-info.java deleted file mode 100644 index 3109529e1..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/model/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -package com.jozufozu.flywheel.backend.model; - -import javax.annotation.ParametersAreNonnullByDefault; - -import net.minecraft.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/core/Materials.java b/src/main/java/com/jozufozu/flywheel/core/Materials.java index d83021605..393ee2126 100644 --- a/src/main/java/com/jozufozu/flywheel/core/Materials.java +++ b/src/main/java/com/jozufozu/flywheel/core/Materials.java @@ -2,44 +2,189 @@ package com.jozufozu.flywheel.core; import com.jozufozu.flywheel.api.RenderStage; import com.jozufozu.flywheel.api.material.Material; +import com.jozufozu.flywheel.backend.ShadersModHandler; +import com.jozufozu.flywheel.backend.gl.GlTextureUnit; import com.jozufozu.flywheel.core.material.SimpleMaterial; +import com.jozufozu.flywheel.core.material.SimpleMaterial.GlStateShard; +import com.jozufozu.flywheel.util.DiffuseLightCalculator; +import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.Sheets; +import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.inventory.InventoryMenu; + +public final class Materials { + public static final Material.VertexTransformer SHADING_TRANSFORMER = (vertexList, level) -> { + if (ShadersModHandler.isShaderPackInUse()) { + return; + } + + DiffuseLightCalculator diffuseCalc = DiffuseLightCalculator.forLevel(level); + for (int i = 0; i < vertexList.getVertexCount(); i++) { + float diffuse = diffuseCalc.getDiffuse(vertexList.normalX(i), vertexList.normalY(i), vertexList.normalZ(i), true); + vertexList.r(i, (byte) Mth.clamp((int) (Byte.toUnsignedInt(vertexList.r(i)) * diffuse), 0, 255)); + vertexList.g(i, (byte) Mth.clamp((int) (Byte.toUnsignedInt(vertexList.g(i)) * diffuse), 0, 255)); + vertexList.b(i, (byte) Mth.clamp((int) (Byte.toUnsignedInt(vertexList.b(i)) * diffuse), 0, 255)); + } + }; -public class Materials { private static final ResourceLocation MINECART_LOCATION = new ResourceLocation("textures/entity/minecart.png"); - public static final Material DEFAULT = SimpleMaterial.builder() + + public static final Material CHUNK_SOLID_SHADED = SimpleMaterial.builder() .stage(RenderStage.AFTER_SOLID_TERRAIN) - .renderType(RenderType.cutout()) - .fragmentShader(Components.Files.CUTOUT_FRAGMENT) + .vertexShader(Components.Files.SHADED_VERTEX) + .fragmentShader(Components.Files.DEFAULT_FRAGMENT) + .addShard(Shards.diffuseTex(InventoryMenu.BLOCK_ATLAS, false, true)) + .batchingRenderType(RenderType.solid()) + .vertexTransformer(SHADING_TRANSFORMER) .register(); + public static final Material CHUNK_SOLID_UNSHADED = SimpleMaterial.builder() + .stage(RenderStage.AFTER_SOLID_TERRAIN) + .vertexShader(Components.Files.DEFAULT_VERTEX) + .fragmentShader(Components.Files.DEFAULT_FRAGMENT) + .addShard(Shards.diffuseTex(InventoryMenu.BLOCK_ATLAS, false, true)) + .batchingRenderType(RenderType.solid()) + .register(); + + public static final Material CHUNK_CUTOUT_MIPPED_SHADED = SimpleMaterial.builder() + .stage(RenderStage.AFTER_SOLID_TERRAIN) + .vertexShader(Components.Files.SHADED_VERTEX) + .fragmentShader(Components.Files.CUTOUT_FRAGMENT) + .addShard(Shards.diffuseTex(InventoryMenu.BLOCK_ATLAS, false, true)) + .batchingRenderType(RenderType.cutoutMipped()) + .vertexTransformer(SHADING_TRANSFORMER) + .register(); + public static final Material CHUNK_CUTOUT_MIPPED_UNSHADED = SimpleMaterial.builder() + .stage(RenderStage.AFTER_SOLID_TERRAIN) + .vertexShader(Components.Files.DEFAULT_VERTEX) + .fragmentShader(Components.Files.CUTOUT_FRAGMENT) + .addShard(Shards.diffuseTex(InventoryMenu.BLOCK_ATLAS, false, true)) + .batchingRenderType(RenderType.cutoutMipped()) + .register(); + + public static final Material CHUNK_CUTOUT_SHADED = SimpleMaterial.builder() + .stage(RenderStage.AFTER_SOLID_TERRAIN) + .vertexShader(Components.Files.SHADED_VERTEX) + .fragmentShader(Components.Files.CUTOUT_FRAGMENT) + .addShard(Shards.diffuseTex(InventoryMenu.BLOCK_ATLAS, false, false)) + .batchingRenderType(RenderType.cutout()) + .vertexTransformer(SHADING_TRANSFORMER) + .register(); + public static final Material CHUNK_CUTOUT_UNSHADED = SimpleMaterial.builder() + .stage(RenderStage.AFTER_SOLID_TERRAIN) + .vertexShader(Components.Files.DEFAULT_VERTEX) + .fragmentShader(Components.Files.CUTOUT_FRAGMENT) + .addShard(Shards.diffuseTex(InventoryMenu.BLOCK_ATLAS, false, false)) + .batchingRenderType(RenderType.cutout()) + .register(); + + public static final Material CHUNK_TRANSLUCENT_SHADED = SimpleMaterial.builder() + .stage(RenderStage.AFTER_TRANSLUCENT_TERRAIN) + .vertexShader(Components.Files.SHADED_VERTEX) + .fragmentShader(Components.Files.DEFAULT_FRAGMENT) + .addShard(Shards.diffuseTex(InventoryMenu.BLOCK_ATLAS, false, true)) + .addShard(Shards.TRANSLUCENT_TRANSPARENCY) + .batchingRenderType(RenderType.translucent()) + .vertexTransformer(SHADING_TRANSFORMER) + .register(); + public static final Material CHUNK_TRANSLUCENT_UNSHADED = SimpleMaterial.builder() + .stage(RenderStage.AFTER_TRANSLUCENT_TERRAIN) + .vertexShader(Components.Files.DEFAULT_VERTEX) + .fragmentShader(Components.Files.DEFAULT_FRAGMENT) + .addShard(Shards.diffuseTex(InventoryMenu.BLOCK_ATLAS, false, true)) + .addShard(Shards.TRANSLUCENT_TRANSPARENCY) + .batchingRenderType(RenderType.translucent()) + .register(); + + public static final Material CHUNK_TRIPWIRE_SHADED = SimpleMaterial.builder() + .stage(RenderStage.AFTER_TRANSLUCENT_TERRAIN) + .vertexShader(Components.Files.SHADED_VERTEX) + .fragmentShader(Components.Files.CUTOUT_FRAGMENT) + .addShard(Shards.diffuseTex(InventoryMenu.BLOCK_ATLAS, false, true)) + .addShard(Shards.TRANSLUCENT_TRANSPARENCY) + .batchingRenderType(RenderType.tripwire()) + .vertexTransformer(SHADING_TRANSFORMER) + .register(); + public static final Material CHUNK_TRIPWIRE_UNSHADED = SimpleMaterial.builder() + .stage(RenderStage.AFTER_TRANSLUCENT_TERRAIN) + .vertexShader(Components.Files.DEFAULT_VERTEX) + .fragmentShader(Components.Files.CUTOUT_FRAGMENT) + .addShard(Shards.diffuseTex(InventoryMenu.BLOCK_ATLAS, false, true)) + .addShard(Shards.TRANSLUCENT_TRANSPARENCY) + .batchingRenderType(RenderType.tripwire()) + .register(); + public static final Material CHEST = SimpleMaterial.builder() .stage(RenderStage.AFTER_BLOCK_ENTITIES) - .renderType(Sheets.chestSheet()) - .diffuseTex(Sheets.CHEST_SHEET) + .vertexShader(Components.Files.SHADED_VERTEX) + .addShard(Shards.diffuseTex(Sheets.CHEST_SHEET, false, false)) + .batchingRenderType(Sheets.chestSheet()) .register(); public static final Material SHULKER = SimpleMaterial.builder() .stage(RenderStage.AFTER_BLOCK_ENTITIES) - .renderType(Sheets.shulkerBoxSheet()) - .diffuseTex(Sheets.SHULKER_SHEET) + .vertexShader(Components.Files.SHADED_VERTEX) .fragmentShader(Components.Files.CUTOUT_FRAGMENT) - .alsoSetup(RenderSystem::disableCull) - .alsoClear(RenderSystem::enableCull) + .addShard(Shards.diffuseTex(Sheets.SHULKER_SHEET, false, false)) + .addShard(Shards.DISABLE_CULL) + .batchingRenderType(Sheets.shulkerBoxSheet()) .register(); public static final Material BELL = SimpleMaterial.builder() .stage(RenderStage.AFTER_BLOCK_ENTITIES) - .renderType(Sheets.solidBlockSheet()) + .vertexShader(Components.Files.SHADED_VERTEX) + .addShard(Shards.diffuseTex(InventoryMenu.BLOCK_ATLAS, false, false)) + .batchingRenderType(Sheets.solidBlockSheet()) .register(); public static final Material MINECART = SimpleMaterial.builder() .stage(RenderStage.AFTER_ENTITIES) - .renderType(RenderType.entitySolid(MINECART_LOCATION)) - .diffuseTex(MINECART_LOCATION) + .vertexShader(Components.Files.SHADED_VERTEX) + .addShard(Shards.diffuseTex(MINECART_LOCATION, false, false)) + .batchingRenderType(RenderType.entitySolid(MINECART_LOCATION)) .register(); public static void init() { // noop } + + public static final class Shards { + public static final GlStateShard DISABLE_CULL = new GlStateShard( + () -> { + RenderSystem.disableCull(); + }, + () -> { + RenderSystem.enableCull(); + } + ); + + public static final GlStateShard TRANSLUCENT_TRANSPARENCY = new GlStateShard( + () -> { + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); + }, + () -> { + RenderSystem.disableBlend(); + RenderSystem.defaultBlendFunc(); + } + ); + + public static GlStateShard diffuseTex(ResourceLocation loc, boolean blur, boolean mipmap) { + return new GlStateShard( + () -> { + GlTextureUnit.T0.makeActive(); + RenderSystem.enableTexture(); + AbstractTexture texture = Minecraft.getInstance().getTextureManager().getTexture(loc); + texture.setFilter(blur, mipmap); + RenderSystem.setShaderTexture(0, texture.getId()); + }, + () -> { + GlTextureUnit.T0.makeActive(); + RenderSystem.setShaderTexture(0, 0); + } + ); + } + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/Models.java b/src/main/java/com/jozufozu/flywheel/core/Models.java deleted file mode 100644 index 6e79277b6..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/Models.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.jozufozu.flywheel.core; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Supplier; - -import com.jozufozu.flywheel.core.model.BlockMesh; -import com.jozufozu.flywheel.core.model.ModelUtil; -import com.jozufozu.flywheel.event.ReloadRenderersEvent; -import com.jozufozu.flywheel.util.Pair; -import com.mojang.blaze3d.vertex.PoseStack; - -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.state.BlockState; - -public class Models { - public static BasicModelSupplier block(BlockState state) { - return BLOCK_STATE.computeIfAbsent(state, it -> new BasicModelSupplier(() -> new BlockMesh(it), Materials.DEFAULT)); - } - - public static BasicModelSupplier partial(PartialModel partial) { - return PARTIAL.computeIfAbsent(partial, it -> new BasicModelSupplier(() -> new BlockMesh(it), Materials.DEFAULT)); - } - - public static BasicModelSupplier partial(PartialModel partial, Direction dir) { - return partial(partial, dir, () -> ModelUtil.rotateToFace(dir)); - } - - public static BasicModelSupplier partial(PartialModel partial, Direction dir, Supplier modelTransform) { - return PARTIAL_DIR.computeIfAbsent(Pair.of(dir, partial), $ -> new BasicModelSupplier(() -> new BlockMesh(partial, modelTransform.get()), Materials.DEFAULT)); - } - - public static void onReload(ReloadRenderersEvent ignored) { - BLOCK_STATE.clear(); - PARTIAL.clear(); - PARTIAL_DIR.clear(); - } - - private static final Map BLOCK_STATE = new HashMap<>(); - private static final Map PARTIAL = new HashMap<>(); - private static final Map, BasicModelSupplier> PARTIAL_DIR = new HashMap<>(); - -} diff --git a/src/main/java/com/jozufozu/flywheel/core/QuadConverter.java b/src/main/java/com/jozufozu/flywheel/core/QuadConverter.java index 901e324f7..0b2477214 100644 --- a/src/main/java/com/jozufozu/flywheel/core/QuadConverter.java +++ b/src/main/java/com/jozufozu/flywheel/core/QuadConverter.java @@ -10,7 +10,7 @@ import com.jozufozu.flywheel.backend.gl.GlNumericType; 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.backend.model.ElementBuffer; +import com.jozufozu.flywheel.backend.instancing.instancing.ElementBuffer; import com.jozufozu.flywheel.event.ReloadRenderersEvent; /** 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 d4034dd3d..7459758f5 100644 --- a/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingRenderer.java +++ b/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingRenderer.java @@ -4,14 +4,11 @@ import java.util.ArrayList; import java.util.List; import java.util.SortedSet; -import com.google.common.collect.ListMultimap; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.gl.GlStateTracker; import com.jozufozu.flywheel.backend.instancing.InstanceManager; import com.jozufozu.flywheel.backend.instancing.SerialTaskEngine; -import com.jozufozu.flywheel.backend.instancing.instancing.DrawCall; import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine; -import com.jozufozu.flywheel.backend.instancing.instancing.ShaderState; import com.jozufozu.flywheel.core.Components; import com.jozufozu.flywheel.core.RenderContext; import com.jozufozu.flywheel.event.ReloadRenderersEvent; diff --git a/src/main/java/com/jozufozu/flywheel/core/hardcoded/ModelPart.java b/src/main/java/com/jozufozu/flywheel/core/hardcoded/ModelPart.java index a60aa14cb..b639d64e0 100644 --- a/src/main/java/com/jozufozu/flywheel/core/hardcoded/ModelPart.java +++ b/src/main/java/com/jozufozu/flywheel/core/hardcoded/ModelPart.java @@ -28,7 +28,7 @@ public class ModelPart implements Mesh { } try (var stack = MemoryStack.stackPush()) { - PosTexNormalWriterUnsafe writer = getType().createWriter(stack.malloc(size())); + PosTexNormalWriterUnsafe writer = getVertexType().createWriter(stack.malloc(size())); for (PartBuilder.CuboidBuilder cuboid : cuboids) { cuboid.buffer(writer); } @@ -57,7 +57,7 @@ public class ModelPart implements Mesh { } @Override - public PosTexNormalVertex getType() { + public PosTexNormalVertex getVertexType() { return Formats.POS_TEX_NORMAL; } } diff --git a/src/main/java/com/jozufozu/flywheel/core/layout/BufferLayout.java b/src/main/java/com/jozufozu/flywheel/core/layout/BufferLayout.java index 6d7ef05f9..74f958d6a 100644 --- a/src/main/java/com/jozufozu/flywheel/core/layout/BufferLayout.java +++ b/src/main/java/com/jozufozu/flywheel/core/layout/BufferLayout.java @@ -6,7 +6,6 @@ import java.util.List; import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.gl.array.VertexAttribute; -import com.jozufozu.flywheel.backend.gl.array.VertexAttributeF; /** * Classic Vertex Format struct with a clever name. diff --git a/src/main/java/com/jozufozu/flywheel/core/material/SimpleMaterial.java b/src/main/java/com/jozufozu/flywheel/core/material/SimpleMaterial.java index 53ab1d25b..0993f645d 100644 --- a/src/main/java/com/jozufozu/flywheel/core/material/SimpleMaterial.java +++ b/src/main/java/com/jozufozu/flywheel/core/material/SimpleMaterial.java @@ -1,39 +1,31 @@ package com.jozufozu.flywheel.core.material; -import org.jetbrains.annotations.Nullable; - import com.jozufozu.flywheel.api.RenderStage; import com.jozufozu.flywheel.api.material.Material; -import com.jozufozu.flywheel.backend.gl.GlTextureUnit; import com.jozufozu.flywheel.core.ComponentRegistry; import com.jozufozu.flywheel.core.Components; import com.jozufozu.flywheel.core.source.FileResolution; -import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderStateShard; import net.minecraft.client.renderer.RenderType; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.inventory.InventoryMenu; public class SimpleMaterial implements Material { protected final RenderStage stage; - protected final RenderType type; protected final FileResolution vertexShader; protected final FileResolution fragmentShader; - protected final ResourceLocation diffuseTex; - @Nullable protected final Runnable setup; - @Nullable protected final Runnable clear; + protected final RenderType batchingRenderType; + protected final VertexTransformer vertexTransformer; - public SimpleMaterial(RenderStage stage, RenderType type, FileResolution vertexShader, FileResolution fragmentShader, ResourceLocation diffuseTex, @Nullable Runnable setup, @Nullable Runnable clear) { + public SimpleMaterial(RenderStage stage, FileResolution vertexShader, FileResolution fragmentShader, Runnable setup, Runnable clear, RenderType batchingRenderType, VertexTransformer vertexTransformer) { this.stage = stage; - this.type = type; this.vertexShader = vertexShader; this.fragmentShader = fragmentShader; - this.diffuseTex = diffuseTex; this.setup = setup; this.clear = clear; + this.batchingRenderType = batchingRenderType; + this.vertexTransformer = vertexTransformer; } public static Builder builder() { @@ -45,11 +37,6 @@ public class SimpleMaterial implements Material { return stage; } - @Override - public RenderType getBatchingRenderType() { - return type; - } - @Override public FileResolution getVertexShader() { return vertexShader; @@ -62,34 +49,32 @@ public class SimpleMaterial implements Material { @Override public void setup() { - - GlTextureUnit.T0.makeActive(); - RenderSystem.setShaderTexture(0, diffuseTex); - Minecraft.getInstance().textureManager.bindForSetup(diffuseTex); - - if (setup != null) { - setup.run(); - } + setup.run(); } @Override public void clear() { - GlTextureUnit.T0.makeActive(); - RenderSystem.setShaderTexture(0, 0); + clear.run(); + } - if (clear != null) { - clear.run(); - } + @Override + public RenderType getBatchingRenderType() { + return batchingRenderType; + } + + @Override + public VertexTransformer getVertexTransformer() { + return vertexTransformer; } public static class Builder { protected RenderStage stage = RenderStage.AFTER_SOLID_TERRAIN; - protected RenderType type = RenderType.solid(); - protected FileResolution vertexShader = Components.Files.SHADED_VERTEX; + protected FileResolution vertexShader = Components.Files.DEFAULT_VERTEX; protected FileResolution fragmentShader = Components.Files.DEFAULT_FRAGMENT; - protected ResourceLocation diffuseTex = InventoryMenu.BLOCK_ATLAS; - protected Runnable setup = null; - protected Runnable clear = null; + protected Runnable setup = () -> {}; + protected Runnable clear = () -> {}; + protected RenderType batchingRenderType = RenderType.solid(); + protected VertexTransformer vertexTransformer = (vertexList, level) -> {}; public Builder() { } @@ -99,11 +84,6 @@ public class SimpleMaterial implements Material { return this; } - public Builder renderType(RenderType type) { - this.type = type; - return this; - } - public Builder vertexShader(FileResolution vertexShader) { this.vertexShader = vertexShader; return this; @@ -114,33 +94,63 @@ public class SimpleMaterial implements Material { return this; } - public Builder shaded() { - this.vertexShader = Components.Files.SHADED_VERTEX; + public Builder addSetup(Runnable setup) { + this.setup = chain(this.setup, setup); return this; } - public Builder unShaded() { - this.vertexShader = Components.Files.DEFAULT_VERTEX; + public Builder addClear(Runnable clear) { + this.clear = chain(this.clear, clear); return this; } - public Builder diffuseTex(ResourceLocation diffuseTex) { - this.diffuseTex = diffuseTex; + public Builder addShard(GlStateShard shard) { + addSetup(shard.getSetup()); + addClear(shard.getClear()); return this; } - public Builder alsoSetup(Runnable runnable) { - this.setup = runnable; + public Builder batchingRenderType(RenderType type) { + this.batchingRenderType = type; return this; } - public Builder alsoClear(Runnable clear) { - this.clear = clear; + public Builder vertexTransformer(VertexTransformer vertexTransformer) { + this.vertexTransformer = vertexTransformer; return this; } public SimpleMaterial register() { - return ComponentRegistry.register(new SimpleMaterial(stage, type, vertexShader, fragmentShader, diffuseTex, setup, clear)); + return ComponentRegistry.register(new SimpleMaterial(stage, vertexShader, fragmentShader, setup, clear, batchingRenderType, vertexTransformer)); + } + + private static Runnable chain(Runnable runnable1, Runnable runnable2) { + return () -> { + runnable1.run(); + runnable2.run(); + }; + } + } + + public static class GlStateShard { + protected final Runnable setup; + protected final Runnable clear; + + public GlStateShard(Runnable setup, Runnable clear) { + this.setup = setup; + this.clear = clear; + } + + public static GlStateShard fromVanilla(RenderStateShard vanillaShard) { + return new GlStateShard(() -> vanillaShard.setupRenderState(), () -> vanillaShard.clearRenderState()); + } + + public Runnable getSetup() { + return setup; + } + + public Runnable getClear() { + return clear; } } } diff --git a/src/main/java/com/jozufozu/flywheel/core/model/BakedModelBuilder.java b/src/main/java/com/jozufozu/flywheel/core/model/BakedModelBuilder.java deleted file mode 100644 index 1c48cfef8..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/model/BakedModelBuilder.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.jozufozu.flywheel.core.model; - -import java.util.Random; - -import com.jozufozu.flywheel.core.virtual.VirtualEmptyBlockGetter; -import com.jozufozu.flywheel.core.virtual.VirtualEmptyModelData; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; - -import net.minecraft.client.renderer.block.ModelBlockRenderer; -import net.minecraft.client.renderer.texture.OverlayTexture; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockState; - -public final class BakedModelBuilder implements Bufferable { - private final BakedModel model; - private BlockAndTintGetter renderWorld = VirtualEmptyBlockGetter.INSTANCE; - private BlockState referenceState = Blocks.AIR.defaultBlockState(); - private PoseStack poseStack = new PoseStack(); - - public BakedModelBuilder(BakedModel model) { - this.model = model; - } - - public BakedModelBuilder withRenderWorld(BlockAndTintGetter renderWorld) { - this.renderWorld = renderWorld; - return this; - } - - public BakedModelBuilder withReferenceState(BlockState referenceState) { - this.referenceState = referenceState; - return this; - } - - public BakedModelBuilder withPoseStack(PoseStack poseStack) { - this.poseStack = poseStack; - return this; - } - - @Override - public void bufferInto(ModelBlockRenderer blockRenderer, VertexConsumer consumer, Random random) { - blockRenderer.tesselateBlock(renderWorld, model, referenceState, BlockPos.ZERO, poseStack, consumer, false, random, 42, OverlayTexture.NO_OVERLAY, VirtualEmptyModelData.INSTANCE); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/model/BlockMesh.java b/src/main/java/com/jozufozu/flywheel/core/model/BlockMesh.java deleted file mode 100644 index 623f5062e..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/model/BlockMesh.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.jozufozu.flywheel.core.model; - -import com.jozufozu.flywheel.api.vertex.VertexList; -import com.jozufozu.flywheel.core.PartialModel; -import com.jozufozu.flywheel.core.vertex.Formats; -import com.mojang.blaze3d.vertex.PoseStack; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.world.level.block.state.BlockState; - -/** - * A model of a single block. - */ -public class BlockMesh implements Mesh { - private static final PoseStack IDENTITY = new PoseStack(); - - private final VertexList reader; - - private final String name; - - public BlockMesh(BlockState state) { - this(Minecraft.getInstance() - .getBlockRenderer() - .getBlockModel(state), state); - } - - public BlockMesh(BakedModel model, BlockState referenceState) { - this(model, referenceState, IDENTITY); - } - - public BlockMesh(PartialModel model) { - this(model, IDENTITY); - } - - public BlockMesh(PartialModel model, PoseStack ms) { - this(ModelUtil.bakedModel(model.get()) - .withPoseStack(ms), model.getName()); - } - - public BlockMesh(BakedModel model, BlockState referenceState, PoseStack ms) { - this(ModelUtil.bakedModel(model) - .withReferenceState(referenceState) - .withPoseStack(ms), referenceState.toString()); - } - - public BlockMesh(Bufferable builder, String name) { - this(Formats.BLOCK.createReader(builder.build()), name); - } - - public BlockMesh(VertexList reader, String name) { - this.reader = reader; - this.name = name; - } - - @Override - public String name() { - return name; - } - - @Override - public VertexList getReader() { - return reader; - } - - @Override - public String toString() { - return "BlockMesh{" + "name='" + name + "',type='" + reader.getVertexType() + "}"; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/model/Bufferable.java b/src/main/java/com/jozufozu/flywheel/core/model/Bufferable.java deleted file mode 100644 index 3f4cfaf41..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/model/Bufferable.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.jozufozu.flywheel.core.model; - -import java.util.Random; - -import com.mojang.blaze3d.vertex.VertexConsumer; - -import net.minecraft.client.renderer.block.ModelBlockRenderer; - -/** - * An interface for objects that can "rendered" into a BufferBuilder. - */ -public interface Bufferable { - void bufferInto(ModelBlockRenderer renderer, VertexConsumer consumer, Random random); - - default ShadeSeparatedBufferBuilder build() { - return ModelUtil.getBufferBuilder(this); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/model/Mesh.java b/src/main/java/com/jozufozu/flywheel/core/model/Mesh.java index 10b13e8a8..c382211c7 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/Mesh.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/Mesh.java @@ -5,27 +5,27 @@ import java.nio.ByteBuffer; import com.jozufozu.flywheel.api.vertex.VertexList; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.api.vertex.VertexWriter; -import com.jozufozu.flywheel.backend.model.ElementBuffer; +import com.jozufozu.flywheel.backend.instancing.instancing.ElementBuffer; import com.jozufozu.flywheel.core.QuadConverter; /** - * A model that can be rendered by flywheel. + * A mesh that can be rendered by flywheel. * *

* It is expected that the following assertion will not fail: *

* *
{@code
- * Model model = ...;
+ * Mesh mesh = ...;
  * VecBuffer into = ...;
  *
  * int initial = VecBuffer.unwrap().position();
  *
- * model.buffer(into);
+ * mesh.buffer(into);
  *
  * int final = VecBuffer.unwrap().position();
  *
- * assert model.size() == final - initial;
+ * assert mesh.size() == final - initial;
  * }
*/ public interface Mesh { @@ -35,6 +35,8 @@ public interface Mesh { */ String name(); + VertexType getVertexType(); + VertexList getReader(); /** @@ -44,8 +46,19 @@ public interface Mesh { return getReader().getVertexCount(); } - default VertexType getType() { - return getReader().getVertexType(); + /** + * Is there nothing to render? + * @return true if there are no vertices. + */ + default boolean isEmpty() { + return getReader().isEmpty(); + } + + /** + * The size in bytes that this model's data takes up. + */ + default int size() { + return getVertexType().byteOffset(getVertexCount()); } /** @@ -63,23 +76,8 @@ public interface Mesh { .quads2Tris(getVertexCount() / 4); } - /** - * The size in bytes that this model's data takes up. - */ - default int size() { - return getType().byteOffset(getVertexCount()); - } - - /** - * Is there nothing to render? - * @return true if there are no vertices. - */ - default boolean empty() { - return getVertexCount() == 0; - } - default void writeInto(ByteBuffer buffer, long byteIndex) { - VertexWriter writer = getType().createWriter(buffer); + VertexWriter writer = getVertexType().createWriter(buffer); writer.seek(byteIndex); writer.writeVertexList(getReader()); } diff --git a/src/main/java/com/jozufozu/flywheel/core/model/Model.java b/src/main/java/com/jozufozu/flywheel/core/model/Model.java new file mode 100644 index 000000000..e0d247387 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/model/Model.java @@ -0,0 +1,17 @@ +package com.jozufozu.flywheel.core.model; + +import java.util.Map; + +import com.jozufozu.flywheel.api.material.Material; + +public interface Model { + Map getMeshes(); + + default int getVertexCount() { + int size = 0; + for (Mesh mesh : getMeshes().values()) { + size += mesh.getVertexCount(); + } + return size; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/model/ModelSupplier.java b/src/main/java/com/jozufozu/flywheel/core/model/ModelSupplier.java deleted file mode 100644 index f92c63bc0..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/model/ModelSupplier.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.jozufozu.flywheel.core.model; - -import java.util.Map; - -import com.jozufozu.flywheel.api.material.Material; - -public interface ModelSupplier { - Map get(); - - int getVertexCount(); -} diff --git a/src/main/java/com/jozufozu/flywheel/core/model/ModelTransformer.java b/src/main/java/com/jozufozu/flywheel/core/model/ModelTransformer.java deleted file mode 100644 index 8013db065..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/model/ModelTransformer.java +++ /dev/null @@ -1,305 +0,0 @@ -package com.jozufozu.flywheel.core.model; - -import java.util.function.IntPredicate; - -import com.jozufozu.flywheel.api.vertex.ShadedVertexList; -import com.jozufozu.flywheel.api.vertex.VertexList; -import com.jozufozu.flywheel.util.DiffuseLightCalculator; -import com.jozufozu.flywheel.util.transform.Transform; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.math.Matrix3f; -import com.mojang.math.Matrix4f; -import com.mojang.math.Quaternion; -import com.mojang.math.Vector3f; -import com.mojang.math.Vector4f; - -import net.minecraft.client.renderer.LightTexture; -import net.minecraft.client.renderer.texture.OverlayTexture; -import net.minecraft.util.Mth; - -public class ModelTransformer { - - private final Mesh mesh; - private final VertexList reader; - private final IntPredicate shadedPredicate; - - public final Context context = new Context(); - - public ModelTransformer(Mesh mesh) { - this.mesh = mesh; - reader = mesh.getReader(); - if (reader instanceof ShadedVertexList shaded) { - shadedPredicate = shaded::isShaded; - } else { - shadedPredicate = index -> true; - } - } - - public void renderInto(Params params, PoseStack input, VertexConsumer builder) { - if (isEmpty()) - return; - - Vector4f pos = new Vector4f(); - Vector3f normal = new Vector3f(); - - Matrix4f modelMat = input.last() - .pose() - .copy(); - modelMat.multiply(params.model); - - Matrix3f normalMat; - if (context.fullNormalTransform) { - normalMat = input.last().normal().copy(); - normalMat.mul(params.normal); - } else { - normalMat = params.normal.copy(); - } - - final DiffuseLightCalculator diffuseCalculator = DiffuseLightCalculator.forCurrentLevel(); - - final 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); - pos.set(x, y, z, 1F); - pos.transform(modelMat); - builder.vertex(pos.x(), pos.y(), pos.z()); - - float normalX = reader.getNX(i); - float normalY = reader.getNY(i); - float normalZ = reader.getNZ(i); - - normal.set(normalX, normalY, normalZ); - normal.transform(normalMat); - normal.normalize(); - float nx = normal.x(); - float ny = normal.y(); - float nz = normal.z(); - - byte r, g, b, a; - if (params.useParamColor) { - r = (byte) params.r; - g = (byte) params.g; - b = (byte) params.b; - a = (byte) params.a; - } else { - r = reader.getR(i); - g = reader.getG(i); - b = reader.getB(i); - a = reader.getA(i); - } - if (context.outputColorDiffuse) { - float instanceDiffuse = diffuseCalculator.getDiffuse(nx, ny, nz, shadedPredicate.test(i)); - int colorR = transformColor(r, instanceDiffuse); - int colorG = transformColor(g, instanceDiffuse); - int colorB = transformColor(b, instanceDiffuse); - builder.color(colorR, colorG, colorB, a); - } else { - builder.color(r, g, b, a); - } - - //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) (normalX * 255)), Math.max(0, (int) (normalY * 255)), Math.max(0, (int) (normalZ * 255)), 0xFF); - - float u = reader.getU(i); - float v = reader.getV(i); - if (params.spriteShiftFunc != null) { - params.spriteShiftFunc.shift(builder, u, v); - } else { - builder.uv(u, v); - } - - // not always used, but will be ignored by formats that don't use it - builder.overlayCoords(params.overlay); - - builder.uv2(params.useParamLight ? params.packedLightCoords : reader.getLight(i)); - - builder.normal(nx, ny, nz); - - builder.endVertex(); - } - } - - public boolean isEmpty() { - return reader.isEmpty(); - } - - @Override - public String toString() { - return "ModelTransformer[" + mesh + ']'; - } - - public static int transformColor(byte component, float scale) { - return Mth.clamp((int) (Byte.toUnsignedInt(component) * scale), 0, 255); - } - - public static int transformColor(int component, float scale) { - return Mth.clamp((int) (component * scale), 0, 255); - } - - @FunctionalInterface - public interface SpriteShiftFunc { - void shift(VertexConsumer builder, float u, float v); - } - - public static class Context { - /** - * Do we need to include the PoseStack transforms in our transformation of the normal? - */ - public boolean fullNormalTransform = false; - - /** - * Do we need to bake diffuse lighting into the output colors? - */ - public boolean outputColorDiffuse = true; - } - - public static class Params implements Transform { - - // Transform - public final Matrix4f model; - public final Matrix3f normal; - - // Vertex Coloring - public boolean useParamColor; - public int r; - public int g; - public int b; - public int a; - - // Vertex Texture Coords - public SpriteShiftFunc spriteShiftFunc; - - // Vertex Overlay Color - public int overlay; - - // Vertex Lighting - public boolean useParamLight; - public int packedLightCoords; - - 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); - useParamColor = from.useParamColor; - r = from.r; - g = from.g; - b = from.b; - a = from.a; - spriteShiftFunc = from.spriteShiftFunc; - overlay = from.overlay; - useParamLight = from.useParamLight; - packedLightCoords = from.packedLightCoords; - } - - public Params color(int r, int g, int b, int a) { - this.useParamColor = true; - this.r = r; - this.g = g; - this.b = b; - this.a = a; - return this; - } - - public Params color(byte r, byte g, byte b, byte a) { - this.useParamColor = true; - this.r = Byte.toUnsignedInt(r); - this.g = Byte.toUnsignedInt(g); - this.b = Byte.toUnsignedInt(b); - this.a = Byte.toUnsignedInt(a); - return this; - } - - public Params color(int color) { - this.useParamColor = true; - this.r = ((color >> 16) & 0xFF); - this.g = ((color >> 8) & 0xFF); - this.b = (color & 0xFF); - this.a = 255; - return this; - } - - public Params shiftUV(SpriteShiftFunc entry) { - this.spriteShiftFunc = entry; - return this; - } - - public Params overlay(int overlay) { - this.overlay = overlay; - return this; - } - - public Params light(int packedLightCoords) { - this.useParamLight = true; - this.packedLightCoords = packedLightCoords; - return this; - } - - @Override - public Params multiply(Quaternion quaternion) { - model.multiply(quaternion); - normal.mul(quaternion); - return this; - } - - @Override - public Params scale(float pX, float pY, float pZ) { - model.multiply(Matrix4f.createScaleMatrix(pX, pY, pZ)); - if (pX == pY && pY == pZ) { - if (pX > 0.0F) { - return this; - } - - normal.mul(-1.0F); - return this; - } - - float f = 1.0F / pX; - float f1 = 1.0F / pY; - float f2 = 1.0F / pZ; - float f3 = Mth.fastInvCubeRoot(Math.abs(f * f1 * f2)); - normal.mul(Matrix3f.createScaleMatrix(f3 * f, f3 * f1, f3 * f2)); - return this; - } - - @Override - public Params translate(double x, double y, double z) { - model.multiplyWithTranslation((float) x, (float) y, (float) z); - - return this; - } - - @Override - public Params mulPose(Matrix4f pose) { - this.model.multiply(pose); - return this; - } - - @Override - public Params mulNormal(Matrix3f normal) { - this.normal.mul(normal); - return this; - } - - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java b/src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java index 97013adb8..b74a35989 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java @@ -1,22 +1,23 @@ package com.jozufozu.flywheel.core.model; import java.lang.reflect.Field; -import java.util.EnumMap; -import java.util.Random; +import java.nio.ByteBuffer; + +import org.jetbrains.annotations.Nullable; import com.jozufozu.flywheel.Flywheel; -import com.jozufozu.flywheel.util.transform.TransformStack; +import com.jozufozu.flywheel.api.material.Material; +import com.jozufozu.flywheel.api.vertex.VertexList; +import com.jozufozu.flywheel.core.Materials; +import com.jozufozu.flywheel.core.vertex.Formats; import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.datafixers.util.Pair; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.BlockRenderDispatcher; import net.minecraft.client.renderer.block.ModelBlockRenderer; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.core.Direction; import net.minecraftforge.fml.util.ObfuscationReflectionHelper; public class ModelUtil { @@ -26,8 +27,6 @@ public class ModelUtil { */ public static final BlockRenderDispatcher VANILLA_RENDERER = createVanillaRenderer(); - private static final ThreadLocal THREAD_LOCAL_OBJECTS = ThreadLocal.withInitial(ThreadLocalObjects::new); - private static BlockRenderDispatcher createVanillaRenderer() { BlockRenderDispatcher defaultDispatcher = Minecraft.getInstance().getBlockRenderer(); BlockRenderDispatcher dispatcher = new BlockRenderDispatcher(null, null, null); @@ -44,66 +43,34 @@ public class ModelUtil { return dispatcher; } - public static BakedModelBuilder bakedModel(BakedModel model) { - return new BakedModelBuilder(model); - } + public static VertexList createVertexList(BufferBuilder bufferBuilder) { + Pair pair = bufferBuilder.popNextBuffer(); + BufferBuilder.DrawState drawState = pair.getFirst(); - public static WorldModelBuilder worldLayer(RenderType layer) { - return new WorldModelBuilder(layer); - } - - public static ShadeSeparatedBufferBuilder getBufferBuilder(Bufferable bufferable) { - ModelBlockRenderer blockRenderer = VANILLA_RENDERER.getModelRenderer(); - ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get(); - - objects.begin(); - - bufferable.bufferInto(blockRenderer, objects.shadeSeparatingWrapper, objects.random); - - objects.end(); - - return objects.separatedBufferBuilder; - } - - private static PoseStack createRotation(Direction facing) { - PoseStack stack = new PoseStack(); - TransformStack.cast(stack) - .centre() - .rotateToFace(facing.getOpposite()) - .unCentre(); - return stack; - } - - public static PoseStack rotateToFace(Direction facing) { - return TRANSFORMS.get(facing); - } - - private static final EnumMap TRANSFORMS = new EnumMap<>(Direction.class); - - static { - for (Direction value : Direction.values()) { - TRANSFORMS.put(value, createRotation(value)); - } - } - - private static class ThreadLocalObjects { - public final Random random = new Random(); - public final ShadeSeparatingVertexConsumer shadeSeparatingWrapper = new ShadeSeparatingVertexConsumer(); - public final ShadeSeparatedBufferBuilder separatedBufferBuilder = new ShadeSeparatedBufferBuilder(512); - public final BufferBuilder unshadedBuilder = new BufferBuilder(512); - - private void begin() { - this.separatedBufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); - this.unshadedBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); - this.shadeSeparatingWrapper.prepare(this.separatedBufferBuilder, this.unshadedBuilder); + if (drawState.format() != DefaultVertexFormat.BLOCK) { + throw new RuntimeException("Cannot use BufferBuilder with " + drawState.format()); } - private void end() { - this.shadeSeparatingWrapper.clear(); - this.unshadedBuilder.end(); - this.separatedBufferBuilder.appendUnshadedVertices(this.unshadedBuilder); - this.separatedBufferBuilder.end(); - } + return Formats.BLOCK.createReader(pair.getSecond(), drawState.vertexCount()); } + @Nullable + public static Material getMaterial(RenderType chunkRenderType, boolean shaded) { + if (chunkRenderType == RenderType.solid()) { + return shaded ? Materials.CHUNK_SOLID_SHADED : Materials.CHUNK_SOLID_UNSHADED; + } + if (chunkRenderType == RenderType.cutoutMipped()) { + return shaded ? Materials.CHUNK_CUTOUT_MIPPED_SHADED : Materials.CHUNK_CUTOUT_MIPPED_UNSHADED; + } + if (chunkRenderType == RenderType.cutout()) { + return shaded ? Materials.CHUNK_CUTOUT_SHADED : Materials.CHUNK_CUTOUT_UNSHADED; + } + if (chunkRenderType == RenderType.translucent()) { + return shaded ? Materials.CHUNK_TRANSLUCENT_SHADED : Materials.CHUNK_TRANSLUCENT_UNSHADED; + } + if (chunkRenderType == RenderType.tripwire()) { + return shaded ? Materials.CHUNK_TRIPWIRE_SHADED : Materials.CHUNK_TRIPWIRE_UNSHADED; + } + return null; + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/model/Models.java b/src/main/java/com/jozufozu/flywheel/core/model/Models.java new file mode 100644 index 000000000..4891a3cd6 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/model/Models.java @@ -0,0 +1,48 @@ +package com.jozufozu.flywheel.core.model; + +import java.util.HashMap; +import java.util.Map; + +import com.jozufozu.flywheel.core.PartialModel; +import com.jozufozu.flywheel.core.model.buffering.BakedModelBuilder; +import com.jozufozu.flywheel.core.model.buffering.BlockModelBuilder; +import com.jozufozu.flywheel.event.ReloadRenderersEvent; +import com.jozufozu.flywheel.util.Pair; +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; + +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.BlockState; + +public class Models { + private static final Map BLOCK_STATE = new HashMap<>(); + private static final Map PARTIAL = new HashMap<>(); + private static final Map, Model> PARTIAL_DIR = new HashMap<>(); + + public static Model block(BlockState state) { + return BLOCK_STATE.computeIfAbsent(state, it -> new BlockModelBuilder(it).build()); + } + + public static Model partial(PartialModel partial) { + return PARTIAL.computeIfAbsent(partial, it -> new BakedModelBuilder(it.get()).build()); + } + + public static Model partial(PartialModel partial, Direction dir) { + return PARTIAL_DIR.computeIfAbsent(Pair.of(partial, dir), it -> new BakedModelBuilder(it.first().get()).poseStack(createRotation(it.second())).build()); + } + + public static PoseStack createRotation(Direction facing) { + PoseStack stack = new PoseStack(); + TransformStack.cast(stack) + .centre() + .rotateToFace(facing.getOpposite()) + .unCentre(); + return stack; + } + + public static void onReload(ReloadRenderersEvent event) { + BLOCK_STATE.clear(); + PARTIAL.clear(); + PARTIAL_DIR.clear(); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/model/SeparatedWorldModelBuilder.java b/src/main/java/com/jozufozu/flywheel/core/model/SeparatedWorldModelBuilder.java deleted file mode 100644 index 7e48ba443..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/model/SeparatedWorldModelBuilder.java +++ /dev/null @@ -1,117 +0,0 @@ -package com.jozufozu.flywheel.core.model; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Random; -import java.util.function.Function; - -import com.google.common.collect.ImmutableMap; -import com.jozufozu.flywheel.core.vertex.Formats; -import com.jozufozu.flywheel.core.virtual.VirtualEmptyBlockGetter; -import com.mojang.blaze3d.vertex.BufferBuilder; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.blaze3d.vertex.VertexFormat; - -import net.minecraft.client.renderer.ItemBlockRenderTypes; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.block.ModelBlockRenderer; -import net.minecraft.client.renderer.texture.OverlayTexture; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.RenderShape; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; -import net.minecraftforge.client.ForgeHooksClient; -import net.minecraftforge.client.model.data.EmptyModelData; -import net.minecraftforge.client.model.data.IModelData; - -public class SeparatedWorldModelBuilder { - - private PoseStack poseStack = new PoseStack(); - private Map modelData = Collections.emptyMap(); - private BlockAndTintGetter renderWorld = VirtualEmptyBlockGetter.INSTANCE; - private Collection blocks = Collections.emptyList(); - - public Map getMeshes() { - Map builders = new HashMap<>(); - - ModelBlockRenderer modelRenderer = ModelUtil.VANILLA_RENDERER.getModelRenderer(); - - buffer(modelRenderer, new Random(), type -> builders.computeIfAbsent(type, $ -> { - var out = new BufferBuilder(512); - - out.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); - - return out; - })); - - return builders.entrySet() - .stream() - .collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, e -> { - var b = e.getValue(); - - b.end(); - - return new BlockMesh(Formats.BLOCK.createReader(b), ""); - })); - } - - public void buffer(ModelBlockRenderer modelRenderer, Random random, Function consumer) { - ModelBlockRenderer.enableCaching(); - for (StructureTemplate.StructureBlockInfo info : this.blocks) { - var state = info.state; - - if (state.getRenderShape() != RenderShape.MODEL) continue; - - var pos = info.pos; - var seed = state.getSeed(pos); - var data = this.modelData.getOrDefault(pos, EmptyModelData.INSTANCE); - var blockModel = ModelUtil.VANILLA_RENDERER.getBlockModel(state); - - this.poseStack.pushPose(); - this.poseStack.translate(pos.getX(), pos.getY(), pos.getZ()); - - for (RenderType type : RenderType.chunkBufferLayers()) { - if (!ItemBlockRenderTypes.canRenderInLayer(state, type)) { - continue; - } - - var vertexConsumer = consumer.apply(type); - - if (vertexConsumer == null) { - continue; - } - - ForgeHooksClient.setRenderType(type); - - modelRenderer.tesselateBlock(this.renderWorld, blockModel, state, pos, poseStack, vertexConsumer, true, random, seed, OverlayTexture.NO_OVERLAY, data); - } - this.poseStack.popPose(); - } - ForgeHooksClient.setRenderType(null); - ModelBlockRenderer.clearCache(); - } - - public SeparatedWorldModelBuilder withRenderWorld(BlockAndTintGetter renderWorld) { - this.renderWorld = renderWorld; - return this; - } - - public SeparatedWorldModelBuilder withBlocks(Collection blocks) { - this.blocks = blocks; - return this; - } - - public SeparatedWorldModelBuilder withModelData(Map modelData) { - this.modelData = modelData; - return this; - } - - public SeparatedWorldModelBuilder withPoseStack(PoseStack poseStack) { - this.poseStack = poseStack; - return this; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/model/ShadeSeparatedBufferBuilder.java b/src/main/java/com/jozufozu/flywheel/core/model/ShadeSeparatedBufferBuilder.java deleted file mode 100644 index 38043702b..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/model/ShadeSeparatedBufferBuilder.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.jozufozu.flywheel.core.model; - -import java.nio.ByteBuffer; - -import com.jozufozu.flywheel.backend.model.BufferBuilderExtension; -import com.mojang.blaze3d.vertex.BufferBuilder; -import com.mojang.datafixers.util.Pair; - -public class ShadeSeparatedBufferBuilder extends BufferBuilder { - protected int unshadedStartVertex; - - public ShadeSeparatedBufferBuilder(int capacity) { - super(capacity); - } - - public void appendUnshadedVertices(BufferBuilder unshadedBuilder) { - Pair data = unshadedBuilder.popNextBuffer(); - unshadedStartVertex = ((BufferBuilderExtension) this).flywheel$getVertices(); - ((BufferBuilderExtension) this).flywheel$appendBufferUnsafe(data.getSecond()); - } - - public int getUnshadedStartVertex() { - return unshadedStartVertex; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/model/ShadeSeparatingVertexConsumer.java b/src/main/java/com/jozufozu/flywheel/core/model/ShadeSeparatingVertexConsumer.java deleted file mode 100644 index ea50184a7..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/model/ShadeSeparatingVertexConsumer.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.jozufozu.flywheel.core.model; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; - -import net.minecraft.client.renderer.block.model.BakedQuad; - -public class ShadeSeparatingVertexConsumer implements VertexConsumer { - protected VertexConsumer shadedConsumer; - protected VertexConsumer unshadedConsumer; - - public void prepare(VertexConsumer shadedConsumer, VertexConsumer unshadedConsumer) { - this.shadedConsumer = shadedConsumer; - this.unshadedConsumer = unshadedConsumer; - } - - public void clear() { - shadedConsumer = null; - unshadedConsumer = null; - } - - @Override - public void putBulkData(PoseStack.Pose poseEntry, BakedQuad quad, float[] colorMuls, float red, float green, float blue, int[] combinedLights, int combinedOverlay, boolean mulColor) { - if (quad.isShade()) { - shadedConsumer.putBulkData(poseEntry, quad, colorMuls, red, green, blue, combinedLights, combinedOverlay, mulColor); - } else { - unshadedConsumer.putBulkData(poseEntry, quad, colorMuls, red, green, blue, combinedLights, combinedOverlay, mulColor); - } - } - - @Override - public void putBulkData(PoseStack.Pose matrixEntry, BakedQuad bakedQuad, float[] baseBrightness, float red, float green, float blue, float alpha, int[] lightmapCoords, int overlayCoords, boolean readExistingColor) { - if (bakedQuad.isShade()) { - shadedConsumer.putBulkData(matrixEntry, bakedQuad, baseBrightness, red, green, blue, alpha, lightmapCoords, overlayCoords, readExistingColor); - } else { - unshadedConsumer.putBulkData(matrixEntry, bakedQuad, baseBrightness, red, green, blue, alpha, lightmapCoords, overlayCoords, readExistingColor); - } - } - - @Override - public VertexConsumer vertex(double x, double y, double z) { - throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!"); - } - - @Override - public VertexConsumer color(int red, int green, int blue, int alpha) { - throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!"); - } - - @Override - public VertexConsumer uv(float u, float v) { - throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!"); - } - - @Override - public VertexConsumer overlayCoords(int u, int v) { - throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!"); - } - - @Override - public VertexConsumer uv2(int u, int v) { - throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!"); - } - - @Override - public VertexConsumer normal(float x, float y, float z) { - throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!"); - } - - @Override - public void endVertex() { - throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!"); - } - - @Override - public void defaultColor(int red, int green, int blue, int alpha) { - throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!"); - } - - @Override - public void unsetDefaultColor() { - throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!"); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/BasicModelSupplier.java b/src/main/java/com/jozufozu/flywheel/core/model/SimpleLazyModel.java similarity index 65% rename from src/main/java/com/jozufozu/flywheel/core/BasicModelSupplier.java rename to src/main/java/com/jozufozu/flywheel/core/model/SimpleLazyModel.java index f4c456691..7933854d2 100644 --- a/src/main/java/com/jozufozu/flywheel/core/BasicModelSupplier.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/SimpleLazyModel.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.core; +package com.jozufozu.flywheel.core.model; import java.util.Map; @@ -6,27 +6,25 @@ import org.jetbrains.annotations.NotNull; import com.google.common.collect.ImmutableMap; import com.jozufozu.flywheel.api.material.Material; -import com.jozufozu.flywheel.core.model.Mesh; -import com.jozufozu.flywheel.core.model.ModelSupplier; import com.jozufozu.flywheel.util.Lazy; import com.jozufozu.flywheel.util.NonNullSupplier; -public class BasicModelSupplier implements ModelSupplier { +public class SimpleLazyModel implements Model { private final Lazy supplier; private Material material; - public BasicModelSupplier(NonNullSupplier supplier, Material material) { + public SimpleLazyModel(NonNullSupplier supplier, Material material) { this.supplier = Lazy.of(supplier); this.material = material; } - public BasicModelSupplier setMaterial(@NotNull Material material) { + public SimpleLazyModel setMaterial(@NotNull Material material) { this.material = material; return this; } @Override - public Map get() { + public Map getMeshes() { return ImmutableMap.of(material, supplier.get()); } diff --git a/src/main/java/com/jozufozu/flywheel/core/model/SimpleMesh.java b/src/main/java/com/jozufozu/flywheel/core/model/SimpleMesh.java new file mode 100644 index 000000000..55f76ef44 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/model/SimpleMesh.java @@ -0,0 +1,36 @@ +package com.jozufozu.flywheel.core.model; + +import com.jozufozu.flywheel.api.vertex.VertexList; +import com.jozufozu.flywheel.api.vertex.VertexType; + +public class SimpleMesh implements Mesh { + private final VertexList reader; + private final VertexType vertexType; + private final String name; + + public SimpleMesh(VertexList reader, VertexType vertexType, String name) { + this.reader = reader; + this.vertexType = vertexType; + this.name = name; + } + + @Override + public String name() { + return name; + } + + @Override + public VertexType getVertexType() { + return vertexType; + } + + @Override + public VertexList getReader() { + return reader; + } + + @Override + public String toString() { + return "SimpleMesh{" + "name='" + name + "',vertexType='" + vertexType + "}"; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/model/TessellatedModel.java b/src/main/java/com/jozufozu/flywheel/core/model/TessellatedModel.java new file mode 100644 index 000000000..0f987bb71 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/model/TessellatedModel.java @@ -0,0 +1,25 @@ +package com.jozufozu.flywheel.core.model; + +import java.util.Map; + +import com.google.common.collect.ImmutableMap; +import com.jozufozu.flywheel.api.material.Material; + +public class TessellatedModel implements Model { + private final ImmutableMap meshes; + private final boolean shadeSeparated; + + public TessellatedModel(ImmutableMap meshes, boolean shadeSeparated) { + this.meshes = meshes; + this.shadeSeparated = shadeSeparated; + } + + @Override + public Map getMeshes() { + return meshes; + } + + public boolean isShadeSeparated() { + return shadeSeparated; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/model/WorldModelBuilder.java b/src/main/java/com/jozufozu/flywheel/core/model/WorldModelBuilder.java deleted file mode 100644 index 03cee1d30..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/model/WorldModelBuilder.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.jozufozu.flywheel.core.model; - -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.Random; - -import com.jozufozu.flywheel.core.virtual.VirtualEmptyBlockGetter; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; - -import net.minecraft.client.renderer.ItemBlockRenderTypes; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.block.ModelBlockRenderer; -import net.minecraft.client.renderer.texture.OverlayTexture; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.RenderShape; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; -import net.minecraftforge.client.ForgeHooksClient; -import net.minecraftforge.client.model.data.EmptyModelData; -import net.minecraftforge.client.model.data.IModelData; - -public final class WorldModelBuilder implements Bufferable { - private final RenderType layer; - - private PoseStack poseStack = new PoseStack(); - private Map modelData = Collections.emptyMap(); - private BlockAndTintGetter renderWorld = VirtualEmptyBlockGetter.INSTANCE; - private Collection blocks = Collections.emptyList(); - - public WorldModelBuilder(RenderType layer) { - this.layer = layer; - } - - @Override - public void bufferInto(ModelBlockRenderer modelRenderer, VertexConsumer consumer, Random random) { - ForgeHooksClient.setRenderType(this.layer); - ModelBlockRenderer.enableCaching(); - for (StructureTemplate.StructureBlockInfo info : this.blocks) { - BlockState state = info.state; - - if (state.getRenderShape() != RenderShape.MODEL) continue; - if (!ItemBlockRenderTypes.canRenderInLayer(state, this.layer)) continue; - - BlockPos pos = info.pos; - - IModelData data = this.modelData.getOrDefault(pos, EmptyModelData.INSTANCE); - - poseStack.pushPose(); - poseStack.translate(pos.getX(), pos.getY(), pos.getZ()); - modelRenderer.tesselateBlock(this.renderWorld, ModelUtil.VANILLA_RENDERER.getBlockModel(state), state, pos, poseStack, consumer, true, random, 42, OverlayTexture.NO_OVERLAY, data); - poseStack.popPose(); - } - ModelBlockRenderer.clearCache(); - ForgeHooksClient.setRenderType(null); - } - - /** - * It is expected that {@code renderWorld.getShade(...)} returns a constant. - */ - public WorldModelBuilder withRenderWorld(BlockAndTintGetter renderWorld) { - this.renderWorld = renderWorld; - return this; - } - - public WorldModelBuilder withBlocks(Collection blocks) { - this.blocks = blocks; - return this; - } - - public WorldModelBuilder withModelData(Map modelData) { - this.modelData = modelData; - return this; - } - - public WorldModelBuilder withPoseStack(PoseStack poseStack) { - this.poseStack = poseStack; - return this; - } - - public BlockMesh intoMesh(String name) { - return new BlockMesh(this, name); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/model/buffering/BakedModelBuilder.java b/src/main/java/com/jozufozu/flywheel/core/model/buffering/BakedModelBuilder.java new file mode 100644 index 000000000..7393ac14b --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/model/buffering/BakedModelBuilder.java @@ -0,0 +1,136 @@ +package com.jozufozu.flywheel.core.model.buffering; + +import java.util.function.BiFunction; + +import com.google.common.collect.ImmutableMap; +import com.jozufozu.flywheel.api.material.Material; +import com.jozufozu.flywheel.core.model.Mesh; +import com.jozufozu.flywheel.core.model.ModelUtil; +import com.jozufozu.flywheel.core.model.SimpleMesh; +import com.jozufozu.flywheel.core.model.TessellatedModel; +import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.BufferFactory; +import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.ResultConsumer; +import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.ShadeSeparatedBufferFactory; +import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.ShadeSeparatedResultConsumer; +import com.jozufozu.flywheel.core.vertex.Formats; +import com.jozufozu.flywheel.core.virtual.VirtualEmptyBlockGetter; +import com.jozufozu.flywheel.core.virtual.VirtualEmptyModelData; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexFormat; + +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.model.data.IModelData; + +public class BakedModelBuilder { + private final BakedModel bakedModel; + private boolean shadeSeparated = true; + private VertexFormat vertexFormat; + private BlockAndTintGetter renderWorld; + private BlockState blockState; + private PoseStack poseStack; + private IModelData modelData; + private BiFunction materialFunc; + + public BakedModelBuilder(BakedModel bakedModel) { + this.bakedModel = bakedModel; + } + + public BakedModelBuilder disableShadeSeparation() { + shadeSeparated = false; + return this; + } + + public BakedModelBuilder vertexFormat(VertexFormat vertexFormat) { + this.vertexFormat = vertexFormat; + return this; + } + + public BakedModelBuilder renderWorld(BlockAndTintGetter renderWorld) { + this.renderWorld = renderWorld; + return this; + } + + public BakedModelBuilder blockState(BlockState blockState) { + this.blockState = blockState; + return this; + } + + public BakedModelBuilder poseStack(PoseStack poseStack) { + this.poseStack = poseStack; + return this; + } + + public BakedModelBuilder modelData(IModelData modelData) { + this.modelData = modelData; + return this; + } + + public BakedModelBuilder materialFunc(BiFunction materialFunc) { + this.materialFunc = materialFunc; + return this; + } + + @SuppressWarnings("unchecked") + public TessellatedModel build() { + ModelBufferingObjects objects = ModelBufferingObjects.THREAD_LOCAL.get(); + + if (vertexFormat == null) { + vertexFormat = DefaultVertexFormat.BLOCK; + } + if (renderWorld == null) { + renderWorld = VirtualEmptyBlockGetter.INSTANCE; + } + if (blockState == null) { + blockState = Blocks.AIR.defaultBlockState(); + } + if (poseStack == null) { + poseStack = objects.identityPoseStack; + } + if (modelData == null) { + modelData = VirtualEmptyModelData.INSTANCE; + } + if (materialFunc == null) { + materialFunc = ModelUtil::getMaterial; + } + + ImmutableMap.Builder meshMapBuilder = ImmutableMap.builder(); + + if (shadeSeparated) { + ShadeSeparatedBufferFactory bufferFactory = (renderType, shaded) -> { + BufferBuilder buffer = new BufferBuilder(64); + buffer.begin(VertexFormat.Mode.QUADS, vertexFormat); + return buffer; + }; + ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, buffer) -> { + buffer.end(); + Material material = materialFunc.apply(renderType, shaded); + if (material != null) { + meshMapBuilder.put(material, new SimpleMesh(ModelUtil.createVertexList(buffer), Formats.BLOCK, "bakedModel=" + bakedModel.toString() + ",renderType=" + renderType.toString() + ",shaded=" + shaded)); + } + }; + ModelBufferingUtil.bufferSingleShadeSeparated(ModelUtil.VANILLA_RENDERER.getModelRenderer(), renderWorld, bakedModel, blockState, poseStack, bufferFactory, objects.shadeSeparatingBufferWrapper, objects.random, modelData, resultConsumer); + } else { + BufferFactory bufferFactory = (renderType) -> { + BufferBuilder buffer = new BufferBuilder(64); + buffer.begin(VertexFormat.Mode.QUADS, vertexFormat); + return buffer; + }; + ResultConsumer resultConsumer = (renderType, buffer) -> { + buffer.end(); + Material material = materialFunc.apply(renderType, false); + if (material != null) { + meshMapBuilder.put(material, new SimpleMesh(ModelUtil.createVertexList(buffer), Formats.BLOCK, "bakedModel=" + bakedModel.toString() + ",renderType=" + renderType.toString())); + } + }; + ModelBufferingUtil.bufferSingle(ModelUtil.VANILLA_RENDERER.getModelRenderer(), renderWorld, bakedModel, blockState, poseStack, bufferFactory, objects.bufferWrapper, objects.random, modelData, resultConsumer); + } + + return new TessellatedModel(meshMapBuilder.build(), shadeSeparated); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/model/buffering/BlockModelBuilder.java b/src/main/java/com/jozufozu/flywheel/core/model/buffering/BlockModelBuilder.java new file mode 100644 index 000000000..022e948b9 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/model/buffering/BlockModelBuilder.java @@ -0,0 +1,125 @@ +package com.jozufozu.flywheel.core.model.buffering; + +import java.util.function.BiFunction; + +import com.google.common.collect.ImmutableMap; +import com.jozufozu.flywheel.api.material.Material; +import com.jozufozu.flywheel.core.model.Mesh; +import com.jozufozu.flywheel.core.model.ModelUtil; +import com.jozufozu.flywheel.core.model.SimpleMesh; +import com.jozufozu.flywheel.core.model.TessellatedModel; +import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.BufferFactory; +import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.ResultConsumer; +import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.ShadeSeparatedBufferFactory; +import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.ShadeSeparatedResultConsumer; +import com.jozufozu.flywheel.core.vertex.Formats; +import com.jozufozu.flywheel.core.virtual.VirtualEmptyBlockGetter; +import com.jozufozu.flywheel.core.virtual.VirtualEmptyModelData; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexFormat; + +import net.minecraft.client.renderer.RenderType; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.model.data.IModelData; + +public class BlockModelBuilder { + private final BlockState state; + private boolean shadeSeparated = true; + private VertexFormat vertexFormat; + private BlockAndTintGetter renderWorld; + private PoseStack poseStack; + private IModelData modelData; + private BiFunction materialFunc; + + public BlockModelBuilder(BlockState state) { + this.state = state; + } + + public BlockModelBuilder disableShadeSeparation() { + shadeSeparated = false; + return this; + } + + public BlockModelBuilder vertexFormat(VertexFormat vertexFormat) { + this.vertexFormat = vertexFormat; + return this; + } + + public BlockModelBuilder renderWorld(BlockAndTintGetter renderWorld) { + this.renderWorld = renderWorld; + return this; + } + + public BlockModelBuilder poseStack(PoseStack poseStack) { + this.poseStack = poseStack; + return this; + } + + public BlockModelBuilder modelData(IModelData modelData) { + this.modelData = modelData; + return this; + } + + public BlockModelBuilder materialFunc(BiFunction materialFunc) { + this.materialFunc = materialFunc; + return this; + } + + @SuppressWarnings("unchecked") + public TessellatedModel build() { + ModelBufferingObjects objects = ModelBufferingObjects.THREAD_LOCAL.get(); + + if (vertexFormat == null) { + vertexFormat = DefaultVertexFormat.BLOCK; + } + if (renderWorld == null) { + renderWorld = VirtualEmptyBlockGetter.INSTANCE; + } + if (poseStack == null) { + poseStack = objects.identityPoseStack; + } + if (modelData == null) { + modelData = VirtualEmptyModelData.INSTANCE; + } + if (materialFunc == null) { + materialFunc = ModelUtil::getMaterial; + } + + ImmutableMap.Builder meshMapBuilder = ImmutableMap.builder(); + + if (shadeSeparated) { + ShadeSeparatedBufferFactory bufferFactory = (renderType, shaded) -> { + BufferBuilder buffer = new BufferBuilder(64); + buffer.begin(VertexFormat.Mode.QUADS, vertexFormat); + return buffer; + }; + ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, buffer) -> { + buffer.end(); + Material material = materialFunc.apply(renderType, shaded); + if (material != null) { + meshMapBuilder.put(material, new SimpleMesh(ModelUtil.createVertexList(buffer), Formats.BLOCK, "state=" + state.toString() + ",renderType=" + renderType.toString() + ",shaded=" + shaded)); + } + }; + ModelBufferingUtil.bufferBlockShadeSeparated(ModelUtil.VANILLA_RENDERER, renderWorld, state, poseStack, bufferFactory, objects.shadeSeparatingBufferWrapper, objects.random, modelData, resultConsumer); + } else { + BufferFactory bufferFactory = (renderType) -> { + BufferBuilder buffer = new BufferBuilder(64); + buffer.begin(VertexFormat.Mode.QUADS, vertexFormat); + return buffer; + }; + ResultConsumer resultConsumer = (renderType, buffer) -> { + buffer.end(); + Material material = materialFunc.apply(renderType, false); + if (material != null) { + meshMapBuilder.put(material, new SimpleMesh(ModelUtil.createVertexList(buffer), Formats.BLOCK, "state=" + state.toString() + ",renderType=" + renderType.toString())); + } + }; + ModelBufferingUtil.bufferBlock(ModelUtil.VANILLA_RENDERER, renderWorld, state, poseStack, bufferFactory, objects.bufferWrapper, objects.random, modelData, resultConsumer); + } + + return new TessellatedModel(meshMapBuilder.build(), shadeSeparated); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/model/buffering/LazyDelegatingVertexConsumer.java b/src/main/java/com/jozufozu/flywheel/core/model/buffering/LazyDelegatingVertexConsumer.java new file mode 100644 index 000000000..10be13717 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/model/buffering/LazyDelegatingVertexConsumer.java @@ -0,0 +1,65 @@ +package com.jozufozu.flywheel.core.model.buffering; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; + +import net.minecraft.client.renderer.block.model.BakedQuad; + +public interface LazyDelegatingVertexConsumer extends VertexConsumer { + T getDelegate(); + + @Override + default VertexConsumer vertex(double x, double y, double z) { + return getDelegate().vertex(x, y, z); + } + + @Override + default VertexConsumer color(int red, int green, int blue, int alpha) { + return getDelegate().color(red, green, blue, alpha); + } + + @Override + default VertexConsumer uv(float u, float v) { + return getDelegate().uv(u, v); + } + + @Override + default VertexConsumer overlayCoords(int u, int v) { + return getDelegate().overlayCoords(u, v); + } + + @Override + default VertexConsumer uv2(int u, int v) { + return getDelegate().uv2(u, v); + } + + @Override + default VertexConsumer normal(float x, float y, float z) { + return getDelegate().normal(x, y, z); + } + + @Override + default void endVertex() { + getDelegate().endVertex(); + } + + @Override + default void defaultColor(int red, int green, int blue, int alpha) { + getDelegate().defaultColor(red, green, blue, alpha); + } + + @Override + default void unsetDefaultColor() { + getDelegate().unsetDefaultColor(); + } + + @Override + default void putBulkData(PoseStack.Pose poseEntry, BakedQuad quad, float[] colorMuls, float red, float green, float blue, int[] combinedLights, int combinedOverlay, boolean mulColor) { + getDelegate().putBulkData(poseEntry, quad, colorMuls, red, green, blue, combinedLights, combinedOverlay, mulColor); + } + + @Override + default void putBulkData(PoseStack.Pose matrixEntry, BakedQuad bakedQuad, float[] baseBrightness, float red, float green, float blue, float alpha, int[] lightmapCoords, int overlayCoords, boolean readExistingColor) { + getDelegate().putBulkData(matrixEntry, bakedQuad, baseBrightness, red, green, blue, alpha, lightmapCoords, overlayCoords, readExistingColor); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/model/buffering/ModelBufferingObjects.java b/src/main/java/com/jozufozu/flywheel/core/model/buffering/ModelBufferingObjects.java new file mode 100644 index 000000000..9b89f1409 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/model/buffering/ModelBufferingObjects.java @@ -0,0 +1,18 @@ +package com.jozufozu.flywheel.core.model.buffering; + +import java.util.Random; + +import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.BufferWrapper; +import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.ShadeSeparatingBufferWrapper; +import com.mojang.blaze3d.vertex.PoseStack; + +public class ModelBufferingObjects { + public static final ThreadLocal THREAD_LOCAL = ThreadLocal.withInitial(ModelBufferingObjects::new); + + public final PoseStack identityPoseStack = new PoseStack(); + @SuppressWarnings("rawtypes") + public final BufferWrapper bufferWrapper = new BufferWrapper<>(); + @SuppressWarnings("rawtypes") + public final ShadeSeparatingBufferWrapper shadeSeparatingBufferWrapper = new ShadeSeparatingBufferWrapper<>(); + public final Random random = new Random(); +} diff --git a/src/main/java/com/jozufozu/flywheel/core/model/buffering/ModelBufferingUtil.java b/src/main/java/com/jozufozu/flywheel/core/model/buffering/ModelBufferingUtil.java new file mode 100644 index 000000000..8b2c96888 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/model/buffering/ModelBufferingUtil.java @@ -0,0 +1,283 @@ +package com.jozufozu.flywheel.core.model.buffering; + +import java.util.Collection; +import java.util.Map; +import java.util.Random; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; + +import net.minecraft.client.renderer.ItemBlockRenderTypes; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.BlockRenderDispatcher; +import net.minecraft.client.renderer.block.ModelBlockRenderer; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; +import net.minecraftforge.client.ForgeHooksClient; +import net.minecraftforge.client.model.data.EmptyModelData; +import net.minecraftforge.client.model.data.IModelData; + +public final class ModelBufferingUtil { + private static final RenderType[] CHUNK_LAYERS = RenderType.chunkBufferLayers().toArray(RenderType[]::new); + private static final int CHUNK_LAYERS_AMOUNT = CHUNK_LAYERS.length; + + public static void bufferSingle(ModelBlockRenderer blockRenderer, BlockAndTintGetter renderWorld, BakedModel model, BlockState state, PoseStack poseStack, BufferFactory bufferFactory, BufferWrapper bufferWrapper, Random random, IModelData modelData, ResultConsumer resultConsumer) { + bufferWrapper.bufferFactory = bufferFactory; + + for (RenderType type : CHUNK_LAYERS) { + if (!ItemBlockRenderTypes.canRenderInLayer(state, type)) { + continue; + } + + bufferWrapper.currentRenderType = type; + bufferWrapper.delegate = null; + + ForgeHooksClient.setRenderType(type); + + poseStack.pushPose(); + blockRenderer.tesselateBlock(renderWorld, model, state, BlockPos.ZERO, poseStack, bufferWrapper, false, random, 42L, OverlayTexture.NO_OVERLAY, modelData); + poseStack.popPose(); + + T buffer = bufferWrapper.delegate; + if (buffer != null) { + resultConsumer.accept(type, buffer); + } + } + + ForgeHooksClient.setRenderType(null); + + bufferWrapper.bufferFactory = null; + bufferWrapper.currentRenderType = null; + bufferWrapper.delegate = null; + } + + public static void bufferSingleShadeSeparated(ModelBlockRenderer blockRenderer, BlockAndTintGetter renderWorld, BakedModel model, BlockState state, PoseStack poseStack, ShadeSeparatedBufferFactory bufferFactory, ShadeSeparatingBufferWrapper bufferWrapper, Random random, IModelData modelData, ShadeSeparatedResultConsumer resultConsumer) { + bufferWrapper.bufferFactory = bufferFactory; + + for (RenderType type : CHUNK_LAYERS) { + if (!ItemBlockRenderTypes.canRenderInLayer(state, type)) { + continue; + } + + bufferWrapper.currentRenderType = type; + bufferWrapper.shadedConsumer = null; + bufferWrapper.unshadedConsumer = null; + + ForgeHooksClient.setRenderType(type); + + poseStack.pushPose(); + blockRenderer.tesselateBlock(renderWorld, model, state, BlockPos.ZERO, poseStack, bufferWrapper, false, random, 42L, OverlayTexture.NO_OVERLAY, modelData); + poseStack.popPose(); + + T shadedConsumer = bufferWrapper.shadedConsumer; + T unshadedConsumer = bufferWrapper.unshadedConsumer; + if (shadedConsumer != null) { + resultConsumer.accept(type, true, shadedConsumer); + } + if (unshadedConsumer != null) { + resultConsumer.accept(type, false, unshadedConsumer); + } + } + + ForgeHooksClient.setRenderType(null); + + bufferWrapper.bufferFactory = null; + bufferWrapper.currentRenderType = null; + bufferWrapper.shadedConsumer = null; + bufferWrapper.unshadedConsumer = null; + } + + public static void bufferBlock(BlockRenderDispatcher renderDispatcher, BlockAndTintGetter renderWorld, BlockState state, PoseStack poseStack, BufferFactory bufferFactory, BufferWrapper bufferWrapper, Random random, IModelData modelData, ResultConsumer resultConsumer) { + if (state.getRenderShape() != RenderShape.MODEL) { + return; + } + + bufferSingle(renderDispatcher.getModelRenderer(), renderWorld, renderDispatcher.getBlockModel(state), state, poseStack, bufferFactory, bufferWrapper, random, modelData, resultConsumer); + } + + public static void bufferBlockShadeSeparated(BlockRenderDispatcher renderDispatcher, BlockAndTintGetter renderWorld, BlockState state, PoseStack poseStack, ShadeSeparatedBufferFactory bufferFactory, ShadeSeparatingBufferWrapper bufferWrapper, Random random, IModelData modelData, ShadeSeparatedResultConsumer resultConsumer) { + if (state.getRenderShape() != RenderShape.MODEL) { + return; + } + + bufferSingleShadeSeparated(renderDispatcher.getModelRenderer(), renderWorld, renderDispatcher.getBlockModel(state), state, poseStack, bufferFactory, bufferWrapper, random, modelData, resultConsumer); + } + + public static void bufferMultiBlock(Collection blocks, BlockRenderDispatcher renderDispatcher, BlockAndTintGetter renderWorld, PoseStack poseStack, BufferFactory bufferFactory, BufferWrapper bufferWrapper, Random random, Map modelDataMap, ResultConsumer resultConsumer) { + ModelBlockRenderer blockRenderer = renderDispatcher.getModelRenderer(); + ModelBlockRenderer.enableCaching(); + + bufferWrapper.bufferFactory = bufferFactory; + @SuppressWarnings("unchecked") + T[] bufferCache = (T[]) new VertexConsumer[CHUNK_LAYERS_AMOUNT]; + + for (StructureTemplate.StructureBlockInfo blockInfo : blocks) { + BlockState state = blockInfo.state; + + if (state.getRenderShape() != RenderShape.MODEL) { + continue; + } + + BakedModel model = renderDispatcher.getBlockModel(state); + BlockPos pos = blockInfo.pos; + long seed = state.getSeed(pos); + IModelData modelData = modelDataMap.getOrDefault(pos, EmptyModelData.INSTANCE); + + for (int layerIndex = 0; layerIndex < CHUNK_LAYERS_AMOUNT; layerIndex++) { + RenderType type = CHUNK_LAYERS[layerIndex]; + + if (!ItemBlockRenderTypes.canRenderInLayer(state, type)) { + continue; + } + + bufferWrapper.currentRenderType = type; + bufferWrapper.delegate = bufferCache[layerIndex]; + + ForgeHooksClient.setRenderType(type); + + poseStack.pushPose(); + poseStack.translate(pos.getX(), pos.getY(), pos.getZ()); + blockRenderer.tesselateBlock(renderWorld, model, state, pos, poseStack, bufferWrapper, true, random, seed, OverlayTexture.NO_OVERLAY, modelData); + poseStack.popPose(); + + bufferCache[layerIndex] = bufferWrapper.delegate; + } + } + + ForgeHooksClient.setRenderType(null); + ModelBlockRenderer.clearCache(); + + bufferWrapper.bufferFactory = null; + bufferWrapper.currentRenderType = null; + bufferWrapper.delegate = null; + + for (int layerIndex = 0; layerIndex < CHUNK_LAYERS_AMOUNT; layerIndex++) { + T buffer = bufferCache[layerIndex]; + if (buffer != null) { + resultConsumer.accept(CHUNK_LAYERS[layerIndex], buffer); + } + } + } + + public static void bufferMultiBlockShadeSeparated(Collection blocks, BlockRenderDispatcher renderDispatcher, BlockAndTintGetter renderWorld, PoseStack poseStack, ShadeSeparatedBufferFactory bufferFactory, ShadeSeparatingBufferWrapper bufferWrapper, Random random, Map modelDataMap, ShadeSeparatedResultConsumer resultConsumer) { + ModelBlockRenderer blockRenderer = renderDispatcher.getModelRenderer(); + ModelBlockRenderer.enableCaching(); + + bufferWrapper.bufferFactory = bufferFactory; + @SuppressWarnings("unchecked") + T[] bufferCache = (T[]) new VertexConsumer[CHUNK_LAYERS_AMOUNT * 2]; + + for (StructureTemplate.StructureBlockInfo blockInfo : blocks) { + BlockState state = blockInfo.state; + + if (state.getRenderShape() != RenderShape.MODEL) { + continue; + } + + BakedModel model = renderDispatcher.getBlockModel(state); + BlockPos pos = blockInfo.pos; + long seed = state.getSeed(pos); + IModelData modelData = modelDataMap.getOrDefault(pos, EmptyModelData.INSTANCE); + + for (int layerIndex = 0; layerIndex < CHUNK_LAYERS_AMOUNT; layerIndex++) { + RenderType type = CHUNK_LAYERS[layerIndex]; + + if (!ItemBlockRenderTypes.canRenderInLayer(state, type)) { + continue; + } + + bufferWrapper.currentRenderType = type; + bufferWrapper.shadedConsumer = bufferCache[layerIndex]; + bufferWrapper.unshadedConsumer = bufferCache[layerIndex + CHUNK_LAYERS_AMOUNT]; + + ForgeHooksClient.setRenderType(type); + + poseStack.pushPose(); + poseStack.translate(pos.getX(), pos.getY(), pos.getZ()); + blockRenderer.tesselateBlock(renderWorld, model, state, pos, poseStack, bufferWrapper, true, random, seed, OverlayTexture.NO_OVERLAY, modelData); + poseStack.popPose(); + + bufferCache[layerIndex] = bufferWrapper.shadedConsumer; + bufferCache[layerIndex + CHUNK_LAYERS_AMOUNT] = bufferWrapper.unshadedConsumer; + } + } + + ForgeHooksClient.setRenderType(null); + ModelBlockRenderer.clearCache(); + + bufferWrapper.bufferFactory = null; + bufferWrapper.currentRenderType = null; + bufferWrapper.shadedConsumer = null; + bufferWrapper.unshadedConsumer = null; + + for (int layerIndex = 0; layerIndex < CHUNK_LAYERS_AMOUNT; layerIndex++) { + RenderType type = CHUNK_LAYERS[layerIndex]; + T shadedConsumer = bufferCache[layerIndex]; + T unshadedConsumer = bufferCache[layerIndex + CHUNK_LAYERS_AMOUNT]; + if (shadedConsumer != null) { + resultConsumer.accept(type, true, shadedConsumer); + } + if (unshadedConsumer != null) { + resultConsumer.accept(type, false, unshadedConsumer); + } + } + } + + public interface BufferFactory { + T get(RenderType renderType); + } + + public interface ShadeSeparatedBufferFactory { + T get(RenderType renderType, boolean shaded); + } + + public interface ResultConsumer { + void accept(RenderType renderType, T vertexConsumer); + } + + public interface ShadeSeparatedResultConsumer { + void accept(RenderType renderType, boolean shaded, T vertexConsumer); + } + + public static class BufferWrapper implements LazyDelegatingVertexConsumer { + protected BufferFactory bufferFactory; + protected RenderType currentRenderType; + protected T delegate; + + @Override + public T getDelegate() { + if (delegate == null) { + delegate = bufferFactory.get(currentRenderType); + } + return delegate; + } + } + + public static class ShadeSeparatingBufferWrapper implements ShadeSeparatingVertexConsumer { + protected ShadeSeparatedBufferFactory bufferFactory; + protected RenderType currentRenderType; + protected T shadedConsumer; + protected T unshadedConsumer; + + @Override + public T getShadedConsumer() { + if (shadedConsumer == null) { + shadedConsumer = bufferFactory.get(currentRenderType, true); + } + return shadedConsumer; + } + + @Override + public T getUnshadedConsumer() { + if (unshadedConsumer == null) { + unshadedConsumer = bufferFactory.get(currentRenderType, false); + } + return unshadedConsumer; + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/model/buffering/MultiBlockModelBuilder.java b/src/main/java/com/jozufozu/flywheel/core/model/buffering/MultiBlockModelBuilder.java new file mode 100644 index 000000000..33acbcdab --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/model/buffering/MultiBlockModelBuilder.java @@ -0,0 +1,128 @@ +package com.jozufozu.flywheel.core.model.buffering; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.function.BiFunction; + +import com.google.common.collect.ImmutableMap; +import com.jozufozu.flywheel.api.material.Material; +import com.jozufozu.flywheel.core.model.Mesh; +import com.jozufozu.flywheel.core.model.ModelUtil; +import com.jozufozu.flywheel.core.model.SimpleMesh; +import com.jozufozu.flywheel.core.model.TessellatedModel; +import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.BufferFactory; +import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.ResultConsumer; +import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.ShadeSeparatedBufferFactory; +import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.ShadeSeparatedResultConsumer; +import com.jozufozu.flywheel.core.vertex.Formats; +import com.jozufozu.flywheel.core.virtual.VirtualEmptyBlockGetter; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexFormat; + +import net.minecraft.client.renderer.RenderType; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; +import net.minecraftforge.client.model.data.IModelData; + +public class MultiBlockModelBuilder { + private final Collection blocks; + private boolean shadeSeparated = true; + private VertexFormat vertexFormat; + private BlockAndTintGetter renderWorld; + private PoseStack poseStack; + private Map modelDataMap; + private BiFunction materialFunc; + + public MultiBlockModelBuilder(Collection blocks) { + this.blocks = blocks; + } + + public MultiBlockModelBuilder disableShadeSeparation() { + shadeSeparated = false; + return this; + } + + public MultiBlockModelBuilder vertexFormat(VertexFormat vertexFormat) { + this.vertexFormat = vertexFormat; + return this; + } + + public MultiBlockModelBuilder renderWorld(BlockAndTintGetter renderWorld) { + this.renderWorld = renderWorld; + return this; + } + + public MultiBlockModelBuilder poseStack(PoseStack poseStack) { + this.poseStack = poseStack; + return this; + } + + public MultiBlockModelBuilder modelDataMap(Map modelDataMap) { + this.modelDataMap = modelDataMap; + return this; + } + + public MultiBlockModelBuilder materialFunc(BiFunction materialFunc) { + this.materialFunc = materialFunc; + return this; + } + + @SuppressWarnings("unchecked") + public TessellatedModel build() { + ModelBufferingObjects objects = ModelBufferingObjects.THREAD_LOCAL.get(); + + if (vertexFormat == null) { + vertexFormat = DefaultVertexFormat.BLOCK; + } + if (renderWorld == null) { + renderWorld = VirtualEmptyBlockGetter.INSTANCE; + } + if (poseStack == null) { + poseStack = objects.identityPoseStack; + } + if (modelDataMap == null) { + modelDataMap = Collections.emptyMap(); + } + if (materialFunc == null) { + materialFunc = ModelUtil::getMaterial; + } + + ImmutableMap.Builder meshMapBuilder = ImmutableMap.builder(); + + if (shadeSeparated) { + ShadeSeparatedBufferFactory bufferFactory = (renderType, shaded) -> { + BufferBuilder buffer = new BufferBuilder(1024); + buffer.begin(VertexFormat.Mode.QUADS, vertexFormat); + return buffer; + }; + ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, buffer) -> { + buffer.end(); + Material material = materialFunc.apply(renderType, shaded); + if (material != null) { + meshMapBuilder.put(material, new SimpleMesh(ModelUtil.createVertexList(buffer), Formats.BLOCK, "renderType=" + renderType.toString() + ",shaded=" + shaded)); + } + }; + ModelBufferingUtil.bufferMultiBlockShadeSeparated(blocks, ModelUtil.VANILLA_RENDERER, renderWorld, poseStack, bufferFactory, objects.shadeSeparatingBufferWrapper, objects.random, modelDataMap, resultConsumer); + } else { + BufferFactory bufferFactory = (renderType) -> { + BufferBuilder buffer = new BufferBuilder(1024); + buffer.begin(VertexFormat.Mode.QUADS, vertexFormat); + return buffer; + }; + ResultConsumer resultConsumer = (renderType, buffer) -> { + buffer.end(); + Material material = materialFunc.apply(renderType, false); + if (material != null) { + meshMapBuilder.put(material, new SimpleMesh(ModelUtil.createVertexList(buffer), Formats.BLOCK, "renderType=" + renderType.toString())); + } + }; + ModelBufferingUtil.bufferMultiBlock(blocks, ModelUtil.VANILLA_RENDERER, renderWorld, poseStack, bufferFactory, objects.bufferWrapper, objects.random, modelDataMap, resultConsumer); + } + + return new TessellatedModel(meshMapBuilder.build(), shadeSeparated); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/model/buffering/ShadeSeparatingVertexConsumer.java b/src/main/java/com/jozufozu/flywheel/core/model/buffering/ShadeSeparatingVertexConsumer.java new file mode 100644 index 000000000..be358b0d6 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/model/buffering/ShadeSeparatingVertexConsumer.java @@ -0,0 +1,75 @@ +package com.jozufozu.flywheel.core.model.buffering; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; + +import net.minecraft.client.renderer.block.model.BakedQuad; + +public interface ShadeSeparatingVertexConsumer extends VertexConsumer { + T getShadedConsumer(); + + T getUnshadedConsumer(); + + @Override + default void putBulkData(PoseStack.Pose poseEntry, BakedQuad quad, float[] colorMuls, float red, float green, float blue, int[] combinedLights, int combinedOverlay, boolean mulColor) { + if (quad.isShade()) { + getShadedConsumer().putBulkData(poseEntry, quad, colorMuls, red, green, blue, combinedLights, combinedOverlay, mulColor); + } else { + getUnshadedConsumer().putBulkData(poseEntry, quad, colorMuls, red, green, blue, combinedLights, combinedOverlay, mulColor); + } + } + + @Override + default void putBulkData(PoseStack.Pose matrixEntry, BakedQuad bakedQuad, float[] baseBrightness, float red, float green, float blue, float alpha, int[] lightmapCoords, int overlayCoords, boolean readExistingColor) { + if (bakedQuad.isShade()) { + getShadedConsumer().putBulkData(matrixEntry, bakedQuad, baseBrightness, red, green, blue, alpha, lightmapCoords, overlayCoords, readExistingColor); + } else { + getUnshadedConsumer().putBulkData(matrixEntry, bakedQuad, baseBrightness, red, green, blue, alpha, lightmapCoords, overlayCoords, readExistingColor); + } + } + + @Override + default VertexConsumer vertex(double x, double y, double z) { + return getUnshadedConsumer().vertex(x, y, z); + } + + @Override + default VertexConsumer color(int red, int green, int blue, int alpha) { + return getUnshadedConsumer().color(red, green, blue, alpha); + } + + @Override + default VertexConsumer uv(float u, float v) { + return getUnshadedConsumer().uv(u, v); + } + + @Override + default VertexConsumer overlayCoords(int u, int v) { + return getUnshadedConsumer().overlayCoords(u, v); + } + + @Override + default VertexConsumer uv2(int u, int v) { + return getUnshadedConsumer().uv2(u, v); + } + + @Override + default VertexConsumer normal(float x, float y, float z) { + return getUnshadedConsumer().normal(x, y, z); + } + + @Override + default void endVertex() { + getUnshadedConsumer().endVertex(); + } + + @Override + default void defaultColor(int red, int green, int blue, int alpha) { + getUnshadedConsumer().defaultColor(red, green, blue, alpha); + } + + @Override + default void unsetDefaultColor() { + getUnshadedConsumer().unsetDefaultColor(); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedType.java b/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedType.java index 10b5e3e07..30d750672 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedType.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedType.java @@ -7,8 +7,9 @@ import com.jozufozu.flywheel.api.struct.StructWriter; import com.jozufozu.flywheel.core.Components; import com.jozufozu.flywheel.core.layout.BufferLayout; import com.jozufozu.flywheel.core.layout.CommonItems; -import com.jozufozu.flywheel.core.model.ModelTransformer; import com.jozufozu.flywheel.core.source.FileResolution; +import com.mojang.math.Vector3f; +import com.mojang.math.Vector4f; public class TransformedType implements StructType { @@ -38,9 +39,41 @@ public class TransformedType implements StructType { } @Override - public void transform(TransformedPart d, ModelTransformer.Params b) { - b.transform(d.model, d.normal) - .color(d.r, d.g, d.b, d.a) - .light(d.getPackedLight()); + public VertexTransformer getVertexTransformer() { + return (vertexList, struct, level) -> { + Vector4f pos = new Vector4f(); + Vector3f normal = new Vector3f(); + + int light = struct.getPackedLight(); + for (int i = 0; i < vertexList.getVertexCount(); i++) { + pos.set( + vertexList.x(i), + vertexList.y(i), + vertexList.z(i), + 1F + ); + pos.transform(struct.model); + vertexList.x(i, pos.x()); + vertexList.y(i, pos.y()); + vertexList.z(i, pos.z()); + + normal.set( + vertexList.normalX(i), + vertexList.normalY(i), + vertexList.normalZ(i) + ); + normal.transform(struct.normal); + normal.normalize(); + vertexList.normalX(i, normal.x()); + vertexList.normalY(i, normal.y()); + vertexList.normalZ(i, normal.z()); + + vertexList.r(i, struct.r); + vertexList.g(i, struct.g); + vertexList.b(i, struct.b); + vertexList.a(i, struct.a); + vertexList.light(i, light); + } + }; } } diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java index d709a0607..93a0226ef 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java @@ -7,9 +7,12 @@ import com.jozufozu.flywheel.api.struct.StructWriter; import com.jozufozu.flywheel.core.Components; import com.jozufozu.flywheel.core.layout.BufferLayout; import com.jozufozu.flywheel.core.layout.CommonItems; -import com.jozufozu.flywheel.core.model.ModelTransformer; import com.jozufozu.flywheel.core.source.FileResolution; +import com.mojang.math.Matrix3f; +import com.mojang.math.Matrix4f; import com.mojang.math.Quaternion; +import com.mojang.math.Vector3f; +import com.mojang.math.Vector4f; public class OrientedType implements StructType { @@ -39,11 +42,51 @@ public class OrientedType implements StructType { } @Override - public void transform(OrientedPart d, ModelTransformer.Params b) { - b.light(d.getPackedLight()) - .color(d.r, d.g, d.b, d.a) - .translate(d.posX + d.pivotX, d.posY + d.pivotY, d.posZ + d.pivotZ) - .multiply(new Quaternion(d.qX, d.qY, d.qZ, d.qW)) - .translate(-d.pivotX, -d.pivotY, -d.pivotZ); + public VertexTransformer getVertexTransformer() { + return (vertexList, struct, level) -> { + Vector4f pos = new Vector4f(); + Vector3f normal = new Vector3f(); + + Quaternion q = new Quaternion(struct.qX, struct.qY, struct.qZ, struct.qW); + + Matrix4f modelMatrix = new Matrix4f(); + modelMatrix.setIdentity(); + modelMatrix.multiplyWithTranslation(struct.posX + struct.pivotX, struct.posY + struct.pivotY, struct.posZ + struct.pivotZ); + modelMatrix.multiply(q); + modelMatrix.multiplyWithTranslation(-struct.pivotX, -struct.pivotY, -struct.pivotZ); + + Matrix3f normalMatrix = new Matrix3f(q); + + int light = struct.getPackedLight(); + for (int i = 0; i < vertexList.getVertexCount(); i++) { + pos.set( + vertexList.x(i), + vertexList.y(i), + vertexList.z(i), + 1f + ); + pos.transform(modelMatrix); + vertexList.x(i, pos.x()); + vertexList.y(i, pos.y()); + vertexList.z(i, pos.z()); + + normal.set( + vertexList.normalX(i), + vertexList.normalY(i), + vertexList.normalZ(i) + ); + normal.transform(normalMatrix); + normal.normalize(); + vertexList.normalX(i, normal.x()); + vertexList.normalY(i, normal.y()); + vertexList.normalZ(i, normal.z()); + + vertexList.r(i, struct.r); + vertexList.g(i, struct.g); + vertexList.b(i, struct.b); + vertexList.a(i, struct.a); + vertexList.light(i, light); + } + }; } } diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java index d41672f8c..9f37d06b8 100644 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java @@ -2,16 +2,11 @@ package com.jozufozu.flywheel.core.vertex; import java.nio.ByteBuffer; -import com.jozufozu.flywheel.api.vertex.VertexList; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.core.Components; import com.jozufozu.flywheel.core.layout.BufferLayout; import com.jozufozu.flywheel.core.layout.CommonItems; -import com.jozufozu.flywheel.core.model.ShadeSeparatedBufferBuilder; import com.jozufozu.flywheel.core.source.FileResolution; -import com.mojang.blaze3d.vertex.BufferBuilder; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import com.mojang.datafixers.util.Pair; public class BlockVertex implements VertexType { @@ -43,24 +38,4 @@ public class BlockVertex implements VertexType { public FileResolution getLayoutShader() { return Components.Files.BLOCK_LAYOUT; } - - public BlockVertexListUnsafe.Shaded createReader(ByteBuffer buffer, int vertexCount, int unshadedStartVertex) { - return new BlockVertexListUnsafe.Shaded(buffer, vertexCount, unshadedStartVertex); - } - - public VertexList createReader(BufferBuilder bufferBuilder) { - // TODO: try to avoid virtual model rendering - Pair pair = bufferBuilder.popNextBuffer(); - BufferBuilder.DrawState drawState = pair.getFirst(); - - if (drawState.format() != DefaultVertexFormat.BLOCK) { - throw new RuntimeException("Cannot use BufferBuilder with " + drawState.format()); - } - - if (bufferBuilder instanceof ShadeSeparatedBufferBuilder separated) { - return createReader(pair.getSecond(), drawState.vertexCount(), separated.getUnshadedStartVertex()); - } else { - return createReader(pair.getSecond(), drawState.vertexCount()); - } - } } diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexList.java b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexList.java index 586679472..a0423246a 100644 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexList.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexList.java @@ -1,11 +1,10 @@ package com.jozufozu.flywheel.core.vertex; -import com.jozufozu.flywheel.api.vertex.ShadedVertexList; -import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.core.model.ShadeSeparatedBufferBuilder; import com.jozufozu.flywheel.util.RenderMath; import com.mojang.blaze3d.vertex.BufferBuilder; +import net.minecraft.client.renderer.texture.OverlayTexture; + public class BlockVertexList extends AbstractVertexList { private final int stride; @@ -26,89 +25,73 @@ public class BlockVertexList extends AbstractVertexList { } @Override - public float getX(int index) { + public float x(int index) { return contents.getFloat(vertIdx(index)); } @Override - public float getY(int index) { + public float y(int index) { return contents.getFloat(vertIdx(index) + 4); } @Override - public float getZ(int index) { + public float z(int index) { return contents.getFloat(vertIdx(index) + 8); } @Override - public byte getR(int index) { + public byte r(int index) { return contents.get(vertIdx(index) + 12); } @Override - public byte getG(int index) { + public byte g(int index) { return contents.get(vertIdx(index) + 13); } @Override - public byte getB(int index) { + public byte b(int index) { return contents.get(vertIdx(index) + 14); } @Override - public byte getA(int index) { + public byte a(int index) { return contents.get(vertIdx(index) + 15); } @Override - public float getU(int index) { + public float u(int index) { return contents.getFloat(vertIdx(index) + 16); } @Override - public float getV(int index) { + public float v(int index) { return contents.getFloat(vertIdx(index) + 20); } @Override - public int getLight(int index) { + public int overlay(int index) { + return OverlayTexture.NO_OVERLAY; + } + + @Override + public int light(int index) { return contents.getInt(vertIdx(index) + 24); } @Override - public float getNX(int index) { + public float normalX(int index) { return RenderMath.f(contents.get(vertIdx(index) + 28)); } @Override - public float getNY(int index) { + public float normalY(int index) { return RenderMath.f(contents.get(vertIdx(index) + 29)); } @Override - public float getNZ(int index) { + public float normalZ(int index) { return RenderMath.f(contents.get(vertIdx(index) + 30)); } - @Override - public VertexType getVertexType() { - return Formats.BLOCK; - } - - public static class Shaded extends BlockVertexList implements ShadedVertexList { - - private final int unshadedStartVertex; - - public Shaded(ShadeSeparatedBufferBuilder builder) { - super(builder); - unshadedStartVertex = builder.getUnshadedStartVertex(); - } - - @Override - public boolean isShaded(int index) { - return index < unshadedStartVertex; - } - - } - } diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexListUnsafe.java b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexListUnsafe.java index a5073832c..2b272f76e 100644 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexListUnsafe.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexListUnsafe.java @@ -4,10 +4,10 @@ import java.nio.ByteBuffer; import org.lwjgl.system.MemoryUtil; -import com.jozufozu.flywheel.api.vertex.ShadedVertexList; -import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.util.RenderMath; +import net.minecraft.client.renderer.texture.OverlayTexture; + public class BlockVertexListUnsafe extends AbstractVertexList { public BlockVertexListUnsafe(ByteBuffer copyFrom, int vertexCount) { @@ -19,89 +19,73 @@ public class BlockVertexListUnsafe extends AbstractVertexList { } @Override - public float getX(int index) { + public float x(int index) { return MemoryUtil.memGetFloat(ptr(index)); } @Override - public float getY(int index) { + public float y(int index) { return MemoryUtil.memGetFloat(ptr(index) + 4); } @Override - public float getZ(int index) { + public float z(int index) { return MemoryUtil.memGetFloat(ptr(index) + 8); } @Override - public byte getR(int index) { + public byte r(int index) { return MemoryUtil.memGetByte(ptr(index) + 12); } @Override - public byte getG(int index) { + public byte g(int index) { return MemoryUtil.memGetByte(ptr(index) + 13); } @Override - public byte getB(int index) { + public byte b(int index) { return MemoryUtil.memGetByte(ptr(index) + 14); } @Override - public byte getA(int index) { + public byte a(int index) { return MemoryUtil.memGetByte(ptr(index) + 15); } @Override - public float getU(int index) { + public float u(int index) { return MemoryUtil.memGetFloat(ptr(index) + 16); } @Override - public float getV(int index) { + public float v(int index) { return MemoryUtil.memGetFloat(ptr(index) + 20); } @Override - public int getLight(int index) { + public int overlay(int index) { + return OverlayTexture.NO_OVERLAY; + } + + @Override + public int light(int index) { return MemoryUtil.memGetInt(ptr(index) + 24); } @Override - public float getNX(int index) { + public float normalX(int index) { return RenderMath.f(MemoryUtil.memGetByte(ptr(index) + 28)); } @Override - public float getNY(int index) { + public float normalY(int index) { return RenderMath.f(MemoryUtil.memGetByte(ptr(index) + 29)); } @Override - public float getNZ(int index) { + public float normalZ(int index) { return RenderMath.f(MemoryUtil.memGetByte(ptr(index) + 30)); } - @Override - public VertexType getVertexType() { - return Formats.BLOCK; - } - - public static class Shaded extends BlockVertexListUnsafe implements ShadedVertexList { - - private final int unshadedStartVertex; - - public Shaded(ByteBuffer buffer, int vertexCount, int unshadedStartVertex) { - super(buffer, vertexCount); - this.unshadedStartVertex = unshadedStartVertex; - } - - @Override - public boolean isShaded(int index) { - return index < unshadedStartVertex; - } - - } - } diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockWriterUnsafe.java b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockWriterUnsafe.java index 212c7c2eb..556e352d9 100644 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockWriterUnsafe.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockWriterUnsafe.java @@ -15,23 +15,23 @@ public class BlockWriterUnsafe extends VertexWriterUnsafe { @Override public void writeVertex(VertexList list, int i) { - float x = list.getX(i); - float y = list.getY(i); - float z = list.getZ(i); + float x = list.x(i); + float y = list.y(i); + float z = list.z(i); - float xN = list.getNX(i); - float yN = list.getNY(i); - float zN = list.getNZ(i); + float xN = list.normalX(i); + float yN = list.normalY(i); + float zN = list.normalZ(i); - float u = list.getU(i); - float v = list.getV(i); + float u = list.u(i); + float v = list.v(i); - byte r = list.getR(i); - byte g = list.getG(i); - byte b = list.getB(i); - byte a = list.getA(i); + byte r = list.r(i); + byte g = list.g(i); + byte b = list.b(i); + byte a = list.a(i); - int light = list.getLight(i); + int light = list.light(i); putVertex(x, y, z, u, v, r, g, b, a, light, xN, yN, zN); } diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertexListUnsafe.java b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertexListUnsafe.java index 95189b2fb..df1091a97 100644 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertexListUnsafe.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertexListUnsafe.java @@ -4,9 +4,10 @@ import java.nio.ByteBuffer; import org.lwjgl.system.MemoryUtil; -import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.util.RenderMath; +import net.minecraft.client.renderer.texture.OverlayTexture; + public class PosTexNormalVertexListUnsafe extends AbstractVertexList { public PosTexNormalVertexListUnsafe(ByteBuffer copyFrom, int vertexCount) { @@ -18,72 +19,72 @@ public class PosTexNormalVertexListUnsafe extends AbstractVertexList { } @Override - public float getX(int index) { + public float x(int index) { return MemoryUtil.memGetFloat(ptr(index)); } @Override - public float getY(int index) { + public float y(int index) { return MemoryUtil.memGetFloat(ptr(index) + 4); } @Override - public float getZ(int index) { + public float z(int index) { return MemoryUtil.memGetFloat(ptr(index) + 8); } @Override - public byte getR(int index) { + public byte r(int index) { return (byte) 0xFF; } @Override - public byte getG(int index) { + public byte g(int index) { return (byte) 0xFF; } @Override - public byte getB(int index) { + public byte b(int index) { return (byte) 0xFF; } @Override - public byte getA(int index) { + public byte a(int index) { return (byte) 0xFF; } @Override - public float getU(int index) { + public float u(int index) { return MemoryUtil.memGetFloat(ptr(index) + 12); } @Override - public float getV(int index) { + public float v(int index) { return MemoryUtil.memGetFloat(ptr(index) + 16); } @Override - public int getLight(int index) { + public int overlay(int index) { + return OverlayTexture.NO_OVERLAY; + } + + @Override + public int light(int index) { return 0; } @Override - public float getNX(int index) { + public float normalX(int index) { return RenderMath.f(MemoryUtil.memGetByte(ptr(index) + 20)); } @Override - public float getNY(int index) { + public float normalY(int index) { return RenderMath.f(MemoryUtil.memGetByte(ptr(index) + 21)); } @Override - public float getNZ(int index) { + public float normalZ(int index) { return RenderMath.f(MemoryUtil.memGetByte(ptr(index) + 22)); } - - @Override - public VertexType getVertexType() { - return Formats.POS_TEX_NORMAL; - } } diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalWriterUnsafe.java b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalWriterUnsafe.java index 8d2a3612a..7e97962bc 100644 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalWriterUnsafe.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalWriterUnsafe.java @@ -15,16 +15,16 @@ public class PosTexNormalWriterUnsafe extends VertexWriterUnsafe implements DynamicInstance { - private static final BasicModelSupplier MODEL = new BasicModelSupplier(BellInstance::createBellModel, Materials.BELL); + private static final SimpleLazyModel MODEL = new SimpleLazyModel(BellInstance::createBellModel, Materials.BELL); private final OrientedPart bell; diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java index f8cc6ff99..39e6650fb 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java @@ -11,9 +11,9 @@ import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.instancer.InstancerManager; import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; -import com.jozufozu.flywheel.core.BasicModelSupplier; import com.jozufozu.flywheel.core.Materials; import com.jozufozu.flywheel.core.hardcoded.ModelPart; +import com.jozufozu.flywheel.core.model.SimpleLazyModel; import com.jozufozu.flywheel.core.structs.StructTypes; import com.jozufozu.flywheel.core.structs.model.TransformedPart; import com.jozufozu.flywheel.core.structs.oriented.OrientedPart; @@ -36,8 +36,8 @@ import net.minecraft.world.level.block.state.properties.ChestType; public class ChestInstance extends BlockEntityInstance implements DynamicInstance { - private static final BiFunction LID = Util.memoize((type, mat) -> new BasicModelSupplier(() -> createLidModel(type, mat), Materials.CHEST)); - private static final BiFunction BASE = Util.memoize((type, mat) -> new BasicModelSupplier(() -> createBaseModel(type, mat), Materials.CHEST)); + private static final BiFunction LID = Util.memoize((type, mat) -> new SimpleLazyModel(() -> createLidModel(type, mat), Materials.CHEST)); + private static final BiFunction BASE = Util.memoize((type, mat) -> new SimpleLazyModel(() -> createBaseModel(type, mat), Materials.CHEST)); private final OrientedPart body; private final TransformedPart lid; diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java index ca56fed30..e12f6d37e 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java @@ -6,11 +6,11 @@ import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instance.TickableInstance; import com.jozufozu.flywheel.api.instancer.InstancerManager; import com.jozufozu.flywheel.backend.instancing.entity.EntityInstance; -import com.jozufozu.flywheel.core.BasicModelSupplier; import com.jozufozu.flywheel.core.Materials; -import com.jozufozu.flywheel.core.Models; import com.jozufozu.flywheel.core.hardcoded.ModelPart; import com.jozufozu.flywheel.core.model.Mesh; +import com.jozufozu.flywheel.core.model.Models; +import com.jozufozu.flywheel.core.model.SimpleLazyModel; import com.jozufozu.flywheel.core.structs.StructTypes; import com.jozufozu.flywheel.core.structs.model.TransformedPart; import com.jozufozu.flywheel.util.AnimationTickHolder; @@ -27,7 +27,7 @@ import net.minecraft.world.phys.Vec3; public class MinecartInstance extends EntityInstance implements DynamicInstance, TickableInstance { - private static final BasicModelSupplier MODEL = new BasicModelSupplier(MinecartInstance::getBodyModel, Materials.MINECART); + private static final SimpleLazyModel MODEL = new SimpleLazyModel(MinecartInstance::getBodyModel, Materials.MINECART); private final PoseStack stack = new PoseStack(); diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java index 41a9150a7..cc9aadb8a 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java @@ -8,9 +8,9 @@ import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.instancer.InstancerManager; import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; -import com.jozufozu.flywheel.core.BasicModelSupplier; import com.jozufozu.flywheel.core.Materials; import com.jozufozu.flywheel.core.hardcoded.ModelPart; +import com.jozufozu.flywheel.core.model.SimpleLazyModel; import com.jozufozu.flywheel.core.structs.StructTypes; import com.jozufozu.flywheel.core.structs.model.TransformedPart; import com.jozufozu.flywheel.util.AnimationTickHolder; @@ -29,8 +29,8 @@ import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity; public class ShulkerBoxInstance extends BlockEntityInstance implements DynamicInstance { - private static final Function BASE = Util.memoize(it -> new BasicModelSupplier(() -> makeBaseModel(it), Materials.SHULKER)); - private static final Function LID = Util.memoize(it -> new BasicModelSupplier(() -> makeLidModel(it), Materials.SHULKER)); + private static final Function BASE = Util.memoize(it -> new SimpleLazyModel(() -> makeBaseModel(it), Materials.SHULKER)); + private static final Function LID = Util.memoize(it -> new SimpleLazyModel(() -> makeLidModel(it), Materials.SHULKER)); private final TextureAtlasSprite texture; diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/effect/ExampleEffect.java b/src/main/java/com/jozufozu/flywheel/vanilla/effect/ExampleEffect.java index f9893b02e..5c583534c 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/effect/ExampleEffect.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/effect/ExampleEffect.java @@ -11,7 +11,7 @@ import com.jozufozu.flywheel.api.instancer.InstancerManager; import com.jozufozu.flywheel.backend.instancing.AbstractInstance; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import com.jozufozu.flywheel.backend.instancing.effect.Effect; -import com.jozufozu.flywheel.core.Models; +import com.jozufozu.flywheel.core.model.Models; import com.jozufozu.flywheel.core.structs.StructTypes; import com.jozufozu.flywheel.core.structs.model.TransformedPart; import com.jozufozu.flywheel.event.ReloadRenderersEvent;