summaryrefslogblamecommitdiffstats
path: root/wgpu/src/layer.rs
blob: 4c864cb04d6a082ebb26cd73956458873f36b6b1 (plain) (tree)
1
2
3
4
5
6
7
8
9

                                                                       
                           


                                               
                              

                              
 





                                   
 
 









                                                  
 
 
                  
                       

                                         

                                   
                   
                        

 

                          
              
                                           
                                                            


                                             
                       
                            


         














                                                                               
                                                               
     
 














                                                                          
                                                        

     






                               
                                   



                                       
                                                  

          
                                                     
     
 








                                                   
                                 



                                                                           

                                                                






                                                            
                                                   

     




                                                        
       




                                                   
 
                                                     













                                                   
                                                   






                                                                          
             

         
                                                     

     

                                                          
 
                                                   
 





                                         

     
































                                                                

     
                                                    
                                         
 

                                         
 
                                                    
 

                                              
                       
                                  
               

                                                 
                
                                                      
         


                                

                             
                                                    


                                                                           

                             











                                                          

                                                                    
 
                                                   

     

                                                        


                             




                                                                      

                               
                                   

                                
                                   
         

                         
                              

                              
 



                                                   
 








                                                                    
 





                                                                   



         


                          

     
use crate::core::renderer;
use crate::core::{Background, Color, Point, Rectangle, Transformation};
use crate::graphics::color;
use crate::graphics::text::{Editor, Paragraph};
use crate::graphics::Mesh;
use crate::image::{self, Image};
use crate::quad::{self, Quad};
use crate::text::{self, Text};
use crate::triangle;

pub struct Layer {
    pub bounds: Rectangle,
    pub quads: quad::Batch,
    pub triangles: triangle::Batch,
    pub text: text::Batch,
    pub images: image::Batch,
}

impl Default for Layer {
    fn default() -> Self {
        Self {
            bounds: Rectangle::INFINITE,
            quads: quad::Batch::default(),
            triangles: triangle::Batch::default(),
            text: text::Batch::default(),
            images: image::Batch::default(),
        }
    }
}

pub struct Stack {
    layers: Vec<Layer>,
    transformations: Vec<Transformation>,
    previous: Vec<usize>,
    pending_meshes: Vec<Vec<Mesh>>,
    pending_text: Vec<Vec<Text>>,
    current: usize,
    active_count: usize,
}

impl Stack {
    pub fn new() -> Self {
        Self {
            layers: vec![Layer::default()],
            transformations: vec![Transformation::IDENTITY],
            previous: vec![],
            pending_meshes: vec![Vec::new()],
            pending_text: vec![Vec::new()],
            current: 0,
            active_count: 1,
        }
    }

    pub fn draw_quad(&mut self, quad: renderer::Quad, background: Background) {
        let transformation = self.transformations.last().unwrap();
        let bounds = quad.bounds * *transformation;

        let quad = Quad {
            position: [bounds.x, bounds.y],
            size: [bounds.width, bounds.height],
            border_color: color::pack(quad.border.color),
            border_radius: quad.border.radius.into(),
            border_width: quad.border.width,
            shadow_color: color::pack(quad.shadow.color),
            shadow_offset: quad.shadow.offset.into(),
            shadow_blur_radius: quad.shadow.blur_radius,
        };

        self.layers[self.current].quads.add(quad, &background);
    }

    pub fn draw_paragraph(
        &mut self,
        paragraph: &Paragraph,
        position: Point,
        color: Color,
        clip_bounds: Rectangle,
    ) {
        let paragraph = Text::Paragraph {
            paragraph: paragraph.downgrade(),
            position,
            color,
            clip_bounds,
            transformation: self.transformations.last().copied().unwrap(),
        };

        self.pending_text[self.current].push(paragraph);
    }

    pub fn draw_editor(
        &mut self,
        editor: &Editor,
        position: Point,
        color: Color,
        clip_bounds: Rectangle,
    ) {
        let editor = Text::Editor {
            editor: editor.downgrade(),
            position,
            color,
            clip_bounds,
            transformation: self.transformation(),
        };

        self.pending_text[self.current].push(editor);
    }

    pub fn draw_text(
        &mut self,
        text: crate::core::Text,
        position: Point,
        color: Color,
        clip_bounds: Rectangle,
    ) {
        let transformation = self.transformation();

        let text = Text::Cached {
            content: text.content,
            bounds: Rectangle::new(position, text.bounds) * transformation,
            color,
            size: text.size * transformation.scale_factor(),
            line_height: text.line_height.to_absolute(text.size)
                * transformation.scale_factor(),
            font: text.font,
            horizontal_alignment: text.horizontal_alignment,
            vertical_alignment: text.vertical_alignment,
            shaping: text.shaping,
            clip_bounds: clip_bounds * transformation,
        };

        self.pending_text[self.current].push(text);
    }

    pub fn draw_image(
        &mut self,
        handle: crate::core::image::Handle,
        filter_method: crate::core::image::FilterMethod,
        bounds: Rectangle,
    ) {
        let image = Image::Raster {
            handle,
            filter_method,
            bounds: bounds * self.transformation(),
        };

        self.layers[self.current].images.push(image);
    }

    pub fn draw_svg(
        &mut self,
        handle: crate::core::svg::Handle,
        color: Option<Color>,
        bounds: Rectangle,
    ) {
        let svg = Image::Vector {
            handle,
            color,
            bounds: bounds * self.transformation(),
        };

        self.layers[self.current].images.push(svg);
    }

    pub fn draw_mesh(&mut self, mut mesh: Mesh) {
        match &mut mesh {
            Mesh::Solid { transformation, .. }
            | Mesh::Gradient { transformation, .. } => {
                *transformation = *transformation * self.transformation();
            }
        }

        self.pending_meshes[self.current].push(mesh);
    }

    pub fn draw_mesh_group(&mut self, meshes: Vec<Mesh>) {
        self.flush_pending();

        let transformation = self.transformation();

        self.layers[self.current]
            .triangles
            .push(triangle::Item::Group {
                transformation,
                meshes,
            });
    }

    pub fn draw_mesh_cache(&mut self, cache: triangle::Cache) {
        self.flush_pending();

        let transformation = self.transformation();

        self.layers[self.current]
            .triangles
            .push(triangle::Item::Cached {
                transformation,
                cache,
            });
    }

    pub fn draw_text_group(&mut self, text: Vec<Text>) {
        self.flush_pending();

        let transformation = self.transformation();

        self.layers[self.current].text.push(text::Item::Group {
            transformation,
            text,
        });
    }

    pub fn draw_text_cache(&mut self, cache: text::Cache) {
        self.flush_pending();

        let transformation = self.transformation();

        self.layers[self.current].text.push(text::Item::Cached {
            transformation,
            cache,
        });
    }

    pub fn push_clip(&mut self, bounds: Rectangle) {
        self.previous.push(self.current);

        self.current = self.active_count;
        self.active_count += 1;

        let bounds = bounds * self.transformation();

        if self.current == self.layers.len() {
            self.layers.push(Layer {
                bounds,
                ..Layer::default()
            });
            self.pending_meshes.push(Vec::new());
            self.pending_text.push(Vec::new());
        } else {
            self.layers[self.current].bounds = bounds;
        }
    }

    pub fn pop_clip(&mut self) {
        self.flush_pending();

        self.current = self.previous.pop().unwrap();
    }

    pub fn push_transformation(&mut self, transformation: Transformation) {
        self.flush_pending();

        self.transformations
            .push(self.transformation() * transformation);
    }

    pub fn pop_transformation(&mut self) {
        let _ = self.transformations.pop();
    }

    fn transformation(&self) -> Transformation {
        self.transformations.last().copied().unwrap()
    }

    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Layer> {
        self.flush_pending();

        self.layers[..self.active_count].iter_mut()
    }

    pub fn iter(&self) -> impl Iterator<Item = &Layer> {
        self.layers[..self.active_count].iter()
    }

    pub fn clear(&mut self) {
        for (live, pending_meshes) in self.layers[..self.active_count]
            .iter_mut()
            .zip(self.pending_meshes.iter_mut())
        {
            live.bounds = Rectangle::INFINITE;

            live.quads.clear();
            live.triangles.clear();
            live.text.clear();
            live.images.clear();
            pending_meshes.clear();
        }

        self.current = 0;
        self.active_count = 1;
        self.previous.clear();
    }

    // We want to keep the allocated memory
    #[allow(clippy::drain_collect)]
    fn flush_pending(&mut self) {
        let transformation = self.transformation();

        let pending_meshes = &mut self.pending_meshes[self.current];
        if !pending_meshes.is_empty() {
            self.layers[self.current]
                .triangles
                .push(triangle::Item::Group {
                    transformation,
                    meshes: pending_meshes.drain(..).collect(),
                });
        }

        let pending_text = &mut self.pending_text[self.current];
        if !pending_text.is_empty() {
            self.layers[self.current].text.push(text::Item::Group {
                transformation,
                text: pending_text.drain(..).collect(),
            });
        }
    }
}

impl Default for Stack {
    fn default() -> Self {
        Self::new()
    }
}