From 78e959d1a945f9ec9587cb1a15f47bf41ff3c8e2 Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Mon, 20 Nov 2023 22:03:04 -0800 Subject: [PATCH] Less building, more converting - Add ModelPartConverter and remove ModelPartBuilder - ModelPartConverter can convert ModelParts into Flywheel Meshes, optionally using a transformation and TextureMapper. A ModelLayerLocation and TextureAtlasSprite can be used instead to quickly replicate entity models. - Add ModelHolder and ModelCache to lazily initialize models and automatically delete them on renderer reload - Add SimpleModel and remove SimpleLazyModel - Add flw.useSerialExecutor system property - Rename ModelBufferingUtil to BakedModelBufferer - Remove Instance.copy - Remove Mesh.name - Make FlwMemoryTracker thread-safe - Fix potential thread-safety issues, texture issues, and memory leaks related to previously memoized models - Fix MinecartVisual only updating when not visible - Fix ChestVisual locks not moving when opening the chest --- .../java/com/jozufozu/flywheel/Flywheel.java | 7 +- .../flywheel/api/instance/Instance.java | 3 - .../com/jozufozu/flywheel/api/model/Mesh.java | 5 - .../engine/batching/BatchedMeshPool.java | 18 +- .../backend/engine/batching/DrawBuffer.java | 22 +- .../engine/instancing/InstancedMeshPool.java | 2 +- .../flywheel/impl/task/FlwTaskExecutor.java | 15 +- .../VisualizationManagerImpl.java | 4 +- .../lib/instance/OrientedInstance.java | 22 -- .../lib/instance/TransformedInstance.java | 14 - .../flywheel/lib/memory/FlwMemoryTracker.java | 18 +- .../flywheel/lib/model/ModelCache.java | 38 +++ .../flywheel/lib/model/ModelHolder.java | 59 ++++ .../jozufozu/flywheel/lib/model/Models.java | 34 +-- .../flywheel/lib/model/SimpleLazyModel.java | 50 --- .../flywheel/lib/model/SimpleMesh.java | 31 +- .../flywheel/lib/model/SimpleModel.java | 28 ++ ...eringUtil.java => BakedModelBufferer.java} | 17 +- .../lib/model/baked/BakedModelBuilder.java | 12 +- .../lib/model/baked/BlockModelBuilder.java | 12 +- .../model/baked/MultiBlockModelBuilder.java | 12 +- .../lib/model/part/ModelPartBuilder.java | 287 ------------------ .../lib/model/part/ModelPartConverter.java | 64 ++++ .../flywheel/lib/model/part/VertexWriter.java | 139 +++++++++ .../flywheel/lib/util/LevelAttached.java | 1 - .../lib/visual/AbstractEntityVisual.java | 8 +- .../jozufozu/flywheel/vanilla/BellVisual.java | 39 +-- .../flywheel/vanilla/ChestVisual.java | 186 +++++------- .../flywheel/vanilla/MinecartVisual.java | 252 ++++++++------- .../flywheel/vanilla/ShulkerBoxVisual.java | 106 +++---- 30 files changed, 675 insertions(+), 830 deletions(-) create mode 100644 src/main/java/com/jozufozu/flywheel/lib/model/ModelCache.java create mode 100644 src/main/java/com/jozufozu/flywheel/lib/model/ModelHolder.java delete mode 100644 src/main/java/com/jozufozu/flywheel/lib/model/SimpleLazyModel.java create mode 100644 src/main/java/com/jozufozu/flywheel/lib/model/SimpleModel.java rename src/main/java/com/jozufozu/flywheel/lib/model/baked/{ModelBufferingUtil.java => BakedModelBufferer.java} (95%) delete mode 100644 src/main/java/com/jozufozu/flywheel/lib/model/part/ModelPartBuilder.java create mode 100644 src/main/java/com/jozufozu/flywheel/lib/model/part/ModelPartConverter.java create mode 100644 src/main/java/com/jozufozu/flywheel/lib/model/part/VertexWriter.java diff --git a/src/main/java/com/jozufozu/flywheel/Flywheel.java b/src/main/java/com/jozufozu/flywheel/Flywheel.java index 8a61064ab..61eeb0132 100644 --- a/src/main/java/com/jozufozu/flywheel/Flywheel.java +++ b/src/main/java/com/jozufozu/flywheel/Flywheel.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import org.apache.maven.artifact.versioning.ArtifactVersion; import org.slf4j.Logger; +import com.jozufozu.flywheel.api.event.ReloadRenderersEvent; import com.jozufozu.flywheel.api.visualization.VisualizationManager; import com.jozufozu.flywheel.backend.Backends; import com.jozufozu.flywheel.backend.Loader; @@ -24,7 +25,8 @@ import com.jozufozu.flywheel.lib.light.LightUpdater; import com.jozufozu.flywheel.lib.material.MaterialIndices; import com.jozufozu.flywheel.lib.material.Materials; import com.jozufozu.flywheel.lib.memory.FlwMemoryTracker; -import com.jozufozu.flywheel.lib.model.Models; +import com.jozufozu.flywheel.lib.model.ModelCache; +import com.jozufozu.flywheel.lib.model.ModelHolder; import com.jozufozu.flywheel.lib.model.baked.PartialModel; import com.jozufozu.flywheel.lib.util.LevelAttached; import com.jozufozu.flywheel.lib.util.ShadersModHandler; @@ -97,7 +99,8 @@ public class Flywheel { forgeEventBus.addListener(UniformBuffer::onReloadRenderers); forgeEventBus.addListener(LightUpdater::onClientTick); - forgeEventBus.addListener(Models::onReloadRenderers); + forgeEventBus.addListener((ReloadRenderersEvent e) -> ModelCache.onReloadRenderers(e)); + forgeEventBus.addListener(ModelHolder::onReloadRenderers); forgeEventBus.addListener((WorldEvent.Unload e) -> LevelAttached.onUnloadLevel(e)); modEventBus.addListener(PartialModel::onModelRegistry); diff --git a/src/main/java/com/jozufozu/flywheel/api/instance/Instance.java b/src/main/java/com/jozufozu/flywheel/api/instance/Instance.java index 45252e661..36fec9ee9 100644 --- a/src/main/java/com/jozufozu/flywheel/api/instance/Instance.java +++ b/src/main/java/com/jozufozu/flywheel/api/instance/Instance.java @@ -2,7 +2,4 @@ package com.jozufozu.flywheel.api.instance; public interface Instance { InstanceType type(); - - @Deprecated - Instance copy(InstanceHandle handle); } diff --git a/src/main/java/com/jozufozu/flywheel/api/model/Mesh.java b/src/main/java/com/jozufozu/flywheel/api/model/Mesh.java index 16fd1486a..48cded4a5 100644 --- a/src/main/java/com/jozufozu/flywheel/api/model/Mesh.java +++ b/src/main/java/com/jozufozu/flywheel/api/model/Mesh.java @@ -63,9 +63,4 @@ public interface Mesh { * Free this mesh's resources, memory, etc. */ void delete(); - - /** - * A name uniquely identifying this mesh. - */ - String name(); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/batching/BatchedMeshPool.java b/src/main/java/com/jozufozu/flywheel/backend/engine/batching/BatchedMeshPool.java index 8bc6dd946..d6ff143f6 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/batching/BatchedMeshPool.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/batching/BatchedMeshPool.java @@ -25,7 +25,7 @@ public class BatchedMeshPool { private final List allBuffered = new ArrayList<>(); private final List pendingBuffer = new ArrayList<>(); - private MemoryBlock memory; + private MemoryBlock data; private long byteSize; private boolean dirty; @@ -37,7 +37,7 @@ public class BatchedMeshPool { public BatchedMeshPool(VertexFormat vertexFormat) { this.vertexFormat = vertexFormat; vertexList = VertexListProviderRegistry.getProvider(vertexFormat).createVertexList(); - growthMargin = vertexFormat.getVertexSize() * 32; + growthMargin = vertexFormat.getVertexSize() * 128; } public VertexFormat getVertexFormat() { @@ -116,10 +116,10 @@ public class BatchedMeshPool { return; } - if (memory == null) { - memory = MemoryBlock.malloc(byteSize); - } else if (byteSize > memory.size()) { - memory = memory.realloc(byteSize + growthMargin); + if (data == null) { + data = MemoryBlock.malloc(byteSize); + } else if (byteSize > data.size()) { + data = data.realloc(byteSize + growthMargin); } } @@ -136,8 +136,8 @@ public class BatchedMeshPool { } public void delete() { - if (memory != null) { - memory.free(); + if (data != null) { + data.free(); } meshes.clear(); allBuffered.clear(); @@ -191,7 +191,7 @@ public class BatchedMeshPool { } private long ptr() { - return BatchedMeshPool.this.memory.ptr() + byteIndex; + return BatchedMeshPool.this.data.ptr() + byteIndex; } private void buffer(ReusableVertexList vertexList) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/batching/DrawBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/engine/batching/DrawBuffer.java index 6cc3fbbeb..11e095fff 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/batching/DrawBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/batching/DrawBuffer.java @@ -29,7 +29,7 @@ public class DrawBuffer { private final int stride; private final VertexListProvider provider; - private MemoryBlock memory; + private MemoryBlock data; private ByteBuffer buffer; private boolean prepared; @@ -64,12 +64,12 @@ public class DrawBuffer { // is called and reallocates the buffer if there is not space for one more vertex. int byteSize = stride * (vertexCount + 1); - if (memory == null) { - memory = MemoryBlock.malloc(byteSize); - buffer = memory.asBuffer(); - } else if (byteSize > memory.size()) { - memory = memory.realloc(byteSize); - buffer = memory.asBuffer(); + if (data == null) { + data = MemoryBlock.malloc(byteSize); + buffer = data.asBuffer(); + } else if (byteSize > data.size()) { + data = data.realloc(byteSize); + buffer = data.asBuffer(); } prepared = true; @@ -91,7 +91,7 @@ public class DrawBuffer { } public long ptrForVertex(long startVertex) { - return memory.ptr() + startVertex * stride; + return data.ptr() + startVertex * stride; } public void verticesToDraw(int verticesToDraw) { @@ -157,12 +157,12 @@ public class DrawBuffer { public void free() { reset(); - if (memory == null) { + if (data == null) { return; } - memory.free(); - memory = null; + data.free(); + data = null; buffer = null; } diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedMeshPool.java b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedMeshPool.java index d2901ada9..42aa24103 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedMeshPool.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedMeshPool.java @@ -39,7 +39,7 @@ public class InstancedMeshPool { this.vertexType = vertexType; int stride = vertexType.getLayout().getStride(); vbo = new GlBuffer(); - vbo.growthFunction(l -> Math.max(l + stride * 32L, (long) (l * 1.6))); + vbo.growthFunction(l -> Math.max(l + stride * 128L, (long) (l * 1.6))); } public VertexType getVertexType() { diff --git a/src/main/java/com/jozufozu/flywheel/impl/task/FlwTaskExecutor.java b/src/main/java/com/jozufozu/flywheel/impl/task/FlwTaskExecutor.java index 73c33d00f..785fac938 100644 --- a/src/main/java/com/jozufozu/flywheel/impl/task/FlwTaskExecutor.java +++ b/src/main/java/com/jozufozu/flywheel/impl/task/FlwTaskExecutor.java @@ -3,8 +3,11 @@ package com.jozufozu.flywheel.impl.task; import org.apache.commons.lang3.concurrent.AtomicSafeInitializer; import org.apache.commons.lang3.concurrent.ConcurrentUtils; +import com.jozufozu.flywheel.api.task.TaskExecutor; + public final class FlwTaskExecutor { - // TODO: system property to use SerialTaskExecutor + public static final boolean USE_SERIAL_EXECUTOR = System.getProperty("flw.useSerialExecutor") != null; + private static final Initializer INITIALIZER = new Initializer(); private FlwTaskExecutor() { @@ -14,13 +17,17 @@ public final class FlwTaskExecutor { * Get a thread pool for running Flywheel related work in parallel. * @return A global Flywheel thread pool. */ - public static ParallelTaskExecutor get() { + public static TaskExecutor get() { return ConcurrentUtils.initializeUnchecked(INITIALIZER); } - private static class Initializer extends AtomicSafeInitializer { + private static class Initializer extends AtomicSafeInitializer { @Override - protected ParallelTaskExecutor initialize() { + protected TaskExecutor initialize() { + if (USE_SERIAL_EXECUTOR) { + return SerialTaskExecutor.INSTANCE; + } + ParallelTaskExecutor executor = new ParallelTaskExecutor("Flywheel"); executor.startWorkers(); return executor; diff --git a/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizationManagerImpl.java b/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizationManagerImpl.java index abd6f48f0..be371d9b2 100644 --- a/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizationManagerImpl.java +++ b/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizationManagerImpl.java @@ -18,7 +18,6 @@ import com.jozufozu.flywheel.api.visualization.VisualizationLevel; import com.jozufozu.flywheel.api.visualization.VisualizationManager; import com.jozufozu.flywheel.extension.ClientLevelExtension; import com.jozufozu.flywheel.impl.task.FlwTaskExecutor; -import com.jozufozu.flywheel.impl.task.ParallelTaskExecutor; import com.jozufozu.flywheel.impl.visualization.manager.BlockEntityVisualManager; import com.jozufozu.flywheel.impl.visualization.manager.EffectVisualManager; import com.jozufozu.flywheel.impl.visualization.manager.EntityVisualManager; @@ -43,7 +42,7 @@ public class VisualizationManagerImpl implements VisualizationManager { private static final LevelAttached MANAGERS = new LevelAttached<>(VisualizationManagerImpl::new, VisualizationManagerImpl::delete); private final Engine engine; - private final ParallelTaskExecutor taskExecutor; + private final TaskExecutor taskExecutor; private final BlockEntityVisualManager blockEntities; private final EntityVisualManager entities; @@ -58,7 +57,6 @@ public class VisualizationManagerImpl implements VisualizationManager { private VisualizationManagerImpl(LevelAccessor level) { engine = BackendManager.getBackend() .createEngine(level); - // FIXME: All VisualizationManagerImpls use the same executor so calls like syncPoint and discardAndAwait could adversely impact other active VisualizationManagerImpls taskExecutor = FlwTaskExecutor.get(); blockEntities = new BlockEntityVisualManager(engine); diff --git a/src/main/java/com/jozufozu/flywheel/lib/instance/OrientedInstance.java b/src/main/java/com/jozufozu/flywheel/lib/instance/OrientedInstance.java index 519a7e637..aba40c003 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/instance/OrientedInstance.java +++ b/src/main/java/com/jozufozu/flywheel/lib/instance/OrientedInstance.java @@ -84,26 +84,4 @@ public class OrientedInstance extends ColoredLitInstance { setChanged(); return this; } - - @Override - public OrientedInstance copy(InstanceHandle handle) { - var out = InstanceTypes.ORIENTED.create(handle); - out.posX = this.posX; - out.posY = this.posY; - out.posZ = this.posZ; - out.pivotX = this.pivotX; - out.pivotY = this.pivotY; - out.pivotZ = this.pivotZ; - out.qX = this.qX; - out.qY = this.qY; - out.qZ = this.qZ; - out.qW = this.qW; - out.r = this.r; - out.g = this.g; - out.b = this.b; - out.a = this.a; - out.blockLight = this.blockLight; - out.skyLight = this.skyLight; - return out; - } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/instance/TransformedInstance.java b/src/main/java/com/jozufozu/flywheel/lib/instance/TransformedInstance.java index 3389b43ed..4d33c0f12 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/instance/TransformedInstance.java +++ b/src/main/java/com/jozufozu/flywheel/lib/instance/TransformedInstance.java @@ -113,18 +113,4 @@ public class TransformedInstance extends ColoredLitInstance implements Transform normal.mul(normal); return this; } - - @Override - public TransformedInstance copy(InstanceHandle handle) { - var out = InstanceTypes.TRANSFORMED.create(handle); - out.model.load(this.model); - out.normal.load(this.normal); - out.r = this.r; - out.g = this.g; - out.b = this.b; - out.a = this.a; - out.blockLight = this.blockLight; - out.skyLight = this.skyLight; - return out; - } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/memory/FlwMemoryTracker.java b/src/main/java/com/jozufozu/flywheel/lib/memory/FlwMemoryTracker.java index 06b3f2946..ba3afb1d1 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/memory/FlwMemoryTracker.java +++ b/src/main/java/com/jozufozu/flywheel/lib/memory/FlwMemoryTracker.java @@ -1,6 +1,7 @@ package com.jozufozu.flywheel.lib.memory; import java.lang.ref.Cleaner; +import java.util.concurrent.atomic.AtomicLong; import org.lwjgl.system.MemoryUtil; @@ -11,9 +12,8 @@ public final class FlwMemoryTracker { static final Cleaner CLEANER = Cleaner.create(); - // TODO: Should these be volatile? - private static long cpuMemory = 0; - private static long gpuMemory = 0; + private static final AtomicLong CPU_MEMORY = new AtomicLong(0); + private static final AtomicLong GPU_MEMORY = new AtomicLong(0); private FlwMemoryTracker() { } @@ -47,26 +47,26 @@ public final class FlwMemoryTracker { } public static void _allocCPUMemory(long size) { - cpuMemory += size; + CPU_MEMORY.getAndAdd(size); } public static void _freeCPUMemory(long size) { - cpuMemory -= size; + CPU_MEMORY.getAndAdd(-size); } public static void _allocGPUMemory(long size) { - gpuMemory += size; + GPU_MEMORY.getAndAdd(size); } public static void _freeGPUMemory(long size) { - gpuMemory -= size; + GPU_MEMORY.getAndAdd(-size); } public static long getCPUMemory() { - return cpuMemory; + return CPU_MEMORY.get(); } public static long getGPUMemory() { - return gpuMemory; + return GPU_MEMORY.get(); } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/ModelCache.java b/src/main/java/com/jozufozu/flywheel/lib/model/ModelCache.java new file mode 100644 index 000000000..5386566d3 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/lib/model/ModelCache.java @@ -0,0 +1,38 @@ +package com.jozufozu.flywheel.lib.model; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; + +import org.jetbrains.annotations.ApiStatus; + +import com.jozufozu.flywheel.api.event.ReloadRenderersEvent; +import com.jozufozu.flywheel.api.model.Model; + +public class ModelCache { + private static final List> ALL = new ArrayList<>(); + private final Function factory; + private final Map map = new ConcurrentHashMap<>(); + + public ModelCache(Function factory) { + this.factory = factory; + ALL.add(this); + } + + public Model get(T key) { + return map.computeIfAbsent(key, factory); + } + + public void clear() { + map.clear(); + } + + @ApiStatus.Internal + public static void onReloadRenderers(ReloadRenderersEvent event) { + for (ModelCache cache : ALL) { + cache.clear(); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/ModelHolder.java b/src/main/java/com/jozufozu/flywheel/lib/model/ModelHolder.java new file mode 100644 index 000000000..ee9d3f4a0 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/lib/model/ModelHolder.java @@ -0,0 +1,59 @@ +package com.jozufozu.flywheel.lib.model; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import com.jozufozu.flywheel.api.event.ReloadRenderersEvent; +import com.jozufozu.flywheel.api.model.Model; + +public class ModelHolder { + private static final List ALL = new ArrayList<>(); + private final Supplier factory; + @Nullable + private volatile Model model; + + public ModelHolder(Supplier factory) { + this.factory = factory; + ALL.add(this); + } + + public Model get() { + Model model = this.model; + + if (model == null) { + synchronized (this) { + model = this.model; + if (model == null) { + this.model = model = factory.get(); + } + } + } + + return model; + } + + public void clear() { + Model model = this.model; + + if (model != null) { + synchronized (this) { + model = this.model; + if (model != null) { + model.delete(); + this.model = null; + } + } + } + } + + @ApiStatus.Internal + public static void onReloadRenderers(ReloadRenderersEvent event) { + for (ModelHolder holder : ALL) { + holder.clear(); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/Models.java b/src/main/java/com/jozufozu/flywheel/lib/model/Models.java index ef49cbff9..406bfb175 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/model/Models.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/Models.java @@ -1,12 +1,5 @@ package com.jozufozu.flywheel.lib.model; -import java.util.Collection; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.jetbrains.annotations.ApiStatus; - -import com.jozufozu.flywheel.api.event.ReloadRenderersEvent; import com.jozufozu.flywheel.api.model.Model; import com.jozufozu.flywheel.lib.model.baked.BakedModelBuilder; import com.jozufozu.flywheel.lib.model.baked.BlockModelBuilder; @@ -19,23 +12,23 @@ import net.minecraft.core.Direction; import net.minecraft.world.level.block.state.BlockState; public final class Models { - private static final Map BLOCK_STATE = new ConcurrentHashMap<>(); - private static final Map PARTIAL = new ConcurrentHashMap<>(); - private static final Map, Model> PARTIAL_DIR = new ConcurrentHashMap<>(); + private static final ModelCache BLOCK_STATE = new ModelCache<>(it -> new BlockModelBuilder(it).build()); + private static final ModelCache PARTIAL = new ModelCache<>(it -> new BakedModelBuilder(it.get()).build()); + private static final ModelCache> PARTIAL_DIR = new ModelCache<>(it -> new BakedModelBuilder(it.first().get()).poseStack(createRotation(it.second())).build()); private Models() { } public static Model block(BlockState state) { - return BLOCK_STATE.computeIfAbsent(state, it -> new BlockModelBuilder(it).build()); + return BLOCK_STATE.get(state); } public static Model partial(PartialModel partial) { - return PARTIAL.computeIfAbsent(partial, it -> new BakedModelBuilder(it.get()).build()); + return PARTIAL.get(partial); } 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()); + return PARTIAL_DIR.get(Pair.of(partial, dir)); } private static PoseStack createRotation(Direction facing) { @@ -46,19 +39,4 @@ public final class Models { .unCentre(); return stack; } - - @ApiStatus.Internal - public static void onReloadRenderers(ReloadRenderersEvent event) { - deleteAll(BLOCK_STATE.values()); - deleteAll(PARTIAL.values()); - deleteAll(PARTIAL_DIR.values()); - - BLOCK_STATE.clear(); - PARTIAL.clear(); - PARTIAL_DIR.clear(); - } - - private static void deleteAll(Collection values) { - values.forEach(Model::delete); - } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/SimpleLazyModel.java b/src/main/java/com/jozufozu/flywheel/lib/model/SimpleLazyModel.java deleted file mode 100644 index 51475933c..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/model/SimpleLazyModel.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.jozufozu.flywheel.lib.model; - -import java.util.Map; -import java.util.function.Supplier; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import com.google.common.collect.ImmutableMap; -import com.jozufozu.flywheel.api.material.Material; -import com.jozufozu.flywheel.api.model.Mesh; -import com.jozufozu.flywheel.api.model.Model; - -public class SimpleLazyModel implements Model { - private final Supplier<@NotNull Mesh> meshSupplier; - private final Material material; - - @Nullable - private Mesh mesh; - @Nullable - private Map meshMap; - - public SimpleLazyModel(Supplier<@NotNull Mesh> meshSupplier, Material material) { - this.meshSupplier = meshSupplier; - this.material = material; - } - - @Override - public Map getMeshes() { - if (mesh == null) { - mesh = meshSupplier.get(); - meshMap = ImmutableMap.of(material, mesh); - } - - return meshMap; - } - - @Override - public void delete() { - if (mesh != null) { - mesh.delete(); - } - } - - @Override - public String toString() { - String name = mesh != null ? mesh.name() : "Uninitialized"; - return "SimpleLazyModel{" + name + '}'; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/SimpleMesh.java b/src/main/java/com/jozufozu/flywheel/lib/model/SimpleMesh.java index 28a967263..742b7fe83 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/model/SimpleMesh.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/SimpleMesh.java @@ -1,5 +1,6 @@ package com.jozufozu.flywheel.lib.model; +import org.jetbrains.annotations.Nullable; import org.joml.Vector4f; import org.joml.Vector4fc; @@ -11,17 +12,18 @@ import com.jozufozu.flywheel.lib.memory.MemoryBlock; public class SimpleMesh implements QuadMesh { private final VertexType vertexType; private final int vertexCount; - private final MemoryBlock contents; + private final MemoryBlock data; private final ReusableVertexList vertexList; private final Vector4f boundingSphere; - private final String name; + @Nullable + private final String descriptor; - public SimpleMesh(VertexType vertexType, MemoryBlock contents, String name) { + public SimpleMesh(VertexType vertexType, MemoryBlock data, @Nullable String descriptor) { this.vertexType = vertexType; - this.contents = contents; - this.name = name; + this.data = data; + this.descriptor = descriptor; - int bytes = (int) contents.size(); + int bytes = (int) data.size(); int stride = vertexType.getLayout().getStride(); if (bytes % stride != 0) { throw new IllegalArgumentException("MemoryBlock contains non-whole amount of vertices!"); @@ -29,12 +31,16 @@ public class SimpleMesh implements QuadMesh { vertexCount = bytes / stride; vertexList = vertexType().createVertexList(); - vertexList.ptr(contents.ptr()); + vertexList.ptr(data.ptr()); vertexList.vertexCount(vertexCount); boundingSphere = ModelUtil.computeBoundingSphere(vertexList); } + public SimpleMesh(VertexType vertexType, MemoryBlock data) { + this(vertexType, data, null); + } + @Override public VertexType vertexType() { return vertexType; @@ -47,7 +53,7 @@ public class SimpleMesh implements QuadMesh { @Override public void write(long ptr) { - contents.copyTo(ptr); + data.copyTo(ptr); } @Override @@ -62,16 +68,11 @@ public class SimpleMesh implements QuadMesh { @Override public void delete() { - contents.free(); - } - - @Override - public String name() { - return name; + data.free(); } @Override public String toString() { - return "SimpleMesh{" + "name='" + name + "',vertexType='" + vertexType + "}"; + return "SimpleMesh{" + "vertexType=" + vertexType + ",vertexCount=" + vertexCount + ",descriptor={" + descriptor + "}" + "}"; } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/SimpleModel.java b/src/main/java/com/jozufozu/flywheel/lib/model/SimpleModel.java new file mode 100644 index 000000000..e58d6ec21 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/lib/model/SimpleModel.java @@ -0,0 +1,28 @@ +package com.jozufozu.flywheel.lib.model; + +import java.util.Map; + +import com.google.common.collect.ImmutableMap; +import com.jozufozu.flywheel.api.material.Material; +import com.jozufozu.flywheel.api.model.Mesh; +import com.jozufozu.flywheel.api.model.Model; + +public class SimpleModel implements Model { + private final Mesh mesh; + private final Map meshMap; + + public SimpleModel(Mesh mesh, Material material) { + this.mesh = mesh; + meshMap = ImmutableMap.of(material, mesh); + } + + @Override + public Map getMeshes() { + return meshMap; + } + + @Override + public void delete() { + mesh.delete(); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/baked/ModelBufferingUtil.java b/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBufferer.java similarity index 95% rename from src/main/java/com/jozufozu/flywheel/lib/model/baked/ModelBufferingUtil.java rename to src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBufferer.java index e5f32ae1e..696b7557d 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/model/baked/ModelBufferingUtil.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBufferer.java @@ -29,14 +29,17 @@ import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.client.model.data.EmptyModelData; import net.minecraftforge.client.model.data.IModelData; -public final class ModelBufferingUtil { +public final class BakedModelBufferer { private static final RenderType[] CHUNK_LAYERS = RenderType.chunkBufferLayers().toArray(RenderType[]::new); private static final int CHUNK_LAYER_AMOUNT = CHUNK_LAYERS.length; - private static final ThreadLocal THREAD_LOCAL_OBJECTS = ThreadLocal.withInitial(ModelBufferingObjects::new); + private static final ThreadLocal THREAD_LOCAL_OBJECTS = ThreadLocal.withInitial(ThreadLocalObjects::new); + + private BakedModelBufferer() { + } public static void bufferSingle(ModelBlockRenderer blockRenderer, BlockAndTintGetter renderWorld, BakedModel model, BlockState state, @Nullable PoseStack poseStack, IModelData modelData, ResultConsumer resultConsumer) { - ModelBufferingObjects objects = THREAD_LOCAL_OBJECTS.get(); + ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get(); if (poseStack == null) { poseStack = objects.identityPoseStack; } @@ -68,7 +71,7 @@ public final class ModelBufferingUtil { } public static void bufferSingleShadeSeparated(ModelBlockRenderer blockRenderer, BlockAndTintGetter renderWorld, BakedModel model, BlockState state, @Nullable PoseStack poseStack, IModelData modelData, ShadeSeparatedResultConsumer resultConsumer) { - ModelBufferingObjects objects = THREAD_LOCAL_OBJECTS.get(); + ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get(); if (poseStack == null) { poseStack = objects.identityPoseStack; } @@ -126,7 +129,7 @@ public final class ModelBufferingUtil { } public static void bufferMultiBlock(Collection blocks, BlockRenderDispatcher renderDispatcher, BlockAndTintGetter renderWorld, @Nullable PoseStack poseStack, Map modelDataMap, ResultConsumer resultConsumer) { - ModelBufferingObjects objects = THREAD_LOCAL_OBJECTS.get(); + ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get(); if (poseStack == null) { poseStack = objects.identityPoseStack; } @@ -183,7 +186,7 @@ public final class ModelBufferingUtil { } public static void bufferMultiBlockShadeSeparated(Collection blocks, BlockRenderDispatcher renderDispatcher, BlockAndTintGetter renderWorld, @Nullable PoseStack poseStack, Map modelDataMap, ShadeSeparatedResultConsumer resultConsumer) { - ModelBufferingObjects objects = THREAD_LOCAL_OBJECTS.get(); + ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get(); if (poseStack == null) { poseStack = objects.identityPoseStack; } @@ -258,7 +261,7 @@ public final class ModelBufferingUtil { void accept(RenderType renderType, boolean shaded, Pair data); } - private static class ModelBufferingObjects { + private static class ThreadLocalObjects { public final PoseStack identityPoseStack = new PoseStack(); public final Random random = new Random(); diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBuilder.java b/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBuilder.java index 453c9bd11..d83ed9c76 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBuilder.java @@ -8,8 +8,8 @@ import com.jozufozu.flywheel.api.model.Mesh; import com.jozufozu.flywheel.lib.memory.MemoryBlock; import com.jozufozu.flywheel.lib.model.ModelUtil; import com.jozufozu.flywheel.lib.model.SimpleMesh; -import com.jozufozu.flywheel.lib.model.baked.ModelBufferingUtil.ResultConsumer; -import com.jozufozu.flywheel.lib.model.baked.ModelBufferingUtil.ShadeSeparatedResultConsumer; +import com.jozufozu.flywheel.lib.model.baked.BakedModelBufferer.ResultConsumer; +import com.jozufozu.flywheel.lib.model.baked.BakedModelBufferer.ShadeSeparatedResultConsumer; import com.jozufozu.flywheel.lib.vertex.VertexTypes; import com.mojang.blaze3d.vertex.PoseStack; @@ -85,22 +85,22 @@ public class BakedModelBuilder { Material material = materialFunc.apply(renderType, shaded); if (material != null) { MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, VertexTypes.BLOCK); - meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, meshData, "bakedModel=" + bakedModel.toString() + ",renderType=" + renderType.toString() + ",shaded=" + shaded)); + meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, meshData, "source=BakedModelBuilder," + "bakedModel=" + bakedModel + ",renderType=" + renderType + ",shaded=" + shaded)); } } }; - ModelBufferingUtil.bufferSingleShadeSeparated(ModelUtil.VANILLA_RENDERER.getModelRenderer(), renderWorld, bakedModel, blockState, poseStack, modelData, resultConsumer); + BakedModelBufferer.bufferSingleShadeSeparated(ModelUtil.VANILLA_RENDERER.getModelRenderer(), renderWorld, bakedModel, blockState, poseStack, modelData, resultConsumer); } else { ResultConsumer resultConsumer = (renderType, data) -> { if (!ModelUtil.isVanillaBufferEmpty(data)) { Material material = materialFunc.apply(renderType, true); if (material != null) { MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, VertexTypes.BLOCK); - meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, meshData, "bakedModel=" + bakedModel.toString() + ",renderType=" + renderType.toString())); + meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, meshData, "source=BakedModelBuilder," + "bakedModel=" + bakedModel + ",renderType=" + renderType)); } } }; - ModelBufferingUtil.bufferSingle(ModelUtil.VANILLA_RENDERER.getModelRenderer(), renderWorld, bakedModel, blockState, poseStack, modelData, resultConsumer); + BakedModelBufferer.bufferSingle(ModelUtil.VANILLA_RENDERER.getModelRenderer(), renderWorld, bakedModel, blockState, poseStack, modelData, resultConsumer); } return new TessellatedModel(meshMapBuilder.build(), shadeSeparated); diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/baked/BlockModelBuilder.java b/src/main/java/com/jozufozu/flywheel/lib/model/baked/BlockModelBuilder.java index 7339723aa..b6eab3dc6 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/model/baked/BlockModelBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/baked/BlockModelBuilder.java @@ -8,8 +8,8 @@ import com.jozufozu.flywheel.api.model.Mesh; import com.jozufozu.flywheel.lib.memory.MemoryBlock; import com.jozufozu.flywheel.lib.model.ModelUtil; import com.jozufozu.flywheel.lib.model.SimpleMesh; -import com.jozufozu.flywheel.lib.model.baked.ModelBufferingUtil.ResultConsumer; -import com.jozufozu.flywheel.lib.model.baked.ModelBufferingUtil.ShadeSeparatedResultConsumer; +import com.jozufozu.flywheel.lib.model.baked.BakedModelBufferer.ResultConsumer; +import com.jozufozu.flywheel.lib.model.baked.BakedModelBufferer.ShadeSeparatedResultConsumer; import com.jozufozu.flywheel.lib.vertex.VertexTypes; import com.mojang.blaze3d.vertex.PoseStack; @@ -74,22 +74,22 @@ public class BlockModelBuilder { Material material = materialFunc.apply(renderType, shaded); if (material != null) { MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, VertexTypes.BLOCK); - meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, meshData, "state=" + state.toString() + ",renderType=" + renderType.toString() + ",shaded=" + shaded)); + meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, meshData, "source=BlockModelBuilder," + "blockState=" + state + ",renderType=" + renderType + ",shaded=" + shaded)); } } }; - ModelBufferingUtil.bufferBlockShadeSeparated(ModelUtil.VANILLA_RENDERER, renderWorld, state, poseStack, modelData, resultConsumer); + BakedModelBufferer.bufferBlockShadeSeparated(ModelUtil.VANILLA_RENDERER, renderWorld, state, poseStack, modelData, resultConsumer); } else { ResultConsumer resultConsumer = (renderType, data) -> { if (!ModelUtil.isVanillaBufferEmpty(data)) { Material material = materialFunc.apply(renderType, true); if (material != null) { MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, VertexTypes.BLOCK); - meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, meshData, "state=" + state.toString() + ",renderType=" + renderType.toString())); + meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, meshData, "source=BlockModelBuilder," + "blockState=" + state + ",renderType=" + renderType)); } } }; - ModelBufferingUtil.bufferBlock(ModelUtil.VANILLA_RENDERER, renderWorld, state, poseStack, modelData, resultConsumer); + BakedModelBufferer.bufferBlock(ModelUtil.VANILLA_RENDERER, renderWorld, state, poseStack, modelData, resultConsumer); } return new TessellatedModel(meshMapBuilder.build(), shadeSeparated); diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/baked/MultiBlockModelBuilder.java b/src/main/java/com/jozufozu/flywheel/lib/model/baked/MultiBlockModelBuilder.java index 53ab943f1..ac6cf1e57 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/model/baked/MultiBlockModelBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/baked/MultiBlockModelBuilder.java @@ -11,8 +11,8 @@ import com.jozufozu.flywheel.api.model.Mesh; import com.jozufozu.flywheel.lib.memory.MemoryBlock; import com.jozufozu.flywheel.lib.model.ModelUtil; import com.jozufozu.flywheel.lib.model.SimpleMesh; -import com.jozufozu.flywheel.lib.model.baked.ModelBufferingUtil.ResultConsumer; -import com.jozufozu.flywheel.lib.model.baked.ModelBufferingUtil.ShadeSeparatedResultConsumer; +import com.jozufozu.flywheel.lib.model.baked.BakedModelBufferer.ResultConsumer; +import com.jozufozu.flywheel.lib.model.baked.BakedModelBufferer.ShadeSeparatedResultConsumer; import com.jozufozu.flywheel.lib.vertex.VertexTypes; import com.mojang.blaze3d.vertex.PoseStack; @@ -78,22 +78,22 @@ public class MultiBlockModelBuilder { Material material = materialFunc.apply(renderType, shaded); if (material != null) { MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, VertexTypes.BLOCK); - meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, meshData, "renderType=" + renderType.toString() + ",shaded=" + shaded)); + meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, meshData, "source=MultiBlockModelBuilder," + "renderType=" + renderType + ",shaded=" + shaded)); } } }; - ModelBufferingUtil.bufferMultiBlockShadeSeparated(blocks, ModelUtil.VANILLA_RENDERER, renderWorld, poseStack, modelDataMap, resultConsumer); + BakedModelBufferer.bufferMultiBlockShadeSeparated(blocks, ModelUtil.VANILLA_RENDERER, renderWorld, poseStack, modelDataMap, resultConsumer); } else { ResultConsumer resultConsumer = (renderType, data) -> { if (!ModelUtil.isVanillaBufferEmpty(data)) { Material material = materialFunc.apply(renderType, true); if (material != null) { MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, VertexTypes.BLOCK); - meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, meshData, "renderType=" + renderType.toString())); + meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, meshData, "source=MultiBlockModelBuilder," + "renderType=" + renderType)); } } }; - ModelBufferingUtil.bufferMultiBlock(blocks, ModelUtil.VANILLA_RENDERER, renderWorld, poseStack, modelDataMap, resultConsumer); + BakedModelBufferer.bufferMultiBlock(blocks, ModelUtil.VANILLA_RENDERER, renderWorld, poseStack, modelDataMap, resultConsumer); } return new TessellatedModel(meshMapBuilder.build(), shadeSeparated); diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/part/ModelPartBuilder.java b/src/main/java/com/jozufozu/flywheel/lib/model/part/ModelPartBuilder.java deleted file mode 100644 index 456be6dfc..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/model/part/ModelPartBuilder.java +++ /dev/null @@ -1,287 +0,0 @@ -package com.jozufozu.flywheel.lib.model.part; - -import java.util.ArrayList; -import java.util.List; - -import org.jetbrains.annotations.Nullable; -import org.lwjgl.system.MemoryUtil; - -import com.jozufozu.flywheel.api.model.Mesh; -import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.lib.math.RenderMath; -import com.jozufozu.flywheel.lib.memory.MemoryBlock; -import com.jozufozu.flywheel.lib.model.SimpleMesh; -import com.jozufozu.flywheel.lib.vertex.VertexTypes; -import com.mojang.math.Matrix3f; -import com.mojang.math.Quaternion; -import com.mojang.math.Vector3f; - -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.core.Direction; - -public class ModelPartBuilder { - private final String name; - private final float textureWidth; - private final float textureHeight; - - private final List cuboids = new ArrayList<>(); - @Nullable - private TextureAtlasSprite sprite; - - public ModelPartBuilder(String name, int textureWidth, int textureHeight) { - this.name = name; - this.textureWidth = (float) textureWidth; - this.textureHeight = (float) textureHeight; - } - - public ModelPartBuilder sprite(TextureAtlasSprite sprite) { - this.sprite = sprite; - return this; - } - - public CuboidBuilder cuboid() { - return new CuboidBuilder(); - } - - private ModelPartBuilder addCuboid(CuboidBuilder builder) { - cuboids.add(builder); - return this; - } - - public Mesh build() { - VertexType vertexType = VertexTypes.POS_TEX_NORMAL; - int vertices = cuboids.size() * 24; - MemoryBlock contents = MemoryBlock.malloc(vertexType.getLayout().getStride() * vertices); - - long ptr = contents.ptr(); - VertexWriter writer = new VertexWriter(ptr); - for (CuboidBuilder cuboid : cuboids) { - cuboid.write(writer); - } - - return new SimpleMesh(vertexType, contents, name); - } - - public class CuboidBuilder { - private TextureAtlasSprite sprite; - - private int textureOffsetU; - private int textureOffsetV; - - private float posX1; - private float posY1; - private float posZ1; - private float posX2; - private float posY2; - private float posZ2; - - private boolean useRotation; - private float rotationX; - private float rotationY; - private float rotationZ; - - private boolean invertYZ; - - private CuboidBuilder() { - sprite = ModelPartBuilder.this.sprite; - } - - public CuboidBuilder sprite(TextureAtlasSprite sprite) { - this.sprite = sprite; - return this; - } - - public CuboidBuilder textureOffset(int u, int v) { - textureOffsetU = u; - textureOffsetV = v; - return this; - } - - public CuboidBuilder start(float x, float y, float z) { - posX1 = x; - posY1 = y; - posZ1 = z; - return this; - } - - public CuboidBuilder end(float x, float y, float z) { - posX2 = x; - posY2 = y; - posZ2 = z; - return this; - } - - public CuboidBuilder size(float x, float y, float z) { - posX2 = posX1 + x; - posY2 = posY1 + y; - posZ2 = posZ1 + z; - return this; - } - - public CuboidBuilder shift(float x, float y, float z) { - posX1 = posX1 - x; - posY1 = posY1 - y; - posZ1 = posZ1 - z; - posX2 = posX2 - x; - posY2 = posY2 - y; - posZ2 = posZ2 - z; - return this; - } - - public CuboidBuilder rotate(float x, float y, float z) { - useRotation = true; - rotationX = x; - rotationY = y; - rotationZ = z; - return this; - } - - public CuboidBuilder rotateX(float x) { - useRotation = true; - rotationX = x; - return this; - } - - public CuboidBuilder rotateY(float y) { - useRotation = true; - rotationY = y; - return this; - } - - public CuboidBuilder rotateZ(float z) { - useRotation = true; - rotationZ = z; - return this; - } - - /** - * Pulls the cuboid "inside out" through the Y and Z axes. - */ - public CuboidBuilder invertYZ() { - invertYZ = true; - return this; - } - - public ModelPartBuilder endCuboid() { - return ModelPartBuilder.this.addCuboid(this); - } - - private void write(VertexWriter writer) { - float sizeX = posX2 - posX1; - float sizeY = posY2 - posY1; - float sizeZ = posZ2 - posZ1; - - float posX1 = this.posX1 / 16f; - float posY1 = this.posY1 / 16f; - float posZ1 = this.posZ1 / 16f; - float posX2 = this.posX2 / 16f; - float posY2 = this.posY2 / 16f; - float posZ2 = this.posZ2 / 16f; - - - Vector3f lll = new Vector3f(posX1, posY1, posZ1); - Vector3f hll = new Vector3f(posX2, posY1, posZ1); - Vector3f hhl = new Vector3f(posX2, posY2, posZ1); - Vector3f lhl = new Vector3f(posX1, posY2, posZ1); - Vector3f llh = new Vector3f(posX1, posY1, posZ2); - Vector3f hlh = new Vector3f(posX2, posY1, posZ2); - Vector3f hhh = new Vector3f(posX2, posY2, posZ2); - Vector3f lhh = new Vector3f(posX1, posY2, posZ2); - - Vector3f down = Direction.DOWN.step(); - Vector3f up = Direction.UP.step(); - Vector3f west = Direction.WEST.step(); - Vector3f north = Direction.NORTH.step(); - Vector3f east = Direction.EAST.step(); - Vector3f south = Direction.SOUTH.step(); - - if (useRotation) { - Matrix3f matrix3f = new Matrix3f(new Quaternion(rotationX, rotationY, rotationZ, false)); - lll.transform(matrix3f); - hll.transform(matrix3f); - hhl.transform(matrix3f); - lhl.transform(matrix3f); - llh.transform(matrix3f); - hlh.transform(matrix3f); - hhh.transform(matrix3f); - lhh.transform(matrix3f); - down.transform(matrix3f); - up.transform(matrix3f); - west.transform(matrix3f); - north.transform(matrix3f); - east.transform(matrix3f); - south.transform(matrix3f); - } - - float f4 = getU((float)textureOffsetU); - float f5 = getU((float)textureOffsetU + sizeZ); - float f6 = getU((float)textureOffsetU + sizeZ + sizeX); - float f7 = getU((float)textureOffsetU + sizeZ + sizeX + sizeX); - float f8 = getU((float)textureOffsetU + sizeZ + sizeX + sizeZ); - float f9 = getU((float)textureOffsetU + sizeZ + sizeX + sizeZ + sizeX); - float f10 = getV((float)textureOffsetV); - float f11 = getV((float)textureOffsetV + sizeZ); - float f12 = getV((float)textureOffsetV + sizeZ + sizeY); - - if (invertYZ) { - writeQuad(writer, new Vector3f[]{hlh, llh, lll, hll}, f6, f11, f7, f10, down); - writeQuad(writer, new Vector3f[]{hhl, lhl, lhh, hhh}, f5, f10, f6, f11, up); - writeQuad(writer, new Vector3f[]{lll, llh, lhh, lhl}, f5, f12, f4, f11, west); - writeQuad(writer, new Vector3f[]{hll, lll, lhl, hhl}, f9, f12, f8, f11, north); - writeQuad(writer, new Vector3f[]{hlh, hll, hhl, hhh}, f8, f12, f6, f11, east); - writeQuad(writer, new Vector3f[]{llh, hlh, hhh, lhh}, f6, f12, f5, f11, south); - } else { - writeQuad(writer, new Vector3f[]{hlh, llh, lll, hll}, f5, f10, f6, f11, down); - writeQuad(writer, new Vector3f[]{hhl, lhl, lhh, hhh}, f6, f11, f7, f10, up); - writeQuad(writer, new Vector3f[]{lll, llh, lhh, lhl}, f4, f11, f5, f12, west); - writeQuad(writer, new Vector3f[]{hll, lll, lhl, hhl}, f5, f11, f6, f12, north); - writeQuad(writer, new Vector3f[]{hlh, hll, hhl, hhh}, f6, f11, f8, f12, east); - writeQuad(writer, new Vector3f[]{llh, hlh, hhh, lhh}, f8, f11, f9, f12, south); - } - } - - private void writeQuad(VertexWriter writer, Vector3f[] vertices, float minU, float minV, float maxU, float maxV, Vector3f normal) { - writer.putVertex(vertices[0].x(), vertices[0].y(), vertices[0].z(), maxU, minV, normal.x(), normal.y(), normal.z()); - writer.putVertex(vertices[1].x(), vertices[1].y(), vertices[1].z(), minU, minV, normal.x(), normal.y(), normal.z()); - writer.putVertex(vertices[2].x(), vertices[2].y(), vertices[2].z(), minU, maxV, normal.x(), normal.y(), normal.z()); - writer.putVertex(vertices[3].x(), vertices[3].y(), vertices[3].z(), maxU, maxV, normal.x(), normal.y(), normal.z()); - } - - private float getU(float u) { - if (sprite != null) { - return sprite.getU(u * 16 / textureWidth); - } else { - return u / textureWidth; - } - } - - private float getV(float v) { - if (sprite != null) { - return sprite.getV(v * 16 / textureHeight); - } else { - return v / textureHeight; - } - } - } - - private static class VertexWriter { - private long ptr; - - public VertexWriter(long ptr) { - this.ptr = ptr; - } - - public void putVertex(float x, float y, float z, float u, float v, float nX, float nY, float nZ) { - MemoryUtil.memPutFloat(ptr, x); - MemoryUtil.memPutFloat(ptr + 4, y); - MemoryUtil.memPutFloat(ptr + 8, z); - MemoryUtil.memPutFloat(ptr + 12, u); - MemoryUtil.memPutFloat(ptr + 16, v); - MemoryUtil.memPutByte(ptr + 20, RenderMath.nb(nX)); - MemoryUtil.memPutByte(ptr + 21, RenderMath.nb(nY)); - MemoryUtil.memPutByte(ptr + 22, RenderMath.nb(nZ)); - - ptr += 23; - } - } -} diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/part/ModelPartConverter.java b/src/main/java/com/jozufozu/flywheel/lib/model/part/ModelPartConverter.java new file mode 100644 index 000000000..88d86ed6a --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/lib/model/part/ModelPartConverter.java @@ -0,0 +1,64 @@ +package com.jozufozu.flywheel.lib.model.part; + +import org.jetbrains.annotations.Nullable; +import org.joml.Vector2f; + +import com.jozufozu.flywheel.api.model.Mesh; +import com.jozufozu.flywheel.lib.memory.MemoryBlock; +import com.jozufozu.flywheel.lib.model.SimpleMesh; +import com.jozufozu.flywheel.lib.vertex.VertexTypes; +import com.mojang.blaze3d.vertex.PoseStack; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.model.geom.EntityModelSet; +import net.minecraft.client.model.geom.ModelLayerLocation; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; + +public final class ModelPartConverter { + private static final ThreadLocal THREAD_LOCAL_OBJECTS = ThreadLocal.withInitial(ThreadLocalObjects::new); + + private ModelPartConverter() { + } + + public static Mesh convert(ModelPart modelPart, @Nullable PoseStack poseStack, @Nullable TextureMapper textureMapper) { + ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get(); + if (poseStack == null) { + poseStack = objects.identityPoseStack; + } + VertexWriter vertexWriter = objects.vertexWriter; + vertexWriter.setTextureMapper(textureMapper); + modelPart.render(poseStack, vertexWriter, LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY); + MemoryBlock data = vertexWriter.copyDataAndReset(); + return new SimpleMesh(VertexTypes.POS_TEX_NORMAL, data, "source=ModelPartConverter"); + } + + public static Mesh convert(ModelLayerLocation layer, @Nullable TextureAtlasSprite sprite, String... childPath) { + EntityModelSet entityModels = Minecraft.getInstance().getEntityModels(); + ModelPart modelPart = entityModels.bakeLayer(layer); + for (String pathPart : childPath) { + modelPart = modelPart.getChild(pathPart); + } + TextureMapper textureMapper = sprite == null ? null : TextureMapper.toSprite(sprite); + return convert(modelPart, null, textureMapper); + } + + public static Mesh convert(ModelLayerLocation layer, String... childPath) { + return convert(layer, null, childPath); + } + + public interface TextureMapper { + void map(Vector2f uv); + + static TextureMapper toSprite(TextureAtlasSprite sprite) { + return uv -> uv.set(sprite.getU(uv.x * 16), sprite.getV(uv.y * 16)); + } + } + + private static class ThreadLocalObjects { + public final PoseStack identityPoseStack = new PoseStack(); + public final VertexWriter vertexWriter = new VertexWriter(); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/part/VertexWriter.java b/src/main/java/com/jozufozu/flywheel/lib/model/part/VertexWriter.java new file mode 100644 index 000000000..d0b043d01 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/lib/model/part/VertexWriter.java @@ -0,0 +1,139 @@ +package com.jozufozu.flywheel.lib.model.part; + +import org.jetbrains.annotations.Nullable; +import org.joml.Vector2f; +import org.lwjgl.system.MemoryUtil; + +import com.jozufozu.flywheel.api.vertex.VertexType; +import com.jozufozu.flywheel.lib.math.RenderMath; +import com.jozufozu.flywheel.lib.memory.MemoryBlock; +import com.jozufozu.flywheel.lib.model.part.ModelPartConverter.TextureMapper; +import com.jozufozu.flywheel.lib.vertex.VertexTypes; +import com.mojang.blaze3d.vertex.VertexConsumer; + +class VertexWriter implements VertexConsumer { + private static final VertexType VERTEX_TYPE = VertexTypes.POS_TEX_NORMAL; + private static final int STRIDE = VERTEX_TYPE.getStride(); + private static final int GROWTH_MARGIN = 128 * STRIDE; + + private MemoryBlock data; + + @Nullable + private TextureMapper textureMapper; + private final Vector2f uvVec = new Vector2f(); + + private int vertexCount; + private boolean filledPosition; + private boolean filledTexture; + private boolean filledNormal; + + public VertexWriter() { + data = MemoryBlock.malloc(GROWTH_MARGIN); + } + + public void setTextureMapper(@Nullable TextureMapper mapper) { + textureMapper = mapper; + } + + @Override + public VertexConsumer vertex(double x, double y, double z) { + if (!filledPosition) { + long ptr = vertexPtr(); + MemoryUtil.memPutFloat(ptr, (float) x); + MemoryUtil.memPutFloat(ptr + 4, (float) y); + MemoryUtil.memPutFloat(ptr + 8, (float) z); + filledPosition = true; + } + return this; + } + + @Override + public VertexConsumer color(int red, int green, int blue, int alpha) { + // ignore color + return this; + } + + @Override + public VertexConsumer uv(float u, float v) { + if (!filledTexture) { + if (textureMapper != null) { + uvVec.set(u, v); + textureMapper.map(uvVec); + u = uvVec.x; + v = uvVec.y; + } + + long ptr = vertexPtr(); + MemoryUtil.memPutFloat(ptr + 12, u); + MemoryUtil.memPutFloat(ptr + 16, v); + filledTexture = true; + } + return this; + } + + @Override + public VertexConsumer overlayCoords(int u, int v) { + // ignore overlay + return this; + } + + @Override + public VertexConsumer uv2(int u, int v) { + // ignore light + return this; + } + + @Override + public VertexConsumer normal(float x, float y, float z) { + if (!filledNormal) { + long ptr = vertexPtr(); + MemoryUtil.memPutByte(ptr + 20, RenderMath.nb(x)); + MemoryUtil.memPutByte(ptr + 21, RenderMath.nb(y)); + MemoryUtil.memPutByte(ptr + 22, RenderMath.nb(z)); + filledNormal = true; + } + return this; + } + + @Override + public void endVertex() { + if (!filledPosition || !filledTexture || !filledNormal) { + throw new IllegalStateException("Not filled all elements of the vertex"); + } + + filledPosition = false; + filledTexture = false; + filledNormal = false; + vertexCount++; + + long byteSize = (vertexCount + 1) * STRIDE; + if (byteSize > data.size()) { + data = data.realloc(byteSize + GROWTH_MARGIN); + } + } + + @Override + public void defaultColor(int red, int green, int blue, int alpha) { + } + + @Override + public void unsetDefaultColor() { + } + + private long vertexPtr() { + return data.ptr() + vertexCount * STRIDE; + } + + public MemoryBlock copyDataAndReset() { + MemoryBlock dataCopy = MemoryBlock.malloc(vertexCount * STRIDE); + data.copyTo(dataCopy.ptr(), dataCopy.size()); + + vertexCount = 0; + filledPosition = false; + filledTexture = false; + filledNormal = false; + textureMapper = null; + + return dataCopy; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/lib/util/LevelAttached.java b/src/main/java/com/jozufozu/flywheel/lib/util/LevelAttached.java index e6139c2a8..551ffc5e0 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/util/LevelAttached.java +++ b/src/main/java/com/jozufozu/flywheel/lib/util/LevelAttached.java @@ -16,7 +16,6 @@ import com.google.common.cache.LoadingCache; import net.minecraft.world.level.LevelAccessor; import net.minecraftforge.event.world.WorldEvent; -// FIXME public final class LevelAttached { private static final ConcurrentLinkedDeque>> ALL = new ConcurrentLinkedDeque<>(); private static final Cleaner CLEANER = Cleaner.create(); diff --git a/src/main/java/com/jozufozu/flywheel/lib/visual/AbstractEntityVisual.java b/src/main/java/com/jozufozu/flywheel/lib/visual/AbstractEntityVisual.java index 13990342e..df23d40a0 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/visual/AbstractEntityVisual.java +++ b/src/main/java/com/jozufozu/flywheel/lib/visual/AbstractEntityVisual.java @@ -97,11 +97,11 @@ public abstract class AbstractEntityVisual extends AbstractVis * * @return The position this visual should be rendered at to appear in the correct location. */ - public Vector3f getVisualPosition(float partialTicks) { + public Vector3f getVisualPosition(float partialTick) { Vec3 pos = entity.position(); - return new Vector3f((float) (Mth.lerp(partialTicks, entity.xOld, pos.x) - renderOrigin.getX()), - (float) (Mth.lerp(partialTicks, entity.yOld, pos.y) - renderOrigin.getY()), - (float) (Mth.lerp(partialTicks, entity.zOld, pos.z) - renderOrigin.getZ())); + return new Vector3f((float) (Mth.lerp(partialTick, entity.xOld, pos.x) - renderOrigin.getX()), + (float) (Mth.lerp(partialTick, entity.yOld, pos.y) - renderOrigin.getY()), + (float) (Mth.lerp(partialTick, entity.zOld, pos.z) - renderOrigin.getZ())); } public boolean isVisible(FrustumIntersection frustum) { diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/BellVisual.java b/src/main/java/com/jozufozu/flywheel/vanilla/BellVisual.java index 65b0a9bc3..e56d3c596 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/BellVisual.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/BellVisual.java @@ -2,29 +2,30 @@ package com.jozufozu.flywheel.vanilla; import java.util.List; -import org.jetbrains.annotations.NotNull; - import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.instance.Instance; -import com.jozufozu.flywheel.api.model.Mesh; import com.jozufozu.flywheel.api.visual.DynamicVisual; import com.jozufozu.flywheel.api.visual.VisualFrameContext; import com.jozufozu.flywheel.api.visualization.VisualizationContext; import com.jozufozu.flywheel.lib.instance.InstanceTypes; import com.jozufozu.flywheel.lib.instance.OrientedInstance; import com.jozufozu.flywheel.lib.material.Materials; -import com.jozufozu.flywheel.lib.model.SimpleLazyModel; -import com.jozufozu.flywheel.lib.model.part.ModelPartBuilder; +import com.jozufozu.flywheel.lib.model.ModelHolder; +import com.jozufozu.flywheel.lib.model.SimpleModel; +import com.jozufozu.flywheel.lib.model.part.ModelPartConverter; import com.jozufozu.flywheel.lib.visual.AbstractBlockEntityVisual; import com.mojang.math.Quaternion; import com.mojang.math.Vector3f; +import net.minecraft.client.model.geom.ModelLayers; import net.minecraft.client.renderer.blockentity.BellRenderer; import net.minecraft.util.Mth; import net.minecraft.world.level.block.entity.BellBlockEntity; public class BellVisual extends AbstractBlockEntityVisual implements DynamicVisual { - private static final SimpleLazyModel BELL_MODEL = new SimpleLazyModel(BellVisual::createBellMesh, Materials.BELL); + private static final ModelHolder BELL_MODEL = new ModelHolder(() -> { + return new SimpleModel(ModelPartConverter.convert(ModelLayers.BELL, BellRenderer.BELL_RESOURCE_LOCATION.sprite(), "bell_body"), Materials.BELL); + }); private OrientedInstance bell; @@ -44,6 +45,11 @@ public class BellVisual extends AbstractBlockEntityVisual imple super.init(partialTick); } + private OrientedInstance createBellInstance() { + return instancerProvider.instancer(InstanceTypes.ORIENTED, BELL_MODEL.get(), RenderStage.AFTER_BLOCK_ENTITIES) + .createInstance(); + } + @Override public void beginFrame(VisualFrameContext context) { if (doDistanceLimitThisFrame(context) || !isVisible(context.frustum())) { @@ -87,25 +93,4 @@ public class BellVisual extends AbstractBlockEntityVisual imple protected void _delete() { bell.delete(); } - - private OrientedInstance createBellInstance() { - return instancerProvider.instancer(InstanceTypes.ORIENTED, BELL_MODEL, RenderStage.AFTER_BLOCK_ENTITIES) - .createInstance(); - } - - @NotNull - private static Mesh createBellMesh() { - return new ModelPartBuilder("bell", 32, 32) - .sprite(BellRenderer.BELL_RESOURCE_LOCATION.sprite()) - .cuboid() - .start(5.0F, 6.0F, 5.0F) - .size(6.0F, 7.0F, 6.0F) - .endCuboid() - .cuboid() - .textureOffset(0, 13) - .start(4.0F, 4.0F, 4.0F) - .size(8.0F, 2.0F, 8.0F) - .endCuboid() - .build(); - } } diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/ChestVisual.java b/src/main/java/com/jozufozu/flywheel/vanilla/ChestVisual.java index 83d42717d..dbe4d1885 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/ChestVisual.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/ChestVisual.java @@ -1,12 +1,12 @@ package com.jozufozu.flywheel.vanilla; import java.util.Calendar; +import java.util.EnumMap; import java.util.List; -import java.util.function.BiFunction; +import java.util.Map; import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.instance.Instance; -import com.jozufozu.flywheel.api.model.Mesh; import com.jozufozu.flywheel.api.visual.DynamicVisual; import com.jozufozu.flywheel.api.visual.VisualFrameContext; import com.jozufozu.flywheel.api.visualization.VisualizationContext; @@ -14,16 +14,19 @@ import com.jozufozu.flywheel.lib.instance.InstanceTypes; import com.jozufozu.flywheel.lib.instance.OrientedInstance; import com.jozufozu.flywheel.lib.instance.TransformedInstance; import com.jozufozu.flywheel.lib.material.Materials; -import com.jozufozu.flywheel.lib.model.SimpleLazyModel; -import com.jozufozu.flywheel.lib.model.part.ModelPartBuilder; +import com.jozufozu.flywheel.lib.model.ModelCache; +import com.jozufozu.flywheel.lib.model.SimpleModel; +import com.jozufozu.flywheel.lib.model.part.ModelPartConverter; +import com.jozufozu.flywheel.lib.util.Pair; import com.jozufozu.flywheel.lib.visual.AbstractBlockEntityVisual; import com.mojang.math.Quaternion; import com.mojang.math.Vector3f; import it.unimi.dsi.fastutil.floats.Float2FloatFunction; -import net.minecraft.Util; +import net.minecraft.client.model.geom.ModelLayerLocation; +import net.minecraft.client.model.geom.ModelLayers; import net.minecraft.client.renderer.Sheets; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.Material; import net.minecraft.world.level.block.AbstractChestBlock; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.ChestBlock; @@ -34,16 +37,31 @@ import net.minecraft.world.level.block.entity.LidBlockEntity; import net.minecraft.world.level.block.state.properties.ChestType; public class ChestVisual extends AbstractBlockEntityVisual implements DynamicVisual { - private static final BiFunction BODY_MODEL_FUNC = Util.memoize((type, mat) -> new SimpleLazyModel(() -> createBodyMesh(type, mat), Materials.CHEST)); - private static final BiFunction LID_MODEL_FUNC = Util.memoize((type, mat) -> new SimpleLazyModel(() -> createLidMesh(type, mat), Materials.CHEST)); + private static final Map LAYER_LOCATIONS = new EnumMap<>(ChestType.class); + static { + LAYER_LOCATIONS.put(ChestType.SINGLE, ModelLayers.CHEST); + LAYER_LOCATIONS.put(ChestType.LEFT, ModelLayers.DOUBLE_CHEST_LEFT); + LAYER_LOCATIONS.put(ChestType.RIGHT, ModelLayers.DOUBLE_CHEST_RIGHT); + } - private OrientedInstance body; + private static final ModelCache> BOTTOM_MODELS = new ModelCache<>(key -> { + return new SimpleModel(ModelPartConverter.convert(LAYER_LOCATIONS.get(key.first()), key.second().sprite(), "bottom"), Materials.CHEST); + }); + private static final ModelCache> LID_MODELS = new ModelCache<>(key -> { + return new SimpleModel(ModelPartConverter.convert(LAYER_LOCATIONS.get(key.first()), key.second().sprite(), "lid"), Materials.CHEST); + }); + private static final ModelCache> LOCK_MODELS = new ModelCache<>(key -> { + return new SimpleModel(ModelPartConverter.convert(LAYER_LOCATIONS.get(key.first()), key.second().sprite(), "lock"), Materials.CHEST); + }); + + private OrientedInstance bottom; private TransformedInstance lid; + private TransformedInstance lock; - private Float2FloatFunction lidProgress; - private TextureAtlasSprite sprite; private ChestType chestType; + private Material texture; private Quaternion baseRotation; + private Float2FloatFunction lidProgress; private float lastProgress = Float.NaN; @@ -53,25 +71,21 @@ public class ChestVisual extends Abstrac @Override public void init(float partialTick) { - Block block = blockState.getBlock(); - chestType = blockState.hasProperty(ChestBlock.TYPE) ? blockState.getValue(ChestBlock.TYPE) : ChestType.SINGLE; - sprite = Sheets.chooseMaterial(blockEntity, chestType, isChristmas()) - .sprite(); + texture = Sheets.chooseMaterial(blockEntity, chestType, isChristmas()); - body = createBodyInstance().setPosition(getVisualPosition()); + bottom = createBottomInstance().setPosition(getVisualPosition()); lid = createLidInstance(); + lock = createLockInstance(); + Block block = blockState.getBlock(); if (block instanceof AbstractChestBlock chestBlock) { float horizontalAngle = blockState.getValue(ChestBlock.FACING).toYRot(); - baseRotation = Vector3f.YP.rotationDegrees(-horizontalAngle); - - body.setRotation(baseRotation); + bottom.setRotation(baseRotation); DoubleBlockCombiner.NeighborCombineResult wrapper = chestBlock.combine(blockState, level, pos, true); - - this.lidProgress = wrapper.apply(ChestBlock.opennessCombiner(blockEntity)); + lidProgress = wrapper.apply(ChestBlock.opennessCombiner(blockEntity)); } else { baseRotation = Quaternion.ONE; lidProgress = $ -> 0f; @@ -80,6 +94,26 @@ public class ChestVisual extends Abstrac super.init(partialTick); } + private OrientedInstance createBottomInstance() { + return instancerProvider.instancer(InstanceTypes.ORIENTED, BOTTOM_MODELS.get(Pair.of(chestType, texture)), RenderStage.AFTER_BLOCK_ENTITIES) + .createInstance(); + } + + private TransformedInstance createLidInstance() { + return instancerProvider.instancer(InstanceTypes.TRANSFORMED, LID_MODELS.get(Pair.of(chestType, texture)), RenderStage.AFTER_BLOCK_ENTITIES) + .createInstance(); + } + + private TransformedInstance createLockInstance() { + return instancerProvider.instancer(InstanceTypes.TRANSFORMED, LOCK_MODELS.get(Pair.of(chestType, texture)), RenderStage.AFTER_BLOCK_ENTITIES) + .createInstance(); + } + + private static boolean isChristmas() { + Calendar calendar = Calendar.getInstance(); + return calendar.get(Calendar.MONTH) + 1 == 12 && calendar.get(Calendar.DATE) >= 24 && calendar.get(Calendar.DATE) <= 26; + } + @Override public void beginFrame(VisualFrameContext context) { if (doDistanceLimitThisFrame(context) || !isVisible(context.frustum())) { @@ -87,11 +121,9 @@ public class ChestVisual extends Abstrac } float progress = lidProgress.get(context.partialTick()); - if (lastProgress == progress) { return; } - lastProgress = progress; progress = 1.0F - progress; @@ -101,113 +133,37 @@ public class ChestVisual extends Abstrac lid.loadIdentity() .translate(getVisualPosition()) - .translate(0, 9f / 16f, 0) .centre() .multiply(baseRotation) .unCentre() - .translate(0, 0, 1f / 16f) - .multiply(Vector3f.XP.rotation(angleX)) - .translate(0, 0, -1f / 16f); + .translate(0, 9f / 16f, 1f / 16f) + .rotateXRadians(angleX) + .translate(0, -9f / 16f, -1f / 16f); + + lock.loadIdentity() + .translate(getVisualPosition()) + .centre() + .multiply(baseRotation) + .unCentre() + .translate(0, 8f / 16f, 0) + .rotateXRadians(angleX) + .translate(0, -8f / 16f, 0); } @Override public void updateLight() { - relight(pos, body, lid); + relight(pos, bottom, lid, lock); } @Override public List getCrumblingInstances() { - return List.of(body, lid); + return List.of(bottom, lid, lock); } @Override protected void _delete() { - body.delete(); + bottom.delete(); lid.delete(); - } - - private OrientedInstance createBodyInstance() { - return instancerProvider.instancer(InstanceTypes.ORIENTED, BODY_MODEL_FUNC.apply(chestType, sprite), RenderStage.AFTER_BLOCK_ENTITIES) - .createInstance(); - } - - private TransformedInstance createLidInstance() { - return instancerProvider.instancer(InstanceTypes.TRANSFORMED, LID_MODEL_FUNC.apply(chestType, sprite), RenderStage.AFTER_BLOCK_ENTITIES) - .createInstance(); - } - - private static Mesh createBodyMesh(ChestType type, TextureAtlasSprite sprite) { - return switch (type) { - case LEFT -> new ModelPartBuilder("chest_base_left", 64, 64) - .sprite(sprite) - .cuboid() - .textureOffset(0, 19) - .start(0, 0, 1) - .size(15, 10, 14) - .endCuboid() - .build(); - case RIGHT -> new ModelPartBuilder("chest_base_right", 64, 64) - .sprite(sprite) - .cuboid() - .textureOffset(0, 19) - .start(1, 0, 1) - .size(15, 10, 14) - .endCuboid() - .build(); - default -> new ModelPartBuilder("chest_base", 64, 64) - .sprite(sprite) - .cuboid() - .textureOffset(0, 19) - .start(1, 0, 1) - .end(15, 10, 15) - .endCuboid() - .build(); - }; - } - - private static Mesh createLidMesh(ChestType type, TextureAtlasSprite sprite) { - return switch (type) { - case LEFT -> new ModelPartBuilder("chest_lid_left", 64, 64) - .sprite(sprite) - .cuboid() - .textureOffset(0, 0) - .start(0, 0, 1) - .size(15, 5, 14) - .endCuboid() - .cuboid() - .start(0, -2, 15) - .size(1, 4, 1) - .endCuboid() - .build(); - case RIGHT -> new ModelPartBuilder("chest_lid_right", 64, 64) - .sprite(sprite) - .cuboid() - .textureOffset(0, 0) - .start(1, 0, 1) - .size(15, 5, 14) - .endCuboid() - .cuboid() - .start(15, -2, 15) - .size(1, 4, 1) - .endCuboid() - .build(); - default -> new ModelPartBuilder("chest_lid", 64, 64) - .sprite(sprite) - .cuboid() - .textureOffset(0, 0) - .start(1, 0, 1) - .size(14, 5, 14) - .endCuboid() - .cuboid() - .start(7, -2, 15) - .size(2, 4, 1) - .endCuboid() - .build(); - }; - } - - public static boolean isChristmas() { - Calendar calendar = Calendar.getInstance(); - return calendar.get(Calendar.MONTH) + 1 == 12 && calendar.get(Calendar.DATE) >= 24 && calendar.get(Calendar.DATE) <= 26; + lock.delete(); } } diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/MinecartVisual.java b/src/main/java/com/jozufozu/flywheel/vanilla/MinecartVisual.java index a4ac5869e..fea3ef492 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/MinecartVisual.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/MinecartVisual.java @@ -1,9 +1,6 @@ package com.jozufozu.flywheel.vanilla; -import org.jetbrains.annotations.NotNull; - import com.jozufozu.flywheel.api.event.RenderStage; -import com.jozufozu.flywheel.api.model.Mesh; import com.jozufozu.flywheel.api.visual.DynamicVisual; import com.jozufozu.flywheel.api.visual.TickableVisual; import com.jozufozu.flywheel.api.visual.VisualFrameContext; @@ -12,14 +9,15 @@ import com.jozufozu.flywheel.api.visualization.VisualizationContext; import com.jozufozu.flywheel.lib.instance.InstanceTypes; import com.jozufozu.flywheel.lib.instance.TransformedInstance; import com.jozufozu.flywheel.lib.material.Materials; +import com.jozufozu.flywheel.lib.model.ModelHolder; import com.jozufozu.flywheel.lib.model.Models; -import com.jozufozu.flywheel.lib.model.SimpleLazyModel; -import com.jozufozu.flywheel.lib.model.part.ModelPartBuilder; -import com.jozufozu.flywheel.lib.transform.TransformStack; +import com.jozufozu.flywheel.lib.model.SimpleModel; +import com.jozufozu.flywheel.lib.model.part.ModelPartConverter; import com.jozufozu.flywheel.lib.visual.AbstractEntityVisual; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Vector3f; +import net.minecraft.client.model.geom.ModelLayers; import net.minecraft.util.Mth; import net.minecraft.world.entity.vehicle.AbstractMinecart; import net.minecraft.world.level.block.RenderShape; @@ -27,15 +25,17 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; public class MinecartVisual extends AbstractEntityVisual implements TickableVisual, DynamicVisual { - private static final SimpleLazyModel BODY_MODEL = new SimpleLazyModel(MinecartVisual::createBodyMesh, Materials.MINECART); - - private final PoseStack stack = new PoseStack(); + private static final ModelHolder BODY_MODEL = new ModelHolder(() -> { + return new SimpleModel(ModelPartConverter.convert(ModelLayers.MINECART), Materials.MINECART); + }); private TransformedInstance body; private TransformedInstance contents; private BlockState blockState; private boolean active; + private final PoseStack stack = new PoseStack(); + public MinecartVisual(VisualizationContext ctx, T entity) { super(ctx, entity); } @@ -51,119 +51,8 @@ public class MinecartVisual extends AbstractEntityVi super.init(partialTick); } - @Override - public void tick(VisualTickContext c) { - BlockState displayBlockState = entity.getDisplayBlockState(); - - if (displayBlockState != blockState) { - blockState = displayBlockState; - contents.delete(); - contents = createContentsInstance(); - if (contents != null) { - relight(entity.blockPosition(), contents); - } - } - } - - @Override - public void beginFrame(VisualFrameContext context) { - if (isVisible(context.frustum())) { - return; - } - - // TODO: add proper way to temporarily disable rendering a specific instance - if (!active) { - return; - } - - updatePosition(context.partialTick()); - } - - private void updatePosition(float partialTick) { - TransformStack tstack = TransformStack.cast(stack); - stack.setIdentity(); - - tstack.translate(Mth.lerp(partialTick, entity.xOld, entity.getX()) - renderOrigin.getX(), Mth.lerp(partialTick, entity.yOld, entity.getY()) - renderOrigin.getY(), Mth.lerp(partialTick, entity.zOld, entity.getZ()) - renderOrigin.getZ()); - - float yaw = Mth.lerp(partialTick, entity.yRotO, entity.getYRot()); - - long i = (long) entity.getId() * 493286711L; - i = i * i * 4392167121L + i * 98761L; - float f = (((float)(i >> 16 & 7L) + 0.5F) / 8 - 0.5F) * 0.004F; - float f1 = (((float)(i >> 20 & 7L) + 0.5F) / 8 - 0.5F) * 0.004F; - float f2 = (((float)(i >> 24 & 7L) + 0.5F) / 8 - 0.5F) * 0.004F; - tstack.translate(f, f1, f2); - tstack.nudge(entity.getId()); - double d0 = Mth.lerp(partialTick, entity.xOld, entity.getX()); - double d1 = Mth.lerp(partialTick, entity.yOld, entity.getY()); - double d2 = Mth.lerp(partialTick, entity.zOld, entity.getZ()); - Vec3 vector3d = entity.getPos(d0, d1, d2); - float f3 = Mth.lerp(partialTick, entity.xRotO, entity.getXRot()); - if (vector3d != null) { - Vec3 vector3d1 = entity.getPosOffs(d0, d1, d2, 0.3F); - Vec3 vector3d2 = entity.getPosOffs(d0, d1, d2, -0.3F); - if (vector3d1 == null) { - vector3d1 = vector3d; - } - - if (vector3d2 == null) { - vector3d2 = vector3d; - } - - tstack.translate(vector3d.x - d0, (vector3d1.y + vector3d2.y) / 2.0D - d1, vector3d.z - d2); - Vec3 vector3d3 = vector3d2.add(-vector3d1.x, -vector3d1.y, -vector3d1.z); - if (vector3d3.length() != 0.0D) { - vector3d3 = vector3d3.normalize(); - yaw = (float)(Math.atan2(vector3d3.z, vector3d3.x) * 180.0D / Math.PI); - f3 = (float)(Math.atan(vector3d3.y) * 73.0D); - } - } - - tstack.translate(0.0D, 0.375D, 0.0D); - tstack.multiply(Vector3f.YP.rotationDegrees(180 - yaw)); - tstack.multiply(Vector3f.ZP.rotationDegrees(-f3)); - float f5 = (float)entity.getHurtTime() - partialTick; - float f6 = entity.getDamage() - partialTick; - if (f6 < 0) { - f6 = 0; - } - - if (f5 > 0) { - tstack.multiply(Vector3f.XP.rotationDegrees(Mth.sin(f5) * f5 * f6 / 10 * (float)entity.getHurtDir())); - } - - int j = entity.getDisplayOffset(); - if (contents != null) { - tstack.pushPose(); - tstack.scale(0.75F); - tstack.translate(-0.5D, (float)(j - 8) / 16, 0.5D); - tstack.multiply(Vector3f.YP.rotationDegrees(90)); - contents.setTransform(stack); - tstack.popPose(); - } - - body.setTransform(stack); - } - - @Override - public void updateLight() { - if (contents == null) { - relight(entity.blockPosition(), body); - } else { - relight(entity.blockPosition(), body, contents); - } - } - - @Override - protected void _delete() { - body.delete(); - if (contents != null) { - contents.delete(); - } - } - private TransformedInstance createBodyInstance() { - return instancerProvider.instancer(InstanceTypes.TRANSFORMED, BODY_MODEL, RenderStage.AFTER_ENTITIES) + return instancerProvider.instancer(InstanceTypes.TRANSFORMED, BODY_MODEL.get(), RenderStage.AFTER_ENTITIES) .createInstance(); } @@ -185,15 +74,118 @@ public class MinecartVisual extends AbstractEntityVi .createInstance(); } - @NotNull - private static Mesh createBodyMesh() { - return new ModelPartBuilder("minecart", 64, 32) - .cuboid().invertYZ().start(-10, -8, 3).size(20, 16, 2).textureOffset(0, 10).rotateZ((float) Math.PI).rotateX(((float)Math.PI / 2F)).endCuboid() - .cuboid().invertYZ().start(-8, -3, -10).size(16, 8, 2).rotateY(((float)Math.PI * 1.5F)).endCuboid() - .cuboid().invertYZ().start(-8, -3, -10).size(16, 8, 2).rotateY(((float)Math.PI / 2F)).endCuboid() - .cuboid().invertYZ().start(-8, -3, -8).size(16, 8, 2).rotateY((float)Math.PI).endCuboid() - .cuboid().invertYZ().start(-8, -3, -8).size(16, 8, 2).endCuboid() - .build(); + @Override + public void tick(VisualTickContext c) { + BlockState displayBlockState = entity.getDisplayBlockState(); + + if (displayBlockState != blockState) { + blockState = displayBlockState; + contents.delete(); + contents = createContentsInstance(); + if (contents != null) { + relight(entity.blockPosition(), contents); + } + } + } + + @Override + public void beginFrame(VisualFrameContext context) { + if (!isVisible(context.frustum())) { + return; + } + + // TODO: add proper way to temporarily disable rendering a specific instance + if (!active) { + return; + } + + updatePosition(context.partialTick()); + } + + private void updatePosition(float partialTick) { + stack.setIdentity(); + + double posX = Mth.lerp(partialTick, entity.xOld, entity.getX()); + double posY = Mth.lerp(partialTick, entity.yOld, entity.getY()); + double posZ = Mth.lerp(partialTick, entity.zOld, entity.getZ()); + + stack.translate(posX - renderOrigin.getX(), posY - renderOrigin.getY(), posZ - renderOrigin.getZ()); + float yaw = Mth.lerp(partialTick, entity.yRotO, entity.getYRot()); + + long randomBits = entity.getId() * 493286711L; + randomBits = randomBits * randomBits * 4392167121L + randomBits * 98761L; + float nudgeX = (((float) (randomBits >> 16 & 7L) + 0.5f) / 8.0f - 0.5F) * 0.004f; + float nudgeY = (((float) (randomBits >> 20 & 7L) + 0.5f) / 8.0f - 0.5F) * 0.004f; + float nudgeZ = (((float) (randomBits >> 24 & 7L) + 0.5f) / 8.0f - 0.5F) * 0.004f; + stack.translate(nudgeX, nudgeY, nudgeZ); + + Vec3 pos = entity.getPos(posX, posY, posZ); + float pitch = Mth.lerp(partialTick, entity.xRotO, entity.getXRot()); + if (pos != null) { + Vec3 offset1 = entity.getPosOffs(posX, posY, posZ, 0.3F); + Vec3 offset2 = entity.getPosOffs(posX, posY, posZ, -0.3F); + + if (offset1 == null) { + offset1 = pos; + } + + if (offset2 == null) { + offset2 = pos; + } + + stack.translate(pos.x - posX, (offset1.y + offset2.y) / 2.0D - posY, pos.z - posZ); + Vec3 vec = offset2.add(-offset1.x, -offset1.y, -offset1.z); + if (vec.length() != 0.0D) { + vec = vec.normalize(); + yaw = (float) (Math.atan2(vec.z, vec.x) * 180.0D / Math.PI); + pitch = (float) (Math.atan(vec.y) * 73.0D); + } + } + + stack.translate(0.0D, 0.375D, 0.0D); + stack.mulPose(Vector3f.YP.rotationDegrees(180 - yaw)); + stack.mulPose(Vector3f.ZP.rotationDegrees(-pitch)); + + float hurtTime = entity.getHurtTime() - partialTick; + float damage = entity.getDamage() - partialTick; + + if (damage < 0) { + damage = 0; + } + + if (hurtTime > 0) { + stack.mulPose(Vector3f.XP.rotationDegrees(Mth.sin(hurtTime) * hurtTime * damage / 10.0F * (float) entity.getHurtDir())); + } + + int displayOffset = entity.getDisplayOffset(); + if (contents != null) { + stack.pushPose(); + stack.scale(0.75F, 0.75F, 0.75F); + stack.translate(-0.5D, (float) (displayOffset - 8) / 16, 0.5D); + stack.mulPose(Vector3f.YP.rotationDegrees(90)); + contents.setTransform(stack); + stack.popPose(); + } + + stack.scale(-1.0F, -1.0F, 1.0F); + body.setTransform(stack); + } + + @Override + public void updateLight() { + if (contents == null) { + relight(entity.blockPosition(), body); + } else { + relight(entity.blockPosition(), body, contents); + } + } + + @Override + protected void _delete() { + body.delete(); + if (contents != null) { + contents.delete(); + } } public static boolean shouldSkipRender(AbstractMinecart minecart) { diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxVisual.java b/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxVisual.java index 546419197..48ded16a5 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxVisual.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxVisual.java @@ -1,41 +1,44 @@ package com.jozufozu.flywheel.vanilla; import java.util.List; -import java.util.function.Function; import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.instance.Instance; -import com.jozufozu.flywheel.api.model.Mesh; import com.jozufozu.flywheel.api.visual.DynamicVisual; import com.jozufozu.flywheel.api.visual.VisualFrameContext; import com.jozufozu.flywheel.api.visualization.VisualizationContext; import com.jozufozu.flywheel.lib.instance.InstanceTypes; import com.jozufozu.flywheel.lib.instance.TransformedInstance; import com.jozufozu.flywheel.lib.material.Materials; -import com.jozufozu.flywheel.lib.model.SimpleLazyModel; -import com.jozufozu.flywheel.lib.model.part.ModelPartBuilder; +import com.jozufozu.flywheel.lib.model.ModelCache; +import com.jozufozu.flywheel.lib.model.SimpleModel; +import com.jozufozu.flywheel.lib.model.part.ModelPartConverter; import com.jozufozu.flywheel.lib.transform.TransformStack; import com.jozufozu.flywheel.lib.visual.AbstractBlockEntityVisual; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Quaternion; import com.mojang.math.Vector3f; -import net.minecraft.Util; +import net.minecraft.client.model.geom.ModelLayers; import net.minecraft.client.renderer.Sheets; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.Material; import net.minecraft.core.Direction; import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.block.ShulkerBoxBlock; import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity; public class ShulkerBoxVisual extends AbstractBlockEntityVisual implements DynamicVisual { - private static final Function BODY_MODEL_FUNC = Util.memoize(it -> new SimpleLazyModel(() -> createBodyMesh(it), Materials.SHULKER)); - private static final Function LID_MODEL_FUNC = Util.memoize(it -> new SimpleLazyModel(() -> createLidMesh(it), Materials.SHULKER)); + private static final ModelCache BASE_MODELS = new ModelCache<>(texture -> { + return new SimpleModel(ModelPartConverter.convert(ModelLayers.SHULKER, texture.sprite(), "base"), Materials.SHULKER); + }); + private static final ModelCache LID_MODELS = new ModelCache<>(texture -> { + return new SimpleModel(ModelPartConverter.convert(ModelLayers.SHULKER, texture.sprite(), "lid"), Materials.SHULKER); + }); - private TextureAtlasSprite texture; - - private TransformedInstance body; + private TransformedInstance base; private TransformedInstance lid; + + private Material texture; private final PoseStack stack = new PoseStack(); private float lastProgress = Float.NaN; @@ -48,31 +51,37 @@ public class ShulkerBoxVisual extends AbstractBlockEntityVisual getCrumblingInstances() { - return List.of(body, lid); + return List.of(base, lid); } @Override protected void _delete() { - body.delete(); + base.delete(); lid.delete(); } - - @Override - public void updateLight() { - relight(pos, body, lid); - } - - private TransformedInstance createBodyInstance() { - return instancerProvider.instancer(InstanceTypes.TRANSFORMED, BODY_MODEL_FUNC.apply(texture), RenderStage.AFTER_BLOCK_ENTITIES) - .createInstance(); - } - - private TransformedInstance createLidInstance() { - return instancerProvider.instancer(InstanceTypes.TRANSFORMED, LID_MODEL_FUNC.apply(texture), RenderStage.AFTER_BLOCK_ENTITIES) - .createInstance(); - } - - private static Mesh createBodyMesh(TextureAtlasSprite texture) { - return new ModelPartBuilder("shulker_base", 64, 64) - .sprite(texture) - .cuboid() - .textureOffset(0, 28) - .size(16, 8, 16) - .invertYZ() - .endCuboid() - .build(); - } - - private static Mesh createLidMesh(TextureAtlasSprite texture) { - return new ModelPartBuilder("shulker_lid", 64, 64) - .sprite(texture) - .cuboid() - .size(16, 12, 16) - .invertYZ() - .endCuboid() - .build(); - } }