VertexArray - FoundryMC/Veil GitHub Wiki

Veil adds a better version of VertexBuffer from Minecraft called VertexArray. They can be created with VertexArray#create and destroyed with VertexArray#free.

Uploading Vertex Data

Vertex arrays support uploading vertex data from BufferBuilder#end by calling VertexArray#upload(MeshData, DrawUsage). However, unlike Minecraft vertex arrays can have multiple meshes uploaded at different locations by specifying the optional attributeStart parameter.

Example

// This initializes the data  
BufferBuilder builder = RenderSystem.renderThreadTesselator().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);  
// Build mesh  
builder.addVertex(0, 0, 0).setColor(-1);  
builder.addVertex(0, 1, 0).setColor(-1);  
builder.addVertex(1, 1, 0).setColor(-1);  
builder.addVertex(1, 0, 0).setColor(-1);  
  
VertexArray vertexArray = VertexArray.create();  
vertexArray.upload(builder.buildOrThrow(), VertexArray.DrawUsage.STATIC);  
  
// This goes inside a render loop  
{  
    // Make sure to bind  
    vertexArray.bind();  
    // Draw data  
    vertexArray.drawWithRenderType(RenderType.debugQuads());  
}  
  
// When not being used anymore, make sure to free it  
vertexArray.free();

Using Custom Vertex Buffers

Vertex arrays can reference any OpenGL buffers, but they also have the ability to "own" their own buffers. This is convenient if a buffer is only used once for the vertex array that owns it.

Defining Custom Vertex Attributes

Vertex attributes can be defined by calling VertexArray#editFormat and building the new format. Vanilla Minecraft VertexFormat attributes can also be applied at arbitrary locations using VertexArrayBuilder#applyFrom(bufferIndex, buffer, attributeStart, format).

  • buffer should contain the vertex data the format specifies.
  • attributeStart allows better control over how the format applies.
  • bufferIndex is an arbitrary index used to bind the vertex buffer to the vertex array.

Full Example

    VertexArray vertexArray = VertexArray.create();  
  
    // Arbitrary OpenGl buffers can be created  
    int defaultVbo = vertexArray.getOrCreateBuffer(VertexArray.VERTEX_BUFFER);  
    int extraVbo = vertexArray.getOrCreateBuffer(2);  
    int vanillaVbo = vertexArray.getOrCreateBuffer(3);  
  
    try (MemoryStack stack = MemoryStack.stackPush()) {  
        ByteBuffer vertexData = stack.malloc(Float.BYTES * 5 * 4);  
  
        // Put data in the buffer  
        vertexData.asFloatBuffer().put(new float[]{  
                0.0F, 0.0F, 0.0F, 0.0F, 0.0F,  
                0.0F, 1.0F, 0.0F, 0.0F, 1.0F,  
                1.0F, 1.0F, 0.0F, 1.0F, 0.0F,  
                1.0F, 0.0F, 0.0F, 0.0F, 1.0F  
        });  
  
        // Upload the data into the buffer  
        VertexArray.upload(defaultVbo, vertexData, VertexArray.DrawUsage.STATIC);  
  
        // Upload some extra data to another buffer  
        ByteBuffer extraData = stack.malloc(Integer.BYTES * 4);  
        extraData.asIntBuffer().put(new int[]{0xFFFFFFFF, 0xFFFF0000, 0xFF00FF00, 0xFF0000FF});  
        VertexArray.upload(extraVbo, extraData, VertexArray.DrawUsage.STATIC);  
  
        // Manually upload indices  
        vertexArray.uploadIndexBuffer(stack.bytes(  
                (byte) 0, (byte) 1, (byte) 2, (byte) 2, (byte) 3, (byte) 0  
        ));  
        vertexArray.setIndexCount(6, VertexArray.IndexType.BYTE);  
        vertexArray.setDrawMode(VertexFormat.Mode.TRIANGLES);  
  
        // 1.2.0+ equivalent  
        vertexArray.uploadIndexBuffer(stack.bytes(  
                (byte) 0, (byte) 1, (byte) 2, (byte) 2, (byte) 3, (byte) 0  
        ), VertexArray.IndexType.BYTE);  
    }  
  
    // Set up vertex format  
    VertexArrayBuilder builder = vertexArray.editFormat();  
  
    // 5 floats per vertex  
    builder.defineVertexBuffer(0, defaultVbo, 0, Float.BYTES * 5, 0);  
    // 1 integer per vertex  
    builder.defineVertexBuffer(1, extraVbo, 0, Integer.BYTES, 0);  
  
    // Position  
    builder.setVertexAttribute(0, 0, 3, VertexArrayBuilder.DataType.FLOAT, false, 0);  
    // UV  
    builder.setVertexAttribute(1, 0, 2, VertexArrayBuilder.DataType.FLOAT, false, Float.BYTES * 3);  
    // Color  
    builder.setVertexAttribute(2, 1, 4, VertexArrayBuilder.DataType.UNSIGNED_BYTE, false, 0);  
  
    // Defines the vertex data to be pulled from the specified buffer and how the vanilla attributes should be applied  
    builder.applyFrom(3, vanillaVbo, 2, DefaultVertexFormat.PARTICLE);  
  
    vertexArray.bind();  
    vertexArray.draw();  
  
    // You can also use a render type to draw  
    vertexArray.drawWithRenderType(RenderType.solid());  
  
    // Frees the vertex array and all owned verted buffers  
    vertexArray.free();

Notes

Vertex buffers can be changed at any time without having to fully re-initialize the vertex format by calling `VertexArrayBuilder#defineVertexBuffer.