2023-10-05 20:42:11 +00:00
|
|
|
use crate::{
|
2023-10-09 16:50:42 +00:00
|
|
|
point, AtlasTextureId, AtlasTile, Bounds, ContentMask, Corners, Edges, Hsla, Pixels, Point,
|
2023-10-10 01:54:23 +00:00
|
|
|
ScaledPixels, StackingOrder,
|
2023-10-05 20:42:11 +00:00
|
|
|
};
|
2023-10-03 15:36:12 +00:00
|
|
|
use collections::BTreeMap;
|
2023-10-05 20:42:11 +00:00
|
|
|
use etagere::euclid::{Point3D, Vector3D};
|
|
|
|
use plane_split::{BspSplitter, Polygon as BspPolygon};
|
2023-10-09 16:50:42 +00:00
|
|
|
use std::{fmt::Debug, iter::Peekable, mem, slice};
|
2023-09-19 19:19:22 +00:00
|
|
|
|
2023-09-23 17:06:10 +00:00
|
|
|
// Exported to metal
|
2023-10-10 11:01:35 +00:00
|
|
|
pub(crate) type PointF = Point<f32>;
|
|
|
|
#[allow(non_camel_case_types, unused)]
|
|
|
|
pub(crate) type PathVertex_ScaledPixels = PathVertex<ScaledPixels>;
|
2023-10-10 01:54:23 +00:00
|
|
|
|
2023-10-05 20:42:11 +00:00
|
|
|
pub type LayerId = u32;
|
2023-10-10 01:54:23 +00:00
|
|
|
|
2023-10-05 20:42:11 +00:00
|
|
|
pub type DrawOrder = u32;
|
2023-09-23 17:06:10 +00:00
|
|
|
|
2023-10-09 16:50:42 +00:00
|
|
|
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>,
|
2023-09-24 22:52:33 +00:00
|
|
|
}
|
|
|
|
|
2023-10-09 16:50:42 +00:00
|
|
|
impl SceneBuilder {
|
|
|
|
pub fn new() -> SceneBuilder {
|
|
|
|
SceneBuilder {
|
|
|
|
layers_by_order: BTreeMap::new(),
|
|
|
|
splitter: BspSplitter::new(),
|
2023-10-05 20:42:11 +00:00
|
|
|
shadows: Vec::new(),
|
2023-10-06 13:34:37 +00:00
|
|
|
quads: Vec::new(),
|
2023-10-09 16:50:42 +00:00
|
|
|
paths: Vec::new(),
|
2023-10-06 13:34:37 +00:00
|
|
|
underlines: Vec::new(),
|
2023-10-05 20:42:11 +00:00
|
|
|
monochrome_sprites: Vec::new(),
|
|
|
|
polychrome_sprites: Vec::new(),
|
2023-09-19 19:19:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-09 16:50:42 +00:00
|
|
|
pub fn build(&mut self) -> Scene {
|
2023-10-05 20:42:11 +00:00
|
|
|
// Map each layer id to a float between 0. and 1., with 1. closer to the viewer.
|
2023-10-09 16:50:42 +00:00
|
|
|
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;
|
2023-10-05 20:42:11 +00:00
|
|
|
}
|
2023-10-09 16:50:42 +00:00
|
|
|
self.layers_by_order.clear();
|
2023-09-19 19:19:22 +00:00
|
|
|
|
2023-10-05 20:42:11 +00:00
|
|
|
// Add all primitives to the BSP splitter to determine draw order
|
2023-10-09 16:50:42 +00:00
|
|
|
self.splitter.reset();
|
2023-10-06 13:34:37 +00:00
|
|
|
|
|
|
|
for (ix, shadow) in self.shadows.iter().enumerate() {
|
|
|
|
let z = layer_z_values[shadow.order as LayerId as usize];
|
2023-10-09 16:50:42 +00:00
|
|
|
self.splitter
|
|
|
|
.add(shadow.bounds.to_bsp_polygon(z, (PrimitiveKind::Shadow, ix)));
|
2023-10-06 13:34:37 +00:00
|
|
|
}
|
|
|
|
|
2023-10-05 20:42:11 +00:00
|
|
|
for (ix, quad) in self.quads.iter().enumerate() {
|
|
|
|
let z = layer_z_values[quad.order as LayerId as usize];
|
2023-10-09 16:50:42 +00:00
|
|
|
self.splitter
|
|
|
|
.add(quad.bounds.to_bsp_polygon(z, (PrimitiveKind::Quad, ix)));
|
2023-10-05 20:42:11 +00:00
|
|
|
}
|
|
|
|
|
2023-10-10 11:01:35 +00:00
|
|
|
for (ix, path) in self.paths.iter().enumerate() {
|
|
|
|
let z = layer_z_values[path.order as LayerId as usize];
|
|
|
|
self.splitter
|
|
|
|
.add(path.bounds.to_bsp_polygon(z, (PrimitiveKind::Path, ix)));
|
|
|
|
}
|
|
|
|
|
2023-10-06 13:34:37 +00:00
|
|
|
for (ix, underline) in self.underlines.iter().enumerate() {
|
|
|
|
let z = layer_z_values[underline.order as LayerId as usize];
|
2023-10-09 16:50:42 +00:00
|
|
|
self.splitter.add(
|
2023-10-06 13:34:37 +00:00
|
|
|
underline
|
|
|
|
.bounds
|
|
|
|
.to_bsp_polygon(z, (PrimitiveKind::Underline, ix)),
|
|
|
|
);
|
2023-10-05 20:42:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (ix, monochrome_sprite) in self.monochrome_sprites.iter().enumerate() {
|
|
|
|
let z = layer_z_values[monochrome_sprite.order as LayerId as usize];
|
2023-10-09 16:50:42 +00:00
|
|
|
self.splitter.add(
|
2023-10-05 20:42:11 +00:00
|
|
|
monochrome_sprite
|
|
|
|
.bounds
|
|
|
|
.to_bsp_polygon(z, (PrimitiveKind::MonochromeSprite, ix)),
|
|
|
|
);
|
|
|
|
}
|
2023-10-03 04:14:45 +00:00
|
|
|
|
2023-10-05 20:42:11 +00:00
|
|
|
for (ix, polychrome_sprite) in self.polychrome_sprites.iter().enumerate() {
|
|
|
|
let z = layer_z_values[polychrome_sprite.order as LayerId as usize];
|
2023-10-09 16:50:42 +00:00
|
|
|
self.splitter.add(
|
2023-10-05 20:42:11 +00:00
|
|
|
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.
|
2023-10-09 16:50:42 +00:00
|
|
|
for (draw_order, polygon) in self
|
|
|
|
.splitter
|
|
|
|
.sort(Vector3D::new(0., 0., 1.))
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
{
|
2023-10-05 20:42:11 +00:00
|
|
|
match polygon.anchor {
|
|
|
|
(PrimitiveKind::Shadow, ix) => self.shadows[ix].order = draw_order as DrawOrder,
|
2023-10-06 13:34:37 +00:00
|
|
|
(PrimitiveKind::Quad, ix) => self.quads[ix].order = draw_order as DrawOrder,
|
2023-10-09 16:50:42 +00:00
|
|
|
(PrimitiveKind::Path, ix) => self.paths[ix].order = draw_order as DrawOrder,
|
2023-10-06 13:34:37 +00:00
|
|
|
(PrimitiveKind::Underline, ix) => {
|
|
|
|
self.underlines[ix].order = draw_order as DrawOrder
|
|
|
|
}
|
2023-10-05 20:42:11 +00:00
|
|
|
(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();
|
2023-10-06 13:34:37 +00:00
|
|
|
self.quads.sort_unstable();
|
2023-10-09 16:50:42 +00:00
|
|
|
self.paths.sort_unstable();
|
2023-10-06 13:34:37 +00:00
|
|
|
self.underlines.sort_unstable();
|
2023-10-04 09:53:20 +00:00
|
|
|
self.monochrome_sprites.sort_unstable();
|
2023-10-04 10:41:21 +00:00
|
|
|
self.polychrome_sprites.sort_unstable();
|
2023-10-05 20:42:11 +00:00
|
|
|
|
2023-10-09 16:50:42 +00:00
|
|
|
Scene {
|
|
|
|
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, order: &StackingOrder, primitive: impl Into<Primitive>) {
|
2023-10-10 11:01:35 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-10-09 16:50:42 +00:00
|
|
|
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
|
|
|
|
};
|
|
|
|
|
|
|
|
match primitive {
|
|
|
|
Primitive::Shadow(mut shadow) => {
|
|
|
|
shadow.order = layer_id;
|
|
|
|
self.shadows.push(shadow);
|
|
|
|
}
|
|
|
|
Primitive::Quad(mut quad) => {
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
Primitive::MonochromeSprite(mut sprite) => {
|
|
|
|
sprite.order = layer_id;
|
|
|
|
self.monochrome_sprites.push(sprite);
|
|
|
|
}
|
|
|
|
Primitive::PolychromeSprite(mut sprite) => {
|
|
|
|
sprite.order = layer_id;
|
|
|
|
self.polychrome_sprites.push(sprite);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Scene {
|
2023-10-10 01:54:23 +00:00
|
|
|
#[allow(dead_code)]
|
2023-10-09 17:50:48 +00:00
|
|
|
pub fn paths(&self) -> &[Path<ScaledPixels>] {
|
|
|
|
&self.paths
|
2023-10-09 16:50:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn batches(&self) -> impl Iterator<Item = PrimitiveBatch> {
|
2023-10-04 10:41:21 +00:00
|
|
|
BatchIterator {
|
2023-10-05 13:30:47 +00:00
|
|
|
shadows: &self.shadows,
|
|
|
|
shadows_start: 0,
|
|
|
|
shadows_iter: self.shadows.iter().peekable(),
|
2023-10-06 13:34:37 +00:00
|
|
|
quads: &self.quads,
|
|
|
|
quads_start: 0,
|
|
|
|
quads_iter: self.quads.iter().peekable(),
|
2023-10-09 16:50:42 +00:00
|
|
|
paths: &self.paths,
|
|
|
|
paths_start: 0,
|
|
|
|
paths_iter: self.paths.iter().peekable(),
|
2023-10-06 13:34:37 +00:00
|
|
|
underlines: &self.underlines,
|
|
|
|
underlines_start: 0,
|
|
|
|
underlines_iter: self.underlines.iter().peekable(),
|
2023-10-04 10:41:21 +00:00
|
|
|
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(),
|
|
|
|
}
|
2023-10-03 04:14:45 +00:00
|
|
|
}
|
2023-09-19 19:19:22 +00:00
|
|
|
}
|
|
|
|
|
2023-10-04 10:41:21 +00:00
|
|
|
struct BatchIterator<'a> {
|
2023-10-05 13:30:47 +00:00
|
|
|
shadows: &'a [Shadow],
|
|
|
|
shadows_start: usize,
|
|
|
|
shadows_iter: Peekable<slice::Iter<'a, Shadow>>,
|
2023-10-09 16:50:42 +00:00
|
|
|
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>>>,
|
2023-10-06 13:34:37 +00:00
|
|
|
underlines: &'a [Underline],
|
|
|
|
underlines_start: usize,
|
|
|
|
underlines_iter: Peekable<slice::Iter<'a, Underline>>,
|
2023-10-04 10:41:21 +00:00
|
|
|
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>>,
|
2023-10-03 04:14:45 +00:00
|
|
|
}
|
|
|
|
|
2023-10-04 10:41:21 +00:00
|
|
|
impl<'a> Iterator for BatchIterator<'a> {
|
2023-10-03 04:14:45 +00:00
|
|
|
type Item = PrimitiveBatch<'a>;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
2023-10-05 20:42:11 +00:00
|
|
|
let mut orders_and_kinds = [
|
2023-10-05 13:30:47 +00:00
|
|
|
(
|
|
|
|
self.shadows_iter.peek().map(|s| s.order),
|
2023-10-05 20:42:11 +00:00
|
|
|
PrimitiveKind::Shadow,
|
2023-10-05 13:30:47 +00:00
|
|
|
),
|
2023-10-06 13:34:37 +00:00
|
|
|
(self.quads_iter.peek().map(|q| q.order), PrimitiveKind::Quad),
|
2023-10-10 11:01:35 +00:00
|
|
|
(self.paths_iter.peek().map(|q| q.order), PrimitiveKind::Path),
|
2023-10-06 13:34:37 +00:00
|
|
|
(
|
|
|
|
self.underlines_iter.peek().map(|u| u.order),
|
|
|
|
PrimitiveKind::Underline,
|
|
|
|
),
|
2023-10-03 15:36:12 +00:00
|
|
|
(
|
2023-10-04 10:41:21 +00:00
|
|
|
self.monochrome_sprites_iter.peek().map(|s| s.order),
|
2023-10-05 20:42:11 +00:00
|
|
|
PrimitiveKind::MonochromeSprite,
|
2023-10-04 10:41:21 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
self.polychrome_sprites_iter.peek().map(|s| s.order),
|
2023-10-05 20:42:11 +00:00
|
|
|
PrimitiveKind::PolychromeSprite,
|
2023-10-03 15:36:12 +00:00
|
|
|
),
|
|
|
|
];
|
2023-10-05 20:42:11 +00:00
|
|
|
orders_and_kinds.sort_by_key(|(order, kind)| (order.unwrap_or(u32::MAX), *kind));
|
2023-10-03 15:36:12 +00:00
|
|
|
|
2023-10-05 20:42:11 +00:00
|
|
|
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))
|
2023-10-03 04:14:45 +00:00
|
|
|
} else {
|
2023-10-03 15:36:12 +00:00
|
|
|
return None;
|
|
|
|
};
|
|
|
|
|
|
|
|
match batch_kind {
|
2023-10-06 13:34:37 +00:00
|
|
|
PrimitiveKind::Shadow => {
|
|
|
|
let shadows_start = self.shadows_start;
|
|
|
|
let mut shadows_end = shadows_start;
|
|
|
|
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],
|
|
|
|
))
|
|
|
|
}
|
2023-10-03 15:36:12 +00:00
|
|
|
PrimitiveKind::Quad => {
|
|
|
|
let quads_start = self.quads_start;
|
2023-10-05 20:42:11 +00:00
|
|
|
let mut quads_end = quads_start;
|
|
|
|
while self
|
|
|
|
.quads_iter
|
|
|
|
.next_if(|quad| quad.order <= max_order)
|
|
|
|
.is_some()
|
|
|
|
{
|
|
|
|
quads_end += 1;
|
|
|
|
}
|
2023-10-03 15:36:12 +00:00
|
|
|
self.quads_start = quads_end;
|
|
|
|
Some(PrimitiveBatch::Quads(&self.quads[quads_start..quads_end]))
|
|
|
|
}
|
2023-10-09 16:50:42 +00:00
|
|
|
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]))
|
|
|
|
}
|
2023-10-06 13:34:37 +00:00
|
|
|
PrimitiveKind::Underline => {
|
|
|
|
let underlines_start = self.underlines_start;
|
|
|
|
let mut underlines_end = underlines_start;
|
2023-10-05 20:42:11 +00:00
|
|
|
while self
|
2023-10-06 13:34:37 +00:00
|
|
|
.underlines_iter
|
|
|
|
.next_if(|underline| underline.order <= max_order)
|
2023-10-05 20:42:11 +00:00
|
|
|
.is_some()
|
|
|
|
{
|
2023-10-06 13:34:37 +00:00
|
|
|
underlines_end += 1;
|
2023-10-05 20:42:11 +00:00
|
|
|
}
|
2023-10-06 13:34:37 +00:00
|
|
|
self.underlines_start = underlines_end;
|
|
|
|
Some(PrimitiveBatch::Underlines(
|
|
|
|
&self.underlines[underlines_start..underlines_end],
|
2023-10-05 13:30:47 +00:00
|
|
|
))
|
|
|
|
}
|
2023-10-04 10:41:21 +00:00
|
|
|
PrimitiveKind::MonochromeSprite => {
|
|
|
|
let texture_id = self.monochrome_sprites_iter.peek().unwrap().tile.texture_id;
|
|
|
|
let sprites_start = self.monochrome_sprites_start;
|
2023-10-05 20:42:11 +00:00
|
|
|
let mut sprites_end = sprites_start;
|
|
|
|
while self
|
|
|
|
.monochrome_sprites_iter
|
|
|
|
.next_if(|sprite| {
|
|
|
|
sprite.order <= max_order && sprite.tile.texture_id == texture_id
|
|
|
|
})
|
|
|
|
.is_some()
|
|
|
|
{
|
|
|
|
sprites_end += 1;
|
|
|
|
}
|
2023-10-04 10:41:21 +00:00
|
|
|
self.monochrome_sprites_start = sprites_end;
|
2023-10-04 09:53:20 +00:00
|
|
|
Some(PrimitiveBatch::MonochromeSprites {
|
2023-10-03 15:36:12 +00:00
|
|
|
texture_id,
|
2023-10-04 10:41:21 +00:00
|
|
|
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;
|
2023-10-05 20:42:11 +00:00
|
|
|
let mut sprites_end = self.polychrome_sprites_start;
|
|
|
|
while self
|
|
|
|
.polychrome_sprites_iter
|
|
|
|
.next_if(|sprite| {
|
|
|
|
sprite.order <= max_order && sprite.tile.texture_id == texture_id
|
|
|
|
})
|
|
|
|
.is_some()
|
|
|
|
{
|
|
|
|
sprites_end += 1;
|
|
|
|
}
|
2023-10-04 10:41:21 +00:00
|
|
|
self.polychrome_sprites_start = sprites_end;
|
|
|
|
Some(PrimitiveBatch::PolychromeSprites {
|
|
|
|
texture_id,
|
|
|
|
sprites: &self.polychrome_sprites[sprites_start..sprites_end],
|
2023-10-03 15:36:12 +00:00
|
|
|
})
|
|
|
|
}
|
2023-10-03 04:14:45 +00:00
|
|
|
}
|
2023-09-19 19:19:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-05 20:42:11 +00:00
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Default)]
|
2023-10-03 04:14:45 +00:00
|
|
|
pub enum PrimitiveKind {
|
2023-10-05 13:30:47 +00:00
|
|
|
Shadow,
|
2023-10-05 20:42:11 +00:00
|
|
|
#[default]
|
|
|
|
Quad,
|
2023-10-09 16:50:42 +00:00
|
|
|
Path,
|
2023-10-06 13:34:37 +00:00
|
|
|
Underline,
|
2023-10-04 10:41:21 +00:00
|
|
|
MonochromeSprite,
|
|
|
|
PolychromeSprite,
|
2023-10-03 04:14:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub enum Primitive {
|
2023-10-05 13:30:47 +00:00
|
|
|
Shadow(Shadow),
|
2023-10-06 13:34:37 +00:00
|
|
|
Quad(Quad),
|
2023-10-09 16:50:42 +00:00
|
|
|
Path(Path<ScaledPixels>),
|
2023-10-06 13:34:37 +00:00
|
|
|
Underline(Underline),
|
2023-10-04 09:53:20 +00:00
|
|
|
MonochromeSprite(MonochromeSprite),
|
|
|
|
PolychromeSprite(PolychromeSprite),
|
2023-10-03 04:14:45 +00:00
|
|
|
}
|
|
|
|
|
2023-10-10 11:01:35 +00:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-05 13:30:47 +00:00
|
|
|
#[derive(Debug)]
|
2023-10-03 15:36:12 +00:00
|
|
|
pub(crate) enum PrimitiveBatch<'a> {
|
2023-10-05 13:30:47 +00:00
|
|
|
Shadows(&'a [Shadow]),
|
2023-10-06 13:34:37 +00:00
|
|
|
Quads(&'a [Quad]),
|
2023-10-09 16:50:42 +00:00
|
|
|
Paths(&'a [Path<ScaledPixels>]),
|
2023-10-06 13:34:37 +00:00
|
|
|
Underlines(&'a [Underline]),
|
2023-10-04 09:53:20 +00:00
|
|
|
MonochromeSprites {
|
2023-10-03 15:36:12 +00:00
|
|
|
texture_id: AtlasTextureId,
|
|
|
|
sprites: &'a [MonochromeSprite],
|
|
|
|
},
|
2023-10-04 09:53:20 +00:00
|
|
|
PolychromeSprites {
|
|
|
|
texture_id: AtlasTextureId,
|
|
|
|
sprites: &'a [PolychromeSprite],
|
|
|
|
},
|
2023-10-03 04:14:45 +00:00
|
|
|
}
|
|
|
|
|
2023-10-05 20:42:11 +00:00
|
|
|
#[derive(Default, Debug, Clone, Eq, PartialEq)]
|
2023-09-19 19:19:22 +00:00
|
|
|
#[repr(C)]
|
|
|
|
pub struct Quad {
|
2023-10-05 20:42:11 +00:00
|
|
|
pub order: u32, // Initially a LayerId, then a DrawOrder.
|
2023-10-03 19:03:29 +00:00
|
|
|
pub bounds: Bounds<ScaledPixels>,
|
2023-10-09 16:50:42 +00:00
|
|
|
pub content_mask: ContentMask<ScaledPixels>,
|
2023-09-19 19:19:22 +00:00
|
|
|
pub background: Hsla,
|
|
|
|
pub border_color: Hsla,
|
2023-10-03 19:03:29 +00:00
|
|
|
pub corner_radii: Corners<ScaledPixels>,
|
|
|
|
pub border_widths: Edges<ScaledPixels>,
|
2023-09-19 19:19:22 +00:00
|
|
|
}
|
|
|
|
|
2023-10-03 15:36:12 +00:00
|
|
|
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))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-23 20:20:07 +00:00
|
|
|
impl From<Quad> for Primitive {
|
|
|
|
fn from(quad: Quad) -> Self {
|
|
|
|
Primitive::Quad(quad)
|
2023-09-19 19:19:22 +00:00
|
|
|
}
|
|
|
|
}
|
2023-10-02 21:43:03 +00:00
|
|
|
|
2023-10-06 13:34:37 +00:00
|
|
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
|
|
#[repr(C)]
|
|
|
|
pub struct Underline {
|
|
|
|
pub order: u32,
|
|
|
|
pub bounds: Bounds<ScaledPixels>,
|
2023-10-09 16:50:42 +00:00
|
|
|
pub content_mask: ContentMask<ScaledPixels>,
|
2023-10-06 13:34:37 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-05 13:30:47 +00:00
|
|
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
|
|
#[repr(C)]
|
|
|
|
pub struct Shadow {
|
|
|
|
pub order: u32,
|
|
|
|
pub bounds: Bounds<ScaledPixels>,
|
|
|
|
pub corner_radii: Corners<ScaledPixels>,
|
2023-10-09 16:50:42 +00:00
|
|
|
pub content_mask: ContentMask<ScaledPixels>,
|
2023-10-05 13:30:47 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-03 15:36:12 +00:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
2023-10-02 21:43:03 +00:00
|
|
|
#[repr(C)]
|
2023-10-03 04:14:45 +00:00
|
|
|
pub struct MonochromeSprite {
|
2023-10-02 21:43:03 +00:00
|
|
|
pub order: u32,
|
2023-10-03 19:52:10 +00:00
|
|
|
pub bounds: Bounds<ScaledPixels>,
|
2023-10-09 16:50:42 +00:00
|
|
|
pub content_mask: ContentMask<ScaledPixels>,
|
2023-10-03 12:48:08 +00:00
|
|
|
pub color: Hsla,
|
|
|
|
pub tile: AtlasTile,
|
2023-10-02 21:43:03 +00:00
|
|
|
}
|
|
|
|
|
2023-10-03 15:36:12 +00:00
|
|
|
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))
|
2023-10-02 21:43:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-03 04:14:45 +00:00
|
|
|
impl From<MonochromeSprite> for Primitive {
|
|
|
|
fn from(sprite: MonochromeSprite) -> Self {
|
2023-10-04 09:53:20 +00:00
|
|
|
Primitive::MonochromeSprite(sprite)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
|
|
#[repr(C)]
|
|
|
|
pub struct PolychromeSprite {
|
|
|
|
pub order: u32,
|
|
|
|
pub bounds: Bounds<ScaledPixels>,
|
2023-10-09 16:50:42 +00:00
|
|
|
pub content_mask: ContentMask<ScaledPixels>,
|
2023-10-04 16:38:08 +00:00
|
|
|
pub corner_radii: Corners<ScaledPixels>,
|
2023-10-04 09:53:20 +00:00
|
|
|
pub tile: AtlasTile,
|
2023-10-04 13:27:51 +00:00
|
|
|
pub grayscale: bool,
|
2023-10-04 09:53:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2023-10-02 21:43:03 +00:00
|
|
|
}
|
|
|
|
}
|
2023-10-03 04:14:45 +00:00
|
|
|
|
2023-10-09 16:50:42 +00:00
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
|
|
|
pub(crate) struct PathId(pub(crate) usize);
|
2023-10-09 14:02:48 +00:00
|
|
|
|
2023-10-09 16:50:42 +00:00
|
|
|
#[derive(Debug)]
|
2023-10-13 18:41:00 +00:00
|
|
|
pub struct Path<P: Clone + Default + Debug> {
|
2023-10-09 16:50:42 +00:00
|
|
|
pub(crate) id: PathId,
|
|
|
|
order: u32,
|
|
|
|
pub(crate) bounds: Bounds<P>,
|
2023-10-10 11:01:35 +00:00
|
|
|
pub(crate) content_mask: ContentMask<P>,
|
2023-10-09 16:50:42 +00:00
|
|
|
pub(crate) vertices: Vec<PathVertex<P>>,
|
2023-10-10 11:01:35 +00:00
|
|
|
pub(crate) color: Hsla,
|
|
|
|
start: Point<P>,
|
2023-10-09 16:50:42 +00:00
|
|
|
current: Point<P>,
|
2023-10-10 11:01:35 +00:00
|
|
|
contour_count: usize,
|
2023-10-09 14:02:48 +00:00
|
|
|
}
|
|
|
|
|
2023-10-09 16:50:42 +00:00
|
|
|
impl Path<Pixels> {
|
2023-10-10 11:01:35 +00:00
|
|
|
pub fn new(start: Point<Pixels>) -> Self {
|
2023-10-09 14:02:48 +00:00
|
|
|
Self {
|
2023-10-09 16:50:42 +00:00
|
|
|
id: PathId(0),
|
|
|
|
order: 0,
|
2023-10-09 14:02:48 +00:00
|
|
|
vertices: Vec::new(),
|
2023-10-10 11:01:35 +00:00
|
|
|
start,
|
|
|
|
current: start,
|
|
|
|
bounds: Bounds {
|
|
|
|
origin: start,
|
|
|
|
size: Default::default(),
|
|
|
|
},
|
|
|
|
content_mask: Default::default(),
|
|
|
|
color: Default::default(),
|
|
|
|
contour_count: 0,
|
2023-10-09 14:02:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-09 16:50:42 +00:00
|
|
|
pub fn scale(&self, factor: f32) -> Path<ScaledPixels> {
|
|
|
|
Path {
|
|
|
|
id: self.id,
|
|
|
|
order: self.order,
|
|
|
|
bounds: self.bounds.scale(factor),
|
2023-10-10 11:01:35 +00:00
|
|
|
content_mask: self.content_mask.scale(factor),
|
2023-10-09 16:50:42 +00:00
|
|
|
vertices: self
|
|
|
|
.vertices
|
|
|
|
.iter()
|
|
|
|
.map(|vertex| vertex.scale(factor))
|
|
|
|
.collect(),
|
|
|
|
start: self.start.map(|start| start.scale(factor)),
|
|
|
|
current: self.current.scale(factor),
|
2023-10-10 11:01:35 +00:00
|
|
|
contour_count: self.contour_count,
|
|
|
|
color: self.color,
|
2023-10-09 16:50:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-09 14:02:48 +00:00
|
|
|
pub fn line_to(&mut self, to: Point<Pixels>) {
|
2023-10-10 11:01:35 +00:00
|
|
|
self.contour_count += 1;
|
|
|
|
if self.contour_count > 1 {
|
2023-10-09 14:02:48 +00:00
|
|
|
self.push_triangle(
|
2023-10-10 11:01:35 +00:00
|
|
|
(self.start, self.current, to),
|
2023-10-09 14:02:48 +00:00
|
|
|
(point(0., 1.), point(0., 1.), point(0., 1.)),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
self.current = to;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn curve_to(&mut self, to: Point<Pixels>, ctrl: Point<Pixels>) {
|
2023-10-10 11:01:35 +00:00
|
|
|
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.)),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-10-09 14:02:48 +00:00
|
|
|
self.push_triangle(
|
|
|
|
(self.current, ctrl, to),
|
|
|
|
(point(0., 0.), point(0.5, 0.), point(1., 1.)),
|
|
|
|
);
|
2023-10-10 11:01:35 +00:00
|
|
|
self.current = to;
|
2023-10-09 14:02:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
2023-10-09 16:50:42 +00:00
|
|
|
content_mask: Default::default(),
|
2023-10-09 14:02:48 +00:00
|
|
|
});
|
|
|
|
self.vertices.push(PathVertex {
|
|
|
|
xy_position: xy.1,
|
|
|
|
st_position: st.1,
|
2023-10-09 16:50:42 +00:00
|
|
|
content_mask: Default::default(),
|
2023-10-09 14:02:48 +00:00
|
|
|
});
|
|
|
|
self.vertices.push(PathVertex {
|
|
|
|
xy_position: xy.2,
|
|
|
|
st_position: st.2,
|
2023-10-09 16:50:42 +00:00
|
|
|
content_mask: Default::default(),
|
2023-10-09 14:02:48 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-09 16:50:42 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-09 17:50:48 +00:00
|
|
|
#[derive(Clone, Debug)]
|
2023-10-09 14:02:48 +00:00
|
|
|
#[repr(C)]
|
2023-10-13 18:41:00 +00:00
|
|
|
pub struct PathVertex<P: Clone + Default + Debug> {
|
2023-10-09 16:50:42 +00:00
|
|
|
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),
|
|
|
|
}
|
|
|
|
}
|
2023-10-09 14:02:48 +00:00
|
|
|
}
|
|
|
|
|
2023-10-03 04:14:45 +00:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
|
|
pub struct AtlasId(pub(crate) usize);
|
2023-10-05 20:42:11 +00:00
|
|
|
|
|
|
|
impl Bounds<ScaledPixels> {
|
|
|
|
fn to_bsp_polygon<A: Copy>(&self, z: f32, anchor: A) -> BspPolygon<A> {
|
|
|
|
let upper_left = self.origin;
|
|
|
|
let upper_right = self.upper_right();
|
|
|
|
let lower_right = self.lower_right();
|
|
|
|
let lower_left = self.lower_left();
|
|
|
|
|
|
|
|
BspPolygon::from_points(
|
|
|
|
[
|
|
|
|
Point3D::new(upper_left.x.into(), upper_left.y.into(), z as f64),
|
|
|
|
Point3D::new(upper_right.x.into(), upper_right.y.into(), z as f64),
|
|
|
|
Point3D::new(lower_right.x.into(), lower_right.y.into(), z as f64),
|
|
|
|
Point3D::new(lower_left.x.into(), lower_left.y.into(), z as f64),
|
|
|
|
],
|
|
|
|
anchor,
|
|
|
|
)
|
|
|
|
.expect("Polygon should not be empty")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use crate::{point, size};
|
|
|
|
|
|
|
|
use super::*;
|
|
|
|
use smallvec::smallvec;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_scene() {
|
2023-10-09 16:50:42 +00:00
|
|
|
let mut scene = SceneBuilder::new();
|
|
|
|
assert_eq!(scene.layers_by_order.len(), 0);
|
2023-10-05 20:42:11 +00:00
|
|
|
|
2023-10-10 01:54:23 +00:00
|
|
|
scene.insert(&smallvec![1].into(), quad());
|
|
|
|
scene.insert(&smallvec![2].into(), shadow());
|
|
|
|
scene.insert(&smallvec![3].into(), quad());
|
2023-10-05 20:42:11 +00:00
|
|
|
|
|
|
|
let mut batches_count = 0;
|
2023-10-09 16:50:42 +00:00
|
|
|
for _ in scene.build().batches() {
|
2023-10-05 20:42:11 +00:00
|
|
|
batches_count += 1;
|
|
|
|
}
|
|
|
|
assert_eq!(batches_count, 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn quad() -> Quad {
|
|
|
|
Quad {
|
|
|
|
order: 0,
|
|
|
|
bounds: Bounds {
|
|
|
|
origin: point(ScaledPixels(0.), ScaledPixels(0.)),
|
|
|
|
size: size(ScaledPixels(100.), ScaledPixels(100.)),
|
|
|
|
},
|
|
|
|
content_mask: Default::default(),
|
|
|
|
background: Default::default(),
|
|
|
|
border_color: Default::default(),
|
|
|
|
corner_radii: Default::default(),
|
|
|
|
border_widths: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn shadow() -> Shadow {
|
|
|
|
Shadow {
|
|
|
|
order: Default::default(),
|
|
|
|
bounds: Bounds {
|
|
|
|
origin: point(ScaledPixels(0.), ScaledPixels(0.)),
|
|
|
|
size: size(ScaledPixels(100.), ScaledPixels(100.)),
|
|
|
|
},
|
|
|
|
corner_radii: Default::default(),
|
|
|
|
content_mask: Default::default(),
|
|
|
|
color: Default::default(),
|
|
|
|
blur_radius: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|