Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Mesh Functions

Loading and drawing 3D meshes.

Retained Meshes

Retained meshes are loaded once in init() and drawn multiple times in render().

load_mesh

Loads a non-indexed mesh from vertex data.

Signature:

#![allow(unused)]
fn main() {
fn load_mesh(data_ptr: *const u8, vertex_count: u32, format: u32) -> u32
}

Parameters:

NameTypeDescription
data_ptr*const u8Pointer to vertex data
vertex_countu32Number of vertices
formatu32Vertex format flags

Returns: Mesh handle (non-zero on success)

Constraints: Init-only.


load_mesh_indexed

Loads an indexed mesh (more efficient for shared vertices).

Signature:

#![allow(unused)]
fn main() {
fn load_mesh_indexed(
    data_ptr: *const u8,
    vertex_count: u32,
    index_ptr: *const u16,
    index_count: u32,
    format: u32
) -> u32
}

Parameters:

NameTypeDescription
data_ptr*const u8Pointer to vertex data
vertex_countu32Number of vertices
index_ptr*const u16Pointer to u16 index data
index_countu32Number of indices
formatu32Vertex format flags

Returns: Mesh handle

Constraints: Init-only.

Example:

#![allow(unused)]
fn main() {
static mut CUBE_MESH: u32 = 0;

// Cube with 8 vertices, 36 indices (12 triangles)
const CUBE_VERTS: [f32; 8 * 6] = [
    // Position (xyz) + Normal (xyz)
    -1.0, -1.0, -1.0,  0.0, 0.0, -1.0,
     1.0, -1.0, -1.0,  0.0, 0.0, -1.0,
    // ... more vertices
];

const CUBE_INDICES: [u16; 36] = [
    0, 1, 2, 2, 3, 0, // Front face
    // ... more indices
];

fn init() {
    unsafe {
        CUBE_MESH = load_mesh_indexed(
            CUBE_VERTS.as_ptr() as *const u8,
            8,
            CUBE_INDICES.as_ptr(),
            36,
            4 // FORMAT_POS_NORMAL
        );
    }
}
}

load_mesh_packed

Loads a packed mesh with half-precision floats (smaller memory footprint).

Signature:

#![allow(unused)]
fn main() {
fn load_mesh_packed(data_ptr: *const u8, vertex_count: u32, format: u32) -> u32
}

Constraints: Init-only. Uses f16 for positions and snorm16 for normals.


load_mesh_indexed_packed

Loads an indexed packed mesh.

Signature:

#![allow(unused)]
fn main() {
fn load_mesh_indexed_packed(
    data_ptr: *const u8,
    vertex_count: u32,
    index_ptr: *const u16,
    index_count: u32,
    format: u32
) -> u32
}

Constraints: Init-only.


draw_mesh

Draws a retained mesh with the current transform and render state.

Signature:

#![allow(unused)]
fn main() {
fn draw_mesh(handle: u32)
}

Parameters:

NameTypeDescription
handleu32Mesh handle from load_mesh*() or procedural generators

Example:

#![allow(unused)]
fn main() {
fn render() {
    // Draw at origin
    push_identity();
    draw_mesh(cube);

    // Draw at different position
    push_identity();
    push_translate(5.0, 0.0, 0.0);
    draw_mesh(cube);

    // Draw with different color
    set_color(0xFF0000FF);
    push_identity();
    push_translate(-5.0, 0.0, 0.0);
    draw_mesh(cube);
}
}

Immediate Mode Drawing

For dynamic geometry that changes every frame.

draw_triangles

Draws non-indexed triangles immediately (not retained).

Signature:

#![allow(unused)]
fn main() {
fn draw_triangles(data_ptr: *const u8, vertex_count: u32, format: u32)
}

Parameters:

NameTypeDescription
data_ptr*const u8Pointer to vertex data
vertex_countu32Number of vertices (must be multiple of 3)
formatu32Vertex format flags

Example:

#![allow(unused)]
fn main() {
fn render() {
    // Dynamic triangle
    let verts: [f32; 18] = [
        // Position (xyz) + Color (rgb)
        0.0, 1.0, 0.0,  1.0, 0.0, 0.0, // Top (red)
        -1.0, -1.0, 0.0,  0.0, 1.0, 0.0, // Left (green)
        1.0, -1.0, 0.0,  0.0, 0.0, 1.0, // Right (blue)
    ];

    push_identity();
    draw_triangles(verts.as_ptr() as *const u8, 3, 2); // FORMAT_POS_COLOR
}
}

draw_triangles_indexed

Draws indexed triangles immediately.

Signature:

#![allow(unused)]
fn main() {
fn draw_triangles_indexed(
    data_ptr: *const u8,
    vertex_count: u32,
    index_ptr: *const u16,
    index_count: u32,
    format: u32
)
}

Vertex Formats

Vertex format is specified as a bitmask of flags:

FlagValueComponentsBytes
Position0xyz (3 floats)12
UV1uv (2 floats)8
Color2rgb (3 floats)12
Normal4xyz (3 floats)12
Skinned8bone indices + weights16

Common Combinations:

FormatValueComponentsStride
POS0Position only12 bytes
POS_UV1Position + UV20 bytes
POS_COLOR2Position + Color24 bytes
POS_UV_COLOR3Position + UV + Color32 bytes
POS_NORMAL4Position + Normal24 bytes
POS_UV_NORMAL5Position + UV + Normal32 bytes
POS_COLOR_NORMAL6Position + Color + Normal36 bytes
POS_UV_COLOR_NORMAL7Position + UV + Color + Normal44 bytes

With Skinning (add 8):

FormatValueStride
POS_NORMAL_SKINNED1240 bytes
POS_UV_NORMAL_SKINNED1348 bytes

Vertex Data Layout

Data is laid out per-vertex in this order:

  1. Position (xyz) - 3 floats
  2. UV (uv) - 2 floats (if enabled)
  3. Color (rgb) - 3 floats (if enabled)
  4. Normal (xyz) - 3 floats (if enabled)
  5. Skinning (indices + weights) - 4 bytes + 4 bytes (if enabled)

Example: POS_UV_NORMAL (format 5)

#![allow(unused)]
fn main() {
// Each vertex: 8 floats (32 bytes)
let vertex: [f32; 8] = [
    0.0, 1.0, 0.0,  // Position
    0.5, 1.0,       // UV
    0.0, 1.0, 0.0,  // Normal
];
}

Complete Example

#![allow(unused)]
fn main() {
static mut TRIANGLE: u32 = 0;
static mut QUAD: u32 = 0;

// Triangle with position + color
const TRI_VERTS: [f32; 3 * 6] = [
    // pos xyz, color rgb
    0.0, 1.0, 0.0,  1.0, 0.0, 0.0,
    -1.0, -1.0, 0.0,  0.0, 1.0, 0.0,
    1.0, -1.0, 0.0,  0.0, 0.0, 1.0,
];

// Quad with position + UV + normal (indexed)
const QUAD_VERTS: [f32; 4 * 8] = [
    // pos xyz, uv, normal xyz
    -1.0, -1.0, 0.0,  0.0, 0.0,  0.0, 0.0, 1.0,
     1.0, -1.0, 0.0,  1.0, 0.0,  0.0, 0.0, 1.0,
     1.0,  1.0, 0.0,  1.0, 1.0,  0.0, 0.0, 1.0,
    -1.0,  1.0, 0.0,  0.0, 1.0,  0.0, 0.0, 1.0,
];

const QUAD_INDICES: [u16; 6] = [0, 1, 2, 2, 3, 0];

fn init() {
    unsafe {
        // Non-indexed triangle
        TRIANGLE = load_mesh(
            TRI_VERTS.as_ptr() as *const u8,
            3,
            2 // POS_COLOR
        );

        // Indexed quad
        QUAD = load_mesh_indexed(
            QUAD_VERTS.as_ptr() as *const u8,
            4,
            QUAD_INDICES.as_ptr(),
            6,
            5 // POS_UV_NORMAL
        );
    }
}

fn render() {
    unsafe {
        camera_set(0.0, 0.0, 5.0, 0.0, 0.0, 0.0);

        // Draw triangle
        push_identity();
        push_translate(-2.0, 0.0, 0.0);
        draw_mesh(TRIANGLE);

        // Draw textured quad
        texture_bind(my_texture);
        push_identity();
        push_translate(2.0, 0.0, 0.0);
        draw_mesh(QUAD);
    }
}
}

See Also: Procedural Meshes, rom_mesh