fast-layer 0.1.0

WIP: A fast WebAssembly-based layer for high-performance MapLibre/Mapbox
Documentation
use wasm_bindgen::prelude::*;
use web_sys::{
    console, window, Element, HtmlCanvasElement, WebGl2RenderingContext, WebGlProgram, WebGlShader,
    WebGlUniformLocation,
};

#[wasm_bindgen]
pub struct FastLayer {
    canvas_id: String,
    context: WebGl2RenderingContext,
    program: Option<WebGlProgram>,
}

#[wasm_bindgen]
impl FastLayer {
    pub fn new(canvas_id: &str) -> FastLayer {
        let document = web_sys::window().unwrap().document().unwrap();
        let canvas = document.get_element_by_id(canvas_id).unwrap();
        let canvas: web_sys::HtmlCanvasElement = canvas
            .dyn_into::<web_sys::HtmlCanvasElement>()
            .map_err(|_| ())
            .unwrap();
        let context = canvas
            .get_context("webgl2")
            .unwrap()
            .unwrap()
            .dyn_into()
            .unwrap();

        FastLayer {
            canvas_id: canvas_id.to_string(),
            context,
            program: None,
        }
    }

    pub fn compile(&mut self) {
        let vertex_source = r#"#version 300 es
        uniform mat4 u_matrix;
        void main() {
            gl_Position = vec4(0.5, 0.5, 0.0, 1.0);
            gl_PointSize = 20.0;
        }"#;

        let fragment_source = r#"#version 300 es

            out highp vec4 fragColor;
        void main() {
            fragColor = vec4(1.0, 0.0, 0.0, 1.0);
        }"#;

        let vertex_shader = self
            .context
            .create_shader(WebGl2RenderingContext::VERTEX_SHADER)
            .unwrap();
        self.context.shader_source(&vertex_shader, vertex_source);
        self.context.compile_shader(&vertex_shader);

        if !self
            .context
            .get_shader_parameter(&vertex_shader, WebGl2RenderingContext::COMPILE_STATUS)
            .as_bool()
            .unwrap_or(false)
        {
            let info = self
                .context
                .get_shader_info_log(&vertex_shader)
                .unwrap_or_else(|| "Unknown error".to_string());
            panic!("Could not compile vertex shader. \n\n{}", info);
        }

        let fragment_shader = self
            .context
            .create_shader(WebGl2RenderingContext::FRAGMENT_SHADER)
            .unwrap();
        self.context
            .shader_source(&fragment_shader, fragment_source);
        self.context.compile_shader(&fragment_shader);

        if !self
            .context
            .get_shader_parameter(&fragment_shader, WebGl2RenderingContext::COMPILE_STATUS)
            .as_bool()
            .unwrap_or(false)
        {
            let info = self
                .context
                .get_shader_info_log(&fragment_shader)
                .unwrap_or_else(|| "Unknown error".to_string());
            panic!("Could not compile fragment shader. \n\n{}", info);
        }

        let program = self.context.create_program().unwrap();
        self.context.attach_shader(&program, &vertex_shader);
        self.context.attach_shader(&program, &fragment_shader);
        self.context.link_program(&program);

        if !self
            .context
            .get_program_parameter(&program, WebGl2RenderingContext::LINK_STATUS)
            .as_bool()
            .unwrap_or(false)
        {
            let info = self
                .context
                .get_program_info_log(&program)
                .unwrap_or_else(|| "Unknown error".to_string());
            panic!("Could not link WebGL program. \n\n{}", info);
        }

        self.program = Some(program);
    }

    pub fn draw(&self, matrix: &[f64]) {
        console::log_1(&format!("{:?}", self.program).into());
        self.context
            .use_program(Some(self.program.as_ref().unwrap()));
        let location = self
            .context
            .get_uniform_location(self.program.as_ref().unwrap(), "u_matrix");

        if let Some(loc) = location {
            if matrix.len() >= 4 {
                self.context.uniform4f(
                    Some(&loc),
                    matrix[0] as f32,
                    matrix[1] as f32,
                    matrix[2] as f32,
                    matrix[3] as f32,
                );
            }
        }

        self.context
            .draw_arrays(web_sys::WebGl2RenderingContext::POINTS, 0, 1);
    }
}