Instance triangles

This commit is contained in:
JozsefA 2021-05-30 22:16:03 -07:00
parent 3500b4ec87
commit 8fab6c4643
12 changed files with 275 additions and 194 deletions

View file

@ -30,7 +30,7 @@ public abstract class GlObject {
this.handle = INVALID_HANDLE;
}
public final void delete() {
public void delete() {
if (!isHandleValid()) {
throw new IllegalStateException("Handle already deleted.");
}

View file

@ -10,7 +10,7 @@ import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
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.core.BufferedModel;
import com.jozufozu.flywheel.core.model.BufferedModel;
import com.jozufozu.flywheel.util.AttribUtil;
public class Instancer<D extends InstanceData> {
@ -47,13 +47,13 @@ public class Instancer<D extends InstanceData> {
vao.bind();
// bind the model's vbo to our vao
model.bindBuffer();
model.getFormat().vertexAttribPointers(0);
model.unbindBuffer();
model.setupState();
AttribUtil.enableArrays(model.getAttributeCount() + instanceFormat.getAttributeCount());
// enable all the attribute arrays in our vao. we only need to do this once
AttribUtil.enableArrays(model.getAttributeCount() + this.instanceFormat.getAttributeCount());
vao.unbind();
model.clearState();
}
public void render() {

View file

@ -15,11 +15,13 @@ import com.google.common.cache.CacheBuilder;
import com.jozufozu.flywheel.backend.RenderWork;
import com.jozufozu.flywheel.backend.gl.GlPrimitive;
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
import com.jozufozu.flywheel.core.BufferedModel;
import com.jozufozu.flywheel.core.PartialModel;
import com.jozufozu.flywheel.core.model.BufferedModel;
import com.jozufozu.flywheel.core.model.IndexedModel;
import com.jozufozu.flywheel.core.shader.IProgramCallback;
import com.jozufozu.flywheel.core.shader.WorldProgram;
import com.jozufozu.flywheel.util.BufferBuilderReader;
import com.jozufozu.flywheel.util.QuadConverter;
import com.jozufozu.flywheel.util.RenderUtil;
import com.jozufozu.flywheel.util.VirtualEmptyModelData;
import com.mojang.blaze3d.matrix.MatrixStack;
@ -128,25 +130,26 @@ public class RenderMaterial<P extends WorldProgram, D extends InstanceData> {
VertexFormat format = spec.getModelFormat();
int vertexCount = reader.getVertexCount();
ByteBuffer to = ByteBuffer.allocate(vertexCount * format.getStride());
to.order(ByteOrder.nativeOrder());
ByteBuffer vertices = ByteBuffer.allocate(vertexCount * format.getStride());
vertices.order(ByteOrder.nativeOrder());
for (int i = 0; i < vertexCount; i++) {
to.putFloat(reader.getX(i));
to.putFloat(reader.getY(i));
to.putFloat(reader.getZ(i));
vertices.putFloat(reader.getX(i));
vertices.putFloat(reader.getY(i));
vertices.putFloat(reader.getZ(i));
to.put(reader.getNX(i));
to.put(reader.getNY(i));
to.put(reader.getNZ(i));
vertices.put(reader.getNX(i));
vertices.put(reader.getNY(i));
vertices.put(reader.getNZ(i));
to.putFloat(reader.getU(i));
to.putFloat(reader.getV(i));
vertices.putFloat(reader.getU(i));
vertices.putFloat(reader.getV(i));
}
to.rewind();
vertices.rewind();
BufferedModel bufferedModel = new BufferedModel(GlPrimitive.QUADS, format, to, vertexCount);
BufferedModel bufferedModel = new IndexedModel(GlPrimitive.TRIANGLES, format, vertices, vertexCount, QuadConverter.getInstance().getEboForNQuads(vertexCount / 4));
//BufferedModel bufferedModel = new BufferedModel(GlPrimitive.QUADS, format, vertices, vertexCount);
return new Instancer<>(bufferedModel, renderer, spec.getInstanceFormat(), spec.getInstanceFactory());
}

View file

@ -1,49 +0,0 @@
package com.jozufozu.flywheel.core;
import java.nio.ByteBuffer;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;
import com.jozufozu.flywheel.backend.gl.GlPrimitive;
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
import com.jozufozu.flywheel.util.AttribUtil;
public class BufferedArrayModel extends BufferedModel {
protected GlVertexArray vao;
public BufferedArrayModel(GlPrimitive primitiveMode, VertexFormat format, ByteBuffer data, int vertices) {
super(primitiveMode, format, data, vertices);
vao = new GlVertexArray();
vao.bind();
// bind the model's vbo to our vao
vbo.bind();
getFormat().vertexAttribPointers(0);
// enable all the attribute arrays in our vao. we only need to do this once
AttribUtil.enableArrays(getAttributeCount());
vbo.unbind();
vao.unbind();
}
public void draw() {
if (vertexCount <= 0 || deleted) return;
vao.bind();
GL20.glDrawArrays(GL11.GL_QUADS, 0, vertexCount);
vao.unbind();
}
@Override
public void delete() {
super.delete();
vao.delete();
}
}

View file

@ -1,69 +0,0 @@
package com.jozufozu.flywheel.core;
import java.nio.ByteBuffer;
import org.lwjgl.opengl.GL20;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.GlNumericType;
import com.jozufozu.flywheel.backend.gl.GlPrimitive;
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
import com.jozufozu.flywheel.util.AttribUtil;
public class IndexedModel extends BufferedModel {
protected int elementCount;
protected GlNumericType eboIndexType;
protected GlBuffer ebo;
public IndexedModel(GlPrimitive primitiveMode, VertexFormat modelFormat, ByteBuffer buf, int vertices, ByteBuffer indices, int elementCount, GlNumericType indexType) {
super(primitiveMode, modelFormat, buf, vertices);
this.ebo = new GlBuffer(GlBufferType.ELEMENT_ARRAY_BUFFER);
this.eboIndexType = indexType;
this.elementCount = elementCount;
int indicesSize = elementCount * indexType.getByteWidth();
ebo.bind();
ebo.alloc(indicesSize);
ebo.getBuffer(0, indicesSize)
.put(indices)
.flush();
ebo.unbind();
}
public void draw() {
ebo.bind();
vbo.bind();
AttribUtil.enableArrays(getAttributeCount());
format.vertexAttribPointers(0);
GL20.glDrawElements(primitiveMode.glEnum, elementCount, eboIndexType.getGlEnum(), 0);
AttribUtil.disableArrays(getAttributeCount());
ebo.unbind();
vbo.unbind();
}
@Override
public void drawInstances(int instanceCount) {
if (vertexCount <= 0 || deleted) return;
ebo.bind();
Backend.compat.drawInstanced.drawElementsInstanced(primitiveMode, 0, eboIndexType, 0, instanceCount);
ebo.unbind();
}
@Override
public void delete() {
super.delete();
ebo.delete();
}
}

View file

@ -0,0 +1,28 @@
package com.jozufozu.flywheel.core.model;
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
public class ArrayModelRenderer extends ModelRenderer {
protected GlVertexArray vao;
public ArrayModelRenderer(BufferedModel model) {
super(model);
vao = new GlVertexArray();
vao.bind();
model.setupState();
vao.unbind();
model.clearState();
}
public void draw() {
if (!model.valid()) return;
vao.bind();
model.drawCall();
vao.unbind();
}
}

View file

@ -1,4 +1,4 @@
package com.jozufozu.flywheel.core;
package com.jozufozu.flywheel.core.model;
import static org.lwjgl.opengl.GL20.glDrawArrays;
@ -55,29 +55,33 @@ public class BufferedModel {
vbo.unbind();
}
public boolean valid() {
return vertexCount > 0 && !deleted;
}
/**
* Renders this model, checking first if there is anything to render.
* The VBO/VAO should be bound externally.
*/
public void draw() {
if (vertexCount <= 0 || deleted) return;
public void setupState() {
vbo.bind();
AttribUtil.enableArrays(getAttributeCount());
format.vertexAttribPointers(0);
}
glDrawArrays(primitiveMode.glEnum, 0, vertexCount);
public void clearState() {
AttribUtil.disableArrays(getAttributeCount());
vbo.unbind();
}
public void drawCall() {
glDrawArrays(primitiveMode.glEnum, 0, vertexCount);
}
/**
* Draws many instances of this model, assuming the appropriate state is already bound.
*/
public void drawInstances(int instanceCount) {
if (vertexCount <= 0 || deleted) return;
if (!valid()) return;
Backend.compat.drawInstanced.drawArraysInstanced(primitiveMode, 0, vertexCount, instanceCount);
}

View file

@ -0,0 +1,30 @@
package com.jozufozu.flywheel.core.model;
import java.nio.ByteBuffer;
import com.jozufozu.flywheel.backend.gl.GlNumericType;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
public class ElementBuffer extends GlBuffer {
public final int elementCount;
public final GlNumericType eboIndexType;
public ElementBuffer(ByteBuffer indices, int elementCount, GlNumericType indexType) {
super(GlBufferType.ELEMENT_ARRAY_BUFFER);
this.eboIndexType = indexType;
this.elementCount = elementCount;
int indicesSize = elementCount * indexType.getByteWidth();
bind();
alloc(indicesSize);
getBuffer(0, indicesSize)
.put(indices)
.flush();
unbind();
}
}

View file

@ -0,0 +1,50 @@
package com.jozufozu.flywheel.core.model;
import java.nio.ByteBuffer;
import org.lwjgl.opengl.GL20;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.GlPrimitive;
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
public class IndexedModel extends BufferedModel {
protected ElementBuffer ebo;
public IndexedModel(GlPrimitive primitiveMode, VertexFormat modelFormat, ByteBuffer buf, int vertices, ElementBuffer ebo) {
super(primitiveMode, modelFormat, buf, vertices);
this.ebo = ebo;
}
@Override
public void setupState() {
super.setupState();
ebo.bind();
}
@Override
public void clearState() {
super.clearState();
ebo.unbind();
}
@Override
public void drawCall() {
GL20.glDrawElements(primitiveMode.glEnum, ebo.elementCount, ebo.eboIndexType.getGlEnum(), 0);
}
@Override
public void drawInstances(int instanceCount) {
if (vertexCount <= 0 || deleted) return;
Backend.compat.drawInstanced.drawElementsInstanced(primitiveMode, ebo.elementCount, ebo.eboIndexType, 0, instanceCount);
}
@Override
public void delete() {
super.delete();
ebo.delete();
}
}

View file

@ -0,0 +1,25 @@
package com.jozufozu.flywheel.core.model;
public class ModelRenderer {
protected BufferedModel model;
public ModelRenderer(BufferedModel model) {
this.model = model;
}
/**
* Renders this model, checking first if there is anything to render.
*/
public void draw() {
if (!model.valid()) return;
model.setupState();
model.drawCall();
model.clearState();
}
public void delete() {
model.delete();
}
}

View file

@ -0,0 +1,88 @@
package com.jozufozu.flywheel.util;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import com.jozufozu.flywheel.backend.gl.GlNumericType;
import com.jozufozu.flywheel.core.model.ElementBuffer;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minecraft.util.math.MathHelper;
public class QuadConverter {
private static QuadConverter INSTANCE = new QuadConverter();
public static QuadConverter getInstance() {
return INSTANCE;
}
private final Int2ObjectMap<CachedEbo> quads2Tris;
public QuadConverter() {
quads2Tris = new Int2ObjectOpenHashMap<>();
}
public ElementBuffer getEboForNQuads(int quads) {
quads2Tris.values().removeIf(CachedEbo::noReferences);
CachedEbo ebo = quads2Tris.computeIfAbsent(quads, quadCount -> {
int triangleCount = quadCount * 2;
int indexCount = triangleCount * 3;
GlNumericType type;
int bitWidth = MathHelper.log2(indexCount);
if (bitWidth <= 8) {
type = GlNumericType.UBYTE;
} else if (bitWidth <= 16) {
type = GlNumericType.USHORT;
} else {
type = GlNumericType.UINT;
}
ByteBuffer indices = ByteBuffer.allocate(indexCount * type.getByteWidth());
indices.order(ByteOrder.nativeOrder());
for (int i = 0; i < quadCount; i++) {
int qStart = 4 * i;
// triangle 1
type.castAndBuffer(indices, qStart);
type.castAndBuffer(indices, qStart + 1);
type.castAndBuffer(indices, qStart + 2);
// triangle 2
type.castAndBuffer(indices, qStart);
type.castAndBuffer(indices, qStart + 2);
type.castAndBuffer(indices, qStart + 3);
}
indices.flip();
return new CachedEbo(indices, indexCount, type);
});
ebo.refCount++;
return ebo;
}
private class CachedEbo extends ElementBuffer {
int refCount = 1;
public CachedEbo(ByteBuffer indices, int elementCount, GlNumericType indexType) {
super(indices, elementCount, indexType);
}
@Override
public void delete() {
refCount--;
if (refCount == 0)
super.delete();
}
public boolean noReferences() {
return refCount == 0;
}
}
}

View file

@ -10,15 +10,17 @@ import java.util.Map;
import javax.annotation.Nullable;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.GlNumericType;
import com.jozufozu.flywheel.backend.gl.GlPrimitive;
import com.jozufozu.flywheel.backend.gl.attrib.CommonAttributes;
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
import com.jozufozu.flywheel.backend.instancing.IInstanceRendered;
import com.jozufozu.flywheel.core.BufferedModel;
import com.jozufozu.flywheel.core.IndexedModel;
import com.jozufozu.flywheel.core.model.ArrayModelRenderer;
import com.jozufozu.flywheel.core.model.BufferedModel;
import com.jozufozu.flywheel.core.model.IndexedModel;
import com.jozufozu.flywheel.core.model.ModelRenderer;
import com.jozufozu.flywheel.light.GridAlignedBB;
import com.jozufozu.flywheel.util.BufferBuilderReader;
import com.jozufozu.flywheel.util.QuadConverter;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
@ -48,7 +50,7 @@ public class RenderedContraption extends ContraptionWorldHolder {
private final ContraptionLighter<?> lighter;
public final ContraptionKineticRenderer kinetics;
private final Map<RenderType, BufferedModel> renderLayers = new HashMap<>();
private final Map<RenderType, ModelRenderer> renderLayers = new HashMap<>();
private Matrix4f model;
private AxisAlignedBB lightBox;
@ -70,7 +72,7 @@ public class RenderedContraption extends ContraptionWorldHolder {
}
public void doRenderLayer(RenderType layer, ContraptionProgram shader) {
BufferedModel structure = renderLayers.get(layer);
ModelRenderer structure = renderLayers.get(layer);
if (structure != null) {
setup(shader);
structure.draw();
@ -111,7 +113,7 @@ public class RenderedContraption extends ContraptionWorldHolder {
}
void invalidate() {
for (BufferedModel buffer : renderLayers.values()) {
for (ModelRenderer buffer : renderLayers.values()) {
buffer.delete();
}
renderLayers.clear();
@ -122,7 +124,7 @@ public class RenderedContraption extends ContraptionWorldHolder {
}
private void buildLayers() {
for (BufferedModel buffer : renderLayers.values()) {
for (ModelRenderer buffer : renderLayers.values()) {
buffer.delete();
}
@ -132,7 +134,13 @@ public class RenderedContraption extends ContraptionWorldHolder {
for (RenderType layer : blockLayers) {
BufferedModel layerModel = buildStructureModel(renderWorld, contraption, layer);
if (layerModel != null) renderLayers.put(layer, layerModel);
if (layerModel != null) {
if (Backend.compat.vertexArrayObjectsSupported())
renderLayers.put(layer, new ArrayModelRenderer(layerModel));
else
renderLayers.put(layer, new ModelRenderer(layerModel));
}
}
}
@ -195,43 +203,6 @@ public class RenderedContraption extends ContraptionWorldHolder {
vertices.rewind();
//// if (Backend.compat.vertexArrayObjectsSupported())
//// return new BufferedArrayModel(GlPrimitive.QUADS, format, vertices, vertexCount);
//// else
// return new BufferedModel(GlPrimitive.QUADS, format, vertices, vertexCount);
int quadCount = vertexCount / 4;
int triangleCount = vertexCount / 2;
int indexCount = triangleCount * 3;
GlNumericType type;
int bitWidth = MathHelper.log2(indexCount);
if (bitWidth <= 8) {
type = GlNumericType.UBYTE;
} else if (bitWidth <= 16) {
type = GlNumericType.USHORT;
} else {
type = GlNumericType.UINT;
}
ByteBuffer indices = ByteBuffer.allocate(indexCount * type.getByteWidth());
indices.order(ByteOrder.nativeOrder());
for (int i = 0; i < quadCount; i++) {
int qStart = 4 * i;
// triangle 1
type.castAndBuffer(indices, qStart);
type.castAndBuffer(indices, qStart + 1);
type.castAndBuffer(indices, qStart + 2);
// triangle 2
type.castAndBuffer(indices, qStart);
type.castAndBuffer(indices, qStart + 2);
type.castAndBuffer(indices, qStart + 3);
}
indices.flip();
return new IndexedModel(GlPrimitive.TRIANGLES, format, vertices, vertexCount, indices, indexCount, type);
return new IndexedModel(GlPrimitive.TRIANGLES, format, vertices, vertexCount, QuadConverter.getInstance().getEboForNQuads(vertexCount / 4));
}
}