Reverts zed-industries/zed#7481 This would regress performance because we'd be using the standard library's hash maps everywhere, so reverting for now.
866 lines
27 KiB
Rust
866 lines
27 KiB
Rust
use crate::{
|
|
point, AtlasTextureId, AtlasTile, Bounds, ContentMask, Corners, Edges, EntityId, Hsla, Pixels,
|
|
Point, ScaledPixels, StackingOrder,
|
|
};
|
|
use collections::{BTreeMap, FxHashSet};
|
|
use std::{fmt::Debug, iter::Peekable, slice};
|
|
|
|
// Exported to metal
|
|
pub(crate) type PointF = Point<f32>;
|
|
#[allow(non_camel_case_types, unused)]
|
|
pub(crate) type PathVertex_ScaledPixels = PathVertex<ScaledPixels>;
|
|
|
|
pub(crate) type LayerId = u32;
|
|
pub(crate) type DrawOrder = u32;
|
|
|
|
#[derive(Default, Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
|
#[repr(C)]
|
|
pub(crate) struct ViewId {
|
|
low_bits: u32,
|
|
high_bits: u32,
|
|
}
|
|
|
|
impl From<EntityId> for ViewId {
|
|
fn from(value: EntityId) -> Self {
|
|
let value = value.as_u64();
|
|
Self {
|
|
low_bits: value as u32,
|
|
high_bits: (value >> 32) as u32,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<ViewId> for EntityId {
|
|
fn from(value: ViewId) -> Self {
|
|
let value = (value.low_bits as u64) | ((value.high_bits as u64) << 32);
|
|
value.into()
|
|
}
|
|
}
|
|
|
|
#[derive(Default)]
|
|
pub(crate) struct Scene {
|
|
last_layer: Option<(StackingOrder, LayerId)>,
|
|
layers_by_order: BTreeMap<StackingOrder, LayerId>,
|
|
orders_by_layer: BTreeMap<LayerId, StackingOrder>,
|
|
pub(crate) shadows: Vec<Shadow>,
|
|
pub(crate) quads: Vec<Quad>,
|
|
pub(crate) paths: Vec<Path<ScaledPixels>>,
|
|
pub(crate) underlines: Vec<Underline>,
|
|
pub(crate) monochrome_sprites: Vec<MonochromeSprite>,
|
|
pub(crate) polychrome_sprites: Vec<PolychromeSprite>,
|
|
pub(crate) surfaces: Vec<Surface>,
|
|
}
|
|
|
|
impl Scene {
|
|
pub fn clear(&mut self) {
|
|
self.last_layer = None;
|
|
self.layers_by_order.clear();
|
|
self.orders_by_layer.clear();
|
|
self.shadows.clear();
|
|
self.quads.clear();
|
|
self.paths.clear();
|
|
self.underlines.clear();
|
|
self.monochrome_sprites.clear();
|
|
self.polychrome_sprites.clear();
|
|
self.surfaces.clear();
|
|
}
|
|
|
|
pub fn paths(&self) -> &[Path<ScaledPixels>] {
|
|
&self.paths
|
|
}
|
|
|
|
pub(crate) fn batches(&self) -> impl Iterator<Item = PrimitiveBatch> {
|
|
BatchIterator {
|
|
shadows: &self.shadows,
|
|
shadows_start: 0,
|
|
shadows_iter: self.shadows.iter().peekable(),
|
|
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(),
|
|
monochrome_sprites: &self.monochrome_sprites,
|
|
monochrome_sprites_start: 0,
|
|
monochrome_sprites_iter: self.monochrome_sprites.iter().peekable(),
|
|
polychrome_sprites: &self.polychrome_sprites,
|
|
polychrome_sprites_start: 0,
|
|
polychrome_sprites_iter: self.polychrome_sprites.iter().peekable(),
|
|
surfaces: &self.surfaces,
|
|
surfaces_start: 0,
|
|
surfaces_iter: self.surfaces.iter().peekable(),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn insert(&mut self, order: &StackingOrder, primitive: impl Into<Primitive>) {
|
|
let primitive = primitive.into();
|
|
let clipped_bounds = primitive
|
|
.bounds()
|
|
.intersect(&primitive.content_mask().bounds);
|
|
if clipped_bounds.size.width <= ScaledPixels(0.)
|
|
|| clipped_bounds.size.height <= ScaledPixels(0.)
|
|
{
|
|
return;
|
|
}
|
|
|
|
let layer_id = self.layer_id_for_order(order);
|
|
match primitive {
|
|
Primitive::Shadow(mut shadow) => {
|
|
shadow.layer_id = layer_id;
|
|
self.shadows.push(shadow);
|
|
}
|
|
Primitive::Quad(mut quad) => {
|
|
quad.layer_id = layer_id;
|
|
self.quads.push(quad);
|
|
}
|
|
Primitive::Path(mut path) => {
|
|
path.layer_id = layer_id;
|
|
path.id = PathId(self.paths.len());
|
|
self.paths.push(path);
|
|
}
|
|
Primitive::Underline(mut underline) => {
|
|
underline.layer_id = layer_id;
|
|
self.underlines.push(underline);
|
|
}
|
|
Primitive::MonochromeSprite(mut sprite) => {
|
|
sprite.layer_id = layer_id;
|
|
self.monochrome_sprites.push(sprite);
|
|
}
|
|
Primitive::PolychromeSprite(mut sprite) => {
|
|
sprite.layer_id = layer_id;
|
|
self.polychrome_sprites.push(sprite);
|
|
}
|
|
Primitive::Surface(mut surface) => {
|
|
surface.layer_id = layer_id;
|
|
self.surfaces.push(surface);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn layer_id_for_order(&mut self, order: &StackingOrder) -> LayerId {
|
|
if let Some((last_order, last_layer_id)) = self.last_layer.as_ref() {
|
|
if order == last_order {
|
|
return *last_layer_id;
|
|
}
|
|
}
|
|
|
|
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);
|
|
self.orders_by_layer.insert(next_id, order.clone());
|
|
next_id
|
|
};
|
|
self.last_layer = Some((order.clone(), layer_id));
|
|
layer_id
|
|
}
|
|
|
|
pub fn reuse_views(&mut self, views: &FxHashSet<EntityId>, prev_scene: &mut Self) {
|
|
for shadow in prev_scene.shadows.drain(..) {
|
|
if views.contains(&shadow.view_id.into()) {
|
|
let order = &prev_scene.orders_by_layer[&shadow.layer_id];
|
|
self.insert(order, shadow);
|
|
}
|
|
}
|
|
|
|
for quad in prev_scene.quads.drain(..) {
|
|
if views.contains(&quad.view_id.into()) {
|
|
let order = &prev_scene.orders_by_layer[&quad.layer_id];
|
|
self.insert(order, quad);
|
|
}
|
|
}
|
|
|
|
for path in prev_scene.paths.drain(..) {
|
|
if views.contains(&path.view_id.into()) {
|
|
let order = &prev_scene.orders_by_layer[&path.layer_id];
|
|
self.insert(order, path);
|
|
}
|
|
}
|
|
|
|
for underline in prev_scene.underlines.drain(..) {
|
|
if views.contains(&underline.view_id.into()) {
|
|
let order = &prev_scene.orders_by_layer[&underline.layer_id];
|
|
self.insert(order, underline);
|
|
}
|
|
}
|
|
|
|
for sprite in prev_scene.monochrome_sprites.drain(..) {
|
|
if views.contains(&sprite.view_id.into()) {
|
|
let order = &prev_scene.orders_by_layer[&sprite.layer_id];
|
|
self.insert(order, sprite);
|
|
}
|
|
}
|
|
|
|
for sprite in prev_scene.polychrome_sprites.drain(..) {
|
|
if views.contains(&sprite.view_id.into()) {
|
|
let order = &prev_scene.orders_by_layer[&sprite.layer_id];
|
|
self.insert(order, sprite);
|
|
}
|
|
}
|
|
|
|
for surface in prev_scene.surfaces.drain(..) {
|
|
if views.contains(&surface.view_id.into()) {
|
|
let order = &prev_scene.orders_by_layer[&surface.layer_id];
|
|
self.insert(order, surface);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn finish(&mut self) {
|
|
let mut orders = vec![0; self.layers_by_order.len()];
|
|
for (ix, layer_id) in self.layers_by_order.values().enumerate() {
|
|
orders[*layer_id as usize] = ix as u32;
|
|
}
|
|
|
|
for shadow in &mut self.shadows {
|
|
shadow.order = orders[shadow.layer_id as usize];
|
|
}
|
|
self.shadows.sort_by_key(|shadow| shadow.order);
|
|
|
|
for quad in &mut self.quads {
|
|
quad.order = orders[quad.layer_id as usize];
|
|
}
|
|
self.quads.sort_by_key(|quad| quad.order);
|
|
|
|
for path in &mut self.paths {
|
|
path.order = orders[path.layer_id as usize];
|
|
}
|
|
self.paths.sort_by_key(|path| path.order);
|
|
|
|
for underline in &mut self.underlines {
|
|
underline.order = orders[underline.layer_id as usize];
|
|
}
|
|
self.underlines.sort_by_key(|underline| underline.order);
|
|
|
|
for monochrome_sprite in &mut self.monochrome_sprites {
|
|
monochrome_sprite.order = orders[monochrome_sprite.layer_id as usize];
|
|
}
|
|
self.monochrome_sprites.sort_by_key(|sprite| sprite.order);
|
|
|
|
for polychrome_sprite in &mut self.polychrome_sprites {
|
|
polychrome_sprite.order = orders[polychrome_sprite.layer_id as usize];
|
|
}
|
|
self.polychrome_sprites.sort_by_key(|sprite| sprite.order);
|
|
|
|
for surface in &mut self.surfaces {
|
|
surface.order = orders[surface.layer_id as usize];
|
|
}
|
|
self.surfaces.sort_by_key(|surface| surface.order);
|
|
}
|
|
}
|
|
|
|
struct BatchIterator<'a> {
|
|
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>>,
|
|
monochrome_sprites: &'a [MonochromeSprite],
|
|
monochrome_sprites_start: usize,
|
|
monochrome_sprites_iter: Peekable<slice::Iter<'a, MonochromeSprite>>,
|
|
polychrome_sprites: &'a [PolychromeSprite],
|
|
polychrome_sprites_start: usize,
|
|
polychrome_sprites_iter: Peekable<slice::Iter<'a, PolychromeSprite>>,
|
|
surfaces: &'a [Surface],
|
|
surfaces_start: usize,
|
|
surfaces_iter: Peekable<slice::Iter<'a, Surface>>,
|
|
}
|
|
|
|
impl<'a> Iterator for BatchIterator<'a> {
|
|
type Item = PrimitiveBatch<'a>;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
let mut orders_and_kinds = [
|
|
(
|
|
self.shadows_iter.peek().map(|s| s.order),
|
|
PrimitiveKind::Shadow,
|
|
),
|
|
(self.quads_iter.peek().map(|q| q.order), PrimitiveKind::Quad),
|
|
(self.paths_iter.peek().map(|q| q.order), PrimitiveKind::Path),
|
|
(
|
|
self.underlines_iter.peek().map(|u| u.order),
|
|
PrimitiveKind::Underline,
|
|
),
|
|
(
|
|
self.monochrome_sprites_iter.peek().map(|s| s.order),
|
|
PrimitiveKind::MonochromeSprite,
|
|
),
|
|
(
|
|
self.polychrome_sprites_iter.peek().map(|s| s.order),
|
|
PrimitiveKind::PolychromeSprite,
|
|
),
|
|
(
|
|
self.surfaces_iter.peek().map(|s| s.order),
|
|
PrimitiveKind::Surface,
|
|
),
|
|
];
|
|
orders_and_kinds.sort_by_key(|(order, kind)| (order.unwrap_or(u32::MAX), *kind));
|
|
|
|
let first = orders_and_kinds[0];
|
|
let second = orders_and_kinds[1];
|
|
let (batch_kind, max_order_and_kind) = if first.0.is_some() {
|
|
(first.1, (second.0.unwrap_or(u32::MAX), second.1))
|
|
} else {
|
|
return None;
|
|
};
|
|
|
|
match batch_kind {
|
|
PrimitiveKind::Shadow => {
|
|
let shadows_start = self.shadows_start;
|
|
let mut shadows_end = shadows_start + 1;
|
|
self.shadows_iter.next();
|
|
while self
|
|
.shadows_iter
|
|
.next_if(|shadow| (shadow.order, batch_kind) < max_order_and_kind)
|
|
.is_some()
|
|
{
|
|
shadows_end += 1;
|
|
}
|
|
self.shadows_start = shadows_end;
|
|
Some(PrimitiveBatch::Shadows(
|
|
&self.shadows[shadows_start..shadows_end],
|
|
))
|
|
}
|
|
PrimitiveKind::Quad => {
|
|
let quads_start = self.quads_start;
|
|
let mut quads_end = quads_start + 1;
|
|
self.quads_iter.next();
|
|
while self
|
|
.quads_iter
|
|
.next_if(|quad| (quad.order, batch_kind) < max_order_and_kind)
|
|
.is_some()
|
|
{
|
|
quads_end += 1;
|
|
}
|
|
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 + 1;
|
|
self.paths_iter.next();
|
|
while self
|
|
.paths_iter
|
|
.next_if(|path| (path.order, batch_kind) < max_order_and_kind)
|
|
.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 + 1;
|
|
self.underlines_iter.next();
|
|
while self
|
|
.underlines_iter
|
|
.next_if(|underline| (underline.order, batch_kind) < max_order_and_kind)
|
|
.is_some()
|
|
{
|
|
underlines_end += 1;
|
|
}
|
|
self.underlines_start = underlines_end;
|
|
Some(PrimitiveBatch::Underlines(
|
|
&self.underlines[underlines_start..underlines_end],
|
|
))
|
|
}
|
|
PrimitiveKind::MonochromeSprite => {
|
|
let texture_id = self.monochrome_sprites_iter.peek().unwrap().tile.texture_id;
|
|
let sprites_start = self.monochrome_sprites_start;
|
|
let mut sprites_end = sprites_start + 1;
|
|
self.monochrome_sprites_iter.next();
|
|
while self
|
|
.monochrome_sprites_iter
|
|
.next_if(|sprite| {
|
|
(sprite.order, batch_kind) < max_order_and_kind
|
|
&& sprite.tile.texture_id == texture_id
|
|
})
|
|
.is_some()
|
|
{
|
|
sprites_end += 1;
|
|
}
|
|
self.monochrome_sprites_start = sprites_end;
|
|
Some(PrimitiveBatch::MonochromeSprites {
|
|
texture_id,
|
|
sprites: &self.monochrome_sprites[sprites_start..sprites_end],
|
|
})
|
|
}
|
|
PrimitiveKind::PolychromeSprite => {
|
|
let texture_id = self.polychrome_sprites_iter.peek().unwrap().tile.texture_id;
|
|
let sprites_start = self.polychrome_sprites_start;
|
|
let mut sprites_end = self.polychrome_sprites_start + 1;
|
|
self.polychrome_sprites_iter.next();
|
|
while self
|
|
.polychrome_sprites_iter
|
|
.next_if(|sprite| {
|
|
(sprite.order, batch_kind) < max_order_and_kind
|
|
&& sprite.tile.texture_id == texture_id
|
|
})
|
|
.is_some()
|
|
{
|
|
sprites_end += 1;
|
|
}
|
|
self.polychrome_sprites_start = sprites_end;
|
|
Some(PrimitiveBatch::PolychromeSprites {
|
|
texture_id,
|
|
sprites: &self.polychrome_sprites[sprites_start..sprites_end],
|
|
})
|
|
}
|
|
PrimitiveKind::Surface => {
|
|
let surfaces_start = self.surfaces_start;
|
|
let mut surfaces_end = surfaces_start + 1;
|
|
self.surfaces_iter.next();
|
|
while self
|
|
.surfaces_iter
|
|
.next_if(|surface| (surface.order, batch_kind) < max_order_and_kind)
|
|
.is_some()
|
|
{
|
|
surfaces_end += 1;
|
|
}
|
|
self.surfaces_start = surfaces_end;
|
|
Some(PrimitiveBatch::Surfaces(
|
|
&self.surfaces[surfaces_start..surfaces_end],
|
|
))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Default)]
|
|
pub(crate) enum PrimitiveKind {
|
|
Shadow,
|
|
#[default]
|
|
Quad,
|
|
Path,
|
|
Underline,
|
|
MonochromeSprite,
|
|
PolychromeSprite,
|
|
Surface,
|
|
}
|
|
|
|
pub(crate) enum Primitive {
|
|
Shadow(Shadow),
|
|
Quad(Quad),
|
|
Path(Path<ScaledPixels>),
|
|
Underline(Underline),
|
|
MonochromeSprite(MonochromeSprite),
|
|
PolychromeSprite(PolychromeSprite),
|
|
Surface(Surface),
|
|
}
|
|
|
|
impl Primitive {
|
|
pub fn bounds(&self) -> &Bounds<ScaledPixels> {
|
|
match self {
|
|
Primitive::Shadow(shadow) => &shadow.bounds,
|
|
Primitive::Quad(quad) => &quad.bounds,
|
|
Primitive::Path(path) => &path.bounds,
|
|
Primitive::Underline(underline) => &underline.bounds,
|
|
Primitive::MonochromeSprite(sprite) => &sprite.bounds,
|
|
Primitive::PolychromeSprite(sprite) => &sprite.bounds,
|
|
Primitive::Surface(surface) => &surface.bounds,
|
|
}
|
|
}
|
|
|
|
pub fn content_mask(&self) -> &ContentMask<ScaledPixels> {
|
|
match self {
|
|
Primitive::Shadow(shadow) => &shadow.content_mask,
|
|
Primitive::Quad(quad) => &quad.content_mask,
|
|
Primitive::Path(path) => &path.content_mask,
|
|
Primitive::Underline(underline) => &underline.content_mask,
|
|
Primitive::MonochromeSprite(sprite) => &sprite.content_mask,
|
|
Primitive::PolychromeSprite(sprite) => &sprite.content_mask,
|
|
Primitive::Surface(surface) => &surface.content_mask,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub(crate) enum PrimitiveBatch<'a> {
|
|
Shadows(&'a [Shadow]),
|
|
Quads(&'a [Quad]),
|
|
Paths(&'a [Path<ScaledPixels>]),
|
|
Underlines(&'a [Underline]),
|
|
MonochromeSprites {
|
|
texture_id: AtlasTextureId,
|
|
sprites: &'a [MonochromeSprite],
|
|
},
|
|
PolychromeSprites {
|
|
texture_id: AtlasTextureId,
|
|
sprites: &'a [PolychromeSprite],
|
|
},
|
|
Surfaces(&'a [Surface]),
|
|
}
|
|
|
|
#[derive(Default, Debug, Clone, Eq, PartialEq)]
|
|
#[repr(C)]
|
|
pub(crate) struct Quad {
|
|
pub view_id: ViewId,
|
|
pub layer_id: LayerId,
|
|
pub order: DrawOrder,
|
|
pub bounds: Bounds<ScaledPixels>,
|
|
pub content_mask: ContentMask<ScaledPixels>,
|
|
pub background: Hsla,
|
|
pub border_color: Hsla,
|
|
pub corner_radii: Corners<ScaledPixels>,
|
|
pub border_widths: Edges<ScaledPixels>,
|
|
}
|
|
|
|
impl Ord for Quad {
|
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
self.order.cmp(&other.order)
|
|
}
|
|
}
|
|
|
|
impl PartialOrd for Quad {
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
impl From<Quad> for Primitive {
|
|
fn from(quad: Quad) -> Self {
|
|
Primitive::Quad(quad)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
#[repr(C)]
|
|
pub(crate) struct Underline {
|
|
pub view_id: ViewId,
|
|
pub layer_id: LayerId,
|
|
pub order: DrawOrder,
|
|
pub bounds: Bounds<ScaledPixels>,
|
|
pub content_mask: ContentMask<ScaledPixels>,
|
|
pub thickness: ScaledPixels,
|
|
pub color: Hsla,
|
|
pub wavy: bool,
|
|
}
|
|
|
|
impl Ord for Underline {
|
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
self.order.cmp(&other.order)
|
|
}
|
|
}
|
|
|
|
impl PartialOrd for Underline {
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
impl From<Underline> for Primitive {
|
|
fn from(underline: Underline) -> Self {
|
|
Primitive::Underline(underline)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
#[repr(C)]
|
|
pub(crate) struct Shadow {
|
|
pub view_id: ViewId,
|
|
pub layer_id: LayerId,
|
|
pub order: DrawOrder,
|
|
pub bounds: Bounds<ScaledPixels>,
|
|
pub corner_radii: Corners<ScaledPixels>,
|
|
pub content_mask: ContentMask<ScaledPixels>,
|
|
pub color: Hsla,
|
|
pub blur_radius: ScaledPixels,
|
|
}
|
|
|
|
impl Ord for Shadow {
|
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
self.order.cmp(&other.order)
|
|
}
|
|
}
|
|
|
|
impl PartialOrd for Shadow {
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
impl From<Shadow> for Primitive {
|
|
fn from(shadow: Shadow) -> Self {
|
|
Primitive::Shadow(shadow)
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
#[repr(C)]
|
|
pub(crate) struct MonochromeSprite {
|
|
pub view_id: ViewId,
|
|
pub layer_id: LayerId,
|
|
pub order: DrawOrder,
|
|
pub bounds: Bounds<ScaledPixels>,
|
|
pub content_mask: ContentMask<ScaledPixels>,
|
|
pub color: Hsla,
|
|
pub tile: AtlasTile,
|
|
}
|
|
|
|
impl Ord for MonochromeSprite {
|
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
match self.order.cmp(&other.order) {
|
|
std::cmp::Ordering::Equal => self.tile.tile_id.cmp(&other.tile.tile_id),
|
|
order => order,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PartialOrd for MonochromeSprite {
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
impl From<MonochromeSprite> for Primitive {
|
|
fn from(sprite: MonochromeSprite) -> Self {
|
|
Primitive::MonochromeSprite(sprite)
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
#[repr(C)]
|
|
pub(crate) struct PolychromeSprite {
|
|
pub view_id: ViewId,
|
|
pub layer_id: LayerId,
|
|
pub order: DrawOrder,
|
|
pub bounds: Bounds<ScaledPixels>,
|
|
pub content_mask: ContentMask<ScaledPixels>,
|
|
pub corner_radii: Corners<ScaledPixels>,
|
|
pub tile: AtlasTile,
|
|
pub grayscale: bool,
|
|
}
|
|
|
|
impl Ord for PolychromeSprite {
|
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
match self.order.cmp(&other.order) {
|
|
std::cmp::Ordering::Equal => self.tile.tile_id.cmp(&other.tile.tile_id),
|
|
order => order,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PartialOrd for PolychromeSprite {
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
impl From<PolychromeSprite> for Primitive {
|
|
fn from(sprite: PolychromeSprite) -> Self {
|
|
Primitive::PolychromeSprite(sprite)
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
pub(crate) struct Surface {
|
|
pub view_id: ViewId,
|
|
pub layer_id: LayerId,
|
|
pub order: DrawOrder,
|
|
pub bounds: Bounds<ScaledPixels>,
|
|
pub content_mask: ContentMask<ScaledPixels>,
|
|
pub image_buffer: media::core_video::CVImageBuffer,
|
|
}
|
|
|
|
impl Ord for Surface {
|
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
self.order.cmp(&other.order)
|
|
}
|
|
}
|
|
|
|
impl PartialOrd for Surface {
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
impl From<Surface> for Primitive {
|
|
fn from(surface: Surface) -> Self {
|
|
Primitive::Surface(surface)
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
|
pub(crate) struct PathId(pub(crate) usize);
|
|
|
|
/// A line made up of a series of vertices and control points.
|
|
#[derive(Debug)]
|
|
pub struct Path<P: Clone + Default + Debug> {
|
|
pub(crate) id: PathId,
|
|
pub(crate) view_id: ViewId,
|
|
layer_id: LayerId,
|
|
order: DrawOrder,
|
|
pub(crate) bounds: Bounds<P>,
|
|
pub(crate) content_mask: ContentMask<P>,
|
|
pub(crate) vertices: Vec<PathVertex<P>>,
|
|
pub(crate) color: Hsla,
|
|
start: Point<P>,
|
|
current: Point<P>,
|
|
contour_count: usize,
|
|
}
|
|
|
|
impl Path<Pixels> {
|
|
/// Create a new path with the given starting point.
|
|
pub fn new(start: Point<Pixels>) -> Self {
|
|
Self {
|
|
id: PathId(0),
|
|
view_id: ViewId::default(),
|
|
layer_id: LayerId::default(),
|
|
order: DrawOrder::default(),
|
|
vertices: Vec::new(),
|
|
start,
|
|
current: start,
|
|
bounds: Bounds {
|
|
origin: start,
|
|
size: Default::default(),
|
|
},
|
|
content_mask: Default::default(),
|
|
color: Default::default(),
|
|
contour_count: 0,
|
|
}
|
|
}
|
|
|
|
/// Scale this path by the given factor.
|
|
pub fn scale(&self, factor: f32) -> Path<ScaledPixels> {
|
|
Path {
|
|
id: self.id,
|
|
view_id: self.view_id,
|
|
layer_id: self.layer_id,
|
|
order: self.order,
|
|
bounds: self.bounds.scale(factor),
|
|
content_mask: self.content_mask.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),
|
|
contour_count: self.contour_count,
|
|
color: self.color,
|
|
}
|
|
}
|
|
|
|
/// Draw a straight line from the current point to the given point.
|
|
pub fn line_to(&mut self, to: Point<Pixels>) {
|
|
self.contour_count += 1;
|
|
if self.contour_count > 1 {
|
|
self.push_triangle(
|
|
(self.start, self.current, to),
|
|
(point(0., 1.), point(0., 1.), point(0., 1.)),
|
|
);
|
|
}
|
|
self.current = to;
|
|
}
|
|
|
|
/// Draw a curve from the current point to the given point, using the given control point.
|
|
pub fn curve_to(&mut self, to: Point<Pixels>, ctrl: Point<Pixels>) {
|
|
self.contour_count += 1;
|
|
if self.contour_count > 1 {
|
|
self.push_triangle(
|
|
(self.start, self.current, to),
|
|
(point(0., 1.), point(0., 1.), point(0., 1.)),
|
|
);
|
|
}
|
|
|
|
self.push_triangle(
|
|
(self.current, ctrl, to),
|
|
(point(0., 0.), point(0.5, 0.), point(1., 1.)),
|
|
);
|
|
self.current = to;
|
|
}
|
|
|
|
fn push_triangle(
|
|
&mut self,
|
|
xy: (Point<Pixels>, Point<Pixels>, Point<Pixels>),
|
|
st: (Point<f32>, Point<f32>, Point<f32>),
|
|
) {
|
|
self.bounds = self
|
|
.bounds
|
|
.union(&Bounds {
|
|
origin: xy.0,
|
|
size: Default::default(),
|
|
})
|
|
.union(&Bounds {
|
|
origin: xy.1,
|
|
size: Default::default(),
|
|
})
|
|
.union(&Bounds {
|
|
origin: xy.2,
|
|
size: Default::default(),
|
|
});
|
|
|
|
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(),
|
|
});
|
|
}
|
|
}
|
|
|
|
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(Clone, Debug)]
|
|
#[repr(C)]
|
|
pub(crate) struct PathVertex<P: Clone + Default + 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),
|
|
}
|
|
}
|
|
}
|