Unified · Split
| @@ -47,7 +47,7 @@ fn generate_shader_bindings() -> PathBuf { · 46 unmodified lines | ||
| 47 | 47 | "Pixels".into(), |
| 48 | 48 | "PointF".into(), |
| 49 | 49 | "Hsla".into(), |
| 50 | − "ScaledContentMask".into(), | |
| 50 | + "ContentMask".into(), | |
| 51 | 51 | "Uniforms".into(), |
| 52 | 52 | "AtlasTile".into(), |
| 53 | 53 | "ShadowInputIndex".into(), |
| @@ -40,7 +40,7 @@ pub(crate) fn current_platform() -> Arc<dyn Platform> { · 39 unmodified lines | ||
| 40 | 40 | Arc::new(MacPlatform::new()) |
| 41 | 41 | } |
| 42 | 42 | |
| 43 | −pub trait Platform: 'static { | |
| 43 | +pub(crate) trait Platform: 'static { | |
| 44 | 44 | fn executor(&self) -> Executor; |
| 45 | 45 | fn display_linker(&self) -> Arc<dyn PlatformDisplayLinker>; |
| 46 | 46 | fn text_system(&self) -> Arc<dyn PlatformTextSystem>; |
| @@ -113,7 +113,7 @@ impl Debug for DisplayId { · 66 unmodified lines | ||
| 113 | 113 | |
| 114 | 114 | unsafe impl Send for DisplayId {} |
| 115 | 115 | |
| 116 | −pub trait PlatformWindow { | |
| 116 | +pub(crate) trait PlatformWindow { | |
| 117 | 117 | fn bounds(&self) -> WindowBounds; |
| 118 | 118 | fn content_size(&self) -> Size<Pixels>; |
| 119 | 119 | fn scale_factor(&self) -> f32; |
| @@ -194,11 +194,17 @@ pub enum AtlasKey { · 74 unmodified lines | ||
| 194 | 194 | } |
| 195 | 195 | |
| 196 | 196 | impl AtlasKey { |
| 197 | − pub fn is_monochrome(&self) -> bool { | |
| 197 | + pub(crate) fn texture_kind(&self) -> AtlasTextureKind { | |
| 198 | 198 | match self { |
| 199 | − AtlasKey::Glyph(params) => !params.is_emoji, | |
| 200 | − AtlasKey::Svg(_) => true, | |
| 201 | − AtlasKey::Image(_) => false, | |
| 199 | + AtlasKey::Glyph(params) => { | |
| 200 | + if params.is_emoji { | |
| 201 | + AtlasTextureKind::Polychrome | |
| 202 | + } else { | |
| 203 | + AtlasTextureKind::Monochrome | |
| 204 | + } | |
| 205 | + } | |
| 206 | + AtlasKey::Svg(_) => AtlasTextureKind::Monochrome, | |
| 207 | + AtlasKey::Image(_) => AtlasTextureKind::Polychrome, | |
| 202 | 208 | } |
| 203 | 209 | } |
| 204 | 210 | } |
| @@ -241,7 +247,19 @@ pub struct AtlasTile { · 36 unmodified lines | ||
| 241 | 247 | |
| 242 | 248 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
| 243 | 249 | #[repr(C)] |
| 244 | −pub(crate) struct AtlasTextureId(pub(crate) u32); // We use u32 instead of usize for Metal Shader Language compatibility | |
| 250 | +pub(crate) struct AtlasTextureId { | |
| 251 | + // We use u32 instead of usize for Metal Shader Language compatibility | |
| 252 | + pub(crate) index: u32, | |
| 253 | + pub(crate) kind: AtlasTextureKind, | |
| 254 | +} | |
| 255 | + | |
| 256 | +#[derive(Clone, Copy, Debug, PartialEq, Eq)] | |
| 257 | +#[repr(C)] | |
| 258 | +pub(crate) enum AtlasTextureKind { | |
| 259 | + Monochrome = 0, | |
| 260 | + Polychrome = 1, | |
| 261 | + Path = 2, | |
| 262 | +} | |
| 245 | 263 | |
| 246 | 264 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] |
| 247 | 265 | #[repr(C)] |
| @@ -1,14 +1,14 @@ | ||
| 1 | −use std::borrow::Cow; | |
| 2 | − | |
| 3 | 1 | use crate::{ |
| 4 | − AtlasKey, AtlasTextureId, AtlasTile, Bounds, DevicePixels, PlatformAtlas, Point, Size, | |
| 2 | + AtlasKey, AtlasTextureId, AtlasTextureKind, AtlasTile, Bounds, DevicePixels, PlatformAtlas, | |
| 3 | + Point, Size, | |
| 5 | 4 | }; |
| 6 | −use anyhow::{anyhow, Result}; | |
| 5 | +use anyhow::Result; | |
| 7 | 6 | use collections::HashMap; |
| 8 | 7 | use derive_more::{Deref, DerefMut}; |
| 9 | 8 | use etagere::BucketedAtlasAllocator; |
| 10 | 9 | use metal::Device; |
| 11 | 10 | use parking_lot::Mutex; |
| 11 | +use std::borrow::Cow; | |
| 12 | 12 | |
| 13 | 13 | pub struct MetalAtlas(Mutex<MetalAtlasState>); |
| 14 | 14 | |
| @@ -16,19 +16,31 @@ impl MetalAtlas { · 1 unmodified line | ||
| 16 | 16 | pub fn new(device: Device) -> Self { |
| 17 | 17 | MetalAtlas(Mutex::new(MetalAtlasState { |
| 18 | 18 | device: AssertSend(device), |
| 19 | − textures: Default::default(), | |
| 19 | + monochrome_textures: Default::default(), | |
| 20 | + polychrome_textures: Default::default(), | |
| 21 | + path_textures: Default::default(), | |
| 20 | 22 | tiles_by_key: Default::default(), |
| 21 | 23 | })) |
| 22 | 24 | } |
| 23 | 25 | |
| 24 | − pub(crate) fn texture(&self, id: AtlasTextureId) -> metal::Texture { | |
| 25 | − self.0.lock().textures[id.0 as usize].metal_texture.clone() | |
| 26 | + pub(crate) fn metal_texture(&self, id: AtlasTextureId) -> metal::Texture { | |
| 27 | + self.0.lock().texture(id).metal_texture.clone() | |
| 28 | + } | |
| 29 | + | |
| 30 | + pub(crate) fn allocate( | |
| 31 | + &self, | |
| 32 | + size: Size<DevicePixels>, | |
| 33 | + texture_kind: AtlasTextureKind, | |
| 34 | + ) -> AtlasTile { | |
| 35 | + self.0.lock().allocate(size, texture_kind) | |
| 26 | 36 | } |
| 27 | 37 | } |
| 28 | 38 | |
| 29 | 39 | struct MetalAtlasState { |
| 30 | 40 | device: AssertSend<Device>, |
| 31 | − textures: Vec<MetalAtlasTexture>, | |
| 41 | + monochrome_textures: Vec<MetalAtlasTexture>, | |
| 42 | + polychrome_textures: Vec<MetalAtlasTexture>, | |
| 43 | + path_textures: Vec<MetalAtlasTexture>, | |
| 32 | 44 | tiles_by_key: HashMap<AtlasKey, AtlasTile>, |
| 33 | 45 | } |
| 34 | 46 | |
| @@ -43,23 +55,9 @@ impl PlatformAtlas for MetalAtlas { · 8 unmodified lines | ||
| 43 | 55 | return Ok(tile.clone()); |
| 44 | 56 | } else { |
| 45 | 57 | let (size, bytes) = build()?; |
| 46 | − let tile = lock | |
| 47 | − .textures | |
| 48 | − .iter_mut() | |
| 49 | − .rev() | |
| 50 | − .find_map(|texture| { | |
| 51 | − if texture.monochrome == key.is_monochrome() { | |
| 52 | − texture.upload(size, &bytes) | |
| 53 | − } else { | |
| 54 | − None | |
| 55 | − } | |
| 56 | − }) | |
| 57 | − .or_else(|| { | |
| 58 | − let texture = lock.push_texture(size, key.is_monochrome()); | |
| 59 | − texture.upload(size, &bytes) | |
| 60 | − }) | |
| 61 | − .ok_or_else(|| anyhow!("could not allocate in new texture"))?; | |
| 62 | − lock.tiles_by_key.insert(key.clone(), tile.clone()); | |
| 58 | + let tile = lock.allocate(size, key.texture_kind()); | |
| 59 | + let texture = lock.texture(tile.texture_id); | |
| 60 | + texture.upload(tile.bounds, &bytes); | |
| 63 | 61 | Ok(tile) |
| 64 | 62 | } |
| 65 | 63 | } |
| @@ -70,10 +68,26 @@ impl PlatformAtlas for MetalAtlas { · 4 unmodified lines | ||
| 70 | 68 | } |
| 71 | 69 | |
| 72 | 70 | impl MetalAtlasState { |
| 71 | + fn allocate(&mut self, size: Size<DevicePixels>, texture_kind: AtlasTextureKind) -> AtlasTile { | |
| 72 | + let textures = match texture_kind { | |
| 73 | + AtlasTextureKind::Monochrome => &mut self.monochrome_textures, | |
| 74 | + AtlasTextureKind::Polychrome => &mut self.polychrome_textures, | |
| 75 | + AtlasTextureKind::Path => &mut self.path_textures, | |
| 76 | + }; | |
| 77 | + textures | |
| 78 | + .iter_mut() | |
| 79 | + .rev() | |
| 80 | + .find_map(|texture| texture.allocate(size)) | |
| 81 | + .unwrap_or_else(|| { | |
| 82 | + let texture = self.push_texture(size, texture_kind); | |
| 83 | + texture.allocate(size).unwrap() | |
| 84 | + }) | |
| 85 | + } | |
| 86 | + | |
| 73 | 87 | fn push_texture( |
| 74 | 88 | &mut self, |
| 75 | 89 | min_size: Size<DevicePixels>, |
| 76 | − monochrome: bool, | |
| 90 | + kind: AtlasTextureKind, | |
| 77 | 91 | ) -> &mut MetalAtlasTexture { |
| 78 | 92 | const DEFAULT_ATLAS_SIZE: Size<DevicePixels> = Size { |
| 79 | 93 | width: DevicePixels(1024), |
| @@ -84,21 +98,38 @@ impl MetalAtlasState { · 4 unmodified lines | ||
| 84 | 98 | let texture_descriptor = metal::TextureDescriptor::new(); |
| 85 | 99 | texture_descriptor.set_width(size.width.into()); |
| 86 | 100 | texture_descriptor.set_height(size.height.into()); |
| 87 | − if monochrome { | |
| 88 | − texture_descriptor.set_pixel_format(metal::MTLPixelFormat::A8Unorm); | |
| 89 | − } else { | |
| 90 | − texture_descriptor.set_pixel_format(metal::MTLPixelFormat::BGRA8Unorm); | |
| 91 | − } | |
| 101 | + let pixel_format = match kind { | |
| 102 | + AtlasTextureKind::Monochrome => metal::MTLPixelFormat::A8Unorm, | |
| 103 | + AtlasTextureKind::Polychrome => metal::MTLPixelFormat::BGRA8Unorm, | |
| 104 | + AtlasTextureKind::Path => metal::MTLPixelFormat::R16Float, | |
| 105 | + }; | |
| 106 | + texture_descriptor.set_pixel_format(pixel_format); | |
| 92 | 107 | let metal_texture = self.device.new_texture(&texture_descriptor); |
| 93 | 108 | |
| 109 | + let textures = match kind { | |
| 110 | + AtlasTextureKind::Monochrome => &mut self.monochrome_textures, | |
| 111 | + AtlasTextureKind::Polychrome => &mut self.polychrome_textures, | |
| 112 | + AtlasTextureKind::Path => &mut self.path_textures, | |
| 113 | + }; | |
| 94 | 114 | let atlas_texture = MetalAtlasTexture { |
| 95 | − id: AtlasTextureId(self.textures.len() as u32), | |
| 115 | + id: AtlasTextureId { | |
| 116 | + index: textures.len() as u32, | |
| 117 | + kind, | |
| 118 | + }, | |
| 96 | 119 | allocator: etagere::BucketedAtlasAllocator::new(size.into()), |
| 97 | 120 | metal_texture: AssertSend(metal_texture), |
| 98 | − monochrome, | |
| 99 | 121 | }; |
| 100 | − self.textures.push(atlas_texture); | |
| 101 | − self.textures.last_mut().unwrap() | |
| 122 | + textures.push(atlas_texture); | |
| 123 | + textures.last_mut().unwrap() | |
| 124 | + } | |
| 125 | + | |
| 126 | + fn texture(&self, id: AtlasTextureId) -> &MetalAtlasTexture { | |
| 127 | + let textures = match id.kind { | |
| 128 | + crate::AtlasTextureKind::Monochrome => &self.monochrome_textures, | |
| 129 | + crate::AtlasTextureKind::Polychrome => &self.polychrome_textures, | |
| 130 | + crate::AtlasTextureKind::Path => &self.path_textures, | |
| 131 | + }; | |
| 132 | + &textures[id.index as usize] | |
| 102 | 133 | } |
| 103 | 134 | } |
| 104 | 135 | |
| @@ -106,11 +137,10 @@ struct MetalAtlasTexture { · 1 unmodified line | ||
| 106 | 137 | id: AtlasTextureId, |
| 107 | 138 | allocator: BucketedAtlasAllocator, |
| 108 | 139 | metal_texture: AssertSend<metal::Texture>, |
| 109 | − monochrome: bool, | |
| 110 | 140 | } |
| 111 | 141 | |
| 112 | 142 | impl MetalAtlasTexture { |
| 113 | − fn upload(&mut self, size: Size<DevicePixels>, bytes: &[u8]) -> Option<AtlasTile> { | |
| 143 | + fn allocate(&mut self, size: Size<DevicePixels>) -> Option<AtlasTile> { | |
| 114 | 144 | let allocation = self.allocator.allocate(size.into())?; |
| 115 | 145 | let tile = AtlasTile { |
| 116 | 146 | texture_id: self.id, |
| @@ -120,20 +150,22 @@ impl MetalAtlasTexture { · 3 unmodified lines | ||
| 120 | 150 | size, |
| 121 | 151 | }, |
| 122 | 152 | }; |
| 153 | + Some(tile) | |
| 154 | + } | |
| 123 | 155 | |
| 156 | + fn upload(&self, bounds: Bounds<DevicePixels>, bytes: &[u8]) { | |
| 124 | 157 | let region = metal::MTLRegion::new_2d( |
| 125 | − tile.bounds.origin.x.into(), | |
| 126 | − tile.bounds.origin.y.into(), | |
| 127 | − tile.bounds.size.width.into(), | |
| 128 | − tile.bounds.size.height.into(), | |
| 158 | + bounds.origin.x.into(), | |
| 159 | + bounds.origin.y.into(), | |
| 160 | + bounds.size.width.into(), | |
| 161 | + bounds.size.height.into(), | |
| 129 | 162 | ); |
| 130 | 163 | self.metal_texture.replace_region( |
| 131 | 164 | region, |
| 132 | 165 | 0, |
| 133 | 166 | bytes.as_ptr() as *const _, |
| 134 | − u32::from(tile.bounds.size.width.to_bytes(self.bytes_per_pixel())) as u64, | |
| 167 | + u32::from(bounds.size.width.to_bytes(self.bytes_per_pixel())) as u64, | |
| 135 | 168 | ); |
| 136 | − Some(tile) | |
| 137 | 169 | } |
| 138 | 170 | |
| 139 | 171 | fn bytes_per_pixel(&self) -> u8 { |
| @@ -1,12 +1,14 @@ | ||
| 1 | 1 | use crate::{ |
| 2 | − point, size, AtlasTextureId, DevicePixels, MetalAtlas, MonochromeSprite, PolychromeSprite, | |
| 3 | − PrimitiveBatch, Quad, Scene, Shadow, Size, Underline, | |
| 2 | + point, size, AtlasTextureId, AtlasTextureKind, AtlasTile, DevicePixels, MetalAtlas, | |
| 3 | + MonochromeSprite, PathId, PolychromeSprite, PrimitiveBatch, Quad, Scene, Shadow, Size, | |
| 4 | + Underline, | |
| 4 | 5 | }; |
| 5 | 6 | use cocoa::{ |
| 6 | 7 | base::{NO, YES}, |
| 7 | 8 | foundation::NSUInteger, |
| 8 | 9 | quartzcore::AutoresizingMask, |
| 9 | 10 | }; |
| 11 | +use collections::HashMap; | |
| 10 | 12 | use metal::{CommandQueue, MTLPixelFormat, MTLResourceOptions, NSRange}; |
| 11 | 13 | use objc::{self, msg_send, sel, sel_impl}; |
| 12 | 14 | use std::{ffi::c_void, mem, ptr, sync::Arc}; |
| @@ -14,7 +16,7 @@ use std::{ffi::c_void, mem, ptr, sync::Arc}; · 1 unmodified line | ||
| 14 | 16 | const SHADERS_METALLIB: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib")); |
| 15 | 17 | const INSTANCE_BUFFER_SIZE: usize = 8192 * 1024; // This is an arbitrary decision. There's probably a more optimal value. |
| 16 | 18 | |
| 17 | −pub struct MetalRenderer { | |
| 19 | +pub(crate) struct MetalRenderer { | |
| 18 | 20 | layer: metal::MetalLayer, |
| 19 | 21 | command_queue: CommandQueue, |
| 20 | 22 | shadows_pipeline_state: metal::RenderPipelineState, |
| @@ -150,7 +152,7 @@ impl MetalRenderer { · 129 unmodified lines | ||
| 150 | 152 | &self.sprite_atlas |
| 151 | 153 | } |
| 152 | 154 | |
| 153 | − pub fn draw(&mut self, scene: &mut Scene) { | |
| 155 | + pub fn draw(&mut self, scene: &Scene) { | |
| 154 | 156 | let layer = self.layer.clone(); |
| 155 | 157 | let viewport_size = layer.drawable_size(); |
| 156 | 158 | let viewport_size: Size<DevicePixels> = size( |
| @@ -192,6 +194,15 @@ impl MetalRenderer { · 35 unmodified lines | ||
| 192 | 194 | }); |
| 193 | 195 | |
| 194 | 196 | let mut instance_offset = 0; |
| 197 | + | |
| 198 | + let mut path_tiles: HashMap<PathId, AtlasTile> = HashMap::default(); | |
| 199 | + for path in scene.paths() { | |
| 200 | + let tile = self | |
| 201 | + .sprite_atlas | |
| 202 | + .allocate(path.bounds.size.map(Into::into), AtlasTextureKind::Path); | |
| 203 | + path_tiles.insert(path.id, tile); | |
| 204 | + } | |
| 205 | + | |
| 195 | 206 | for batch in scene.batches() { |
| 196 | 207 | match batch { |
| 197 | 208 | PrimitiveBatch::Shadows(shadows) => { |
| @@ -205,6 +216,9 @@ impl MetalRenderer { · 7 unmodified lines | ||
| 205 | 216 | PrimitiveBatch::Quads(quads) => { |
| 206 | 217 | self.draw_quads(quads, &mut instance_offset, viewport_size, command_encoder); |
| 207 | 218 | } |
| 219 | + PrimitiveBatch::Paths(paths) => { | |
| 220 | + // self.draw_paths(paths, &mut instance_offset, viewport_size, command_encoder); | |
| 221 | + } | |
| 208 | 222 | PrimitiveBatch::Underlines(underlines) => { |
| 209 | 223 | self.draw_underlines( |
| 210 | 224 | underlines, |
| @@ -441,7 +455,7 @@ impl MetalRenderer { · 230 unmodified lines | ||
| 441 | 455 | } |
| 442 | 456 | align_offset(offset); |
| 443 | 457 | |
| 444 | − let texture = self.sprite_atlas.texture(texture_id); | |
| 458 | + let texture = self.sprite_atlas.metal_texture(texture_id); | |
| 445 | 459 | let texture_size = size( |
| 446 | 460 | DevicePixels(texture.width() as i32), |
| 447 | 461 | DevicePixels(texture.height() as i32), |
| @@ -512,7 +526,7 @@ impl MetalRenderer { · 64 unmodified lines | ||
| 512 | 526 | } |
| 513 | 527 | align_offset(offset); |
| 514 | 528 | |
| 515 | − let texture = self.sprite_atlas.texture(texture_id); | |
| 529 | + let texture = self.sprite_atlas.metal_texture(texture_id); | |
| 516 | 530 | let texture_size = size( |
| 517 | 531 | DevicePixels(texture.width() as i32), |
| 518 | 532 | DevicePixels(texture.height() as i32), |
| @@ -911,7 +911,7 @@ impl PlatformWindow for MacWindow { · 910 unmodified lines | ||
| 911 | 911 | } |
| 912 | 912 | } |
| 913 | 913 | |
| 914 | − fn draw(&self, scene: crate::Scene) { | |
| 914 | + fn draw(&self, scene: Scene) { | |
| 915 | 915 | let mut this = self.0.lock(); |
| 916 | 916 | this.scene_to_render = Some(scene); |
| 917 | 917 | unsafe { |
| @@ -1395,8 +1395,8 @@ extern "C" fn display_layer(this: &Object, _: Sel, _: id) { · 477 unmodified lines | ||
| 1395 | 1395 | unsafe { |
| 1396 | 1396 | let window_state = get_window_state(this); |
| 1397 | 1397 | let mut window_state = window_state.as_ref().lock(); |
| 1398 | − if let Some(mut scene) = window_state.scene_to_render.take() { | |
| 1399 | − window_state.renderer.draw(&mut scene); | |
| 1398 | + if let Some(scene) = window_state.scene_to_render.take() { | |
| 1399 | + window_state.renderer.draw(&scene); | |
| 1400 | 1400 | } |
| 1401 | 1401 | } |
| 1402 | 1402 | } |
| @@ -1,16 +1,12 @@ | ||
| 1 | 1 | use crate::{ |
| 2 | − point, px, AtlasTextureId, AtlasTile, Bounds, Corners, Edges, Hsla, Pixels, Point, | |
| 3 | − ScaledContentMask, ScaledPixels, | |
| 2 | + point, AtlasTextureId, AtlasTile, Bounds, ContentMask, Corners, Edges, Hsla, Pixels, Point, | |
| 3 | + ScaledPixels, | |
| 4 | 4 | }; |
| 5 | 5 | use collections::BTreeMap; |
| 6 | 6 | use etagere::euclid::{Point3D, Vector3D}; |
| 7 | 7 | use plane_split::{BspSplitter, Polygon as BspPolygon}; |
| 8 | 8 | use smallvec::SmallVec; |
| 9 | −use std::{ | |
| 10 | − iter::Peekable, | |
| 11 | − mem, slice, | |
| 12 | − sync::atomic::{AtomicU32, Ordering::SeqCst}, | |
| 13 | −}; | |
| 9 | +use std::{fmt::Debug, iter::Peekable, mem, slice}; | |
| 14 | 10 | |
| 15 | 11 | // Exported to metal |
| 16 | 12 | pub type PointF = Point<f32>; |
| @@ -18,94 +14,57 @@ pub type StackingOrder = SmallVec<[u32; 16]>; · 1 unmodified line | ||
| 18 | 14 | pub type LayerId = u32; |
| 19 | 15 | pub type DrawOrder = u32; |
| 20 | 16 | |
| 21 | −#[derive(Debug)] | |
| 22 | −pub struct Scene { | |
| 23 | − pub(crate) scale_factor: f32, | |
| 24 | − pub(crate) layers: BTreeMap<StackingOrder, LayerId>, | |
| 25 | − pub shadows: Vec<Shadow>, | |
| 26 | − pub quads: Vec<Quad>, | |
| 27 | − pub underlines: Vec<Underline>, | |
| 28 | − pub monochrome_sprites: Vec<MonochromeSprite>, | |
| 29 | − pub polychrome_sprites: Vec<PolychromeSprite>, | |
| 30 | −} | |
| 31 | − | |
| 32 | −impl Scene { | |
| 33 | − pub fn new(scale_factor: f32) -> Scene { | |
| 34 | − Scene { | |
| 35 | − scale_factor, | |
| 36 | − layers: BTreeMap::new(), | |
| 17 | +pub(crate) struct SceneBuilder { | |
| 18 | + layers_by_order: BTreeMap<StackingOrder, LayerId>, | |
| 19 | + splitter: BspSplitter<(PrimitiveKind, usize)>, | |
| 20 | + shadows: Vec<Shadow>, | |
| 21 | + quads: Vec<Quad>, | |
| 22 | + paths: Vec<Path<ScaledPixels>>, | |
| 23 | + underlines: Vec<Underline>, | |
| 24 | + monochrome_sprites: Vec<MonochromeSprite>, | |
| 25 | + polychrome_sprites: Vec<PolychromeSprite>, | |
| 26 | +} | |
| 27 | + | |
| 28 | +impl SceneBuilder { | |
| 29 | + pub fn new() -> SceneBuilder { | |
| 30 | + SceneBuilder { | |
| 31 | + layers_by_order: BTreeMap::new(), | |
| 32 | + splitter: BspSplitter::new(), | |
| 37 | 33 | shadows: Vec::new(), |
| 38 | 34 | quads: Vec::new(), |
| 35 | + paths: Vec::new(), | |
| 39 | 36 | underlines: Vec::new(), |
| 40 | 37 | monochrome_sprites: Vec::new(), |
| 41 | 38 | polychrome_sprites: Vec::new(), |
| 42 | 39 | } |
| 43 | 40 | } |
| 44 | 41 | |
| 45 | − pub fn take(&mut self) -> Scene { | |
| 46 | − Scene { | |
| 47 | − scale_factor: self.scale_factor, | |
| 48 | − layers: mem::take(&mut self.layers), | |
| 49 | − shadows: mem::take(&mut self.shadows), | |
| 50 | − quads: mem::take(&mut self.quads), | |
| 51 | − underlines: mem::take(&mut self.underlines), | |
| 52 | − monochrome_sprites: mem::take(&mut self.monochrome_sprites), | |
| 53 | − polychrome_sprites: mem::take(&mut self.polychrome_sprites), | |
| 54 | − } | |
| 55 | − } | |
| 56 | − | |
| 57 | − pub fn insert(&mut self, layer_id: StackingOrder, primitive: impl Into<Primitive>) { | |
| 58 | − let next_id = self.layers.len() as LayerId; | |
| 59 | − let layer_id = *self.layers.entry(layer_id).or_insert(next_id); | |
| 60 | − let primitive = primitive.into(); | |
| 61 | − match primitive { | |
| 62 | − Primitive::Shadow(mut shadow) => { | |
| 63 | − shadow.order = layer_id; | |
| 64 | − self.shadows.push(shadow); | |
| 65 | − } | |
| 66 | − Primitive::Quad(mut quad) => { | |
| 67 | − quad.order = layer_id; | |
| 68 | − self.quads.push(quad); | |
| 69 | − } | |
| 70 | − Primitive::Underline(mut underline) => { | |
| 71 | − underline.order = layer_id; | |
| 72 | − self.underlines.push(underline); | |
| 73 | − } | |
| 74 | − Primitive::MonochromeSprite(mut sprite) => { | |
| 75 | − sprite.order = layer_id; | |
| 76 | − self.monochrome_sprites.push(sprite); | |
| 77 | − } | |
| 78 | − Primitive::PolychromeSprite(mut sprite) => { | |
| 79 | − sprite.order = layer_id; | |
| 80 | − self.polychrome_sprites.push(sprite); | |
| 81 | − } | |
| 82 | − } | |
| 83 | − } | |
| 84 | − | |
| 85 | − pub(crate) fn batches(&mut self) -> impl Iterator<Item = PrimitiveBatch> { | |
| 42 | + pub fn build(&mut self) -> Scene { | |
| 86 | 43 | // Map each layer id to a float between 0. and 1., with 1. closer to the viewer. |
| 87 | − let mut layer_z_values = vec![0.; self.layers.len()]; | |
| 88 | − for (ix, layer_id) in self.layers.values().enumerate() { | |
| 89 | − layer_z_values[*layer_id as usize] = ix as f32 / self.layers.len() as f32; | |
| 44 | + let mut layer_z_values = vec![0.; self.layers_by_order.len()]; | |
| 45 | + for (ix, layer_id) in self.layers_by_order.values().enumerate() { | |
| 46 | + layer_z_values[*layer_id as usize] = ix as f32 / self.layers_by_order.len() as f32; | |
| 90 | 47 | } |
| 48 | + self.layers_by_order.clear(); | |
| 91 | 49 | |
| 92 | 50 | // Add all primitives to the BSP splitter to determine draw order |
| 93 | − // todo!("reuse the same splitter") | |
| 94 | − let mut splitter = BspSplitter::new(); | |
| 51 | + self.splitter.reset(); | |
| 95 | 52 | |
| 96 | 53 | for (ix, shadow) in self.shadows.iter().enumerate() { |
| 97 | 54 | let z = layer_z_values[shadow.order as LayerId as usize]; |
| 98 | − splitter.add(shadow.bounds.to_bsp_polygon(z, (PrimitiveKind::Shadow, ix))); | |
| 55 | + self.splitter | |
| 56 | + .add(shadow.bounds.to_bsp_polygon(z, (PrimitiveKind::Shadow, ix))); | |
| 99 | 57 | } |
| 100 | 58 | |
| 101 | 59 | for (ix, quad) in self.quads.iter().enumerate() { |
| 102 | 60 | let z = layer_z_values[quad.order as LayerId as usize]; |
| 103 | − splitter.add(quad.bounds.to_bsp_polygon(z, (PrimitiveKind::Quad, ix))); | |
| 61 | + self.splitter | |
| 62 | + .add(quad.bounds.to_bsp_polygon(z, (PrimitiveKind::Quad, ix))); | |
| 104 | 63 | } |
| 105 | 64 | |
| 106 | 65 | for (ix, underline) in self.underlines.iter().enumerate() { |
| 107 | 66 | let z = layer_z_values[underline.order as LayerId as usize]; |
| 108 | − splitter.add( | |
| 67 | + self.splitter.add( | |
| 109 | 68 | underline |
| 110 | 69 | .bounds |
| 111 | 70 | .to_bsp_polygon(z, (PrimitiveKind::Underline, ix)), |
| @@ -114,7 +73,7 @@ impl Scene { · 2 unmodified lines | ||
| 114 | 73 | |
| 115 | 74 | for (ix, monochrome_sprite) in self.monochrome_sprites.iter().enumerate() { |
| 116 | 75 | let z = layer_z_values[monochrome_sprite.order as LayerId as usize]; |
| 117 | − splitter.add( | |
| 76 | + self.splitter.add( | |
| 118 | 77 | monochrome_sprite |
| 119 | 78 | .bounds |
| 120 | 79 | .to_bsp_polygon(z, (PrimitiveKind::MonochromeSprite, ix)), |
| @@ -123,7 +82,7 @@ impl Scene { · 2 unmodified lines | ||
| 123 | 82 | |
| 124 | 83 | for (ix, polychrome_sprite) in self.polychrome_sprites.iter().enumerate() { |
| 125 | 84 | let z = layer_z_values[polychrome_sprite.order as LayerId as usize]; |
| 126 | − splitter.add( | |
| 85 | + self.splitter.add( | |
| 127 | 86 | polychrome_sprite |
| 128 | 87 | .bounds |
| 129 | 88 | .to_bsp_polygon(z, (PrimitiveKind::PolychromeSprite, ix)), |
| @@ -132,10 +91,16 @@ impl Scene { · 2 unmodified lines | ||
| 132 | 91 | |
| 133 | 92 | // Sort all polygons, then reassign the order field of each primitive to `draw_order` |
| 134 | 93 | // We need primitives to be repr(C), hence the weird reuse of the order field for two different types. |
| 135 | − for (draw_order, polygon) in splitter.sort(Vector3D::new(0., 0., 1.)).iter().enumerate() { | |
| 94 | + for (draw_order, polygon) in self | |
| 95 | + .splitter | |
| 96 | + .sort(Vector3D::new(0., 0., 1.)) | |
| 97 | + .iter() | |
| 98 | + .enumerate() | |
| 99 | + { | |
| 136 | 100 | match polygon.anchor { |
| 137 | 101 | (PrimitiveKind::Shadow, ix) => self.shadows[ix].order = draw_order as DrawOrder, |
| 138 | 102 | (PrimitiveKind::Quad, ix) => self.quads[ix].order = draw_order as DrawOrder, |
| 103 | + (PrimitiveKind::Path, ix) => self.paths[ix].order = draw_order as DrawOrder, | |
| 139 | 104 | (PrimitiveKind::Underline, ix) => { |
| 140 | 105 | self.underlines[ix].order = draw_order as DrawOrder |
| 141 | 106 | } |
| @@ -148,13 +113,78 @@ impl Scene { · 6 unmodified lines | ||
| 148 | 113 | } |
| 149 | 114 | } |
| 150 | 115 | |
| 151 | − // Sort the primitives | |
| 152 | 116 | self.shadows.sort_unstable(); |
| 153 | 117 | self.quads.sort_unstable(); |
| 118 | + self.paths.sort_unstable(); | |
| 154 | 119 | self.underlines.sort_unstable(); |
| 155 | 120 | self.monochrome_sprites.sort_unstable(); |
| 156 | 121 | self.polychrome_sprites.sort_unstable(); |
| 157 | 122 | |
| 123 | + Scene { | |
| 124 | + shadows: mem::take(&mut self.shadows), | |
| 125 | + quads: mem::take(&mut self.quads), | |
| 126 | + paths: mem::take(&mut self.paths), | |
| 127 | + underlines: mem::take(&mut self.underlines), | |
| 128 | + monochrome_sprites: mem::take(&mut self.monochrome_sprites), | |
| 129 | + polychrome_sprites: mem::take(&mut self.polychrome_sprites), | |
| 130 | + } | |
| 131 | + } | |
| 132 | + | |
| 133 | + pub fn insert(&mut self, order: &StackingOrder, primitive: impl Into<Primitive>) { | |
| 134 | + let layer_id = if let Some(layer_id) = self.layers_by_order.get(order) { | |
| 135 | + *layer_id | |
| 136 | + } else { | |
| 137 | + let next_id = self.layers_by_order.len() as LayerId; | |
| 138 | + self.layers_by_order.insert(order.clone(), next_id); | |
| 139 | + next_id | |
| 140 | + }; | |
| 141 | + | |
| 142 | + let primitive = primitive.into(); | |
| 143 | + match primitive { | |
| 144 | + Primitive::Shadow(mut shadow) => { | |
| 145 | + shadow.order = layer_id; | |
| 146 | + self.shadows.push(shadow); | |
| 147 | + } | |
| 148 | + Primitive::Quad(mut quad) => { | |
| 149 | + quad.order = layer_id; | |
| 150 | + self.quads.push(quad); | |
| 151 | + } | |
| 152 | + Primitive::Path(mut path) => { | |
| 153 | + path.order = layer_id; | |
| 154 | + path.id = PathId(self.paths.len()); | |
| 155 | + self.paths.push(path); | |
| 156 | + } | |
| 157 | + Primitive::Underline(mut underline) => { | |
| 158 | + underline.order = layer_id; | |
| 159 | + self.underlines.push(underline); | |
| 160 | + } | |
| 161 | + Primitive::MonochromeSprite(mut sprite) => { | |
| 162 | + sprite.order = layer_id; | |
| 163 | + self.monochrome_sprites.push(sprite); | |
| 164 | + } | |
| 165 | + Primitive::PolychromeSprite(mut sprite) => { | |
| 166 | + sprite.order = layer_id; | |
| 167 | + self.polychrome_sprites.push(sprite); | |
| 168 | + } | |
| 169 | + } | |
| 170 | + } | |
| 171 | +} | |
| 172 | + | |
| 173 | +pub(crate) struct Scene { | |
| 174 | + pub shadows: Vec<Shadow>, | |
| 175 | + pub quads: Vec<Quad>, | |
| 176 | + pub paths: Vec<Path<ScaledPixels>>, | |
| 177 | + pub underlines: Vec<Underline>, | |
| 178 | + pub monochrome_sprites: Vec<MonochromeSprite>, | |
| 179 | + pub polychrome_sprites: Vec<PolychromeSprite>, | |
| 180 | +} | |
| 181 | + | |
| 182 | +impl Scene { | |
| 183 | + pub fn paths(&self) -> impl Iterator<Item = &Path<ScaledPixels>> { | |
| 184 | + self.paths.iter() | |
| 185 | + } | |
| 186 | + | |
| 187 | + pub fn batches(&self) -> impl Iterator<Item = PrimitiveBatch> { | |
| 158 | 188 | BatchIterator { |
| 159 | 189 | shadows: &self.shadows, |
| 160 | 190 | shadows_start: 0, |
| @@ -162,6 +192,9 @@ impl Scene { · 1 unmodified line | ||
| 162 | 192 | quads: &self.quads, |
| 163 | 193 | quads_start: 0, |
| 164 | 194 | quads_iter: self.quads.iter().peekable(), |
| 195 | + paths: &self.paths, | |
| 196 | + paths_start: 0, | |
| 197 | + paths_iter: self.paths.iter().peekable(), | |
| 165 | 198 | underlines: &self.underlines, |
| 166 | 199 | underlines_start: 0, |
| 167 | 200 | underlines_iter: self.underlines.iter().peekable(), |
| @@ -176,12 +209,15 @@ impl Scene { · 8 unmodified lines | ||
| 176 | 209 | } |
| 177 | 210 | |
| 178 | 211 | struct BatchIterator<'a> { |
| 179 | − quads: &'a [Quad], | |
| 180 | − quads_start: usize, | |
| 181 | − quads_iter: Peekable<slice::Iter<'a, Quad>>, | |
| 182 | 212 | shadows: &'a [Shadow], |
| 183 | 213 | shadows_start: usize, |
| 184 | 214 | shadows_iter: Peekable<slice::Iter<'a, Shadow>>, |
| 215 | + quads: &'a [Quad], | |
| 216 | + quads_start: usize, | |
| 217 | + quads_iter: Peekable<slice::Iter<'a, Quad>>, | |
| 218 | + paths: &'a [Path<ScaledPixels>], | |
| 219 | + paths_start: usize, | |
| 220 | + paths_iter: Peekable<slice::Iter<'a, Path<ScaledPixels>>>, | |
| 185 | 221 | underlines: &'a [Underline], |
| 186 | 222 | underlines_start: usize, |
| 187 | 223 | underlines_iter: Peekable<slice::Iter<'a, Underline>>, |
| @@ -255,6 +291,19 @@ impl<'a> Iterator for BatchIterator<'a> { · 67 unmodified lines | ||
| 255 | 291 | self.quads_start = quads_end; |
| 256 | 292 | Some(PrimitiveBatch::Quads(&self.quads[quads_start..quads_end])) |
| 257 | 293 | } |
| 294 | + PrimitiveKind::Path => { | |
| 295 | + let paths_start = self.paths_start; | |
| 296 | + let mut paths_end = paths_start; | |
| 297 | + while self | |
| 298 | + .paths_iter | |
| 299 | + .next_if(|path| path.order <= max_order) | |
| 300 | + .is_some() | |
| 301 | + { | |
| 302 | + paths_end += 1; | |
| 303 | + } | |
| 304 | + self.paths_start = paths_end; | |
| 305 | + Some(PrimitiveBatch::Paths(&self.paths[paths_start..paths_end])) | |
| 306 | + } | |
| 258 | 307 | PrimitiveKind::Underline => { |
| 259 | 308 | let underlines_start = self.underlines_start; |
| 260 | 309 | let mut underlines_end = underlines_start; |
| @@ -317,15 +366,16 @@ pub enum PrimitiveKind { · 56 unmodified lines | ||
| 317 | 366 | Shadow, |
| 318 | 367 | #[default] |
| 319 | 368 | Quad, |
| 369 | + Path, | |
| 320 | 370 | Underline, |
| 321 | 371 | MonochromeSprite, |
| 322 | 372 | PolychromeSprite, |
| 323 | 373 | } |
| 324 | 374 | |
| 325 | −#[derive(Clone, Debug)] | |
| 326 | 375 | pub enum Primitive { |
| 327 | 376 | Shadow(Shadow), |
| 328 | 377 | Quad(Quad), |
| 378 | + Path(Path<ScaledPixels>), | |
| 329 | 379 | Underline(Underline), |
| 330 | 380 | MonochromeSprite(MonochromeSprite), |
| 331 | 381 | PolychromeSprite(PolychromeSprite), |
| @@ -335,6 +385,7 @@ pub enum Primitive { · 3 unmodified lines | ||
| 335 | 385 | pub(crate) enum PrimitiveBatch<'a> { |
| 336 | 386 | Shadows(&'a [Shadow]), |
| 337 | 387 | Quads(&'a [Quad]), |
| 388 | + Paths(&'a [Path<ScaledPixels>]), | |
| 338 | 389 | Underlines(&'a [Underline]), |
| 339 | 390 | MonochromeSprites { |
| 340 | 391 | texture_id: AtlasTextureId, |
| @@ -351,7 +402,7 @@ pub(crate) enum PrimitiveBatch<'a> { · 10 unmodified lines | ||
| 351 | 402 | pub struct Quad { |
| 352 | 403 | pub order: u32, // Initially a LayerId, then a DrawOrder. |
| 353 | 404 | pub bounds: Bounds<ScaledPixels>, |
| 354 | − pub content_mask: ScaledContentMask, | |
| 405 | + pub content_mask: ContentMask<ScaledPixels>, | |
| 355 | 406 | pub background: Hsla, |
| 356 | 407 | pub border_color: Hsla, |
| 357 | 408 | pub corner_radii: Corners<ScaledPixels>, |
| @@ -381,7 +432,7 @@ impl From<Quad> for Primitive { · 23 unmodified lines | ||
| 381 | 432 | pub struct Underline { |
| 382 | 433 | pub order: u32, |
| 383 | 434 | pub bounds: Bounds<ScaledPixels>, |
| 384 | − pub content_mask: ScaledContentMask, | |
| 435 | + pub content_mask: ContentMask<ScaledPixels>, | |
| 385 | 436 | pub thickness: ScaledPixels, |
| 386 | 437 | pub color: Hsla, |
| 387 | 438 | pub wavy: bool, |
| @@ -411,7 +462,7 @@ pub struct Shadow { · 23 unmodified lines | ||
| 411 | 462 | pub order: u32, |
| 412 | 463 | pub bounds: Bounds<ScaledPixels>, |
| 413 | 464 | pub corner_radii: Corners<ScaledPixels>, |
| 414 | − pub content_mask: ScaledContentMask, | |
| 465 | + pub content_mask: ContentMask<ScaledPixels>, | |
| 415 | 466 | pub color: Hsla, |
| 416 | 467 | pub blur_radius: ScaledPixels, |
| 417 | 468 | } |
| @@ -439,7 +490,7 @@ impl From<Shadow> for Primitive { · 21 unmodified lines | ||
| 439 | 490 | pub struct MonochromeSprite { |
| 440 | 491 | pub order: u32, |
| 441 | 492 | pub bounds: Bounds<ScaledPixels>, |
| 442 | − pub content_mask: ScaledContentMask, | |
| 493 | + pub content_mask: ContentMask<ScaledPixels>, | |
| 443 | 494 | pub color: Hsla, |
| 444 | 495 | pub tile: AtlasTile, |
| 445 | 496 | } |
| @@ -470,7 +521,7 @@ impl From<MonochromeSprite> for Primitive { · 24 unmodified lines | ||
| 470 | 521 | pub struct PolychromeSprite { |
| 471 | 522 | pub order: u32, |
| 472 | 523 | pub bounds: Bounds<ScaledPixels>, |
| 473 | − pub content_mask: ScaledContentMask, | |
| 524 | + pub content_mask: ContentMask<ScaledPixels>, | |
| 474 | 525 | pub corner_radii: Corners<ScaledPixels>, |
| 475 | 526 | pub tile: AtlasTile, |
| 476 | 527 | pub grayscale: bool, |
| @@ -497,21 +548,24 @@ impl From<PolychromeSprite> for Primitive { · 20 unmodified lines | ||
| 497 | 548 | } |
| 498 | 549 | } |
| 499 | 550 | |
| 500 | −#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] | |
| 501 | −pub struct PathId(u32); | |
| 551 | +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | |
| 552 | +pub(crate) struct PathId(pub(crate) usize); | |
| 502 | 553 | |
| 503 | −pub struct PathBuilder { | |
| 504 | − bounds: Bounds<Pixels>, | |
| 505 | − vertices: Vec<PathVertex>, | |
| 506 | − start: Option<Point<Pixels>>, | |
| 507 | − current: Point<Pixels>, | |
| 554 | +#[derive(Debug)] | |
| 555 | +pub struct Path<P: Clone + Debug> { | |
| 556 | + pub(crate) id: PathId, | |
| 557 | + order: u32, | |
| 558 | + pub(crate) bounds: Bounds<P>, | |
| 559 | + pub(crate) vertices: Vec<PathVertex<P>>, | |
| 560 | + start: Option<Point<P>>, | |
| 561 | + current: Point<P>, | |
| 508 | 562 | } |
| 509 | 563 | |
| 510 | −impl PathBuilder { | |
| 564 | +impl Path<Pixels> { | |
| 511 | 565 | pub fn new() -> Self { |
| 512 | − const NEXT_PATH_ID: AtomicU32 = AtomicU32::new(0); | |
| 513 | − | |
| 514 | 566 | Self { |
| 567 | + id: PathId(0), | |
| 568 | + order: 0, | |
| 515 | 569 | vertices: Vec::new(), |
| 516 | 570 | start: Default::default(), |
| 517 | 571 | current: Default::default(), |
| @@ -519,6 +573,21 @@ impl PathBuilder { · 1 unmodified line | ||
| 519 | 573 | } |
| 520 | 574 | } |
| 521 | 575 | |
| 576 | + pub fn scale(&self, factor: f32) -> Path<ScaledPixels> { | |
| 577 | + Path { | |
| 578 | + id: self.id, | |
| 579 | + order: self.order, | |
| 580 | + bounds: self.bounds.scale(factor), | |
| 581 | + vertices: self | |
| 582 | + .vertices | |
| 583 | + .iter() | |
| 584 | + .map(|vertex| vertex.scale(factor)) | |
| 585 | + .collect(), | |
| 586 | + start: self.start.map(|start| start.scale(factor)), | |
| 587 | + current: self.current.scale(factor), | |
| 588 | + } | |
| 589 | + } | |
| 590 | + | |
| 522 | 591 | pub fn line_to(&mut self, to: Point<Pixels>) { |
| 523 | 592 | if let Some(start) = self.start { |
| 524 | 593 | self.push_triangle( |
| @@ -568,23 +637,63 @@ impl PathBuilder { · 43 unmodified lines | ||
| 568 | 637 | self.vertices.push(PathVertex { |
| 569 | 638 | xy_position: xy.0, |
| 570 | 639 | st_position: st.0, |
| 640 | + content_mask: Default::default(), | |
| 571 | 641 | }); |
| 572 | 642 | self.vertices.push(PathVertex { |
| 573 | 643 | xy_position: xy.1, |
| 574 | 644 | st_position: st.1, |
| 645 | + content_mask: Default::default(), | |
| 575 | 646 | }); |
| 576 | 647 | self.vertices.push(PathVertex { |
| 577 | 648 | xy_position: xy.2, |
| 578 | 649 | st_position: st.2, |
| 650 | + content_mask: Default::default(), | |
| 579 | 651 | }); |
| 580 | 652 | } |
| 581 | 653 | } |
| 582 | 654 | |
| 583 | −#[derive(Clone, Debug)] | |
| 655 | +impl Eq for Path<ScaledPixels> {} | |
| 656 | + | |
| 657 | +impl PartialEq for Path<ScaledPixels> { | |
| 658 | + fn eq(&self, other: &Self) -> bool { | |
| 659 | + self.order == other.order | |
| 660 | + } | |
| 661 | +} | |
| 662 | + | |
| 663 | +impl Ord for Path<ScaledPixels> { | |
| 664 | + fn cmp(&self, other: &Self) -> std::cmp::Ordering { | |
| 665 | + self.order.cmp(&other.order) | |
| 666 | + } | |
| 667 | +} | |
| 668 | + | |
| 669 | +impl PartialOrd for Path<ScaledPixels> { | |
| 670 | + fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { | |
| 671 | + Some(self.cmp(other)) | |
| 672 | + } | |
| 673 | +} | |
| 674 | + | |
| 675 | +impl From<Path<ScaledPixels>> for Primitive { | |
| 676 | + fn from(path: Path<ScaledPixels>) -> Self { | |
| 677 | + Primitive::Path(path) | |
| 678 | + } | |
| 679 | +} | |
| 680 | + | |
| 681 | +#[derive(Debug)] | |
| 584 | 682 | #[repr(C)] |
| 585 | −pub struct PathVertex { | |
| 586 | − pub xy_position: Point<Pixels>, | |
| 587 | − pub st_position: Point<f32>, | |
| 683 | +pub struct PathVertex<P: Clone + Debug> { | |
| 684 | + pub(crate) xy_position: Point<P>, | |
| 685 | + pub(crate) st_position: Point<f32>, | |
| 686 | + pub(crate) content_mask: ContentMask<P>, | |
| 687 | +} | |
| 688 | + | |
| 689 | +impl PathVertex<Pixels> { | |
| 690 | + pub fn scale(&self, factor: f32) -> PathVertex<ScaledPixels> { | |
| 691 | + PathVertex { | |
| 692 | + xy_position: self.xy_position.scale(factor), | |
| 693 | + st_position: self.st_position, | |
| 694 | + content_mask: self.content_mask.scale(factor), | |
| 695 | + } | |
| 696 | + } | |
| 588 | 697 | } |
| 589 | 698 | |
| 590 | 699 | #[derive(Copy, Clone, Debug)] |
| @@ -619,15 +728,15 @@ mod tests { · 28 unmodified lines | ||
| 619 | 728 | |
| 620 | 729 | #[test] |
| 621 | 730 | fn test_scene() { |
| 622 | − let mut scene = Scene::new(1.0); | |
| 623 | − assert_eq!(scene.layers.len(), 0); | |
| 731 | + let mut scene = SceneBuilder::new(); | |
| 732 | + assert_eq!(scene.layers_by_order.len(), 0); | |
| 624 | 733 | |
| 625 | − scene.insert(smallvec![1], quad()); | |
| 626 | − scene.insert(smallvec![2], shadow()); | |
| 627 | − scene.insert(smallvec![3], quad()); | |
| 734 | + scene.insert(&smallvec![1], quad()); | |
| 735 | + scene.insert(&smallvec![2], shadow()); | |
| 736 | + scene.insert(&smallvec![3], quad()); | |
| 628 | 737 | |
| 629 | 738 | let mut batches_count = 0; |
| 630 | − for _ in scene.batches() { | |
| 739 | + for _ in scene.build().batches() { | |
| 631 | 740 | batches_count += 1; |
| 632 | 741 | } |
| 633 | 742 | assert_eq!(batches_count, 3); |
| @@ -1,8 +1,8 @@ | ||
| 1 | 1 | use crate::{ |
| 2 | 2 | phi, point, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, ContentMask, Corners, |
| 3 | 3 | CornersRefinement, DefiniteLength, Edges, EdgesRefinement, Font, FontFeatures, FontStyle, |
| 4 | − FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Quad, Rems, Result, RunStyle, Shadow, | |
| 5 | − SharedString, Size, SizeRefinement, ViewContext, WindowContext, | |
| 4 | + FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rems, Result, RunStyle, SharedString, | |
| 5 | + Size, SizeRefinement, ViewContext, WindowContext, | |
| 6 | 6 | }; |
| 7 | 7 | use refineable::Refineable; |
| 8 | 8 | use smallvec::SmallVec; |
| @@ -243,51 +243,24 @@ impl Style { · 234 unmodified lines | ||
| 243 | 243 | /// Paints the background of an element styled with this style. |
| 244 | 244 | pub fn paint<V: 'static>(&self, bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) { |
| 245 | 245 | let rem_size = cx.rem_size(); |
| 246 | − let scale = cx.scale_factor(); | |
| 247 | − | |
| 248 | − for shadow in &self.box_shadow { | |
| 249 | − let content_mask = cx.content_mask(); | |
| 250 | − let mut shadow_bounds = bounds; | |
| 251 | − shadow_bounds.origin += shadow.offset; | |
| 252 | − shadow_bounds.dilate(shadow.spread_radius); | |
| 253 | − cx.stack(0, |cx| { | |
| 254 | − let layer_id = cx.current_stacking_order(); | |
| 255 | − cx.scene().insert( | |
| 256 | − layer_id, | |
| 257 | − Shadow { | |
| 258 | − order: 0, | |
| 259 | − bounds: shadow_bounds.scale(scale), | |
| 260 | − content_mask: content_mask.scale(scale), | |
| 261 | − corner_radii: self | |
| 262 | − .corner_radii | |
| 263 | − .to_pixels(shadow_bounds.size, rem_size) | |
| 264 | − .scale(scale), | |
| 265 | − color: shadow.color, | |
| 266 | − blur_radius: shadow.blur_radius.scale(scale), | |
| 267 | − }, | |
| 268 | − ); | |
| 269 | − }) | |
| 270 | − } | |
| 246 | + | |
| 247 | + cx.stack(0, |cx| { | |
| 248 | + cx.paint_shadows( | |
| 249 | + bounds, | |
| 250 | + self.corner_radii.to_pixels(bounds.size, rem_size), | |
| 251 | + &self.box_shadow, | |
| 252 | + ); | |
| 253 | + }); | |
| 271 | 254 | |
| 272 | 255 | let background_color = self.fill.as_ref().and_then(Fill::color); |
| 273 | 256 | if background_color.is_some() || self.is_border_visible() { |
| 274 | − let content_mask = cx.content_mask(); | |
| 275 | 257 | cx.stack(1, |cx| { |
| 276 | − let order = cx.current_stacking_order(); | |
| 277 | − cx.scene().insert( | |
| 278 | − order, | |
| 279 | − Quad { | |
| 280 | − order: 0, | |
| 281 | − bounds: bounds.scale(scale), | |
| 282 | − content_mask: content_mask.scale(scale), | |
| 283 | − background: background_color.unwrap_or_default(), | |
| 284 | − border_color: self.border_color.unwrap_or_default(), | |
| 285 | − corner_radii: self | |
| 286 | − .corner_radii | |
| 287 | − .to_pixels(bounds.size, rem_size) | |
| 288 | − .scale(scale), | |
| 289 | − border_widths: self.border_widths.to_pixels(rem_size).scale(scale), | |
| 290 | − }, | |
| 258 | + cx.paint_quad( | |
| 259 | + bounds, | |
| 260 | + self.corner_radii.to_pixels(bounds.size, rem_size), | |
| 261 | + background_color.unwrap_or_default(), | |
| 262 | + self.border_widths.to_pixels(rem_size), | |
| 263 | + self.border_color.unwrap_or_default(), | |
| 291 | 264 | ); |
| 292 | 265 | }); |
| 293 | 266 | } |
| @@ -1,15 +1,17 @@ | ||
| 1 | 1 | use crate::{ |
| 2 | 2 | image_cache::RenderImageParams, px, size, AnyView, AppContext, AsyncWindowContext, |
| 3 | − AvailableSpace, BorrowAppContext, Bounds, Context, Corners, DevicePixels, DisplayId, Effect, | |
| 4 | − Element, EntityId, FontId, GlyphId, Handle, Hsla, ImageData, IsZero, LayoutId, MainThread, | |
| 5 | − MainThreadOnly, MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, Point, | |
| 6 | − PolychromeSprite, Reference, RenderGlyphParams, RenderSvgParams, ScaledPixels, Scene, | |
| 7 | − SharedString, Size, StackingOrder, Style, TaffyLayoutEngine, Task, Underline, UnderlineStyle, | |
| 8 | − WeakHandle, WindowOptions, SUBPIXEL_VARIANTS, | |
| 3 | + AvailableSpace, BorrowAppContext, Bounds, BoxShadow, Context, Corners, DevicePixels, DisplayId, | |
| 4 | + Edges, Effect, Element, EntityId, FontId, GlyphId, Handle, Hsla, ImageData, IsZero, LayoutId, | |
| 5 | + MainThread, MainThreadOnly, MonochromeSprite, Path, Pixels, PlatformAtlas, PlatformWindow, | |
| 6 | + Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderSvgParams, ScaledPixels, | |
| 7 | + SceneBuilder, Shadow, SharedString, Size, StackingOrder, Style, TaffyLayoutEngine, Task, | |
| 8 | + Underline, UnderlineStyle, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS, | |
| 9 | 9 | }; |
| 10 | 10 | use anyhow::Result; |
| 11 | 11 | use smallvec::SmallVec; |
| 12 | −use std::{any::TypeId, borrow::Cow, future::Future, marker::PhantomData, mem, sync::Arc}; | |
| 12 | +use std::{ | |
| 13 | + any::TypeId, borrow::Cow, fmt::Debug, future::Future, marker::PhantomData, mem, sync::Arc, | |
| 14 | +}; | |
| 13 | 15 | use util::ResultExt; |
| 14 | 16 | |
| 15 | 17 | pub struct AnyWindow {} |
| @@ -25,8 +27,9 @@ pub struct Window { · 9 unmodified lines | ||
| 25 | 27 | pub(crate) root_view: Option<AnyView<()>>, |
| 26 | 28 | mouse_position: Point<Pixels>, |
| 27 | 29 | current_stacking_order: StackingOrder, |
| 28 | − content_mask_stack: Vec<ContentMask>, | |
| 29 | − pub(crate) scene: Scene, | |
| 30 | + content_mask_stack: Vec<ContentMask<Pixels>>, | |
| 31 | + scale_factor: f32, | |
| 32 | + pub(crate) scene_builder: SceneBuilder, | |
| 30 | 33 | pub(crate) dirty: bool, |
| 31 | 34 | } |
| 32 | 35 | |
| @@ -47,7 +50,8 @@ impl Window { · 14 unmodified lines | ||
| 47 | 50 | let cx = cx.to_async(); |
| 48 | 51 | move |content_size, scale_factor| { |
| 49 | 52 | cx.update_window(handle, |cx| { |
| 50 | − cx.window.scene = Scene::new(scale_factor); | |
| 53 | + cx.window.scale_factor = scale_factor; | |
| 54 | + cx.window.scene_builder = SceneBuilder::new(); | |
| 51 | 55 | cx.window.content_size = content_size; |
| 52 | 56 | cx.window.display_id = cx |
| 53 | 57 | .window |
| @@ -75,20 +79,22 @@ impl Window { · 21 unmodified lines | ||
| 75 | 79 | mouse_position, |
| 76 | 80 | current_stacking_order: SmallVec::new(), |
| 77 | 81 | content_mask_stack: Vec::new(), |
| 78 | − scene: Scene::new(scale_factor), | |
| 82 | + scale_factor, | |
| 83 | + scene_builder: SceneBuilder::new(), | |
| 79 | 84 | dirty: true, |
| 80 | 85 | } |
| 81 | 86 | } |
| 82 | 87 | } |
| 83 | 88 | |
| 84 | −#[derive(Clone, Debug)] | |
| 85 | −pub struct ContentMask { | |
| 86 | − pub bounds: Bounds<Pixels>, | |
| 89 | +#[derive(Clone, Debug, Default, PartialEq, Eq)] | |
| 90 | +#[repr(C)] | |
| 91 | +pub struct ContentMask<P: Clone + Debug> { | |
| 92 | + pub bounds: Bounds<P>, | |
| 87 | 93 | } |
| 88 | 94 | |
| 89 | −impl ContentMask { | |
| 90 | − pub fn scale(&self, factor: f32) -> ScaledContentMask { | |
| 91 | − ScaledContentMask { | |
| 95 | +impl ContentMask<Pixels> { | |
| 96 | + pub fn scale(&self, factor: f32) -> ContentMask<ScaledPixels> { | |
| 97 | + ContentMask { | |
| 92 | 98 | bounds: self.bounds.scale(factor), |
| 93 | 99 | } |
| 94 | 100 | } |
| @@ -99,12 +105,6 @@ impl ContentMask { · 4 unmodified lines | ||
| 99 | 105 | } |
| 100 | 106 | } |
| 101 | 107 | |
| 102 | −#[derive(Default, Clone, Debug, PartialEq, Eq)] | |
| 103 | −#[repr(C)] | |
| 104 | −pub struct ScaledContentMask { | |
| 105 | − bounds: Bounds<ScaledPixels>, | |
| 106 | −} | |
| 107 | − | |
| 108 | 108 | pub struct WindowContext<'a, 'w> { |
| 109 | 109 | app: Reference<'a, AppContext>, |
| 110 | 110 | window: Reference<'w, Window>, |
| @@ -234,7 +234,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 123 unmodified lines | ||
| 234 | 234 | } |
| 235 | 235 | |
| 236 | 236 | pub fn scale_factor(&self) -> f32 { |
| 237 | − self.window.scene.scale_factor | |
| 237 | + self.window.scale_factor | |
| 238 | 238 | } |
| 239 | 239 | |
| 240 | 240 | pub fn rem_size(&self) -> Pixels { |
| @@ -245,10 +245,6 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 4 unmodified lines | ||
| 245 | 245 | self.window.mouse_position |
| 246 | 246 | } |
| 247 | 247 | |
| 248 | − pub fn scene(&mut self) -> &mut Scene { | |
| 249 | − &mut self.window.scene | |
| 250 | − } | |
| 251 | − | |
| 252 | 248 | pub fn stack<R>(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R { |
| 253 | 249 | self.window.current_stacking_order.push(order); |
| 254 | 250 | let result = f(self); |
| @@ -256,8 +252,69 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 1 unmodified line | ||
| 256 | 252 | result |
| 257 | 253 | } |
| 258 | 254 | |
| 259 | − pub fn current_stacking_order(&self) -> StackingOrder { | |
| 260 | − self.window.current_stacking_order.clone() | |
| 255 | + pub fn paint_shadows( | |
| 256 | + &mut self, | |
| 257 | + bounds: Bounds<Pixels>, | |
| 258 | + corner_radii: Corners<Pixels>, | |
| 259 | + shadows: &[BoxShadow], | |
| 260 | + ) { | |
| 261 | + let scale_factor = self.scale_factor(); | |
| 262 | + let content_mask = self.content_mask(); | |
| 263 | + let window = &mut *self.window; | |
| 264 | + for shadow in shadows { | |
| 265 | + let mut shadow_bounds = bounds; | |
| 266 | + shadow_bounds.origin += shadow.offset; | |
| 267 | + shadow_bounds.dilate(shadow.spread_radius); | |
| 268 | + window.scene_builder.insert( | |
| 269 | + &window.current_stacking_order, | |
| 270 | + Shadow { | |
| 271 | + order: 0, | |
| 272 | + bounds: shadow_bounds.scale(scale_factor), | |
| 273 | + content_mask: content_mask.scale(scale_factor), | |
| 274 | + corner_radii: corner_radii.scale(scale_factor), | |
| 275 | + color: shadow.color, | |
| 276 | + blur_radius: shadow.blur_radius.scale(scale_factor), | |
| 277 | + }, | |
| 278 | + ); | |
| 279 | + } | |
| 280 | + } | |
| 281 | + | |
| 282 | + pub fn paint_quad( | |
| 283 | + &mut self, | |
| 284 | + bounds: Bounds<Pixels>, | |
| 285 | + corner_radii: Corners<Pixels>, | |
| 286 | + background: impl Into<Hsla>, | |
| 287 | + border_widths: Edges<Pixels>, | |
| 288 | + border_color: impl Into<Hsla>, | |
| 289 | + ) { | |
| 290 | + let scale_factor = self.scale_factor(); | |
| 291 | + let content_mask = self.content_mask(); | |
| 292 | + | |
| 293 | + let window = &mut *self.window; | |
| 294 | + window.scene_builder.insert( | |
| 295 | + &window.current_stacking_order, | |
| 296 | + Quad { | |
| 297 | + order: 0, | |
| 298 | + bounds: bounds.scale(scale_factor), | |
| 299 | + content_mask: content_mask.scale(scale_factor), | |
| 300 | + background: background.into(), | |
| 301 | + border_color: border_color.into(), | |
| 302 | + corner_radii: corner_radii.scale(scale_factor), | |
| 303 | + border_widths: border_widths.scale(scale_factor), | |
| 304 | + }, | |
| 305 | + ); | |
| 306 | + } | |
| 307 | + | |
| 308 | + pub fn paint_path(&mut self, mut path: Path<Pixels>) { | |
| 309 | + let scale_factor = self.scale_factor(); | |
| 310 | + let content_mask = self.content_mask(); | |
| 311 | + for vertex in &mut path.vertices { | |
| 312 | + vertex.content_mask = content_mask.clone(); | |
| 313 | + } | |
| 314 | + let window = &mut *self.window; | |
| 315 | + window | |
| 316 | + .scene_builder | |
| 317 | + .insert(&window.current_stacking_order, path.scale(scale_factor)); | |
| 261 | 318 | } |
| 262 | 319 | |
| 263 | 320 | pub fn paint_underline( |
| @@ -277,9 +334,9 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 13 unmodified lines | ||
| 277 | 334 | size: size(width, height), |
| 278 | 335 | }; |
| 279 | 336 | let content_mask = self.content_mask(); |
| 280 | − let layer_id = self.current_stacking_order(); | |
| 281 | − self.window.scene.insert( | |
| 282 | − layer_id, | |
| 337 | + let window = &mut *self.window; | |
| 338 | + window.scene_builder.insert( | |
| 339 | + &window.current_stacking_order, | |
| 283 | 340 | Underline { |
| 284 | 341 | order: 0, |
| 285 | 342 | bounds: bounds.scale(scale_factor), |
| @@ -317,7 +374,6 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 31 unmodified lines | ||
| 317 | 374 | |
| 318 | 375 | let raster_bounds = self.text_system().raster_bounds(¶ms)?; |
| 319 | 376 | if !raster_bounds.is_zero() { |
| 320 | − let layer_id = self.current_stacking_order(); | |
| 321 | 377 | let tile = |
| 322 | 378 | self.window |
| 323 | 379 | .sprite_atlas |
| @@ -330,9 +386,9 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 6 unmodified lines | ||
| 330 | 386 | size: tile.bounds.size.map(Into::into), |
| 331 | 387 | }; |
| 332 | 388 | let content_mask = self.content_mask().scale(scale_factor); |
| 333 | − | |
| 334 | − self.window.scene.insert( | |
| 335 | − layer_id, | |
| 389 | + let window = &mut *self.window; | |
| 390 | + window.scene_builder.insert( | |
| 391 | + &window.current_stacking_order, | |
| 336 | 392 | MonochromeSprite { |
| 337 | 393 | order: 0, |
| 338 | 394 | bounds, |
| @@ -366,7 +422,6 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 27 unmodified lines | ||
| 366 | 422 | |
| 367 | 423 | let raster_bounds = self.text_system().raster_bounds(¶ms)?; |
| 368 | 424 | if !raster_bounds.is_zero() { |
| 369 | − let layer_id = self.current_stacking_order(); | |
| 370 | 425 | let tile = |
| 371 | 426 | self.window |
| 372 | 427 | .sprite_atlas |
| @@ -379,9 +434,10 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 6 unmodified lines | ||
| 379 | 434 | size: tile.bounds.size.map(Into::into), |
| 380 | 435 | }; |
| 381 | 436 | let content_mask = self.content_mask().scale(scale_factor); |
| 437 | + let window = &mut *self.window; | |
| 382 | 438 | |
| 383 | − self.window.scene.insert( | |
| 384 | − layer_id, | |
| 439 | + window.scene_builder.insert( | |
| 440 | + &window.current_stacking_order, | |
| 385 | 441 | PolychromeSprite { |
| 386 | 442 | order: 0, |
| 387 | 443 | bounds, |
| @@ -411,7 +467,6 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 23 unmodified lines | ||
| 411 | 467 | .map(|pixels| DevicePixels::from((pixels.0 * 2.).ceil() as i32)), |
| 412 | 468 | }; |
| 413 | 469 | |
| 414 | − let layer_id = self.current_stacking_order(); | |
| 415 | 470 | let tile = |
| 416 | 471 | self.window |
| 417 | 472 | .sprite_atlas |
| @@ -421,8 +476,9 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 3 unmodified lines | ||
| 421 | 476 | })?; |
| 422 | 477 | let content_mask = self.content_mask().scale(scale_factor); |
| 423 | 478 | |
| 424 | − self.window.scene.insert( | |
| 425 | − layer_id, | |
| 479 | + let window = &mut *self.window; | |
| 480 | + window.scene_builder.insert( | |
| 481 | + &window.current_stacking_order, | |
| 426 | 482 | MonochromeSprite { |
| 427 | 483 | order: 0, |
| 428 | 484 | bounds, |
| @@ -446,7 +502,6 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 17 unmodified lines | ||
| 446 | 502 | let bounds = bounds.scale(scale_factor); |
| 447 | 503 | let params = RenderImageParams { image_id: data.id }; |
| 448 | 504 | |
| 449 | − let order = self.current_stacking_order(); | |
| 450 | 505 | let tile = self |
| 451 | 506 | .window |
| 452 | 507 | .sprite_atlas |
| @@ -456,8 +511,9 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 3 unmodified lines | ||
| 456 | 511 | let content_mask = self.content_mask().scale(scale_factor); |
| 457 | 512 | let corner_radii = corner_radii.scale(scale_factor); |
| 458 | 513 | |
| 459 | − self.window.scene.insert( | |
| 460 | − order, | |
| 514 | + let window = &mut *self.window; | |
| 515 | + window.scene_builder.insert( | |
| 516 | + &window.current_stacking_order, | |
| 461 | 517 | PolychromeSprite { |
| 462 | 518 | order: 0, |
| 463 | 519 | bounds, |
| @@ -467,7 +523,6 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 3 unmodified lines | ||
| 467 | 523 | grayscale, |
| 468 | 524 | }, |
| 469 | 525 | ); |
| 470 | − | |
| 471 | 526 | Ok(()) |
| 472 | 527 | } |
| 473 | 528 | |
| @@ -485,7 +540,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 11 unmodified lines | ||
| 485 | 540 | |
| 486 | 541 | root_view.paint(layout, &mut (), &mut frame_state, cx)?; |
| 487 | 542 | cx.window.root_view = Some(root_view); |
| 488 | − let scene = cx.window.scene.take(); | |
| 543 | + let scene = cx.window.scene_builder.build(); | |
| 489 | 544 | |
| 490 | 545 | cx.run_on_main(view, |_, cx| { |
| 491 | 546 | cx.window |
| @@ -557,7 +612,11 @@ pub trait BorrowWindow: BorrowAppContext { · 65 unmodified lines | ||
| 557 | 612 | fn window(&self) -> &Window; |
| 558 | 613 | fn window_mut(&mut self) -> &mut Window; |
| 559 | 614 | |
| 560 | − fn with_content_mask<R>(&mut self, mask: ContentMask, f: impl FnOnce(&mut Self) -> R) -> R { | |
| 615 | + fn with_content_mask<R>( | |
| 616 | + &mut self, | |
| 617 | + mask: ContentMask<Pixels>, | |
| 618 | + f: impl FnOnce(&mut Self) -> R, | |
| 619 | + ) -> R { | |
| 561 | 620 | let mask = mask.intersect(&self.content_mask()); |
| 562 | 621 | self.window_mut().content_mask_stack.push(mask); |
| 563 | 622 | let result = f(self); |
| @@ -565,7 +624,7 @@ pub trait BorrowWindow: BorrowAppContext { · 1 unmodified line | ||
| 565 | 624 | result |
| 566 | 625 | } |
| 567 | 626 | |
| 568 | − fn content_mask(&self) -> ContentMask { | |
| 627 | + fn content_mask(&self) -> ContentMask<Pixels> { | |
| 569 | 628 | self.window() |
| 570 | 629 | .content_mask_stack |
| 571 | 630 | .last() |