Your own geometry

gpu is client.gpu() — script-owned vertex formats, meshes, pipelines and draw calls. Vertex positions are relative to the camera, the buffers are freed while the script is off, and every type on this page is API 2.

val format = gpu.format(VertexAttribute.floats(3), VertexAttribute.color())
val mesh = gpu.indexedMesh(format)
val pipeline = gpu.pipeline(myShader, DrawMode.TRIANGLES, BlendMode.ALPHA, DepthMode.TEST)
val pass = gpu.renderType(pipeline, mesh)

on<Render3DEvent> { event ->
    val verts = mesh.verts()
    val base = verts.putVec3(0f, 0f, 0f).putColor(Colors.RED).next()
    verts.putVec3(1f, 0f, 0f).putColor(Colors.GREEN).next()
    verts.putVec3(0f, 1f, 0f).putColor(Colors.BLUE).next()
    mesh.idx()?.putTriangle(base, base + 1, base + 2)

    myShader.setMat4("u_view", event.viewMatrix())
    myShader.setMat4("u_projection", event.projectionMatrix())
    pass.draw()
}

The factory

Method Type Description
gpu.format(attributes...) VertexFormat interleaved vertex layout (throws IllegalArgumentException below 1 or above 16 attributes)
gpu.mesh(format) Mesh non-indexed mesh, 1024-byte initial vertex buffer (throws IllegalArgumentException on a foreign format)
gpu.indexedMesh(format) Mesh mesh with an index buffer, 1024 bytes each
gpu.pipeline(shader, drawMode, blend, depth) Pipeline culling disabled
gpu.pipeline(shader, drawMode, blend, depth, cull) Pipeline nulls default to TRIANGLES/ALPHA/OFF (throws IllegalArgumentException on a foreign shader)
gpu.renderType(pipeline, mesh) RenderType non-instanced draw pairing
gpu.instancedRenderType(pipeline, mesh, verticesPerInstance) RenderType verticesPerInstance clamped to 0 or more (throws IllegalArgumentException on a foreign pipeline or mesh)

Every method throws IllegalStateException once the script session is closed. Meshes, pipelines and render types are tracked resources; formats are not.

The vertex format

Method Type Description
VertexAttribute(count, type, normalized, instanced) VertexAttribute canonical constructor
attribute.count() int component count
attribute.type() AttributeType component type
attribute.normalized() boolean normalization flag, ignored — only UNSIGNED_BYTE is normalized
attribute.instanced() boolean true when the attribute advances once per instance
VertexAttribute.floats(count) VertexAttribute static, count floats, per-vertex
VertexAttribute.ints(count) VertexAttribute static, count ints, per-vertex
VertexAttribute.color() VertexAttribute static, 4 normalized unsigned bytes, per-vertex
attribute.perInstance() VertexAttribute copy with instanced = true

AttributeType

Constant Description
AttributeType.FLOAT 32-bit float components
AttributeType.INT 32-bit signed integer components
AttributeType.UNSIGNED_BYTE 4 normalized bytes regardless of the declared count

The format itself

Method Type Description
format.stride() int bytes per vertex
format.attributeCount() int attributes in the layout

Attributes map to the shader's layout(location = N) inputs in declaration order; nothing checks that what you write matches the format.

Writing vertices

Method Type Description
mesh.format() VertexFormat the format the mesh was created with
mesh.verts() VertexWriter vertex writer (throws IllegalStateException when the mesh is closed)
mesh.idx() IndexWriter? index writer, null on a non-indexed mesh
mesh.indexed() boolean true when created by gpu.indexedMesh
mesh.clear() void resets both writers, no-op if the mesh was never used

The GL buffer is created on first use, and that first write must happen on the render thread. draw() uploads both writers and empties them, so each frame writes its geometry from scratch.

The vertex writer

Method Type Description
verts.putFloat(value) VertexWriter writes 4 bytes
verts.putInt(value) VertexWriter writes 4 bytes
verts.putVec2(x, y) VertexWriter writes two floats, identical to putUv
verts.putVec3(x, y, z) VertexWriter writes three floats
verts.putVec3(position) VertexWriter same from a Vec, components cast to float
verts.putUv(u, v) VertexWriter writes two floats
verts.putColor(argb) VertexWriter writes the ARGB int; reaches GLSL as BGRA
verts.next() int ends the vertex, returns its 0-based index (throws IllegalStateException at 1048576 vertices)
verts.vertexCount() int vertices finished so far, 0 when the mesh is closed

Indices

Method Type Description
idx.put(index) IndexWriter appends one vertex index (throws IllegalStateException at 4194304 indices)
idx.putTriangle(a, b, c) IndexWriter appends three indices
idx.putQuad(a, b, c, d) IndexWriter appends triangles (a, b, c) and (a, c, d)
idx.indexCount() int indices written so far, 0 when the mesh is closed

The pipeline

Method Type Description
pipeline.shader() Shader the shader this pipeline draws with — Shaders
pipeline.drawMode() DrawMode primitive topology

DrawMode

Constant Description
DrawMode.TRIANGLES GL_TRIANGLES, also the fallback for a null mode
DrawMode.TRIANGLE_STRIP GL_TRIANGLE_STRIP
DrawMode.TRIANGLE_FAN GL_TRIANGLE_FAN
DrawMode.LINES GL_LINES
DrawMode.LINE_STRIP GL_LINE_STRIP
DrawMode.POINTS GL_POINTS

BlendMode

Constant Description
BlendMode.OFF blending disabled
BlendMode.ALPHA SRC_ALPHA, ONE_MINUS_SRC_ALPHA, the fallback for a null mode
BlendMode.PREMULTIPLIED ONE, ONE_MINUS_SRC_ALPHA on colour and alpha
BlendMode.ADDITIVE SRC_ALPHA, ONE on colour and alpha
BlendMode.INVERT ONE_MINUS_DST_COLOR, ONE_MINUS_SRC_COLOR on colour, ONE, ZERO on alpha, the blend of the vanilla crosshair (API 7)

DepthMode

Constant Description
DepthMode.OFF depth test off, depth write off, the fallback for a null mode
DepthMode.TEST depth test on, depth write off
DepthMode.TEST_AND_WRITE depth test on, depth write on

Drawing

Method Type Description
pass.pipeline() Pipeline the pipeline used
pass.mesh() Mesh the mesh used
pass.draw() void binds the client framebuffer and issues one draw call (throws IllegalStateException when the render type or mesh is closed)
pass.drawInstanced() void draws instances of verticesPerInstance vertices, instancedRenderType only

No built-in uniforms are supplied, unlike Render.shader: u_view, u_projection and anything else are yours to set before the call. Both calls draw nothing while the mesh is empty or the shader failed to compile.

Limits

Limit Value
live gpu resources per script 64 meshes, pipelines and render types together
attributes per vertex format 16
vertices per mesh 1 048 576
indices per mesh 4 194 304
embedded font or PNG 8 MiB

The exception each limit throws: Sandbox and limits.

Last updated