Parse raw buffer instead of intercepting all BufferBuilder calls

This commit is contained in:
Jonas Herzig
2018-03-04 12:02:30 +01:00
parent 1bdf7da525
commit 40da0d10c8
2 changed files with 117 additions and 211 deletions

View File

@@ -6,6 +6,7 @@ import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.renderer.vertex.VertexFormatElement;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.vector.ReadableVector3f;
import org.lwjgl.util.vector.Vector2f;
import org.lwjgl.util.vector.Vector3f;
@@ -16,8 +17,6 @@ import net.minecraft.client.renderer.BufferBuilder;
//#endif
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;
@@ -30,22 +29,14 @@ public class BlendMeshBuilder
//$$ extends WorldRenderer
//#endif
{
private static final ReadableVector3f VEC3F_ZERO = new Vector3f(0, 0, 0);
private final DMesh mesh;
private final List<DMesh.Vertex> vertices = new ArrayList<>();
private final List<Vector2f> uvs = new ArrayList<>();
private final List<Integer> colors = new ArrayList<>();
private Vector3f offset = new Vector3f(0, 0, 0);
private Vector3f offset;
private boolean isDrawing;
private boolean wellBehaved;
private int mode;
//#if MC>=11200
private double x, y, z;
//#endif
private float u, v;
private int color = 0xffffffff; // Default not in parent class but probably set implicitly somewhere due to re-use
public BlendMeshBuilder(DMesh mesh) {
super(0);
super(1024);
this.mesh = mesh;
}
@@ -68,23 +59,31 @@ public class BlendMeshBuilder
// Someone probably finished drawing with the global instance instead of this one,
// let's just assume that what's happened and finish our last draw by ourselves
// (might miss correct texture though)
doFinish();
super.finishDrawing();
addBufferToMesh();
} else {
throw new IllegalStateException("Already drawing!");
}
}
this.isDrawing = true;
this.mode = mode;
if (!wellBehaved) {
// In case the calling code finishes with Tessellator.getInstance().draw()
BufferBuilder_beginPosTexCol(mode);
}
//#if MC>=11200
super.begin(mode, vertexFormat);
//#else
//$$ super.startDrawing(mode);
//#endif
}
public void maybeFinishDrawing() {
if (isDrawing) {
doFinish();
isDrawing = false;
super.finishDrawing();
addBufferToMesh();
}
}
@@ -101,16 +100,106 @@ public class BlendMeshBuilder
getBuffer(Tessellator.getInstance()).finishDrawing();
}
doFinish();
//#if MC<11200
//$$ return -1;
//$$ int ret =
//#endif
super.finishDrawing();
addBufferToMesh();
//#if MC<11200
//$$ return ret;
//#endif
}
}
private void doFinish() {
this.isDrawing = false;
private void addBufferToMesh() {
addBufferToMesh(this, mesh, offset);
}
//#if MC>=11200
public static DMesh addBufferToMesh(BufferBuilder bufferBuilder, DMesh mesh, ReadableVector3f vertOffset) {
//#else
//$$ public static DMesh addBufferToMesh(WorldRenderer bufferBuilder, DMesh mesh, Vector3f vertOffset) {
//#endif
return addBufferToMesh(bufferBuilder.getByteBuffer(), bufferBuilder.getDrawMode(), bufferBuilder.getVertexFormat(), mesh, vertOffset);
}
public static DMesh addBufferToMesh(ByteBuffer buffer, int mode, VertexFormat vertexFormat, DMesh mesh, ReadableVector3f vertOffset) {
return addBufferToMesh(buffer, buffer.remaining() / vertexFormat.getNextOffset(), mode, vertexFormat, mesh, vertOffset);
}
public static DMesh addBufferToMesh(ByteBuffer buffer, int vertexCount, int mode, VertexFormat vertexFormat, DMesh mesh, ReadableVector3f vertOffset) {
if (mesh == null) {
mesh = new DMesh();
}
if (vertOffset == null) {
vertOffset = VEC3F_ZERO;
}
// Determine offset of vertex components
int posOffset = -1, colorOffset = -1, uvOffset = -1;
int index = 0;
for (VertexFormatElement element : vertexFormat.getElements()) {
//#if MC>11200
int offset = vertexFormat.getOffset(index);
//#else
//$$ int offset = element.getOffset();
//#endif
switch (element.getUsage()) {
case POSITION:
if (element.getType() != VertexFormatElement.EnumType.FLOAT) {
throw new UnsupportedOperationException("Only float is supported for position elements!");
}
posOffset = offset;
break;
case COLOR:
if (element.getType() != VertexFormatElement.EnumType.UBYTE) {
throw new UnsupportedOperationException("Only unsigned byte is supported for color elements!");
}
colorOffset = offset;
break;
case UV:
if (element.getIndex() != 0) break;
if (element.getType() != VertexFormatElement.EnumType.FLOAT) {
throw new UnsupportedOperationException("Only float is supported for UV elements!");
}
uvOffset = offset;
break;
}
index++;
}
if (posOffset == -1) throw new IllegalStateException("No position element in " + vertexFormat);
// Extract vertex components from byte buffer
List<DMesh.Vertex> vertices = new ArrayList<>(vertexCount);
List<Vector2f> uvs = new ArrayList<>(vertexCount);
List<Integer> colors = new ArrayList<>(vertexCount);
int step = vertexFormat.getNextOffset();
for (int offset = 0; offset < vertexCount * step; offset += step) {
vertices.add(new DMesh.Vertex(
buffer.getFloat(offset ) - vertOffset.getX(),
-buffer.getFloat(offset + 8) + vertOffset.getZ(),
buffer.getFloat(offset + 4) - vertOffset.getY()
));
if (colorOffset != -1) {
colors.add(buffer.getInt(offset + colorOffset));
} else {
colors.add(0xffffffff);
}
if (uvOffset != -1) {
uvs.add(new Vector2f(
buffer.getFloat(offset + uvOffset),
1 - buffer.getFloat(offset + uvOffset + 4)
));
} else {
uvs.add(new Vector2f(0, 0));
}
}
// Determine and store current material
DMaterial activeMaterial = BlendState.getState().getMaterials().getActiveMaterial();
int materialSlot = mesh.materials.indexOf(activeMaterial);
if (materialSlot < 0) {
@@ -118,6 +207,7 @@ public class BlendMeshBuilder
mesh.materials.add(activeMaterial);
}
// Bundle vertices into shapes and add them to the mesh
switch (mode) {
case GL11.GL_TRIANGLES:
for (int i = 0; i < vertices.size(); i+=3) {
@@ -157,148 +247,7 @@ public class BlendMeshBuilder
default:
throw new UnsupportedOperationException("Unsupported mode: " + mode);
}
return mesh;
}
//#if MC>=11200
// TODO these should all behave differently depending on the order in which they're called
// e.g. tex may be called multiple times, if there are multiple active texture units
@Override
public BlendMeshBuilder tex(double u, double v) {
this.u = (float) u;
this.v = (float) (1 - v);
return this;
}
@Override
public BufferBuilder lightmap(int p_187314_1_, int p_187314_2_) {
// TODO we probably do care about this
return this;
}
@Override
public BlendMeshBuilder color(int r, int g, int b, int a) {
this.color = r | (g << 8) | (b << 16) | (a << 24);
return this;
}
@Override
public BufferBuilder normal(float x, float y, float z) {
// TODO do we care about normals?
return this;
}
@Override
public BlendMeshBuilder pos(double x, double y, double z) {
this.x = x - offset.x;
this.y = y - offset.y;
this.z = z - offset.z;
return this;
}
@Override
public void endVertex() {
vertices.add(new DMesh.Vertex((float) x, (float) -z, (float) y));
uvs.add(new Vector2f(u, v));
colors.add(color);
}
//#else
//$$ @Override
//$$ public void setTextureUV(double u, double v) {
//$$ this.u = (float) u;
//$$ this.v = (float) (1 - v);
//$$ }
//$$
//$$ @Override
//$$ public void setColorRGBA(int r, int g, int b, int a) {
//$$ this.color = r | (g << 8) | (b << 16) | (a << 24);
//$$ }
//$$
//$$ @Override
//$$ public void addVertex(double x, double y, double z) {
//$$ x -= offset.x;
//$$ y -= offset.y;
//$$ z -= offset.z;
//$$ vertices.add(new DMesh.Vertex((float) x, (float) -z, (float) y));
//$$ uvs.add(new Vector2f(u, v));
//$$ colors.add(color);
//$$ }
//#endif
@Override
@SuppressWarnings("unchecked")
public void addVertexData(int[] ints) {
ByteBuffer buffer = ByteBuffer.allocate(ints.length * 4).order(ByteOrder.nativeOrder());
IntBuffer intBuffer = buffer.asIntBuffer();
intBuffer.put(ints);
VertexFormat vertexFormat = getVertexFormat();
int posOffset = -1, colorOffset = -1, uvOffset = -1;
List<VertexFormatElement> elements = vertexFormat.getElements();
int index = 0;
for (VertexFormatElement element : elements) {
//#if MC>11200
int offset = vertexFormat.getOffset(index);
//#else
//$$ int offset = element.getOffset();
//#endif
switch (element.getUsage()) {
case POSITION: posOffset = offset; break;
case COLOR: colorOffset = offset; break;
case UV: if (element.getIndex() == 0) uvOffset = offset; break;
}
index++;
}
if (posOffset == -1) throw new IllegalStateException("No position element in " + vertexFormat);
if (uvOffset == -1) throw new IllegalStateException("No uv element in " + vertexFormat);
for (int offset = 0; offset < buffer.remaining(); offset += vertexFormat.getNextOffset()) {
// TODO doesn't check buffer element types (works for vanilla because they're always the same)
if (colorOffset != -1) {
color = buffer.getInt(offset + colorOffset);
}
//#if MC>11200
tex(
//#else
//$$ setTextureUV(
//#endif
buffer.getFloat(offset + uvOffset),
buffer.getFloat(offset + uvOffset + 4)
);
//#if MC>11200
pos(
//#else
//$$ addVertex(
//#endif
buffer.getFloat(offset + posOffset ),
buffer.getFloat(offset + posOffset + 4),
buffer.getFloat(offset + posOffset + 8)
);
//#if MC>11200
endVertex();
//#endif
}
}
@Override
public int getVertexCount() {
return vertices.size();
}
public void putColorRGBA(int byteIndex, int r, int g, int b, int a) {
int color = r | (g << 8) | (b << 16) | (a << 24);
putColor(color, -1); // FIXME: reverse index calculation
}
private void putColor(int color, int reverseIndex) {
colors.set(colors.size() - reverseIndex, color);
}
public void putColor4(int color) {
for (int i = 0; i < 4; i++) {
putColor(color, i + 1);
}
}
// FIXME overwrite putX and more
}