mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-29 14:24:58 +01:00
Finish porting to 1.19 (mostly)
- Terrible, terrible mixins to ChunkRenderDispatcher and its subclasses - Index buffers may break chunk rendering sometimes, needs debugging
This commit is contained in:
parent
b5ea5f561e
commit
ae945f6ace
27 changed files with 349 additions and 240 deletions
|
@ -13,6 +13,17 @@ insert_final_newline = true
|
|||
[*.json]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
max_line_length = 500
|
||||
ij_json_keep_blank_lines_in_code = 0
|
||||
ij_json_keep_indents_on_empty_lines = false
|
||||
ij_json_keep_line_breaks = true
|
||||
ij_json_space_after_colon = true
|
||||
ij_json_space_after_comma = true
|
||||
ij_json_space_before_colon = true
|
||||
ij_json_space_before_comma = false
|
||||
ij_json_spaces_within_braces = true
|
||||
ij_json_spaces_within_brackets = false
|
||||
ij_json_wrap_long_lines = false
|
||||
|
||||
[*.java]
|
||||
indent_style = tab
|
||||
|
|
|
@ -39,7 +39,7 @@ public class MappedBuffer extends VecBuffer implements AutoCloseable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
public void close() {
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.jozufozu.flywheel.backend.instancing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -359,4 +360,14 @@ public abstract class InstanceManager<T> implements InstancingEngine.OriginShift
|
|||
LightUpdater.get(value.world).removeListener(value);
|
||||
}
|
||||
}
|
||||
|
||||
public void queueAddAll(Collection<? extends T> objects) {
|
||||
if (!Backend.isOn() || objects.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (queuedAdditions) {
|
||||
queuedAdditions.addAll(objects);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,14 +2,16 @@ package com.jozufozu.flywheel.backend.model;
|
|||
|
||||
import com.jozufozu.flywheel.backend.gl.GlNumericType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
||||
import com.mojang.blaze3d.vertex.VertexBuffer;
|
||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||
|
||||
public class ElementBuffer {
|
||||
|
||||
private final GlBuffer buffer;
|
||||
public final int elementCount;
|
||||
public final GlNumericType eboIndexType;
|
||||
public final VertexFormat.IndexType eboIndexType;
|
||||
|
||||
public ElementBuffer(GlBuffer backing, int elementCount, GlNumericType indexType) {
|
||||
public ElementBuffer(GlBuffer backing, int elementCount, VertexFormat.IndexType indexType) {
|
||||
this.buffer = backing;
|
||||
this.eboIndexType = indexType;
|
||||
this.elementCount = elementCount;
|
||||
|
|
|
@ -60,7 +60,7 @@ public class IndexedModel implements BufferedModel {
|
|||
@Override
|
||||
public void drawCall() {
|
||||
ebo.bind();
|
||||
GL20.glDrawElements(primitiveMode.glEnum, ebo.elementCount, ebo.eboIndexType.getGlEnum(), 0);
|
||||
GL20.glDrawElements(primitiveMode.glEnum, ebo.elementCount, ebo.eboIndexType.asGLType, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,7 +72,7 @@ public class IndexedModel implements BufferedModel {
|
|||
|
||||
ebo.bind();
|
||||
|
||||
GL31.glDrawElementsInstanced(primitiveMode.glEnum, ebo.elementCount, ebo.eboIndexType.getGlEnum(), 0, instanceCount);
|
||||
GL31.glDrawElementsInstanced(primitiveMode.glEnum, ebo.elementCount, ebo.eboIndexType.asGLType, 0, instanceCount);
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
|
|
|
@ -189,7 +189,7 @@ public class ModelPool implements ModelAllocator {
|
|||
|
||||
@Override
|
||||
public void drawCall() {
|
||||
GL32.glDrawElementsBaseVertex(GlPrimitive.TRIANGLES.glEnum, ebo.elementCount, ebo.eboIndexType.getGlEnum(), 0, first);
|
||||
GL32.glDrawElementsBaseVertex(GlPrimitive.TRIANGLES.glEnum, ebo.elementCount, ebo.eboIndexType.asGLType, 0, first);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -200,7 +200,7 @@ public class ModelPool implements ModelAllocator {
|
|||
|
||||
//Backend.log.info(StringUtil.args("drawElementsInstancedBaseVertex", GlPrimitive.TRIANGLES, ebo.elementCount, ebo.eboIndexType, 0, instanceCount, first));
|
||||
|
||||
GL32.glDrawElementsInstancedBaseVertex(GlPrimitive.TRIANGLES.glEnum, ebo.elementCount, ebo.eboIndexType.getGlEnum(), 0, instanceCount, first);
|
||||
GL32.glDrawElementsInstancedBaseVertex(GlPrimitive.TRIANGLES.glEnum, ebo.elementCount, ebo.eboIndexType.asGLType, 0, instanceCount, first);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -3,41 +3,30 @@ package com.jozufozu.flywheel.core;
|
|||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GlNumericType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedGlBuffer;
|
||||
import com.jozufozu.flywheel.backend.model.ElementBuffer;
|
||||
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
|
||||
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.eventbus.api.EventPriority;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||
|
||||
/**
|
||||
* A class to manage EBOs that index quads as triangles.
|
||||
*/
|
||||
@Mod.EventBusSubscriber(Dist.CLIENT)
|
||||
public class QuadConverter {
|
||||
|
||||
public static final int STARTING_CAPACITY = 42; // 255 / 6 = 42
|
||||
|
||||
private static QuadConverter INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@NotNull
|
||||
public static QuadConverter getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new QuadConverter(STARTING_CAPACITY);
|
||||
INSTANCE = new QuadConverter();
|
||||
}
|
||||
|
||||
return INSTANCE;
|
||||
|
@ -48,130 +37,80 @@ public class QuadConverter {
|
|||
return INSTANCE;
|
||||
}
|
||||
|
||||
Map<GlNumericType, GlBuffer> ebos;
|
||||
int[] capacities;
|
||||
private final MappedGlBuffer ebo;
|
||||
private int quadCapacity;
|
||||
|
||||
public QuadConverter(int initialCapacity) {
|
||||
this.ebos = new EnumMap<>(GlNumericType.class);
|
||||
initCapacities();
|
||||
|
||||
fillBuffer(initialCapacity);
|
||||
public QuadConverter() {
|
||||
this.ebo = new MappedGlBuffer(GlBufferType.ELEMENT_ARRAY_BUFFER);
|
||||
this.quadCapacity = 0;
|
||||
}
|
||||
|
||||
public ElementBuffer quads2Tris(int quads) {
|
||||
int indexCount = quads * 6;
|
||||
GlNumericType type = getSmallestIndexType(indexCount);
|
||||
|
||||
if (quads > getCapacity(type)) {
|
||||
fillBuffer(quads, indexCount, type);
|
||||
if (quads > quadCapacity) {
|
||||
ebo.bind();
|
||||
ebo.ensureCapacity((long) indexCount * GlNumericType.UINT.getByteWidth());
|
||||
|
||||
try (MappedBuffer map = ebo.getBuffer()) {
|
||||
ByteBuffer indices = map.unwrap();
|
||||
|
||||
fillBuffer(indices, quads);
|
||||
}
|
||||
ebo.unbind();
|
||||
|
||||
this.quadCapacity = quads;
|
||||
}
|
||||
|
||||
return new ElementBuffer(getBuffer(type), indexCount, type);
|
||||
}
|
||||
|
||||
private void initCapacities() {
|
||||
this.capacities = new int[GlNumericType.values().length];
|
||||
}
|
||||
|
||||
private int getCapacity(GlNumericType type) {
|
||||
return capacities[type.ordinal()];
|
||||
}
|
||||
|
||||
private void updateCapacity(GlNumericType type, int capacity) {
|
||||
if (getCapacity(type) < capacity) {
|
||||
capacities[type.ordinal()] = capacity;
|
||||
}
|
||||
return new ElementBuffer(ebo, indexCount, VertexFormat.IndexType.INT);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
ebos.values()
|
||||
.forEach(GlBuffer::delete);
|
||||
ebos.clear();
|
||||
initCapacities();
|
||||
ebo.delete();
|
||||
this.quadCapacity = 0;
|
||||
}
|
||||
|
||||
private void fillBuffer(int quads) {
|
||||
int indexCount = quads * 6;
|
||||
private void fillBuffer(ByteBuffer indices, int quads) {
|
||||
long addr = MemoryUtil.memAddress(indices);
|
||||
int numVertices = 4 * quads;
|
||||
int baseVertex = 0;
|
||||
while (baseVertex < numVertices) {
|
||||
// writeQuadIndices(indices, baseVertex);
|
||||
writeQuadIndicesUnsafe(addr, baseVertex);
|
||||
|
||||
fillBuffer(quads, indexCount, getSmallestIndexType(indexCount));
|
||||
}
|
||||
|
||||
private void fillBuffer(int quads, int indexCount, GlNumericType type) {
|
||||
MemoryStack stack = MemoryStack.stackPush();
|
||||
int bytes = indexCount * type.getByteWidth();
|
||||
|
||||
ByteBuffer indices;
|
||||
if (bytes > stack.getSize()) {
|
||||
indices = MemoryUtil.memAlloc(bytes); // not enough space on the preallocated stack
|
||||
} else {
|
||||
stack.push();
|
||||
indices = stack.malloc(bytes);
|
||||
baseVertex += 4;
|
||||
addr += 6 * 4;
|
||||
}
|
||||
|
||||
indices.order(ByteOrder.nativeOrder());
|
||||
|
||||
fillBuffer(indices, type, quads);
|
||||
|
||||
GlBuffer buffer = getBuffer(type);
|
||||
|
||||
buffer.bind();
|
||||
buffer.upload(indices);
|
||||
buffer.unbind();
|
||||
|
||||
if (bytes > stack.getSize()) {
|
||||
MemoryUtil.memFree(indices);
|
||||
} else {
|
||||
stack.pop();
|
||||
}
|
||||
|
||||
updateCapacity(type, quads);
|
||||
// ((Buffer) indices).flip();
|
||||
}
|
||||
|
||||
private void fillBuffer(ByteBuffer indices, GlNumericType type, int quads) {
|
||||
for (int i = 0, max = 4 * quads; i < max; i += 4) {
|
||||
// triangle a
|
||||
type.castAndBuffer(indices, i);
|
||||
type.castAndBuffer(indices, i + 1);
|
||||
type.castAndBuffer(indices, i + 2);
|
||||
// triangle b
|
||||
type.castAndBuffer(indices, i);
|
||||
type.castAndBuffer(indices, i + 2);
|
||||
type.castAndBuffer(indices, i + 3);
|
||||
}
|
||||
((Buffer) indices).flip();
|
||||
private void writeQuadIndices(ByteBuffer indices, int baseVertex) {
|
||||
// triangle a
|
||||
indices.putInt(baseVertex);
|
||||
indices.putInt(baseVertex + 1);
|
||||
indices.putInt(baseVertex + 2);
|
||||
// triangle b
|
||||
indices.putInt(baseVertex);
|
||||
indices.putInt(baseVertex + 2);
|
||||
indices.putInt(baseVertex + 3);
|
||||
}
|
||||
|
||||
private GlBuffer getBuffer(GlNumericType type) {
|
||||
return ebos.computeIfAbsent(type, $ -> new MappedGlBuffer(GlBufferType.ELEMENT_ARRAY_BUFFER));
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the needed number of indices, what is the smallest bit width type that can index everything? <br>
|
||||
*
|
||||
* <pre>
|
||||
* | indexCount | type |
|
||||
* |--------------|-------|
|
||||
* | [0, 255) | byte |
|
||||
* | [256, 65536) | short |
|
||||
* | [65537, ) | int |
|
||||
* </pre>
|
||||
*/
|
||||
private static GlNumericType getSmallestIndexType(int indexCount) {
|
||||
// indexCount = indexCount >>> 8;
|
||||
// if (indexCount == 0) {
|
||||
// return GlNumericType.UBYTE;
|
||||
// }
|
||||
// indexCount = indexCount >>> 8;
|
||||
// if (indexCount == 0) {
|
||||
// return GlNumericType.USHORT;
|
||||
// }
|
||||
|
||||
return GlNumericType.UINT;
|
||||
private void writeQuadIndicesUnsafe(long addr, int baseVertex) {
|
||||
// triangle a
|
||||
MemoryUtil.memPutInt(addr, baseVertex);
|
||||
MemoryUtil.memPutInt(addr + 4, baseVertex + 1);
|
||||
MemoryUtil.memPutInt(addr + 8, baseVertex + 2);
|
||||
// triangle b
|
||||
MemoryUtil.memPutInt(addr + 12, baseVertex);
|
||||
MemoryUtil.memPutInt(addr + 16, baseVertex + 2);
|
||||
MemoryUtil.memPutInt(addr + 20, baseVertex + 3);
|
||||
}
|
||||
|
||||
// make sure this gets reset first so it has a chance to repopulate
|
||||
@SubscribeEvent(priority = EventPriority.HIGHEST)
|
||||
public static void onRendererReload(ReloadRenderersEvent event) {
|
||||
if (INSTANCE != null) INSTANCE.delete();
|
||||
if (INSTANCE != null) {
|
||||
INSTANCE.delete();
|
||||
INSTANCE = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,9 @@ package com.jozufozu.flywheel.core.hardcoded;
|
|||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexList;
|
||||
import com.jozufozu.flywheel.backend.model.ElementBuffer;
|
||||
import com.jozufozu.flywheel.core.Formats;
|
||||
import com.jozufozu.flywheel.core.QuadConverter;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
import com.jozufozu.flywheel.core.vertex.PosTexNormalWriterUnsafe;
|
||||
import com.mojang.blaze3d.platform.MemoryTracker;
|
||||
|
@ -51,4 +53,10 @@ public class ModelPart implements Model {
|
|||
public VertexList getReader() {
|
||||
return reader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementBuffer createEBO() {
|
||||
return QuadConverter.getInstance()
|
||||
.quads2Tris(vertices / 4);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,25 @@
|
|||
package com.jozufozu.flywheel.core.model;
|
||||
|
||||
import java.lang.management.MemoryUsage;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexList;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.gl.GlNumericType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferUsage;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedGlBuffer;
|
||||
import com.jozufozu.flywheel.backend.model.ElementBuffer;
|
||||
import com.jozufozu.flywheel.core.Formats;
|
||||
import com.jozufozu.flywheel.core.QuadConverter;
|
||||
import com.mojang.blaze3d.platform.MemoryTracker;
|
||||
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexBuffer;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
|
@ -12,12 +29,12 @@ import net.minecraft.world.level.block.state.BlockState;
|
|||
* A model of a single block.
|
||||
*/
|
||||
public class BlockModel implements Model {
|
||||
private static final PoseStack IDENTITY = new PoseStack();
|
||||
|
||||
private final VertexList reader;
|
||||
|
||||
private final String name;
|
||||
|
||||
private final Supplier<ElementBuffer> eboSupplier;
|
||||
|
||||
public BlockModel(BlockState state) {
|
||||
this(Minecraft.getInstance()
|
||||
.getBlockRenderer()
|
||||
|
@ -25,12 +42,49 @@ public class BlockModel implements Model {
|
|||
}
|
||||
|
||||
public BlockModel(BakedModel model, BlockState referenceState) {
|
||||
this(model, referenceState, IDENTITY);
|
||||
this(new BakedModelBuilder(model).withReferenceState(referenceState), referenceState.toString());
|
||||
}
|
||||
|
||||
public BlockModel(BakedModel model, BlockState referenceState, PoseStack ms) {
|
||||
reader = Formats.BLOCK.createReader(ModelUtil.getBufferBuilder(model, referenceState, ms));
|
||||
name = referenceState.toString();
|
||||
this(new BakedModelBuilder(model).withReferenceState(referenceState)
|
||||
.withPoseStack(ms), referenceState.toString());
|
||||
}
|
||||
|
||||
public BlockModel(Bufferable bufferable, String name) {
|
||||
this(bufferable.build(), name);
|
||||
}
|
||||
|
||||
public BlockModel(ShadeSeparatedBufferBuilder buffer, String name) {
|
||||
this.name = name;
|
||||
|
||||
BufferBuilder.RenderedBuffer renderedBuffer = buffer.endOrDiscardIfEmpty();
|
||||
|
||||
if (renderedBuffer == null) {
|
||||
reader = null;
|
||||
eboSupplier = () -> null;
|
||||
return;
|
||||
}
|
||||
|
||||
BufferBuilder.DrawState drawState = renderedBuffer.drawState();
|
||||
|
||||
reader = Formats.BLOCK.createReader(renderedBuffer, buffer.getUnshadedStartVertex());
|
||||
|
||||
if (drawState.sequentialIndex()) {
|
||||
ByteBuffer src = renderedBuffer.indexBuffer();
|
||||
ByteBuffer indexBuffer = MemoryTracker.create(src.capacity());
|
||||
MemoryUtil.memCopy(src, indexBuffer);
|
||||
eboSupplier = () -> {
|
||||
|
||||
MappedGlBuffer vbo = new MappedGlBuffer(GlBufferType.ELEMENT_ARRAY_BUFFER, GlBufferUsage.STATIC_DRAW);
|
||||
|
||||
vbo.upload(indexBuffer);
|
||||
|
||||
return new ElementBuffer(vbo, drawState.indexCount(), drawState.indexType());
|
||||
};
|
||||
} else {
|
||||
eboSupplier = () -> QuadConverter.getInstance()
|
||||
.quads2Tris(vertexCount() / 4);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -47,4 +101,14 @@ public class BlockModel implements Model {
|
|||
public VertexList getReader() {
|
||||
return reader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementBuffer createEBO() {
|
||||
return eboSupplier.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexType getType() {
|
||||
return Formats.BLOCK;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,10 +56,7 @@ public interface Model {
|
|||
* </p>
|
||||
* @return an element buffer object indexing this model's vertices.
|
||||
*/
|
||||
default ElementBuffer createEBO() {
|
||||
return QuadConverter.getInstance()
|
||||
.quads2Tris(vertexCount() / 4);
|
||||
}
|
||||
ElementBuffer createEBO();
|
||||
|
||||
/**
|
||||
* The size in bytes that this model's data takes up.
|
||||
|
|
|
@ -14,9 +14,16 @@ public class ShadeSeparatedBufferBuilder extends BufferBuilder {
|
|||
}
|
||||
|
||||
public void appendUnshadedVertices(BufferBuilder unshadedBuilder) {
|
||||
Pair<DrawState, ByteBuffer> data = unshadedBuilder.popNextBuffer();
|
||||
RenderedBuffer renderedBuffer = unshadedBuilder.endOrDiscardIfEmpty();
|
||||
|
||||
if (renderedBuffer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Unshaded indices
|
||||
ByteBuffer buffer = renderedBuffer.vertexBuffer();
|
||||
unshadedStartVertex = ((BufferBuilderExtension) this).flywheel$getVertices();
|
||||
((BufferBuilderExtension) this).flywheel$appendBufferUnsafe(data.getSecond());
|
||||
((BufferBuilderExtension) this).flywheel$appendBufferUnsafe(buffer);
|
||||
}
|
||||
|
||||
public int getUnshadedStartVertex() {
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.model;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexList;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.core.Formats;
|
||||
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||
|
||||
public class WorldModel implements Model {
|
||||
|
||||
private final VertexList reader;
|
||||
private final String name;
|
||||
|
||||
public WorldModel(BufferBuilder bufferBuilder, String name) {
|
||||
this.reader = Formats.BLOCK.createReader(bufferBuilder);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexType getType() {
|
||||
return Formats.BLOCK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int vertexCount() {
|
||||
return reader.getVertexCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexList getReader() {
|
||||
return reader;
|
||||
}
|
||||
}
|
|
@ -77,7 +77,7 @@ public final class WorldModelBuilder implements Bufferable {
|
|||
return this;
|
||||
}
|
||||
|
||||
public WorldModel intoMesh(String name) {
|
||||
return new WorldModel(ModelUtil.getBufferBuilder(this), name);
|
||||
public BlockModel intoMesh(String name) {
|
||||
return new BlockModel(this, name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,15 +22,6 @@ public abstract class AbstractVertexList implements VertexList, AutoCloseable {
|
|||
init(copyFrom);
|
||||
}
|
||||
|
||||
public AbstractVertexList(BufferBuilder builder) {
|
||||
var pair = builder.popNextBuffer();
|
||||
ByteBuffer copyFrom = pair.getSecond();
|
||||
this.contents = MemoryTracker.create(copyFrom.capacity());
|
||||
this.vertexCount = pair.getFirst().vertexCount();
|
||||
this.base = MemoryUtil.memAddress(this.contents);
|
||||
init(copyFrom);
|
||||
}
|
||||
|
||||
private void init(ByteBuffer copyFrom) {
|
||||
this.contents.order(copyFrom.order());
|
||||
this.contents.put(copyFrom);
|
||||
|
|
|
@ -62,19 +62,20 @@ Vertex FLWCreateVertex() {
|
|||
return new BlockVertexListUnsafe.Shaded(buffer, vertexCount, unshadedStartVertex);
|
||||
}
|
||||
|
||||
public VertexList createReader(BufferBuilder bufferBuilder) {
|
||||
public VertexList createReader(BufferBuilder.RenderedBuffer renderedBuffer, int unshadedStartVertex) {
|
||||
|
||||
// TODO: try to avoid virtual model rendering
|
||||
Pair<BufferBuilder.DrawState, ByteBuffer> pair = bufferBuilder.popNextBuffer();
|
||||
BufferBuilder.DrawState drawState = pair.getFirst();
|
||||
BufferBuilder.DrawState drawState = renderedBuffer.drawState();
|
||||
|
||||
if (drawState.format() != DefaultVertexFormat.BLOCK) {
|
||||
throw new RuntimeException("Cannot use BufferBuilder with " + drawState.format());
|
||||
}
|
||||
ByteBuffer vertexBuffer = renderedBuffer.vertexBuffer();
|
||||
|
||||
if (bufferBuilder instanceof ShadeSeparatedBufferBuilder separated) {
|
||||
return createReader(pair.getSecond(), drawState.vertexCount(), separated.getUnshadedStartVertex());
|
||||
if (unshadedStartVertex > 0) {
|
||||
return createReader(vertexBuffer, drawState.vertexCount(), unshadedStartVertex);
|
||||
} else {
|
||||
return createReader(pair.getSecond(), drawState.vertexCount());
|
||||
return createReader(vertexBuffer, drawState.vertexCount());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.jozufozu.flywheel.core.vertex;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.ShadedVertexList;
|
||||
import com.jozufozu.flywheel.core.model.ShadeSeparatedBufferBuilder;
|
||||
import com.jozufozu.flywheel.util.RenderMath;
|
||||
|
@ -9,10 +11,9 @@ public class BlockVertexList extends AbstractVertexList {
|
|||
|
||||
private final int stride;
|
||||
|
||||
public BlockVertexList(BufferBuilder builder) {
|
||||
super(builder);
|
||||
this.stride = builder.getVertexFormat()
|
||||
.getVertexSize();
|
||||
public BlockVertexList(ByteBuffer copyFrom, int vertexCount, int stride) {
|
||||
super(copyFrom, vertexCount);
|
||||
this.stride = stride;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -93,9 +94,9 @@ public class BlockVertexList extends AbstractVertexList {
|
|||
|
||||
private final int unshadedStartVertex;
|
||||
|
||||
public Shaded(ShadeSeparatedBufferBuilder builder) {
|
||||
super(builder);
|
||||
unshadedStartVertex = builder.getUnshadedStartVertex();
|
||||
public Shaded(ByteBuffer copyFrom, int vertexCount, int stride, int unshadedStartVertex) {
|
||||
super(copyFrom, vertexCount, stride);
|
||||
this.unshadedStartVertex = unshadedStartVertex;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -10,6 +10,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||
|
||||
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
||||
import com.mojang.blaze3d.vertex.BufferUploader;
|
||||
import com.mojang.blaze3d.vertex.VertexBuffer;
|
||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||
|
||||
@Mixin(BufferUploader.class)
|
||||
|
@ -17,13 +18,13 @@ public class BufferUploaderMixin {
|
|||
|
||||
@Shadow
|
||||
@Nullable
|
||||
private static VertexFormat lastFormat;
|
||||
private static VertexBuffer lastImmediateBuffer;
|
||||
|
||||
@Inject(method = "reset", at = @At("HEAD"))
|
||||
private static void stopBufferUploaderFromClearingBufferStateIfNothingIsBound(CallbackInfo ci) {
|
||||
// Trust our tracker over BufferUploader's.
|
||||
if (GlStateTracker.getVertexArray() == 0) {
|
||||
lastFormat = null;
|
||||
lastImmediateBuffer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
package com.jozufozu.flywheel.mixin;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry;
|
||||
|
||||
import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
@Mixin(targets = "net.minecraft.client.renderer.chunk.ChunkRenderDispatcher$RenderChunk$RebuildTask")
|
||||
public class ChunkRebuildHooksMixin {
|
||||
|
||||
@Inject(method = "handleBlockEntity", at = @At("HEAD"), cancellable = true)
|
||||
private <E extends BlockEntity> void addAndFilterBEs(ChunkRenderDispatcher.CompiledChunk compiledChunk, Set<BlockEntity> set, E be, CallbackInfo ci) {
|
||||
if (Backend.canUseInstancing(be.getLevel())) {
|
||||
if (InstancedRenderRegistry.canInstance(be.getType()))
|
||||
InstancedRenderDispatcher.getBlockEntities(be.getLevel()).queueAdd(be);
|
||||
|
||||
if (InstancedRenderRegistry.shouldSkipRender(be))
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package com.jozufozu.flywheel.mixin.instancemanage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry;
|
||||
import com.jozufozu.flywheel.util.RenderChunkExtension;
|
||||
|
||||
import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher;
|
||||
import net.minecraft.client.renderer.chunk.RenderChunkRegion;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
@Mixin(targets = "net.minecraft.client.renderer.chunk.ChunkRenderDispatcher$RenderChunk$RebuildTask")
|
||||
public abstract class ChunkRebuildHooksMixin {
|
||||
@Unique
|
||||
private Level flywheel$level;
|
||||
|
||||
@Inject(method = "<init>(Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk;Lnet/minecraft/world/level/ChunkPos;DLnet/minecraft/client/renderer/chunk/RenderChunkRegion;Z)V", at = @At("RETURN"))
|
||||
private void setLevel(ChunkRenderDispatcher.RenderChunk this$1, ChunkPos pos, double p_194427_, RenderChunkRegion region, boolean p_194429_, CallbackInfo ci) {
|
||||
flywheel$level = ((RenderChunkExtension) this$1).flywheel$getLevel();
|
||||
}
|
||||
|
||||
@Redirect(method = "doTask", at = @At(value = "INVOKE", target = "Ljava/util/List;addAll(Ljava/util/Collection;)Z"))
|
||||
private <E extends BlockEntity> boolean addAndFilterBEs(List<BlockEntity> self, Collection<? extends E> es) {
|
||||
if (!Backend.canUseInstancing(flywheel$level)) {
|
||||
return self.addAll(es);
|
||||
}
|
||||
|
||||
boolean added = false;
|
||||
var instanced = new ArrayList<BlockEntity>();
|
||||
for (E be : es) {
|
||||
if (InstancedRenderRegistry.canInstance(be.getType())) {
|
||||
instanced.add(be);
|
||||
}
|
||||
|
||||
if (!InstancedRenderRegistry.shouldSkipRender(be)) {
|
||||
self.add(be);
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
InstancedRenderDispatcher.getBlockEntities(flywheel$level).queueAddAll(instanced);
|
||||
return added;
|
||||
}
|
||||
|
||||
@Redirect(method = "doTask", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk;updateGlobalBlockEntities(Ljava/util/Collection;)V"))
|
||||
private void addAndFilterBEs(ChunkRenderDispatcher.RenderChunk self, Collection<BlockEntity> bes) {
|
||||
if (!Backend.canUseInstancing(flywheel$level)) {
|
||||
((RenderChunkAccessor) self).flywheel$updateGlobalBlockEntities(bes);
|
||||
return;
|
||||
}
|
||||
|
||||
var global = new ArrayList<BlockEntity>();
|
||||
var instanced = new ArrayList<BlockEntity>();
|
||||
for (BlockEntity be : bes) {
|
||||
if (InstancedRenderRegistry.canInstance(be.getType())) {
|
||||
instanced.add(be);
|
||||
}
|
||||
|
||||
if (!InstancedRenderRegistry.shouldSkipRender(be)) {
|
||||
global.add(be);
|
||||
}
|
||||
}
|
||||
|
||||
InstancedRenderDispatcher.getBlockEntities(flywheel$level).queueAddAll(instanced);
|
||||
((RenderChunkAccessor) self).flywheel$updateGlobalBlockEntities(global);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.jozufozu.flywheel.mixin.instancemanage;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher;
|
||||
|
||||
@Mixin(ChunkRenderDispatcher.class)
|
||||
public interface ChunkRenderDispatcherAccessor {
|
||||
|
||||
@Accessor
|
||||
ClientLevel getLevel();
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.mixin;
|
||||
package com.jozufozu.flywheel.mixin.instancemanage;
|
||||
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.mixin;
|
||||
package com.jozufozu.flywheel.mixin.instancemanage;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.jozufozu.flywheel.mixin.instancemanage;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
|
||||
/**
|
||||
* For use in {@link ChunkRebuildHooksMixin#addAndFilterBEs(ChunkRenderDispatcher.RenderChunk, Collection)}
|
||||
*/
|
||||
@Mixin(ChunkRenderDispatcher.RenderChunk.class)
|
||||
public interface RenderChunkAccessor {
|
||||
|
||||
@Invoker("updateGlobalBlockEntities")
|
||||
void flywheel$updateGlobalBlockEntities(Collection<BlockEntity> blockEntities);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package com.jozufozu.flywheel.mixin.instancemanage;
|
||||
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher;
|
||||
|
||||
@Mixin(ChunkRenderDispatcher.RenderChunk.class)
|
||||
public class RenderChunkMixin implements com.jozufozu.flywheel.util.RenderChunkExtension {
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private ChunkRenderDispatcher this$0;
|
||||
|
||||
@Override
|
||||
public ClientLevel flywheel$getLevel() {
|
||||
return ((ChunkRenderDispatcherAccessor) this$0).getLevel();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.jozufozu.flywheel.util;
|
||||
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
|
||||
public interface RenderChunkExtension {
|
||||
ClientLevel flywheel$getLevel();
|
||||
}
|
|
@ -17,13 +17,13 @@ A modern engine for modded minecraft.'''
|
|||
[[dependencies.flywheel]]
|
||||
modId = "forge"
|
||||
mandatory = true
|
||||
versionRange = "[40.0.0,)"
|
||||
versionRange = "[41.0.0,)"
|
||||
ordering = "NONE"
|
||||
side = "CLIENT"
|
||||
|
||||
[[dependencies.flywheel]]
|
||||
modId = "minecraft"
|
||||
mandatory = true
|
||||
versionRange = "[1.18.2,1.19)"
|
||||
versionRange = "[1.19,1.20)"
|
||||
ordering = "NONE"
|
||||
side = "CLIENT"
|
||||
|
|
|
@ -10,17 +10,20 @@
|
|||
"BufferBuilderMixin",
|
||||
"BufferUploaderMixin",
|
||||
"CameraMixin",
|
||||
"instancemanage.ChunkRebuildHooksMixin",
|
||||
"instancemanage.ChunkRenderDispatcherAccessor",
|
||||
"ClientLevelMixin",
|
||||
"ChunkRebuildHooksMixin",
|
||||
"EntityTypeMixin",
|
||||
"FixFabulousDepthMixin",
|
||||
"FrustumMixin",
|
||||
"GlStateManagerMixin",
|
||||
"InstanceAddMixin",
|
||||
"InstanceRemoveMixin",
|
||||
"instancemanage.InstanceAddMixin",
|
||||
"instancemanage.InstanceRemoveMixin",
|
||||
"LevelRendererAccessor",
|
||||
"LevelRendererMixin",
|
||||
"PausedPartialTickAccessor",
|
||||
"instancemanage.RenderChunkAccessor",
|
||||
"instancemanage.RenderChunkMixin",
|
||||
"RenderTexturesMixin",
|
||||
"RenderTypeMixin",
|
||||
"atlas.AtlasDataMixin",
|
||||
|
|
Loading…
Reference in a new issue