mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-10 14:06:11 +03:00
Checkpoint
This commit is contained in:
parent
6a4c2a0d40
commit
d889cdecde
@ -47,7 +47,7 @@ fn generate_shader_bindings() -> PathBuf {
|
||||
"Pixels".into(),
|
||||
"PointF".into(),
|
||||
"Hsla".into(),
|
||||
"ScaledContentMask".into(),
|
||||
"ContentMask".into(),
|
||||
"Uniforms".into(),
|
||||
"AtlasTile".into(),
|
||||
"ShadowInputIndex".into(),
|
||||
|
@ -40,7 +40,7 @@ pub(crate) fn current_platform() -> Arc<dyn Platform> {
|
||||
Arc::new(MacPlatform::new())
|
||||
}
|
||||
|
||||
pub trait Platform: 'static {
|
||||
pub(crate) trait Platform: 'static {
|
||||
fn executor(&self) -> Executor;
|
||||
fn display_linker(&self) -> Arc<dyn PlatformDisplayLinker>;
|
||||
fn text_system(&self) -> Arc<dyn PlatformTextSystem>;
|
||||
@ -113,7 +113,7 @@ impl Debug for DisplayId {
|
||||
|
||||
unsafe impl Send for DisplayId {}
|
||||
|
||||
pub trait PlatformWindow {
|
||||
pub(crate) trait PlatformWindow {
|
||||
fn bounds(&self) -> WindowBounds;
|
||||
fn content_size(&self) -> Size<Pixels>;
|
||||
fn scale_factor(&self) -> f32;
|
||||
@ -194,11 +194,17 @@ pub enum AtlasKey {
|
||||
}
|
||||
|
||||
impl AtlasKey {
|
||||
pub fn is_monochrome(&self) -> bool {
|
||||
pub(crate) fn texture_kind(&self) -> AtlasTextureKind {
|
||||
match self {
|
||||
AtlasKey::Glyph(params) => !params.is_emoji,
|
||||
AtlasKey::Svg(_) => true,
|
||||
AtlasKey::Image(_) => false,
|
||||
AtlasKey::Glyph(params) => {
|
||||
if params.is_emoji {
|
||||
AtlasTextureKind::Polychrome
|
||||
} else {
|
||||
AtlasTextureKind::Monochrome
|
||||
}
|
||||
}
|
||||
AtlasKey::Svg(_) => AtlasTextureKind::Monochrome,
|
||||
AtlasKey::Image(_) => AtlasTextureKind::Polychrome,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -241,7 +247,19 @@ pub struct AtlasTile {
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct AtlasTextureId(pub(crate) u32); // We use u32 instead of usize for Metal Shader Language compatibility
|
||||
pub(crate) struct AtlasTextureId {
|
||||
// We use u32 instead of usize for Metal Shader Language compatibility
|
||||
pub(crate) index: u32,
|
||||
pub(crate) kind: AtlasTextureKind,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
pub(crate) enum AtlasTextureKind {
|
||||
Monochrome = 0,
|
||||
Polychrome = 1,
|
||||
Path = 2,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[repr(C)]
|
||||
|
@ -1,14 +1,14 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::{
|
||||
AtlasKey, AtlasTextureId, AtlasTile, Bounds, DevicePixels, PlatformAtlas, Point, Size,
|
||||
AtlasKey, AtlasTextureId, AtlasTextureKind, AtlasTile, Bounds, DevicePixels, PlatformAtlas,
|
||||
Point, Size,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use anyhow::Result;
|
||||
use collections::HashMap;
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use etagere::BucketedAtlasAllocator;
|
||||
use metal::Device;
|
||||
use parking_lot::Mutex;
|
||||
use std::borrow::Cow;
|
||||
|
||||
pub struct MetalAtlas(Mutex<MetalAtlasState>);
|
||||
|
||||
@ -16,19 +16,31 @@ impl MetalAtlas {
|
||||
pub fn new(device: Device) -> Self {
|
||||
MetalAtlas(Mutex::new(MetalAtlasState {
|
||||
device: AssertSend(device),
|
||||
textures: Default::default(),
|
||||
monochrome_textures: Default::default(),
|
||||
polychrome_textures: Default::default(),
|
||||
path_textures: Default::default(),
|
||||
tiles_by_key: Default::default(),
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn texture(&self, id: AtlasTextureId) -> metal::Texture {
|
||||
self.0.lock().textures[id.0 as usize].metal_texture.clone()
|
||||
pub(crate) fn metal_texture(&self, id: AtlasTextureId) -> metal::Texture {
|
||||
self.0.lock().texture(id).metal_texture.clone()
|
||||
}
|
||||
|
||||
pub(crate) fn allocate(
|
||||
&self,
|
||||
size: Size<DevicePixels>,
|
||||
texture_kind: AtlasTextureKind,
|
||||
) -> AtlasTile {
|
||||
self.0.lock().allocate(size, texture_kind)
|
||||
}
|
||||
}
|
||||
|
||||
struct MetalAtlasState {
|
||||
device: AssertSend<Device>,
|
||||
textures: Vec<MetalAtlasTexture>,
|
||||
monochrome_textures: Vec<MetalAtlasTexture>,
|
||||
polychrome_textures: Vec<MetalAtlasTexture>,
|
||||
path_textures: Vec<MetalAtlasTexture>,
|
||||
tiles_by_key: HashMap<AtlasKey, AtlasTile>,
|
||||
}
|
||||
|
||||
@ -43,23 +55,9 @@ impl PlatformAtlas for MetalAtlas {
|
||||
return Ok(tile.clone());
|
||||
} else {
|
||||
let (size, bytes) = build()?;
|
||||
let tile = lock
|
||||
.textures
|
||||
.iter_mut()
|
||||
.rev()
|
||||
.find_map(|texture| {
|
||||
if texture.monochrome == key.is_monochrome() {
|
||||
texture.upload(size, &bytes)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.or_else(|| {
|
||||
let texture = lock.push_texture(size, key.is_monochrome());
|
||||
texture.upload(size, &bytes)
|
||||
})
|
||||
.ok_or_else(|| anyhow!("could not allocate in new texture"))?;
|
||||
lock.tiles_by_key.insert(key.clone(), tile.clone());
|
||||
let tile = lock.allocate(size, key.texture_kind());
|
||||
let texture = lock.texture(tile.texture_id);
|
||||
texture.upload(tile.bounds, &bytes);
|
||||
Ok(tile)
|
||||
}
|
||||
}
|
||||
@ -70,10 +68,26 @@ impl PlatformAtlas for MetalAtlas {
|
||||
}
|
||||
|
||||
impl MetalAtlasState {
|
||||
fn allocate(&mut self, size: Size<DevicePixels>, texture_kind: AtlasTextureKind) -> AtlasTile {
|
||||
let textures = match texture_kind {
|
||||
AtlasTextureKind::Monochrome => &mut self.monochrome_textures,
|
||||
AtlasTextureKind::Polychrome => &mut self.polychrome_textures,
|
||||
AtlasTextureKind::Path => &mut self.path_textures,
|
||||
};
|
||||
textures
|
||||
.iter_mut()
|
||||
.rev()
|
||||
.find_map(|texture| texture.allocate(size))
|
||||
.unwrap_or_else(|| {
|
||||
let texture = self.push_texture(size, texture_kind);
|
||||
texture.allocate(size).unwrap()
|
||||
})
|
||||
}
|
||||
|
||||
fn push_texture(
|
||||
&mut self,
|
||||
min_size: Size<DevicePixels>,
|
||||
monochrome: bool,
|
||||
kind: AtlasTextureKind,
|
||||
) -> &mut MetalAtlasTexture {
|
||||
const DEFAULT_ATLAS_SIZE: Size<DevicePixels> = Size {
|
||||
width: DevicePixels(1024),
|
||||
@ -84,21 +98,38 @@ impl MetalAtlasState {
|
||||
let texture_descriptor = metal::TextureDescriptor::new();
|
||||
texture_descriptor.set_width(size.width.into());
|
||||
texture_descriptor.set_height(size.height.into());
|
||||
if monochrome {
|
||||
texture_descriptor.set_pixel_format(metal::MTLPixelFormat::A8Unorm);
|
||||
} else {
|
||||
texture_descriptor.set_pixel_format(metal::MTLPixelFormat::BGRA8Unorm);
|
||||
}
|
||||
let pixel_format = match kind {
|
||||
AtlasTextureKind::Monochrome => metal::MTLPixelFormat::A8Unorm,
|
||||
AtlasTextureKind::Polychrome => metal::MTLPixelFormat::BGRA8Unorm,
|
||||
AtlasTextureKind::Path => metal::MTLPixelFormat::R16Float,
|
||||
};
|
||||
texture_descriptor.set_pixel_format(pixel_format);
|
||||
let metal_texture = self.device.new_texture(&texture_descriptor);
|
||||
|
||||
let textures = match kind {
|
||||
AtlasTextureKind::Monochrome => &mut self.monochrome_textures,
|
||||
AtlasTextureKind::Polychrome => &mut self.polychrome_textures,
|
||||
AtlasTextureKind::Path => &mut self.path_textures,
|
||||
};
|
||||
let atlas_texture = MetalAtlasTexture {
|
||||
id: AtlasTextureId(self.textures.len() as u32),
|
||||
id: AtlasTextureId {
|
||||
index: textures.len() as u32,
|
||||
kind,
|
||||
},
|
||||
allocator: etagere::BucketedAtlasAllocator::new(size.into()),
|
||||
metal_texture: AssertSend(metal_texture),
|
||||
monochrome,
|
||||
};
|
||||
self.textures.push(atlas_texture);
|
||||
self.textures.last_mut().unwrap()
|
||||
textures.push(atlas_texture);
|
||||
textures.last_mut().unwrap()
|
||||
}
|
||||
|
||||
fn texture(&self, id: AtlasTextureId) -> &MetalAtlasTexture {
|
||||
let textures = match id.kind {
|
||||
crate::AtlasTextureKind::Monochrome => &self.monochrome_textures,
|
||||
crate::AtlasTextureKind::Polychrome => &self.polychrome_textures,
|
||||
crate::AtlasTextureKind::Path => &self.path_textures,
|
||||
};
|
||||
&textures[id.index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,11 +137,10 @@ struct MetalAtlasTexture {
|
||||
id: AtlasTextureId,
|
||||
allocator: BucketedAtlasAllocator,
|
||||
metal_texture: AssertSend<metal::Texture>,
|
||||
monochrome: bool,
|
||||
}
|
||||
|
||||
impl MetalAtlasTexture {
|
||||
fn upload(&mut self, size: Size<DevicePixels>, bytes: &[u8]) -> Option<AtlasTile> {
|
||||
fn allocate(&mut self, size: Size<DevicePixels>) -> Option<AtlasTile> {
|
||||
let allocation = self.allocator.allocate(size.into())?;
|
||||
let tile = AtlasTile {
|
||||
texture_id: self.id,
|
||||
@ -120,20 +150,22 @@ impl MetalAtlasTexture {
|
||||
size,
|
||||
},
|
||||
};
|
||||
Some(tile)
|
||||
}
|
||||
|
||||
fn upload(&self, bounds: Bounds<DevicePixels>, bytes: &[u8]) {
|
||||
let region = metal::MTLRegion::new_2d(
|
||||
tile.bounds.origin.x.into(),
|
||||
tile.bounds.origin.y.into(),
|
||||
tile.bounds.size.width.into(),
|
||||
tile.bounds.size.height.into(),
|
||||
bounds.origin.x.into(),
|
||||
bounds.origin.y.into(),
|
||||
bounds.size.width.into(),
|
||||
bounds.size.height.into(),
|
||||
);
|
||||
self.metal_texture.replace_region(
|
||||
region,
|
||||
0,
|
||||
bytes.as_ptr() as *const _,
|
||||
u32::from(tile.bounds.size.width.to_bytes(self.bytes_per_pixel())) as u64,
|
||||
u32::from(bounds.size.width.to_bytes(self.bytes_per_pixel())) as u64,
|
||||
);
|
||||
Some(tile)
|
||||
}
|
||||
|
||||
fn bytes_per_pixel(&self) -> u8 {
|
||||
|
@ -1,12 +1,14 @@
|
||||
use crate::{
|
||||
point, size, AtlasTextureId, DevicePixels, MetalAtlas, MonochromeSprite, PolychromeSprite,
|
||||
PrimitiveBatch, Quad, Scene, Shadow, Size, Underline,
|
||||
point, size, AtlasTextureId, AtlasTextureKind, AtlasTile, DevicePixels, MetalAtlas,
|
||||
MonochromeSprite, PathId, PolychromeSprite, PrimitiveBatch, Quad, Scene, Shadow, Size,
|
||||
Underline,
|
||||
};
|
||||
use cocoa::{
|
||||
base::{NO, YES},
|
||||
foundation::NSUInteger,
|
||||
quartzcore::AutoresizingMask,
|
||||
};
|
||||
use collections::HashMap;
|
||||
use metal::{CommandQueue, MTLPixelFormat, MTLResourceOptions, NSRange};
|
||||
use objc::{self, msg_send, sel, sel_impl};
|
||||
use std::{ffi::c_void, mem, ptr, sync::Arc};
|
||||
@ -14,7 +16,7 @@ use std::{ffi::c_void, mem, ptr, sync::Arc};
|
||||
const SHADERS_METALLIB: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib"));
|
||||
const INSTANCE_BUFFER_SIZE: usize = 8192 * 1024; // This is an arbitrary decision. There's probably a more optimal value.
|
||||
|
||||
pub struct MetalRenderer {
|
||||
pub(crate) struct MetalRenderer {
|
||||
layer: metal::MetalLayer,
|
||||
command_queue: CommandQueue,
|
||||
shadows_pipeline_state: metal::RenderPipelineState,
|
||||
@ -150,7 +152,7 @@ impl MetalRenderer {
|
||||
&self.sprite_atlas
|
||||
}
|
||||
|
||||
pub fn draw(&mut self, scene: &mut Scene) {
|
||||
pub fn draw(&mut self, scene: &Scene) {
|
||||
let layer = self.layer.clone();
|
||||
let viewport_size = layer.drawable_size();
|
||||
let viewport_size: Size<DevicePixels> = size(
|
||||
@ -192,6 +194,15 @@ impl MetalRenderer {
|
||||
});
|
||||
|
||||
let mut instance_offset = 0;
|
||||
|
||||
let mut path_tiles: HashMap<PathId, AtlasTile> = HashMap::default();
|
||||
for path in scene.paths() {
|
||||
let tile = self
|
||||
.sprite_atlas
|
||||
.allocate(path.bounds.size.map(Into::into), AtlasTextureKind::Path);
|
||||
path_tiles.insert(path.id, tile);
|
||||
}
|
||||
|
||||
for batch in scene.batches() {
|
||||
match batch {
|
||||
PrimitiveBatch::Shadows(shadows) => {
|
||||
@ -205,6 +216,9 @@ impl MetalRenderer {
|
||||
PrimitiveBatch::Quads(quads) => {
|
||||
self.draw_quads(quads, &mut instance_offset, viewport_size, command_encoder);
|
||||
}
|
||||
PrimitiveBatch::Paths(paths) => {
|
||||
// self.draw_paths(paths, &mut instance_offset, viewport_size, command_encoder);
|
||||
}
|
||||
PrimitiveBatch::Underlines(underlines) => {
|
||||
self.draw_underlines(
|
||||
underlines,
|
||||
@ -441,7 +455,7 @@ impl MetalRenderer {
|
||||
}
|
||||
align_offset(offset);
|
||||
|
||||
let texture = self.sprite_atlas.texture(texture_id);
|
||||
let texture = self.sprite_atlas.metal_texture(texture_id);
|
||||
let texture_size = size(
|
||||
DevicePixels(texture.width() as i32),
|
||||
DevicePixels(texture.height() as i32),
|
||||
@ -512,7 +526,7 @@ impl MetalRenderer {
|
||||
}
|
||||
align_offset(offset);
|
||||
|
||||
let texture = self.sprite_atlas.texture(texture_id);
|
||||
let texture = self.sprite_atlas.metal_texture(texture_id);
|
||||
let texture_size = size(
|
||||
DevicePixels(texture.width() as i32),
|
||||
DevicePixels(texture.height() as i32),
|
||||
|
@ -911,7 +911,7 @@ impl PlatformWindow for MacWindow {
|
||||
}
|
||||
}
|
||||
|
||||
fn draw(&self, scene: crate::Scene) {
|
||||
fn draw(&self, scene: Scene) {
|
||||
let mut this = self.0.lock();
|
||||
this.scene_to_render = Some(scene);
|
||||
unsafe {
|
||||
@ -1395,8 +1395,8 @@ extern "C" fn display_layer(this: &Object, _: Sel, _: id) {
|
||||
unsafe {
|
||||
let window_state = get_window_state(this);
|
||||
let mut window_state = window_state.as_ref().lock();
|
||||
if let Some(mut scene) = window_state.scene_to_render.take() {
|
||||
window_state.renderer.draw(&mut scene);
|
||||
if let Some(scene) = window_state.scene_to_render.take() {
|
||||
window_state.renderer.draw(&scene);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,12 @@
|
||||
use crate::{
|
||||
point, px, AtlasTextureId, AtlasTile, Bounds, Corners, Edges, Hsla, Pixels, Point,
|
||||
ScaledContentMask, ScaledPixels,
|
||||
point, AtlasTextureId, AtlasTile, Bounds, ContentMask, Corners, Edges, Hsla, Pixels, Point,
|
||||
ScaledPixels,
|
||||
};
|
||||
use collections::BTreeMap;
|
||||
use etagere::euclid::{Point3D, Vector3D};
|
||||
use plane_split::{BspSplitter, Polygon as BspPolygon};
|
||||
use smallvec::SmallVec;
|
||||
use std::{
|
||||
iter::Peekable,
|
||||
mem, slice,
|
||||
sync::atomic::{AtomicU32, Ordering::SeqCst},
|
||||
};
|
||||
use std::{fmt::Debug, iter::Peekable, mem, slice};
|
||||
|
||||
// Exported to metal
|
||||
pub type PointF = Point<f32>;
|
||||
@ -18,45 +14,131 @@ pub type StackingOrder = SmallVec<[u32; 16]>;
|
||||
pub type LayerId = u32;
|
||||
pub type DrawOrder = u32;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Scene {
|
||||
pub(crate) scale_factor: f32,
|
||||
pub(crate) layers: BTreeMap<StackingOrder, LayerId>,
|
||||
pub shadows: Vec<Shadow>,
|
||||
pub quads: Vec<Quad>,
|
||||
pub underlines: Vec<Underline>,
|
||||
pub monochrome_sprites: Vec<MonochromeSprite>,
|
||||
pub polychrome_sprites: Vec<PolychromeSprite>,
|
||||
pub(crate) struct SceneBuilder {
|
||||
layers_by_order: BTreeMap<StackingOrder, LayerId>,
|
||||
splitter: BspSplitter<(PrimitiveKind, usize)>,
|
||||
shadows: Vec<Shadow>,
|
||||
quads: Vec<Quad>,
|
||||
paths: Vec<Path<ScaledPixels>>,
|
||||
underlines: Vec<Underline>,
|
||||
monochrome_sprites: Vec<MonochromeSprite>,
|
||||
polychrome_sprites: Vec<PolychromeSprite>,
|
||||
}
|
||||
|
||||
impl Scene {
|
||||
pub fn new(scale_factor: f32) -> Scene {
|
||||
Scene {
|
||||
scale_factor,
|
||||
layers: BTreeMap::new(),
|
||||
impl SceneBuilder {
|
||||
pub fn new() -> SceneBuilder {
|
||||
SceneBuilder {
|
||||
layers_by_order: BTreeMap::new(),
|
||||
splitter: BspSplitter::new(),
|
||||
shadows: Vec::new(),
|
||||
quads: Vec::new(),
|
||||
paths: Vec::new(),
|
||||
underlines: Vec::new(),
|
||||
monochrome_sprites: Vec::new(),
|
||||
polychrome_sprites: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn take(&mut self) -> Scene {
|
||||
pub fn build(&mut self) -> Scene {
|
||||
// Map each layer id to a float between 0. and 1., with 1. closer to the viewer.
|
||||
let mut layer_z_values = vec![0.; self.layers_by_order.len()];
|
||||
for (ix, layer_id) in self.layers_by_order.values().enumerate() {
|
||||
layer_z_values[*layer_id as usize] = ix as f32 / self.layers_by_order.len() as f32;
|
||||
}
|
||||
self.layers_by_order.clear();
|
||||
|
||||
// Add all primitives to the BSP splitter to determine draw order
|
||||
self.splitter.reset();
|
||||
|
||||
for (ix, shadow) in self.shadows.iter().enumerate() {
|
||||
let z = layer_z_values[shadow.order as LayerId as usize];
|
||||
self.splitter
|
||||
.add(shadow.bounds.to_bsp_polygon(z, (PrimitiveKind::Shadow, ix)));
|
||||
}
|
||||
|
||||
for (ix, quad) in self.quads.iter().enumerate() {
|
||||
let z = layer_z_values[quad.order as LayerId as usize];
|
||||
self.splitter
|
||||
.add(quad.bounds.to_bsp_polygon(z, (PrimitiveKind::Quad, ix)));
|
||||
}
|
||||
|
||||
for (ix, underline) in self.underlines.iter().enumerate() {
|
||||
let z = layer_z_values[underline.order as LayerId as usize];
|
||||
self.splitter.add(
|
||||
underline
|
||||
.bounds
|
||||
.to_bsp_polygon(z, (PrimitiveKind::Underline, ix)),
|
||||
);
|
||||
}
|
||||
|
||||
for (ix, monochrome_sprite) in self.monochrome_sprites.iter().enumerate() {
|
||||
let z = layer_z_values[monochrome_sprite.order as LayerId as usize];
|
||||
self.splitter.add(
|
||||
monochrome_sprite
|
||||
.bounds
|
||||
.to_bsp_polygon(z, (PrimitiveKind::MonochromeSprite, ix)),
|
||||
);
|
||||
}
|
||||
|
||||
for (ix, polychrome_sprite) in self.polychrome_sprites.iter().enumerate() {
|
||||
let z = layer_z_values[polychrome_sprite.order as LayerId as usize];
|
||||
self.splitter.add(
|
||||
polychrome_sprite
|
||||
.bounds
|
||||
.to_bsp_polygon(z, (PrimitiveKind::PolychromeSprite, ix)),
|
||||
);
|
||||
}
|
||||
|
||||
// Sort all polygons, then reassign the order field of each primitive to `draw_order`
|
||||
// We need primitives to be repr(C), hence the weird reuse of the order field for two different types.
|
||||
for (draw_order, polygon) in self
|
||||
.splitter
|
||||
.sort(Vector3D::new(0., 0., 1.))
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
match polygon.anchor {
|
||||
(PrimitiveKind::Shadow, ix) => self.shadows[ix].order = draw_order as DrawOrder,
|
||||
(PrimitiveKind::Quad, ix) => self.quads[ix].order = draw_order as DrawOrder,
|
||||
(PrimitiveKind::Path, ix) => self.paths[ix].order = draw_order as DrawOrder,
|
||||
(PrimitiveKind::Underline, ix) => {
|
||||
self.underlines[ix].order = draw_order as DrawOrder
|
||||
}
|
||||
(PrimitiveKind::MonochromeSprite, ix) => {
|
||||
self.monochrome_sprites[ix].order = draw_order as DrawOrder
|
||||
}
|
||||
(PrimitiveKind::PolychromeSprite, ix) => {
|
||||
self.polychrome_sprites[ix].order = draw_order as DrawOrder
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.shadows.sort_unstable();
|
||||
self.quads.sort_unstable();
|
||||
self.paths.sort_unstable();
|
||||
self.underlines.sort_unstable();
|
||||
self.monochrome_sprites.sort_unstable();
|
||||
self.polychrome_sprites.sort_unstable();
|
||||
|
||||
Scene {
|
||||
scale_factor: self.scale_factor,
|
||||
layers: mem::take(&mut self.layers),
|
||||
shadows: mem::take(&mut self.shadows),
|
||||
quads: mem::take(&mut self.quads),
|
||||
paths: mem::take(&mut self.paths),
|
||||
underlines: mem::take(&mut self.underlines),
|
||||
monochrome_sprites: mem::take(&mut self.monochrome_sprites),
|
||||
polychrome_sprites: mem::take(&mut self.polychrome_sprites),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, layer_id: StackingOrder, primitive: impl Into<Primitive>) {
|
||||
let next_id = self.layers.len() as LayerId;
|
||||
let layer_id = *self.layers.entry(layer_id).or_insert(next_id);
|
||||
pub fn insert(&mut self, order: &StackingOrder, primitive: impl Into<Primitive>) {
|
||||
let layer_id = if let Some(layer_id) = self.layers_by_order.get(order) {
|
||||
*layer_id
|
||||
} else {
|
||||
let next_id = self.layers_by_order.len() as LayerId;
|
||||
self.layers_by_order.insert(order.clone(), next_id);
|
||||
next_id
|
||||
};
|
||||
|
||||
let primitive = primitive.into();
|
||||
match primitive {
|
||||
Primitive::Shadow(mut shadow) => {
|
||||
@ -67,6 +149,11 @@ impl Scene {
|
||||
quad.order = layer_id;
|
||||
self.quads.push(quad);
|
||||
}
|
||||
Primitive::Path(mut path) => {
|
||||
path.order = layer_id;
|
||||
path.id = PathId(self.paths.len());
|
||||
self.paths.push(path);
|
||||
}
|
||||
Primitive::Underline(mut underline) => {
|
||||
underline.order = layer_id;
|
||||
self.underlines.push(underline);
|
||||
@ -81,80 +168,23 @@ impl Scene {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn batches(&mut self) -> impl Iterator<Item = PrimitiveBatch> {
|
||||
// Map each layer id to a float between 0. and 1., with 1. closer to the viewer.
|
||||
let mut layer_z_values = vec![0.; self.layers.len()];
|
||||
for (ix, layer_id) in self.layers.values().enumerate() {
|
||||
layer_z_values[*layer_id as usize] = ix as f32 / self.layers.len() as f32;
|
||||
}
|
||||
pub(crate) struct Scene {
|
||||
pub shadows: Vec<Shadow>,
|
||||
pub quads: Vec<Quad>,
|
||||
pub paths: Vec<Path<ScaledPixels>>,
|
||||
pub underlines: Vec<Underline>,
|
||||
pub monochrome_sprites: Vec<MonochromeSprite>,
|
||||
pub polychrome_sprites: Vec<PolychromeSprite>,
|
||||
}
|
||||
|
||||
// Add all primitives to the BSP splitter to determine draw order
|
||||
// todo!("reuse the same splitter")
|
||||
let mut splitter = BspSplitter::new();
|
||||
|
||||
for (ix, shadow) in self.shadows.iter().enumerate() {
|
||||
let z = layer_z_values[shadow.order as LayerId as usize];
|
||||
splitter.add(shadow.bounds.to_bsp_polygon(z, (PrimitiveKind::Shadow, ix)));
|
||||
}
|
||||
|
||||
for (ix, quad) in self.quads.iter().enumerate() {
|
||||
let z = layer_z_values[quad.order as LayerId as usize];
|
||||
splitter.add(quad.bounds.to_bsp_polygon(z, (PrimitiveKind::Quad, ix)));
|
||||
}
|
||||
|
||||
for (ix, underline) in self.underlines.iter().enumerate() {
|
||||
let z = layer_z_values[underline.order as LayerId as usize];
|
||||
splitter.add(
|
||||
underline
|
||||
.bounds
|
||||
.to_bsp_polygon(z, (PrimitiveKind::Underline, ix)),
|
||||
);
|
||||
}
|
||||
|
||||
for (ix, monochrome_sprite) in self.monochrome_sprites.iter().enumerate() {
|
||||
let z = layer_z_values[monochrome_sprite.order as LayerId as usize];
|
||||
splitter.add(
|
||||
monochrome_sprite
|
||||
.bounds
|
||||
.to_bsp_polygon(z, (PrimitiveKind::MonochromeSprite, ix)),
|
||||
);
|
||||
}
|
||||
|
||||
for (ix, polychrome_sprite) in self.polychrome_sprites.iter().enumerate() {
|
||||
let z = layer_z_values[polychrome_sprite.order as LayerId as usize];
|
||||
splitter.add(
|
||||
polychrome_sprite
|
||||
.bounds
|
||||
.to_bsp_polygon(z, (PrimitiveKind::PolychromeSprite, ix)),
|
||||
);
|
||||
}
|
||||
|
||||
// Sort all polygons, then reassign the order field of each primitive to `draw_order`
|
||||
// We need primitives to be repr(C), hence the weird reuse of the order field for two different types.
|
||||
for (draw_order, polygon) in splitter.sort(Vector3D::new(0., 0., 1.)).iter().enumerate() {
|
||||
match polygon.anchor {
|
||||
(PrimitiveKind::Shadow, ix) => self.shadows[ix].order = draw_order as DrawOrder,
|
||||
(PrimitiveKind::Quad, ix) => self.quads[ix].order = draw_order as DrawOrder,
|
||||
(PrimitiveKind::Underline, ix) => {
|
||||
self.underlines[ix].order = draw_order as DrawOrder
|
||||
}
|
||||
(PrimitiveKind::MonochromeSprite, ix) => {
|
||||
self.monochrome_sprites[ix].order = draw_order as DrawOrder
|
||||
}
|
||||
(PrimitiveKind::PolychromeSprite, ix) => {
|
||||
self.polychrome_sprites[ix].order = draw_order as DrawOrder
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the primitives
|
||||
self.shadows.sort_unstable();
|
||||
self.quads.sort_unstable();
|
||||
self.underlines.sort_unstable();
|
||||
self.monochrome_sprites.sort_unstable();
|
||||
self.polychrome_sprites.sort_unstable();
|
||||
impl Scene {
|
||||
pub fn paths(&self) -> impl Iterator<Item = &Path<ScaledPixels>> {
|
||||
self.paths.iter()
|
||||
}
|
||||
|
||||
pub fn batches(&self) -> impl Iterator<Item = PrimitiveBatch> {
|
||||
BatchIterator {
|
||||
shadows: &self.shadows,
|
||||
shadows_start: 0,
|
||||
@ -162,6 +192,9 @@ impl Scene {
|
||||
quads: &self.quads,
|
||||
quads_start: 0,
|
||||
quads_iter: self.quads.iter().peekable(),
|
||||
paths: &self.paths,
|
||||
paths_start: 0,
|
||||
paths_iter: self.paths.iter().peekable(),
|
||||
underlines: &self.underlines,
|
||||
underlines_start: 0,
|
||||
underlines_iter: self.underlines.iter().peekable(),
|
||||
@ -176,12 +209,15 @@ impl Scene {
|
||||
}
|
||||
|
||||
struct BatchIterator<'a> {
|
||||
quads: &'a [Quad],
|
||||
quads_start: usize,
|
||||
quads_iter: Peekable<slice::Iter<'a, Quad>>,
|
||||
shadows: &'a [Shadow],
|
||||
shadows_start: usize,
|
||||
shadows_iter: Peekable<slice::Iter<'a, Shadow>>,
|
||||
quads: &'a [Quad],
|
||||
quads_start: usize,
|
||||
quads_iter: Peekable<slice::Iter<'a, Quad>>,
|
||||
paths: &'a [Path<ScaledPixels>],
|
||||
paths_start: usize,
|
||||
paths_iter: Peekable<slice::Iter<'a, Path<ScaledPixels>>>,
|
||||
underlines: &'a [Underline],
|
||||
underlines_start: usize,
|
||||
underlines_iter: Peekable<slice::Iter<'a, Underline>>,
|
||||
@ -255,6 +291,19 @@ impl<'a> Iterator for BatchIterator<'a> {
|
||||
self.quads_start = quads_end;
|
||||
Some(PrimitiveBatch::Quads(&self.quads[quads_start..quads_end]))
|
||||
}
|
||||
PrimitiveKind::Path => {
|
||||
let paths_start = self.paths_start;
|
||||
let mut paths_end = paths_start;
|
||||
while self
|
||||
.paths_iter
|
||||
.next_if(|path| path.order <= max_order)
|
||||
.is_some()
|
||||
{
|
||||
paths_end += 1;
|
||||
}
|
||||
self.paths_start = paths_end;
|
||||
Some(PrimitiveBatch::Paths(&self.paths[paths_start..paths_end]))
|
||||
}
|
||||
PrimitiveKind::Underline => {
|
||||
let underlines_start = self.underlines_start;
|
||||
let mut underlines_end = underlines_start;
|
||||
@ -317,15 +366,16 @@ pub enum PrimitiveKind {
|
||||
Shadow,
|
||||
#[default]
|
||||
Quad,
|
||||
Path,
|
||||
Underline,
|
||||
MonochromeSprite,
|
||||
PolychromeSprite,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Primitive {
|
||||
Shadow(Shadow),
|
||||
Quad(Quad),
|
||||
Path(Path<ScaledPixels>),
|
||||
Underline(Underline),
|
||||
MonochromeSprite(MonochromeSprite),
|
||||
PolychromeSprite(PolychromeSprite),
|
||||
@ -335,6 +385,7 @@ pub enum Primitive {
|
||||
pub(crate) enum PrimitiveBatch<'a> {
|
||||
Shadows(&'a [Shadow]),
|
||||
Quads(&'a [Quad]),
|
||||
Paths(&'a [Path<ScaledPixels>]),
|
||||
Underlines(&'a [Underline]),
|
||||
MonochromeSprites {
|
||||
texture_id: AtlasTextureId,
|
||||
@ -351,7 +402,7 @@ pub(crate) enum PrimitiveBatch<'a> {
|
||||
pub struct Quad {
|
||||
pub order: u32, // Initially a LayerId, then a DrawOrder.
|
||||
pub bounds: Bounds<ScaledPixels>,
|
||||
pub content_mask: ScaledContentMask,
|
||||
pub content_mask: ContentMask<ScaledPixels>,
|
||||
pub background: Hsla,
|
||||
pub border_color: Hsla,
|
||||
pub corner_radii: Corners<ScaledPixels>,
|
||||
@ -381,7 +432,7 @@ impl From<Quad> for Primitive {
|
||||
pub struct Underline {
|
||||
pub order: u32,
|
||||
pub bounds: Bounds<ScaledPixels>,
|
||||
pub content_mask: ScaledContentMask,
|
||||
pub content_mask: ContentMask<ScaledPixels>,
|
||||
pub thickness: ScaledPixels,
|
||||
pub color: Hsla,
|
||||
pub wavy: bool,
|
||||
@ -411,7 +462,7 @@ pub struct Shadow {
|
||||
pub order: u32,
|
||||
pub bounds: Bounds<ScaledPixels>,
|
||||
pub corner_radii: Corners<ScaledPixels>,
|
||||
pub content_mask: ScaledContentMask,
|
||||
pub content_mask: ContentMask<ScaledPixels>,
|
||||
pub color: Hsla,
|
||||
pub blur_radius: ScaledPixels,
|
||||
}
|
||||
@ -439,7 +490,7 @@ impl From<Shadow> for Primitive {
|
||||
pub struct MonochromeSprite {
|
||||
pub order: u32,
|
||||
pub bounds: Bounds<ScaledPixels>,
|
||||
pub content_mask: ScaledContentMask,
|
||||
pub content_mask: ContentMask<ScaledPixels>,
|
||||
pub color: Hsla,
|
||||
pub tile: AtlasTile,
|
||||
}
|
||||
@ -470,7 +521,7 @@ impl From<MonochromeSprite> for Primitive {
|
||||
pub struct PolychromeSprite {
|
||||
pub order: u32,
|
||||
pub bounds: Bounds<ScaledPixels>,
|
||||
pub content_mask: ScaledContentMask,
|
||||
pub content_mask: ContentMask<ScaledPixels>,
|
||||
pub corner_radii: Corners<ScaledPixels>,
|
||||
pub tile: AtlasTile,
|
||||
pub grayscale: bool,
|
||||
@ -497,21 +548,24 @@ impl From<PolychromeSprite> for Primitive {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct PathId(u32);
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub(crate) struct PathId(pub(crate) usize);
|
||||
|
||||
pub struct PathBuilder {
|
||||
bounds: Bounds<Pixels>,
|
||||
vertices: Vec<PathVertex>,
|
||||
start: Option<Point<Pixels>>,
|
||||
current: Point<Pixels>,
|
||||
#[derive(Debug)]
|
||||
pub struct Path<P: Clone + Debug> {
|
||||
pub(crate) id: PathId,
|
||||
order: u32,
|
||||
pub(crate) bounds: Bounds<P>,
|
||||
pub(crate) vertices: Vec<PathVertex<P>>,
|
||||
start: Option<Point<P>>,
|
||||
current: Point<P>,
|
||||
}
|
||||
|
||||
impl PathBuilder {
|
||||
impl Path<Pixels> {
|
||||
pub fn new() -> Self {
|
||||
const NEXT_PATH_ID: AtomicU32 = AtomicU32::new(0);
|
||||
|
||||
Self {
|
||||
id: PathId(0),
|
||||
order: 0,
|
||||
vertices: Vec::new(),
|
||||
start: Default::default(),
|
||||
current: Default::default(),
|
||||
@ -519,6 +573,21 @@ impl PathBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scale(&self, factor: f32) -> Path<ScaledPixels> {
|
||||
Path {
|
||||
id: self.id,
|
||||
order: self.order,
|
||||
bounds: self.bounds.scale(factor),
|
||||
vertices: self
|
||||
.vertices
|
||||
.iter()
|
||||
.map(|vertex| vertex.scale(factor))
|
||||
.collect(),
|
||||
start: self.start.map(|start| start.scale(factor)),
|
||||
current: self.current.scale(factor),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn line_to(&mut self, to: Point<Pixels>) {
|
||||
if let Some(start) = self.start {
|
||||
self.push_triangle(
|
||||
@ -568,23 +637,63 @@ impl PathBuilder {
|
||||
self.vertices.push(PathVertex {
|
||||
xy_position: xy.0,
|
||||
st_position: st.0,
|
||||
content_mask: Default::default(),
|
||||
});
|
||||
self.vertices.push(PathVertex {
|
||||
xy_position: xy.1,
|
||||
st_position: st.1,
|
||||
content_mask: Default::default(),
|
||||
});
|
||||
self.vertices.push(PathVertex {
|
||||
xy_position: xy.2,
|
||||
st_position: st.2,
|
||||
content_mask: Default::default(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
impl Eq for Path<ScaledPixels> {}
|
||||
|
||||
impl PartialEq for Path<ScaledPixels> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.order == other.order
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Path<ScaledPixels> {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.order.cmp(&other.order)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Path<ScaledPixels> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Path<ScaledPixels>> for Primitive {
|
||||
fn from(path: Path<ScaledPixels>) -> Self {
|
||||
Primitive::Path(path)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct PathVertex {
|
||||
pub xy_position: Point<Pixels>,
|
||||
pub st_position: Point<f32>,
|
||||
pub struct PathVertex<P: Clone + Debug> {
|
||||
pub(crate) xy_position: Point<P>,
|
||||
pub(crate) st_position: Point<f32>,
|
||||
pub(crate) content_mask: ContentMask<P>,
|
||||
}
|
||||
|
||||
impl PathVertex<Pixels> {
|
||||
pub fn scale(&self, factor: f32) -> PathVertex<ScaledPixels> {
|
||||
PathVertex {
|
||||
xy_position: self.xy_position.scale(factor),
|
||||
st_position: self.st_position,
|
||||
content_mask: self.content_mask.scale(factor),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
@ -619,15 +728,15 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_scene() {
|
||||
let mut scene = Scene::new(1.0);
|
||||
assert_eq!(scene.layers.len(), 0);
|
||||
let mut scene = SceneBuilder::new();
|
||||
assert_eq!(scene.layers_by_order.len(), 0);
|
||||
|
||||
scene.insert(smallvec![1], quad());
|
||||
scene.insert(smallvec![2], shadow());
|
||||
scene.insert(smallvec![3], quad());
|
||||
scene.insert(&smallvec![1], quad());
|
||||
scene.insert(&smallvec![2], shadow());
|
||||
scene.insert(&smallvec![3], quad());
|
||||
|
||||
let mut batches_count = 0;
|
||||
for _ in scene.batches() {
|
||||
for _ in scene.build().batches() {
|
||||
batches_count += 1;
|
||||
}
|
||||
assert_eq!(batches_count, 3);
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::{
|
||||
phi, point, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, ContentMask, Corners,
|
||||
CornersRefinement, DefiniteLength, Edges, EdgesRefinement, Font, FontFeatures, FontStyle,
|
||||
FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Quad, Rems, Result, RunStyle, Shadow,
|
||||
SharedString, Size, SizeRefinement, ViewContext, WindowContext,
|
||||
FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rems, Result, RunStyle, SharedString,
|
||||
Size, SizeRefinement, ViewContext, WindowContext,
|
||||
};
|
||||
use refineable::Refineable;
|
||||
use smallvec::SmallVec;
|
||||
@ -243,51 +243,24 @@ impl Style {
|
||||
/// Paints the background of an element styled with this style.
|
||||
pub fn paint<V: 'static>(&self, bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) {
|
||||
let rem_size = cx.rem_size();
|
||||
let scale = cx.scale_factor();
|
||||
|
||||
for shadow in &self.box_shadow {
|
||||
let content_mask = cx.content_mask();
|
||||
let mut shadow_bounds = bounds;
|
||||
shadow_bounds.origin += shadow.offset;
|
||||
shadow_bounds.dilate(shadow.spread_radius);
|
||||
cx.stack(0, |cx| {
|
||||
let layer_id = cx.current_stacking_order();
|
||||
cx.scene().insert(
|
||||
layer_id,
|
||||
Shadow {
|
||||
order: 0,
|
||||
bounds: shadow_bounds.scale(scale),
|
||||
content_mask: content_mask.scale(scale),
|
||||
corner_radii: self
|
||||
.corner_radii
|
||||
.to_pixels(shadow_bounds.size, rem_size)
|
||||
.scale(scale),
|
||||
color: shadow.color,
|
||||
blur_radius: shadow.blur_radius.scale(scale),
|
||||
},
|
||||
);
|
||||
})
|
||||
}
|
||||
cx.stack(0, |cx| {
|
||||
cx.paint_shadows(
|
||||
bounds,
|
||||
self.corner_radii.to_pixels(bounds.size, rem_size),
|
||||
&self.box_shadow,
|
||||
);
|
||||
});
|
||||
|
||||
let background_color = self.fill.as_ref().and_then(Fill::color);
|
||||
if background_color.is_some() || self.is_border_visible() {
|
||||
let content_mask = cx.content_mask();
|
||||
cx.stack(1, |cx| {
|
||||
let order = cx.current_stacking_order();
|
||||
cx.scene().insert(
|
||||
order,
|
||||
Quad {
|
||||
order: 0,
|
||||
bounds: bounds.scale(scale),
|
||||
content_mask: content_mask.scale(scale),
|
||||
background: background_color.unwrap_or_default(),
|
||||
border_color: self.border_color.unwrap_or_default(),
|
||||
corner_radii: self
|
||||
.corner_radii
|
||||
.to_pixels(bounds.size, rem_size)
|
||||
.scale(scale),
|
||||
border_widths: self.border_widths.to_pixels(rem_size).scale(scale),
|
||||
},
|
||||
cx.paint_quad(
|
||||
bounds,
|
||||
self.corner_radii.to_pixels(bounds.size, rem_size),
|
||||
background_color.unwrap_or_default(),
|
||||
self.border_widths.to_pixels(rem_size),
|
||||
self.border_color.unwrap_or_default(),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -1,15 +1,17 @@
|
||||
use crate::{
|
||||
image_cache::RenderImageParams, px, size, AnyView, AppContext, AsyncWindowContext,
|
||||
AvailableSpace, BorrowAppContext, Bounds, Context, Corners, DevicePixels, DisplayId, Effect,
|
||||
Element, EntityId, FontId, GlyphId, Handle, Hsla, ImageData, IsZero, LayoutId, MainThread,
|
||||
MainThreadOnly, MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, Point,
|
||||
PolychromeSprite, Reference, RenderGlyphParams, RenderSvgParams, ScaledPixels, Scene,
|
||||
SharedString, Size, StackingOrder, Style, TaffyLayoutEngine, Task, Underline, UnderlineStyle,
|
||||
WeakHandle, WindowOptions, SUBPIXEL_VARIANTS,
|
||||
AvailableSpace, BorrowAppContext, Bounds, BoxShadow, Context, Corners, DevicePixels, DisplayId,
|
||||
Edges, Effect, Element, EntityId, FontId, GlyphId, Handle, Hsla, ImageData, IsZero, LayoutId,
|
||||
MainThread, MainThreadOnly, MonochromeSprite, Path, Pixels, PlatformAtlas, PlatformWindow,
|
||||
Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderSvgParams, ScaledPixels,
|
||||
SceneBuilder, Shadow, SharedString, Size, StackingOrder, Style, TaffyLayoutEngine, Task,
|
||||
Underline, UnderlineStyle, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use smallvec::SmallVec;
|
||||
use std::{any::TypeId, borrow::Cow, future::Future, marker::PhantomData, mem, sync::Arc};
|
||||
use std::{
|
||||
any::TypeId, borrow::Cow, fmt::Debug, future::Future, marker::PhantomData, mem, sync::Arc,
|
||||
};
|
||||
use util::ResultExt;
|
||||
|
||||
pub struct AnyWindow {}
|
||||
@ -25,8 +27,9 @@ pub struct Window {
|
||||
pub(crate) root_view: Option<AnyView<()>>,
|
||||
mouse_position: Point<Pixels>,
|
||||
current_stacking_order: StackingOrder,
|
||||
content_mask_stack: Vec<ContentMask>,
|
||||
pub(crate) scene: Scene,
|
||||
content_mask_stack: Vec<ContentMask<Pixels>>,
|
||||
scale_factor: f32,
|
||||
pub(crate) scene_builder: SceneBuilder,
|
||||
pub(crate) dirty: bool,
|
||||
}
|
||||
|
||||
@ -47,7 +50,8 @@ impl Window {
|
||||
let cx = cx.to_async();
|
||||
move |content_size, scale_factor| {
|
||||
cx.update_window(handle, |cx| {
|
||||
cx.window.scene = Scene::new(scale_factor);
|
||||
cx.window.scale_factor = scale_factor;
|
||||
cx.window.scene_builder = SceneBuilder::new();
|
||||
cx.window.content_size = content_size;
|
||||
cx.window.display_id = cx
|
||||
.window
|
||||
@ -75,20 +79,22 @@ impl Window {
|
||||
mouse_position,
|
||||
current_stacking_order: SmallVec::new(),
|
||||
content_mask_stack: Vec::new(),
|
||||
scene: Scene::new(scale_factor),
|
||||
scale_factor,
|
||||
scene_builder: SceneBuilder::new(),
|
||||
dirty: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ContentMask {
|
||||
pub bounds: Bounds<Pixels>,
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
pub struct ContentMask<P: Clone + Debug> {
|
||||
pub bounds: Bounds<P>,
|
||||
}
|
||||
|
||||
impl ContentMask {
|
||||
pub fn scale(&self, factor: f32) -> ScaledContentMask {
|
||||
ScaledContentMask {
|
||||
impl ContentMask<Pixels> {
|
||||
pub fn scale(&self, factor: f32) -> ContentMask<ScaledPixels> {
|
||||
ContentMask {
|
||||
bounds: self.bounds.scale(factor),
|
||||
}
|
||||
}
|
||||
@ -99,12 +105,6 @@ impl ContentMask {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Debug, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
pub struct ScaledContentMask {
|
||||
bounds: Bounds<ScaledPixels>,
|
||||
}
|
||||
|
||||
pub struct WindowContext<'a, 'w> {
|
||||
app: Reference<'a, AppContext>,
|
||||
window: Reference<'w, Window>,
|
||||
@ -234,7 +234,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
}
|
||||
|
||||
pub fn scale_factor(&self) -> f32 {
|
||||
self.window.scene.scale_factor
|
||||
self.window.scale_factor
|
||||
}
|
||||
|
||||
pub fn rem_size(&self) -> Pixels {
|
||||
@ -245,10 +245,6 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
self.window.mouse_position
|
||||
}
|
||||
|
||||
pub fn scene(&mut self) -> &mut Scene {
|
||||
&mut self.window.scene
|
||||
}
|
||||
|
||||
pub fn stack<R>(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R {
|
||||
self.window.current_stacking_order.push(order);
|
||||
let result = f(self);
|
||||
@ -256,8 +252,69 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
result
|
||||
}
|
||||
|
||||
pub fn current_stacking_order(&self) -> StackingOrder {
|
||||
self.window.current_stacking_order.clone()
|
||||
pub fn paint_shadows(
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
corner_radii: Corners<Pixels>,
|
||||
shadows: &[BoxShadow],
|
||||
) {
|
||||
let scale_factor = self.scale_factor();
|
||||
let content_mask = self.content_mask();
|
||||
let window = &mut *self.window;
|
||||
for shadow in shadows {
|
||||
let mut shadow_bounds = bounds;
|
||||
shadow_bounds.origin += shadow.offset;
|
||||
shadow_bounds.dilate(shadow.spread_radius);
|
||||
window.scene_builder.insert(
|
||||
&window.current_stacking_order,
|
||||
Shadow {
|
||||
order: 0,
|
||||
bounds: shadow_bounds.scale(scale_factor),
|
||||
content_mask: content_mask.scale(scale_factor),
|
||||
corner_radii: corner_radii.scale(scale_factor),
|
||||
color: shadow.color,
|
||||
blur_radius: shadow.blur_radius.scale(scale_factor),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn paint_quad(
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
corner_radii: Corners<Pixels>,
|
||||
background: impl Into<Hsla>,
|
||||
border_widths: Edges<Pixels>,
|
||||
border_color: impl Into<Hsla>,
|
||||
) {
|
||||
let scale_factor = self.scale_factor();
|
||||
let content_mask = self.content_mask();
|
||||
|
||||
let window = &mut *self.window;
|
||||
window.scene_builder.insert(
|
||||
&window.current_stacking_order,
|
||||
Quad {
|
||||
order: 0,
|
||||
bounds: bounds.scale(scale_factor),
|
||||
content_mask: content_mask.scale(scale_factor),
|
||||
background: background.into(),
|
||||
border_color: border_color.into(),
|
||||
corner_radii: corner_radii.scale(scale_factor),
|
||||
border_widths: border_widths.scale(scale_factor),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
pub fn paint_path(&mut self, mut path: Path<Pixels>) {
|
||||
let scale_factor = self.scale_factor();
|
||||
let content_mask = self.content_mask();
|
||||
for vertex in &mut path.vertices {
|
||||
vertex.content_mask = content_mask.clone();
|
||||
}
|
||||
let window = &mut *self.window;
|
||||
window
|
||||
.scene_builder
|
||||
.insert(&window.current_stacking_order, path.scale(scale_factor));
|
||||
}
|
||||
|
||||
pub fn paint_underline(
|
||||
@ -277,9 +334,9 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
size: size(width, height),
|
||||
};
|
||||
let content_mask = self.content_mask();
|
||||
let layer_id = self.current_stacking_order();
|
||||
self.window.scene.insert(
|
||||
layer_id,
|
||||
let window = &mut *self.window;
|
||||
window.scene_builder.insert(
|
||||
&window.current_stacking_order,
|
||||
Underline {
|
||||
order: 0,
|
||||
bounds: bounds.scale(scale_factor),
|
||||
@ -317,7 +374,6 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
|
||||
let raster_bounds = self.text_system().raster_bounds(¶ms)?;
|
||||
if !raster_bounds.is_zero() {
|
||||
let layer_id = self.current_stacking_order();
|
||||
let tile =
|
||||
self.window
|
||||
.sprite_atlas
|
||||
@ -330,9 +386,9 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
size: tile.bounds.size.map(Into::into),
|
||||
};
|
||||
let content_mask = self.content_mask().scale(scale_factor);
|
||||
|
||||
self.window.scene.insert(
|
||||
layer_id,
|
||||
let window = &mut *self.window;
|
||||
window.scene_builder.insert(
|
||||
&window.current_stacking_order,
|
||||
MonochromeSprite {
|
||||
order: 0,
|
||||
bounds,
|
||||
@ -366,7 +422,6 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
|
||||
let raster_bounds = self.text_system().raster_bounds(¶ms)?;
|
||||
if !raster_bounds.is_zero() {
|
||||
let layer_id = self.current_stacking_order();
|
||||
let tile =
|
||||
self.window
|
||||
.sprite_atlas
|
||||
@ -379,9 +434,10 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
size: tile.bounds.size.map(Into::into),
|
||||
};
|
||||
let content_mask = self.content_mask().scale(scale_factor);
|
||||
let window = &mut *self.window;
|
||||
|
||||
self.window.scene.insert(
|
||||
layer_id,
|
||||
window.scene_builder.insert(
|
||||
&window.current_stacking_order,
|
||||
PolychromeSprite {
|
||||
order: 0,
|
||||
bounds,
|
||||
@ -411,7 +467,6 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
.map(|pixels| DevicePixels::from((pixels.0 * 2.).ceil() as i32)),
|
||||
};
|
||||
|
||||
let layer_id = self.current_stacking_order();
|
||||
let tile =
|
||||
self.window
|
||||
.sprite_atlas
|
||||
@ -421,8 +476,9 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
})?;
|
||||
let content_mask = self.content_mask().scale(scale_factor);
|
||||
|
||||
self.window.scene.insert(
|
||||
layer_id,
|
||||
let window = &mut *self.window;
|
||||
window.scene_builder.insert(
|
||||
&window.current_stacking_order,
|
||||
MonochromeSprite {
|
||||
order: 0,
|
||||
bounds,
|
||||
@ -446,7 +502,6 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
let bounds = bounds.scale(scale_factor);
|
||||
let params = RenderImageParams { image_id: data.id };
|
||||
|
||||
let order = self.current_stacking_order();
|
||||
let tile = self
|
||||
.window
|
||||
.sprite_atlas
|
||||
@ -456,8 +511,9 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
let content_mask = self.content_mask().scale(scale_factor);
|
||||
let corner_radii = corner_radii.scale(scale_factor);
|
||||
|
||||
self.window.scene.insert(
|
||||
order,
|
||||
let window = &mut *self.window;
|
||||
window.scene_builder.insert(
|
||||
&window.current_stacking_order,
|
||||
PolychromeSprite {
|
||||
order: 0,
|
||||
bounds,
|
||||
@ -467,7 +523,6 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
grayscale,
|
||||
},
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -485,7 +540,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
|
||||
root_view.paint(layout, &mut (), &mut frame_state, cx)?;
|
||||
cx.window.root_view = Some(root_view);
|
||||
let scene = cx.window.scene.take();
|
||||
let scene = cx.window.scene_builder.build();
|
||||
|
||||
cx.run_on_main(view, |_, cx| {
|
||||
cx.window
|
||||
@ -557,7 +612,11 @@ pub trait BorrowWindow: BorrowAppContext {
|
||||
fn window(&self) -> &Window;
|
||||
fn window_mut(&mut self) -> &mut Window;
|
||||
|
||||
fn with_content_mask<R>(&mut self, mask: ContentMask, f: impl FnOnce(&mut Self) -> R) -> R {
|
||||
fn with_content_mask<R>(
|
||||
&mut self,
|
||||
mask: ContentMask<Pixels>,
|
||||
f: impl FnOnce(&mut Self) -> R,
|
||||
) -> R {
|
||||
let mask = mask.intersect(&self.content_mask());
|
||||
self.window_mut().content_mask_stack.push(mask);
|
||||
let result = f(self);
|
||||
@ -565,7 +624,7 @@ pub trait BorrowWindow: BorrowAppContext {
|
||||
result
|
||||
}
|
||||
|
||||
fn content_mask(&self) -> ContentMask {
|
||||
fn content_mask(&self) -> ContentMask<Pixels> {
|
||||
self.window()
|
||||
.content_mask_stack
|
||||
.last()
|
||||
|
Loading…
Reference in New Issue
Block a user