scena 1.0.1

A Rust-native scene-graph renderer with typed scene state, glTF assets, and explicit prepare/render lifecycles.
Documentation
use crate::geometry::{Primitive, PrimitiveVertexAttributes, Vertex};
use crate::render::prepare::transforms::{
    invert_matrix4, unbake_normal_to_model_space, unbake_position_to_model_space,
};
use web_sys::{WebGl2RenderingContext, WebGlProgram};

pub(super) fn encode_vertices(primitives: &[Primitive]) -> Vec<f32> {
    let mut vertices = Vec::with_capacity(primitives.len() * 3 * 17);
    for primitive in primitives {
        let world_from_model = primitive.world_from_model();
        let normal_from_model = primitive.normal_from_model();
        let position_inverse = invert_matrix4(&world_from_model);
        let normal_inverse = invert_matrix4(&normal_from_model);
        for (vertex, attributes) in primitive
            .vertices()
            .iter()
            .zip(primitive.vertex_attributes().iter())
        {
            let model_vertex = match position_inverse {
                Some(inv) => Vertex {
                    position: unbake_position_to_model_space(vertex.position, &inv),
                    color: vertex.color,
                },
                None => *vertex,
            };
            let model_attributes = match normal_inverse {
                Some(inv) => PrimitiveVertexAttributes {
                    normal: unbake_normal_to_model_space(attributes.normal, &inv),
                    tex_coord0: attributes.tex_coord0,
                    tangent: unbake_normal_to_model_space(attributes.tangent, &inv),
                    tangent_handedness: attributes.tangent_handedness,
                    shadow_visibility: attributes.shadow_visibility,
                },
                None => *attributes,
            };
            vertices.extend_from_slice(&[
                model_vertex.position.x,
                model_vertex.position.y,
                model_vertex.position.z,
                model_vertex.color.r,
                model_vertex.color.g,
                model_vertex.color.b,
                model_vertex.color.a,
                model_attributes.normal.x,
                model_attributes.normal.y,
                model_attributes.normal.z,
                model_attributes.tex_coord0[0],
                model_attributes.tex_coord0[1],
                model_attributes.tangent.x,
                model_attributes.tangent.y,
                model_attributes.tangent.z,
                model_attributes.tangent_handedness,
                model_attributes.shadow_visibility.clamp(0.0, 1.0),
            ]);
        }
    }
    vertices
}

pub(super) fn configure_vertex_attributes(
    gl: &WebGl2RenderingContext,
    program: &WebGlProgram,
) -> Result<(), wasm_bindgen::JsValue> {
    let stride = (17 * std::mem::size_of::<f32>()) as i32;
    let position = gl.get_attrib_location(program, "position");
    let color = gl.get_attrib_location(program, "color");
    let normal = gl.get_attrib_location(program, "normal");
    let tex_coord0 = gl.get_attrib_location(program, "tex_coord0");
    let tangent = gl.get_attrib_location(program, "tangent");
    let shadow_visibility = gl.get_attrib_location(program, "shadow_visibility");
    if position < 0
        || color < 0
        || normal < 0
        || tex_coord0 < 0
        || tangent < 0
        || shadow_visibility < 0
    {
        return Err(wasm_bindgen::JsValue::from_str(
            "webgl2 shader is missing required vertex attributes",
        ));
    }
    let position = position as u32;
    let color = color as u32;
    let normal = normal as u32;
    let tex_coord0 = tex_coord0 as u32;
    let tangent = tangent as u32;
    let shadow_visibility = shadow_visibility as u32;
    gl.enable_vertex_attrib_array(position);
    gl.vertex_attrib_pointer_with_i32(position, 3, WebGl2RenderingContext::FLOAT, false, stride, 0);
    gl.enable_vertex_attrib_array(color);
    gl.vertex_attrib_pointer_with_i32(
        color,
        4,
        WebGl2RenderingContext::FLOAT,
        false,
        stride,
        (3 * std::mem::size_of::<f32>()) as i32,
    );
    gl.enable_vertex_attrib_array(normal);
    gl.vertex_attrib_pointer_with_i32(
        normal,
        3,
        WebGl2RenderingContext::FLOAT,
        false,
        stride,
        (7 * std::mem::size_of::<f32>()) as i32,
    );
    gl.enable_vertex_attrib_array(tex_coord0);
    gl.vertex_attrib_pointer_with_i32(
        tex_coord0,
        2,
        WebGl2RenderingContext::FLOAT,
        false,
        stride,
        (10 * std::mem::size_of::<f32>()) as i32,
    );
    gl.enable_vertex_attrib_array(tangent);
    gl.vertex_attrib_pointer_with_i32(
        tangent,
        4,
        WebGl2RenderingContext::FLOAT,
        false,
        stride,
        (12 * std::mem::size_of::<f32>()) as i32,
    );
    gl.enable_vertex_attrib_array(shadow_visibility);
    gl.vertex_attrib_pointer_with_i32(
        shadow_visibility,
        1,
        WebGl2RenderingContext::FLOAT,
        false,
        stride,
        (16 * std::mem::size_of::<f32>()) as i32,
    );
    Ok(())
}