mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-27 07:26:48 +01:00
Fix poor design choices resulting in memory leaks
- Add ShadeSeparatedBufferedData which is returned by buffering utilities and can be released - Remove ShadeSeparatedBufferBuilder and add ModelUtil#endAndCombine - Add VertexList#delete - Replace all usage of MemoryTracker with MemoryUtil - Add FlwUtil#copyBuffer - Turn most BlockModel constructors into static methods - Add BakedModelBuilder#toModel
This commit is contained in:
parent
873facfd34
commit
e79f6bcbf6
14 changed files with 188 additions and 131 deletions
|
@ -25,11 +25,11 @@ public interface Material<D extends InstanceData> {
|
||||||
Instancer<D> model(Object key, Supplier<Model> modelSupplier);
|
Instancer<D> model(Object key, Supplier<Model> modelSupplier);
|
||||||
|
|
||||||
default Instancer<D> getModel(PartialModel partial, BlockState referenceState) {
|
default Instancer<D> getModel(PartialModel partial, BlockState referenceState) {
|
||||||
return model(partial, () -> new BlockModel(partial.get(), referenceState));
|
return model(partial, () -> BlockModel.of(partial.get(), referenceState));
|
||||||
}
|
}
|
||||||
|
|
||||||
default Instancer<D> getModel(PartialModel partial) {
|
default Instancer<D> getModel(PartialModel partial) {
|
||||||
return model(partial, () -> new BlockModel(partial.get(), Blocks.AIR.defaultBlockState()));
|
return model(partial, () -> BlockModel.of(partial.get(), Blocks.AIR.defaultBlockState()));
|
||||||
}
|
}
|
||||||
|
|
||||||
default Instancer<D> getModel(PartialModel partial, BlockState referenceState, Direction dir) {
|
default Instancer<D> getModel(PartialModel partial, BlockState referenceState, Direction dir) {
|
||||||
|
@ -37,10 +37,10 @@ public interface Material<D extends InstanceData> {
|
||||||
}
|
}
|
||||||
|
|
||||||
default Instancer<D> getModel(PartialModel partial, BlockState referenceState, Direction dir, Supplier<PoseStack> modelTransform) {
|
default Instancer<D> getModel(PartialModel partial, BlockState referenceState, Direction dir, Supplier<PoseStack> modelTransform) {
|
||||||
return model(Pair.of(dir, partial), () -> new BlockModel(partial.get(), referenceState, modelTransform.get()));
|
return model(Pair.of(dir, partial), () -> BlockModel.of(partial.get(), referenceState, modelTransform.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
default Instancer<D> getModel(BlockState toRender) {
|
default Instancer<D> getModel(BlockState toRender) {
|
||||||
return model(toRender, () -> new BlockModel(toRender));
|
return model(toRender, () -> BlockModel.of(toRender));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,4 +41,7 @@ public interface VertexList {
|
||||||
default boolean isEmpty() {
|
default boolean isEmpty() {
|
||||||
return getVertexCount() == 0;
|
return getVertexCount() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default void delete() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,10 @@ package com.jozufozu.flywheel.backend.instancing;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.model.BufferBuilderExtension;
|
import com.jozufozu.flywheel.backend.model.BufferBuilderExtension;
|
||||||
import com.jozufozu.flywheel.backend.model.DirectVertexConsumer;
|
import com.jozufozu.flywheel.backend.model.DirectVertexConsumer;
|
||||||
import com.mojang.blaze3d.platform.MemoryTracker;
|
|
||||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
@ -48,10 +48,10 @@ public class DrawBuffer {
|
||||||
int byteSize = format.getVertexSize() * (vertexCount + 1);
|
int byteSize = format.getVertexSize() * (vertexCount + 1);
|
||||||
|
|
||||||
if (backingBuffer == null) {
|
if (backingBuffer == null) {
|
||||||
backingBuffer = MemoryTracker.create(byteSize);
|
backingBuffer = MemoryUtil.memAlloc(byteSize);
|
||||||
}
|
}
|
||||||
if (byteSize > backingBuffer.capacity()) {
|
if (byteSize > backingBuffer.capacity()) {
|
||||||
backingBuffer = MemoryTracker.resize(backingBuffer, byteSize);
|
backingBuffer = MemoryUtil.memRealloc(backingBuffer, byteSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new DirectVertexConsumer(backingBuffer, format, vertexCount);
|
return new DirectVertexConsumer(backingBuffer, format, vertexCount);
|
||||||
|
|
|
@ -10,7 +10,6 @@ import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||||
import com.jozufozu.flywheel.core.Formats;
|
import com.jozufozu.flywheel.core.Formats;
|
||||||
import com.jozufozu.flywheel.core.model.Model;
|
import com.jozufozu.flywheel.core.model.Model;
|
||||||
import com.jozufozu.flywheel.core.vertex.PosTexNormalWriterUnsafe;
|
import com.jozufozu.flywheel.core.vertex.PosTexNormalWriterUnsafe;
|
||||||
import com.mojang.blaze3d.platform.MemoryTracker;
|
|
||||||
|
|
||||||
public class ModelPart implements Model {
|
public class ModelPart implements Model {
|
||||||
|
|
||||||
|
@ -29,7 +28,7 @@ public class ModelPart implements Model {
|
||||||
this.vertices = vertices;
|
this.vertices = vertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteBuffer buffer = MemoryTracker.create(size());
|
ByteBuffer buffer = MemoryUtil.memAlloc(size());
|
||||||
PosTexNormalWriterUnsafe writer = Formats.POS_TEX_NORMAL.createWriter(buffer);
|
PosTexNormalWriterUnsafe writer = Formats.POS_TEX_NORMAL.createWriter(buffer);
|
||||||
for (PartBuilder.CuboidBuilder cuboid : cuboids) {
|
for (PartBuilder.CuboidBuilder cuboid : cuboids) {
|
||||||
cuboid.buffer(writer);
|
cuboid.buffer(writer);
|
||||||
|
@ -65,12 +64,6 @@ public class ModelPart implements Model {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delete() {
|
public void delete() {
|
||||||
if (reader instanceof AutoCloseable closeable) {
|
reader.delete();
|
||||||
try {
|
|
||||||
closeable.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,15 @@ public final class BakedModelBuilder implements Bufferable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bufferInto(ModelBlockRenderer blockRenderer, VertexConsumer consumer, Random random) {
|
public void bufferInto(VertexConsumer consumer, ModelBlockRenderer blockRenderer, Random random) {
|
||||||
blockRenderer.tesselateBlock(renderWorld, model, referenceState, BlockPos.ZERO, poseStack, consumer, false, random, 42, OverlayTexture.NO_OVERLAY, VirtualEmptyModelData.INSTANCE);
|
blockRenderer.tesselateBlock(renderWorld, model, referenceState, BlockPos.ZERO, poseStack, consumer, false, random, 42, OverlayTexture.NO_OVERLAY, VirtualEmptyModelData.INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BlockModel toModel(String name) {
|
||||||
|
return BlockModel.of(this, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockModel toModel() {
|
||||||
|
return toModel(referenceState.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
package com.jozufozu.flywheel.core.model;
|
package com.jozufozu.flywheel.core.model;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.vertex.VertexList;
|
import com.jozufozu.flywheel.api.vertex.VertexList;
|
||||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||||
import com.jozufozu.flywheel.core.Formats;
|
import com.jozufozu.flywheel.core.Formats;
|
||||||
|
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||||
|
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
@ -17,28 +21,55 @@ public class BlockModel implements Model {
|
||||||
private final VertexList reader;
|
private final VertexList reader;
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
public BlockModel(BlockState state) {
|
public BlockModel(ByteBuffer vertexBuffer, BufferBuilder.DrawState drawState, int unshadedStartVertex, String name) {
|
||||||
this(Minecraft.getInstance()
|
if (drawState.format() != DefaultVertexFormat.BLOCK) {
|
||||||
|
throw new RuntimeException("Cannot use buffered data with non-block format '" + drawState.format() + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
reader = Formats.BLOCK.createReader(vertexBuffer, drawState.vertexCount(), unshadedStartVertex);
|
||||||
|
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockModel(ByteBuffer vertexBuffer, BufferBuilder.DrawState drawState, String name) {
|
||||||
|
if (drawState.format() != DefaultVertexFormat.BLOCK) {
|
||||||
|
throw new RuntimeException("Cannot use buffered data with non-block format '" + drawState.format() + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
reader = Formats.BLOCK.createReader(vertexBuffer, drawState.vertexCount());
|
||||||
|
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockModel(ShadeSeparatedBufferedData data, String name) {
|
||||||
|
this(data.vertexBuffer(), data.drawState(), data.unshadedStartVertex(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockModel of(Bufferable bufferable, String name) {
|
||||||
|
ShadeSeparatedBufferedData data = bufferable.build();
|
||||||
|
BlockModel model = new BlockModel(data, name);
|
||||||
|
data.release();
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockModel of(BakedModel model, BlockState referenceState) {
|
||||||
|
ShadeSeparatedBufferedData data = ModelUtil.getBufferedData(model, referenceState);
|
||||||
|
BlockModel blockModel = new BlockModel(data, referenceState.toString());
|
||||||
|
data.release();
|
||||||
|
return blockModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockModel of(BlockState state) {
|
||||||
|
return of(Minecraft.getInstance()
|
||||||
.getBlockRenderer()
|
.getBlockRenderer()
|
||||||
.getBlockModel(state), state);
|
.getBlockModel(state), state);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BlockModel(BakedModel model, BlockState referenceState) {
|
public static BlockModel of(BakedModel model, BlockState referenceState, PoseStack ms) {
|
||||||
this(new BakedModelBuilder(model).withReferenceState(referenceState), referenceState.toString());
|
ShadeSeparatedBufferedData data = ModelUtil.getBufferedData(model, referenceState, ms);
|
||||||
}
|
BlockModel blockModel = new BlockModel(data, referenceState.toString());
|
||||||
|
data.release();
|
||||||
public BlockModel(BakedModel model, BlockState referenceState, PoseStack ms) {
|
return blockModel;
|
||||||
this(new BakedModelBuilder(model).withReferenceState(referenceState)
|
|
||||||
.withPoseStack(ms), referenceState.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockModel(Bufferable bufferable, String name) {
|
|
||||||
this(bufferable.build(), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockModel(ShadeSeparatedBufferBuilder bufferBuilder, String name) {
|
|
||||||
this.name = name;
|
|
||||||
reader = Formats.BLOCK.createReader(bufferBuilder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -63,12 +94,6 @@ public class BlockModel implements Model {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delete() {
|
public void delete() {
|
||||||
if (reader instanceof AutoCloseable closeable) {
|
reader.delete();
|
||||||
try {
|
|
||||||
closeable.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,12 @@ import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
import net.minecraft.client.renderer.block.ModelBlockRenderer;
|
import net.minecraft.client.renderer.block.ModelBlockRenderer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface for objects that can "rendered" into a BufferBuilder.
|
* An interface for objects that can buffered into a VertexConsumer.
|
||||||
*/
|
*/
|
||||||
public interface Bufferable {
|
public interface Bufferable {
|
||||||
void bufferInto(ModelBlockRenderer renderer, VertexConsumer consumer, Random random);
|
void bufferInto(VertexConsumer consumer, ModelBlockRenderer renderer, Random random);
|
||||||
|
|
||||||
default ShadeSeparatedBufferBuilder build() {
|
default ShadeSeparatedBufferedData build() {
|
||||||
return ModelUtil.getBufferBuilder(this);
|
return ModelUtil.getBufferedData(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
package com.jozufozu.flywheel.core.model;
|
package com.jozufozu.flywheel.core.model;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.Flywheel;
|
import com.jozufozu.flywheel.Flywheel;
|
||||||
|
import com.jozufozu.flywheel.backend.model.BufferBuilderExtension;
|
||||||
import com.jozufozu.flywheel.util.transform.TransformStack;
|
import com.jozufozu.flywheel.util.transform.TransformStack;
|
||||||
import com.mojang.blaze3d.vertex.BufferBuilder;
|
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
import com.mojang.blaze3d.vertex.BufferBuilder.DrawState;
|
||||||
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
@ -48,39 +52,52 @@ public class ModelUtil {
|
||||||
return dispatcher;
|
return dispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShadeSeparatedBufferBuilder getBufferBuilder(Bufferable bufferable) {
|
public static ShadeSeparatedBufferedData endAndCombine(BufferBuilder shadedBuilder, BufferBuilder unshadedBuilder) {
|
||||||
|
int unshadedStartVertex = ((BufferBuilderExtension) shadedBuilder).flywheel$getVertices();
|
||||||
|
unshadedBuilder.end();
|
||||||
|
Pair<DrawState, ByteBuffer> unshadedData = unshadedBuilder.popNextBuffer();
|
||||||
|
((BufferBuilderExtension) shadedBuilder).flywheel$appendBufferUnsafe(unshadedData.getSecond());
|
||||||
|
shadedBuilder.end();
|
||||||
|
Pair<DrawState, ByteBuffer> data = shadedBuilder.popNextBuffer();
|
||||||
|
return new ShadeSeparatedBufferedData.NativeImpl(data.getSecond(), data.getFirst(), unshadedStartVertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShadeSeparatedBufferedData getBufferedData(Bufferable bufferable) {
|
||||||
ModelBlockRenderer blockRenderer = VANILLA_RENDERER.getModelRenderer();
|
ModelBlockRenderer blockRenderer = VANILLA_RENDERER.getModelRenderer();
|
||||||
ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get();
|
ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get();
|
||||||
|
|
||||||
objects.begin();
|
objects.begin();
|
||||||
|
|
||||||
bufferable.bufferInto(blockRenderer, objects.shadeSeparatingWrapper, objects.random);
|
bufferable.bufferInto(objects.shadeSeparatingWrapper, blockRenderer, objects.random);
|
||||||
|
|
||||||
objects.end();
|
return objects.end();
|
||||||
|
|
||||||
return objects.separatedBufferBuilder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShadeSeparatedBufferBuilder getBufferBuilder(BakedModel model, BlockState referenceState, PoseStack poseStack) {
|
public static ShadeSeparatedBufferedData getBufferedData(BakedModel model, BlockState referenceState) {
|
||||||
|
return new BakedModelBuilder(model).withReferenceState(referenceState)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShadeSeparatedBufferedData getBufferedData(BakedModel model, BlockState referenceState, PoseStack poseStack) {
|
||||||
return new BakedModelBuilder(model).withReferenceState(referenceState)
|
return new BakedModelBuilder(model).withReferenceState(referenceState)
|
||||||
.withPoseStack(poseStack)
|
.withPoseStack(poseStack)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShadeSeparatedBufferBuilder getBufferBuilder(BlockAndTintGetter renderWorld, BakedModel model, BlockState referenceState, PoseStack poseStack) {
|
public static ShadeSeparatedBufferedData getBufferedData(BlockAndTintGetter renderWorld, BakedModel model, BlockState referenceState, PoseStack poseStack) {
|
||||||
return new BakedModelBuilder(model).withReferenceState(referenceState)
|
return new BakedModelBuilder(model).withReferenceState(referenceState)
|
||||||
.withPoseStack(poseStack)
|
.withPoseStack(poseStack)
|
||||||
.withRenderWorld(renderWorld)
|
.withRenderWorld(renderWorld)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShadeSeparatedBufferBuilder getBufferBuilderFromTemplate(BlockAndTintGetter renderWorld, RenderType layer, Collection<StructureTemplate.StructureBlockInfo> blocks) {
|
public static ShadeSeparatedBufferedData getBufferedDataFromTemplate(BlockAndTintGetter renderWorld, RenderType layer, Collection<StructureTemplate.StructureBlockInfo> blocks) {
|
||||||
return new WorldModelBuilder(layer).withRenderWorld(renderWorld)
|
return new WorldModelBuilder(layer).withRenderWorld(renderWorld)
|
||||||
.withBlocks(blocks)
|
.withBlocks(blocks)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShadeSeparatedBufferBuilder getBufferBuilderFromTemplate(BlockAndTintGetter renderWorld, RenderType layer, Collection<StructureTemplate.StructureBlockInfo> blocks, PoseStack poseStack) {
|
public static ShadeSeparatedBufferedData getBufferedDataFromTemplate(BlockAndTintGetter renderWorld, RenderType layer, Collection<StructureTemplate.StructureBlockInfo> blocks, PoseStack poseStack) {
|
||||||
return new WorldModelBuilder(layer).withRenderWorld(renderWorld)
|
return new WorldModelBuilder(layer).withRenderWorld(renderWorld)
|
||||||
.withBlocks(blocks)
|
.withBlocks(blocks)
|
||||||
.withPoseStack(poseStack)
|
.withPoseStack(poseStack)
|
||||||
|
@ -101,20 +118,18 @@ public class ModelUtil {
|
||||||
private static class ThreadLocalObjects {
|
private static class ThreadLocalObjects {
|
||||||
public final Random random = new Random();
|
public final Random random = new Random();
|
||||||
public final ShadeSeparatingVertexConsumer shadeSeparatingWrapper = new ShadeSeparatingVertexConsumer();
|
public final ShadeSeparatingVertexConsumer shadeSeparatingWrapper = new ShadeSeparatingVertexConsumer();
|
||||||
public final ShadeSeparatedBufferBuilder separatedBufferBuilder = new ShadeSeparatedBufferBuilder(512);
|
public final BufferBuilder shadedBuilder = new BufferBuilder(512);
|
||||||
public final BufferBuilder unshadedBuilder = new BufferBuilder(512);
|
public final BufferBuilder unshadedBuilder = new BufferBuilder(512);
|
||||||
|
|
||||||
private void begin() {
|
private void begin() {
|
||||||
this.separatedBufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
|
this.shadedBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
|
||||||
this.unshadedBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
|
this.unshadedBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
|
||||||
this.shadeSeparatingWrapper.prepare(this.separatedBufferBuilder, this.unshadedBuilder);
|
this.shadeSeparatingWrapper.prepare(this.shadedBuilder, this.unshadedBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void end() {
|
private ShadeSeparatedBufferedData end() {
|
||||||
this.shadeSeparatingWrapper.clear();
|
this.shadeSeparatingWrapper.clear();
|
||||||
this.unshadedBuilder.end();
|
return ModelUtil.endAndCombine(shadedBuilder, unshadedBuilder);
|
||||||
this.separatedBufferBuilder.appendUnshadedVertices(this.unshadedBuilder);
|
|
||||||
this.separatedBufferBuilder.end();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<DrawState, ByteBuffer> data = unshadedBuilder.popNextBuffer();
|
|
||||||
unshadedStartVertex = ((BufferBuilderExtension) this).flywheel$getVertices();
|
|
||||||
((BufferBuilderExtension) this).flywheel$appendBufferUnsafe(data.getSecond());
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getUnshadedStartVertex() {
|
|
||||||
return unshadedStartVertex;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
package com.jozufozu.flywheel.core.model;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.util.FlwUtil;
|
||||||
|
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||||
|
import com.mojang.blaze3d.vertex.BufferBuilder.DrawState;
|
||||||
|
|
||||||
|
public interface ShadeSeparatedBufferedData {
|
||||||
|
ByteBuffer vertexBuffer();
|
||||||
|
|
||||||
|
BufferBuilder.DrawState drawState();
|
||||||
|
|
||||||
|
int unshadedStartVertex();
|
||||||
|
|
||||||
|
void release();
|
||||||
|
|
||||||
|
static final class NativeImpl implements ShadeSeparatedBufferedData {
|
||||||
|
private final ByteBuffer vertexBuffer;
|
||||||
|
private final BufferBuilder.DrawState drawState;
|
||||||
|
private final int unshadedStartVertex;
|
||||||
|
|
||||||
|
public NativeImpl(ByteBuffer vertexBuffer, BufferBuilder.DrawState drawState, int unshadedStartVertex) {
|
||||||
|
this.vertexBuffer = FlwUtil.copyBuffer(vertexBuffer);
|
||||||
|
this.drawState = drawState;
|
||||||
|
this.unshadedStartVertex = unshadedStartVertex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteBuffer vertexBuffer() {
|
||||||
|
return vertexBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DrawState drawState() {
|
||||||
|
return drawState;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int unshadedStartVertex() {
|
||||||
|
return unshadedStartVertex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void release() {
|
||||||
|
MemoryUtil.memFree(vertexBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,7 +35,7 @@ public final class WorldModelBuilder implements Bufferable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bufferInto(ModelBlockRenderer modelRenderer, VertexConsumer consumer, Random random) {
|
public void bufferInto(VertexConsumer consumer, ModelBlockRenderer modelRenderer, Random random) {
|
||||||
ForgeHooksClient.setRenderType(this.layer);
|
ForgeHooksClient.setRenderType(this.layer);
|
||||||
ModelBlockRenderer.enableCaching();
|
ModelBlockRenderer.enableCaching();
|
||||||
for (StructureTemplate.StructureBlockInfo info : this.blocks) {
|
for (StructureTemplate.StructureBlockInfo info : this.blocks) {
|
||||||
|
@ -80,7 +80,7 @@ public final class WorldModelBuilder implements Bufferable {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BlockModel intoMesh(String name) {
|
public BlockModel toModel(String name) {
|
||||||
return new BlockModel(this, name);
|
return BlockModel.of(this, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,39 +1,31 @@
|
||||||
package com.jozufozu.flywheel.core.vertex;
|
package com.jozufozu.flywheel.core.vertex;
|
||||||
|
|
||||||
import java.nio.Buffer;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.vertex.VertexList;
|
import com.jozufozu.flywheel.api.vertex.VertexList;
|
||||||
import com.mojang.blaze3d.platform.MemoryTracker;
|
import com.jozufozu.flywheel.util.FlwUtil;
|
||||||
|
|
||||||
public abstract class AbstractVertexList implements VertexList, AutoCloseable {
|
public abstract class AbstractVertexList implements VertexList {
|
||||||
|
|
||||||
protected final ByteBuffer contents;
|
protected final ByteBuffer contents;
|
||||||
protected final long base;
|
protected final long base;
|
||||||
protected final int vertexCount;
|
protected final int vertexCount;
|
||||||
|
|
||||||
protected AbstractVertexList(ByteBuffer copyFrom, int vertexCount) {
|
protected AbstractVertexList(ByteBuffer copyFrom, int vertexCount) {
|
||||||
this.contents = MemoryTracker.create(copyFrom.capacity());
|
this.contents = FlwUtil.copyBuffer(copyFrom);
|
||||||
this.vertexCount = vertexCount;
|
this.vertexCount = vertexCount;
|
||||||
this.base = MemoryUtil.memAddress(this.contents);
|
this.base = MemoryUtil.memAddress(this.contents);
|
||||||
init(copyFrom);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init(ByteBuffer copyFrom) {
|
|
||||||
this.contents.order(copyFrom.order());
|
|
||||||
this.contents.put(copyFrom);
|
|
||||||
((Buffer) this.contents).flip();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
MemoryUtil.memFree(contents);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getVertexCount() {
|
public int getVertexCount() {
|
||||||
return vertexCount;
|
return vertexCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete() {
|
||||||
|
MemoryUtil.memFree(contents);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,9 @@ package com.jozufozu.flywheel.core.vertex;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.vertex.VertexList;
|
|
||||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||||
import com.jozufozu.flywheel.core.layout.BufferLayout;
|
import com.jozufozu.flywheel.core.layout.BufferLayout;
|
||||||
import com.jozufozu.flywheel.core.layout.CommonItems;
|
import com.jozufozu.flywheel.core.layout.CommonItems;
|
||||||
import com.jozufozu.flywheel.core.model.ShadeSeparatedBufferBuilder;
|
|
||||||
import com.mojang.blaze3d.vertex.BufferBuilder;
|
|
||||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
|
||||||
import com.mojang.datafixers.util.Pair;
|
|
||||||
|
|
||||||
public class BlockVertex implements VertexType {
|
public class BlockVertex implements VertexType {
|
||||||
|
|
||||||
|
@ -37,6 +32,10 @@ public class BlockVertex implements VertexType {
|
||||||
return new BlockVertexListUnsafe(buffer, vertexCount);
|
return new BlockVertexListUnsafe(buffer, vertexCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BlockVertexListUnsafe.Shaded createReader(ByteBuffer buffer, int vertexCount, int unshadedStartVertex) {
|
||||||
|
return new BlockVertexListUnsafe.Shaded(buffer, vertexCount, unshadedStartVertex);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getShaderHeader() {
|
public String getShaderHeader() {
|
||||||
return """
|
return """
|
||||||
|
@ -57,24 +56,4 @@ Vertex FLWCreateVertex() {
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
}
|
}
|
||||||
|
|
||||||
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<BufferBuilder.DrawState, ByteBuffer> 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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
package com.jozufozu.flywheel.util;
|
package com.jozufozu.flywheel.util;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.mixin.BlockEntityRenderDispatcherAccessor;
|
import com.jozufozu.flywheel.mixin.BlockEntityRenderDispatcherAccessor;
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
@ -73,4 +76,17 @@ public class FlwUtil {
|
||||||
public static <R> Stream<R> mapValues(Map<?, R> map) {
|
public static <R> Stream<R> mapValues(Map<?, R> map) {
|
||||||
return map.values().stream();
|
return map.values().stream();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The returned buffer is backed by native memory and will cause a memory leak if not freed using {@link MemoryUtil#memFree(java.nio.Buffer)}.
|
||||||
|
*/
|
||||||
|
public static ByteBuffer copyBuffer(ByteBuffer buffer) {
|
||||||
|
int pos = buffer.position();
|
||||||
|
ByteBuffer copy = MemoryUtil.memAlloc(buffer.remaining());
|
||||||
|
copy.order(buffer.order());
|
||||||
|
copy.put(buffer);
|
||||||
|
buffer.position(pos);
|
||||||
|
copy.flip();
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue