zed/crates/gpui/src/scene.rs
Antonio Scandurra 4ff514ca7e Merge remote-tracking branch 'origin/main' into cache
# Conflicts:
#	crates/gpui/src/elements/div.rs
2024-01-15 11:37:46 +01:00

851 lines
26 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 type LayerId = u32;
pub type DrawOrder = u32;
#[derive(Default, Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[repr(C)]
pub 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 struct Scene {
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.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 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(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
}
}
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) = if first.0.is_some() {
(first.1, second.0.unwrap_or(u32::MAX))
} 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 < max_order)
.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 < max_order)
.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 < 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 + 1;
self.underlines_iter.next();
while self
.underlines_iter
.next_if(|underline| underline.order < max_order)
.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 < max_order && 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 < max_order && 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 < max_order)
.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 enum PrimitiveKind {
Shadow,
#[default]
Quad,
Path,
Underline,
MonochromeSprite,
PolychromeSprite,
Surface,
}
pub 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 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 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 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 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 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 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);
#[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> {
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,
}
}
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,
}
}
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;
}
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 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),
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct AtlasId(pub(crate) usize);