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

Texture Functions

Loading, binding, and configuring textures.

Loading Textures

load_texture

Loads an RGBA8 texture from WASM memory.

Signature:

#![allow(unused)]
fn main() {
fn load_texture(width: u32, height: u32, pixels: *const u8) -> u32
}

Parameters:

NameTypeDescription
widthu32Texture width in pixels
heightu32Texture height in pixels
pixels*const u8Pointer to RGBA8 pixel data (4 bytes per pixel)

Returns: Texture handle (non-zero on success)

Constraints: Init-only. Must be called in init().

Example:

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

// Embedded pixel data (8x8 checkerboard)
const CHECKER: [u8; 8 * 8 * 4] = {
    let mut pixels = [0u8; 256];
    let mut i = 0;
    while i < 64 {
        let x = i % 8;
        let y = i / 8;
        let white = ((x + y) % 2) == 0;
        let idx = i * 4;
        pixels[idx] = if white { 255 } else { 0 };     // R
        pixels[idx + 1] = if white { 255 } else { 0 }; // G
        pixels[idx + 2] = if white { 255 } else { 0 }; // B
        pixels[idx + 3] = 255;                          // A
        i += 1;
    }
    pixels
};

fn init() {
    unsafe {
        PLAYER_TEX = load_texture(8, 8, CHECKER.as_ptr());
    }
}
}

Note: Prefer rom_texture() for assets bundled in the ROM data pack.

See Also: rom_texture


Binding Textures

texture_bind

Binds a texture to slot 0 (albedo/diffuse).

Signature:

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

Parameters:

NameTypeDescription
handleu32Texture handle from load_texture() or rom_texture()

Example:

#![allow(unused)]
fn main() {
fn render() {
    texture_bind(player_tex);
    draw_mesh(player_model);

    texture_bind(enemy_tex);
    draw_mesh(enemy_model);
}
}

texture_bind_slot

Binds a texture to a specific slot.

Signature:

#![allow(unused)]
fn main() {
fn texture_bind_slot(handle: u32, slot: u32)
}

Parameters:

NameTypeDescription
handleu32Texture handle
slotu32Texture slot (0-3)

Texture Slots:

SlotPurpose
0Albedo/diffuse texture
1MRE texture (Mode 2) or Specular (Mode 3)
2Reserved
3Reserved

Example:

#![allow(unused)]
fn main() {
fn render() {
    // Bind albedo to slot 0
    texture_bind_slot(albedo_tex, 0);

    // Bind MRE (Metallic/Roughness/Emissive) to slot 1
    texture_bind_slot(mre_tex, 1);

    draw_mesh(pbr_model);
}
}

Matcap Textures

matcap_blend_mode

Sets the blend mode for a matcap texture slot.

Signature:

#![allow(unused)]
fn main() {
fn matcap_blend_mode(slot: u32, mode: u32)
}

Parameters:

NameTypeDescription
slotu32Matcap slot (1-3)
modeu32Blend mode

Blend Modes:

ValueModeDescription
0MultiplyDarkens (shadows, ambient occlusion)
1AddBrightens (highlights, rim light)
2HSV ModulateHue/saturation shift

Example:

#![allow(unused)]
fn main() {
fn init() {
    render_mode(1); // Matcap mode
}

fn render() {
    // Dark matcap for shadows (multiply)
    matcap_set(1, shadow_matcap);
    matcap_blend_mode(1, 0);

    // Bright matcap for highlights (add)
    matcap_set(2, highlight_matcap);
    matcap_blend_mode(2, 1);

    texture_bind(albedo_tex);
    draw_mesh(character);
}
}

See Also: matcap_set, Render Modes Guide


Texture Formats

RGBA8

Standard 8-bit RGBA format. 4 bytes per pixel.

#![allow(unused)]
fn main() {
// Pixel layout: [R, G, B, A, R, G, B, A, ...]
let pixels: [u8; 4 * 4 * 4] = [
    255, 0, 0, 255,    // Red pixel
    0, 255, 0, 255,    // Green pixel
    0, 0, 255, 255,    // Blue pixel
    255, 255, 255, 128, // Semi-transparent white
    // ... more pixels
];
}

Texture Tips

  • Power-of-two dimensions recommended (8, 16, 32, 64, 128, 256, 512)
  • Texture atlases reduce bind calls and improve batching
  • Use rom_texture() for large textures (bypasses WASM memory)
  • Use load_texture() only for small procedural/runtime textures

Complete Example

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

// Generate checkerboard at compile time
const CHECKER_PIXELS: [u8; 16 * 16 * 4] = {
    let mut pixels = [0u8; 16 * 16 * 4];
    let mut i = 0;
    while i < 256 {
        let x = i % 16;
        let y = i / 16;
        let white = ((x / 2 + y / 2) % 2) == 0;
        let idx = i * 4;
        let c = if white { 200 } else { 50 };
        pixels[idx] = c;
        pixels[idx + 1] = c;
        pixels[idx + 2] = c;
        pixels[idx + 3] = 255;
        i += 1;
    }
    pixels
};

// Generate gradient at compile time
const GRADIENT_PIXELS: [u8; 8 * 8 * 4] = {
    let mut pixels = [0u8; 8 * 8 * 4];
    let mut i = 0;
    while i < 64 {
        let x = i % 8;
        let y = i / 8;
        let idx = i * 4;
        pixels[idx] = (x * 32) as u8;     // R increases right
        pixels[idx + 1] = (y * 32) as u8; // G increases down
        pixels[idx + 2] = 128;             // B constant
        pixels[idx + 3] = 255;
        i += 1;
    }
    pixels
};

fn init() {
    unsafe {
        CHECKER_TEX = load_texture(16, 16, CHECKER_PIXELS.as_ptr());
        GRADIENT_TEX = load_texture(8, 8, GRADIENT_PIXELS.as_ptr());
    }
}

fn render() {
    unsafe {
        // Draw floor with checker texture
        texture_bind(CHECKER_TEX);
        texture_filter(0); // Nearest for crisp pixels
        push_identity();
        push_scale(10.0, 1.0, 10.0);
        draw_mesh(plane);

        // Draw object with gradient
        texture_bind(GRADIENT_TEX);
        texture_filter(1); // Linear for smooth
        push_identity();
        push_translate(0.0, 1.0, 0.0);
        draw_mesh(cube);
    }
}
}