// pathfinder/renderer/src/scene.rs // // Copyright © 2019 The Pathfinder Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! A set of paths to be rendered. use crate::gpu_data::BuiltObject; use crate::paint::{ObjectShader, Paint, PaintId, ShaderId}; use crate::tiles::Tiler; use crate::z_buffer::ZBuffer; use euclid::Rect; use hashbrown::HashMap; use pathfinder_geometry::clip::PolygonClipper3D; use pathfinder_geometry::outline::Outline; use pathfinder_geometry::point::Point3DF32; use pathfinder_geometry::transform3d::Perspective; use pathfinder_geometry::transform::Transform2DF32; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; #[derive(Clone, Debug)] pub struct Scene { pub objects: Vec, pub paints: Vec, pub paint_cache: HashMap, pub bounds: Rect, pub view_box: Rect, } impl Scene { #[inline] pub fn new() -> Scene { Scene { objects: vec![], paints: vec![], paint_cache: HashMap::new(), bounds: Rect::zero(), view_box: Rect::zero(), } } #[allow(clippy::trivially_copy_pass_by_ref)] pub fn push_paint(&mut self, paint: &Paint) -> PaintId { if let Some(paint_id) = self.paint_cache.get(paint) { return *paint_id; } let paint_id = PaintId(self.paints.len() as u16); self.paint_cache.insert(*paint, paint_id); self.paints.push(*paint); paint_id } pub fn build_shaders(&self) -> Vec { self.paints .iter() .map(|paint| ObjectShader { fill_color: paint.color, }) .collect() } pub fn build_objects_sequentially(&self, z_buffer: &ZBuffer) -> Vec { self.objects .iter() .enumerate() .map(|(object_index, object)| { let mut tiler = Tiler::new( &object.outline, &self.view_box, object_index as u16, ShaderId(object.paint.0), z_buffer, ); tiler.generate_tiles(); tiler.built_object }) .collect() } pub fn build_objects(&self, z_buffer: &ZBuffer) -> Vec { self.objects .par_iter() .enumerate() .map(|(object_index, object)| { let mut tiler = Tiler::new( &object.outline, &self.view_box, object_index as u16, ShaderId(object.paint.0), z_buffer, ); tiler.generate_tiles(); tiler.built_object }) .collect() } pub fn transform(&mut self, transform: &Transform2DF32) { let mut bounds = Rect::zero(); for (object_index, object) in self.objects.iter_mut().enumerate() { object.outline.transform(transform); object.outline.clip_against_rect(&self.view_box); if object_index == 0 { bounds = *object.outline.bounds(); } else { bounds = bounds.union(object.outline.bounds()); } } //println!("new bounds={:?}", bounds); self.bounds = bounds; } pub fn apply_perspective(&mut self, perspective: &Perspective) { let quad = self.clip_bounding_quad_with_perspective(perspective); println!("bounds={:?} quad={:?}", self.bounds, quad); let mut bounds = Rect::zero(); for (object_index, object) in self.objects.iter_mut().enumerate() { object.outline.apply_perspective(perspective); object.outline.clip_against_rect(&self.view_box); if object_index == 0 { bounds = *object.outline.bounds(); } else { bounds = bounds.union(object.outline.bounds()); } } //println!("new bounds={:?}", bounds); self.bounds = bounds; } fn clip_bounding_quad_with_perspective(&self, perspective: &Perspective) -> Vec { let mut points = vec![ Point3DF32::from_euclid_2d(&self.bounds.origin), Point3DF32::from_euclid_2d(&self.bounds.top_right()), Point3DF32::from_euclid_2d(&self.bounds.bottom_right()), Point3DF32::from_euclid_2d(&self.bounds.bottom_left()), ]; for point in &mut points { *point = perspective.transform_point_3d(point); } PolygonClipper3D::new(points).clip() } } #[derive(Clone, Debug)] pub struct PathObject { outline: Outline, paint: PaintId, name: String, kind: PathObjectKind, } #[derive(Clone, Copy, Debug)] pub enum PathObjectKind { Fill, Stroke, } impl PathObject { #[inline] pub fn new(outline: Outline, paint: PaintId, name: String, kind: PathObjectKind) -> PathObject { PathObject { outline, paint, name, kind, } } } #[inline] pub fn scene_tile_index(tile_x: i16, tile_y: i16, tile_rect: Rect) -> u32 { (tile_y - tile_rect.origin.y) as u32 * tile_rect.size.width as u32 + (tile_x - tile_rect.origin.x) as u32 }