makepad-draw 1.0.0

Makepad 2d drawing API
Documentation
use {
    crate::{
        makepad_derive_live::*,
        makepad_platform::*,
    },
};

live_design!{
    pub GeometryQuad2D = {{GeometryQuad2D}} {
    }
    
    pub GeometryCube3D = {{GeometryCube3D}} {
    }
}

impl LiveHook for GeometryQuad2D {
    fn after_apply(&mut self, cx: &mut Cx, _apply:&mut Apply, _index:usize, _nodes:&[LiveNode]) {
        let mut fp = GeometryFingerprint::new(LiveType::of::<Self>());
        fp.push(self.x1);
        fp.push(self.y1);
        fp.push(self.x2);
        fp.push(self.y2);
        // lets get the fingerprint
        self.geometry_ref = Some(cx.get_geometry_ref(fp));
        GeometryGen::from_quad_2d(
            self.x1,
            self.y1,
            self.x2,
            self.y2,
        ).to_geometry(cx, &self.geometry_ref.as_ref().unwrap().0);
    }
}

impl GeometryFields for GeometryQuad2D {
    fn geometry_fields(&self, fields: &mut Vec<GeometryField>) {
        fields.push(GeometryField {id: live_id!(geom_pos), ty: ShaderTy::Vec2});
    }
    
    fn get_geometry_id(&self) -> Option<GeometryId> {
        // ok so what about doing a Rc<Geometry> based on input and class type
        if let Some(gr) = &self.geometry_ref{
            Some(gr.0.geometry_id())
        }
        else{
            None
        }
    }
    
    fn live_type_check(&self) -> LiveType {
        LiveType::of::<Self>()
    }
}

#[derive(Live, LiveRegister)]
pub struct GeometryQuad2D {
    #[rust] pub geometry_ref: Option<GeometryRef>,
    #[live(0.0)] pub x1: f32,
    #[live(0.0)] pub y1: f32,
    #[live(1.0)] pub x2: f32,
    #[live(1.0)] pub y2: f32,
}

impl LiveHook for GeometryCube3D {
    fn after_apply(&mut self, cx: &mut Cx, _apply:&mut Apply, _index:usize, _nodes:&[LiveNode]) {
        let mut fp = GeometryFingerprint::new(LiveType::of::<Self>());
        fp.push(self.width);
        fp.push(self.height);
        fp.push(self.depth);
        fp.push(self.width_segments as f32);
        fp.push(self.height_segments as f32);
        fp.push(self.depth_segments as f32);
        // lets get the fingerprint
        self.geometry_ref = Some(cx.get_geometry_ref(fp));
        GeometryGen::from_cube_3d(
            self.width,
            self.height,
            self.depth,
            self.width_segments,
            self.height_segments,
            self.depth_segments,
        ).to_geometry(cx, &self.geometry_ref.as_ref().unwrap().0);
    }
}

impl GeometryFields for GeometryCube3D {
    fn geometry_fields(&self, fields: &mut Vec<GeometryField>) {
        fields.push(GeometryField {id: live_id!(geom_pos), ty: ShaderTy::Vec3});
        fields.push(GeometryField {id: live_id!(geom_id), ty: ShaderTy::Float});
        fields.push(GeometryField {id: live_id!(geom_normal), ty: ShaderTy::Vec3});
        fields.push(GeometryField {id: live_id!(geom_uv), ty: ShaderTy::Vec2});
    }
    
    fn get_geometry_id(&self) -> Option<GeometryId> {
        // ok so what about doing a Rc<Geometry> based on input and class type
        if let Some(gr) = &self.geometry_ref{
            Some(gr.0.geometry_id())
        }
        else{
            None
        }
    }
        
    fn live_type_check(&self) -> LiveType {
        LiveType::of::<Self>()
    }
}


#[derive(Live, LiveRegister)]
pub struct GeometryCube3D {
    #[rust] pub geometry_ref: Option<GeometryRef>,
    #[live(1.0)] width: f32,
    #[live(1.0)] height: f32,
    #[live(1.0)] depth: f32,
    #[live(1usize)] width_segments: usize,
    #[live(1usize)] height_segments: usize,
    #[live(1usize)] depth_segments: usize
}


#[derive(Clone, Debug, Default, PartialEq)]
pub struct GeometryGen {
    pub vertices: Vec<f32>, // vec4 pos, vec3 normal, vec2 uv
    pub indices: Vec<u32>
}

#[derive(Clone, Copy)]
pub enum GeometryAxis {
    X = 0,
    Y = 1,
    Z = 2,
}

impl GeometryGen {
    
    pub fn to_geometry(self, cx:&mut Cx, geometry:&Geometry){
        geometry.update(cx, self.indices, self.vertices);
    }
    
    pub fn from_quad_2d(x1: f32, y1: f32, x2: f32, y2: f32) -> GeometryGen {
        let mut g = Self::default();
        g.add_quad_2d(x1, y1, x2, y2);
        g
    }
    
    pub fn from_cube_3d(
        width: f32,
        height: f32,
        depth: f32,
        width_segments: usize,
        height_segments: usize,
        depth_segments: usize
    ) -> GeometryGen {
        let mut g = Self::default();
        g.add_cube_3d(width, height, depth, width_segments, height_segments, depth_segments);
        g
    }
    
    // requires pos:vec2 normalized layout
    pub fn add_quad_2d(&mut self, x1: f32, y1: f32, x2: f32, y2: f32) {
        let vertex_offset = self.vertices.len() as u32;
        self.vertices.push(x1);
        self.vertices.push(y1);
        self.vertices.push(x2);
        self.vertices.push(y1);
        self.vertices.push(x2);
        self.vertices.push(y2);
        self.vertices.push(x1);
        self.vertices.push(y2);
        self.indices.push(vertex_offset + 0);
        self.indices.push(vertex_offset + 1);
        self.indices.push(vertex_offset + 2);
        self.indices.push(vertex_offset + 2);
        self.indices.push(vertex_offset + 3);
        self.indices.push(vertex_offset + 0);
    }
    
    // requires pos:vec3, id:float, normal:vec3, uv:vec2 layout
    pub fn add_cube_3d(
        &mut self,
        width: f32,
        height: f32,
        depth: f32,
        width_segments: usize,
        height_segments: usize,
        depth_segments: usize
    ) {
        self.add_plane_3d(GeometryAxis::Z, GeometryAxis::Y, GeometryAxis::X, -1.0, -1.0, depth, height, width, depth_segments, height_segments, 0.0);
        self.add_plane_3d(GeometryAxis::Z, GeometryAxis::Y, GeometryAxis::X, 1.0, -1.0, depth, height, -width, depth_segments, height_segments, 1.0);
        self.add_plane_3d(GeometryAxis::X, GeometryAxis::Z, GeometryAxis::Y, 1.0, 1.0, width, depth, height, width_segments, depth_segments, 2.0);
        self.add_plane_3d(GeometryAxis::X, GeometryAxis::Z, GeometryAxis::Y, 1.0, -1.0, width, depth, -height, width_segments, depth_segments, 3.0);
        self.add_plane_3d(GeometryAxis::X, GeometryAxis::Y, GeometryAxis::Z, 1.0, -1.0, width, height, depth, width_segments, height_segments, 4.0);
        self.add_plane_3d(GeometryAxis::X, GeometryAxis::Y, GeometryAxis::Z, -1.0, -1.0, width, height, -depth, width_segments, height_segments, 5.0);
    }
    
    
    // requires pos:vec3, id:float, normal:vec3, uv:vec2 layout
    pub fn add_plane_3d(
        &mut self,
        u: GeometryAxis,
        v: GeometryAxis,
        w: GeometryAxis,
        udir: f32,
        vdir: f32,
        width: f32,
        height: f32,
        depth: f32,
        grid_x: usize,
        grid_y: usize,
        id: f32
    ) {
        let segment_width = width / (grid_x as f32);
        let segment_height = height / (grid_y as f32);
        let width_half = width / 2.0;
        let height_half = height / 2.0;
        let depth_half = depth / 2.0;
        let grid_x1 = grid_x + 1;
        let grid_y1 = grid_y + 1;
        
        let vertex_offset = self.vertices.len() / 9;
        
        for iy in 0..grid_y1 {
            let y = (iy as f32) * segment_height - height_half;
            
            for ix in 0..grid_x1 {
                
                let x = (ix as f32) * segment_width - width_half;
                let off = self.vertices.len();
                self.vertices.push(0.0);
                self.vertices.push(0.0);
                self.vertices.push(0.0);
                
                self.vertices[off + u as usize] = x * udir;
                self.vertices[off + v as usize] = y * vdir;
                self.vertices[off + w as usize] = depth_half;
                
                self.vertices.push(id);
                let off = self.vertices.len();
                self.vertices.push(0.0);
                self.vertices.push(0.0);
                self.vertices.push(0.0);
                self.vertices[off + w as usize] = if depth > 0.0 {1.0} else {-1.0};
                
                self.vertices.push((ix as f32) / (grid_x as f32));
                self.vertices.push(1.0 - (iy as f32) / (grid_y as f32));
            }
        }
        
        for iy in 0..grid_y {
            for ix in 0..grid_x {
                let a = vertex_offset + ix + grid_x1 * iy;
                let b = vertex_offset + ix + grid_x1 * (iy + 1);
                let c = vertex_offset + (ix + 1) + grid_x1 * (iy + 1);
                let d = vertex_offset + (ix + 1) + grid_x1 * iy;
                self.indices.push(a as u32);
                self.indices.push(b as u32);
                self.indices.push(d as u32);
                self.indices.push(b as u32);
                self.indices.push(c as u32);
                self.indices.push(d as u32);
            }
        }
    }
}