Replace Primitive::Translate with Transform

This commit is contained in:
Héctor Ramón Jiménez 2023-10-23 03:13:28 +02:00
parent 759f0e9225
commit 5467c19c80
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
11 changed files with 205 additions and 133 deletions

View file

@ -102,10 +102,10 @@ impl<T: Damage> Damage for Primitive<T> {
.fold(Rectangle::with_size(Size::ZERO), |a, b| { .fold(Rectangle::with_size(Size::ZERO), |a, b| {
Rectangle::union(&a, &b) Rectangle::union(&a, &b)
}), }),
Self::Translate { Self::Transform {
translation, transformation,
content, content,
} => content.bounds() + *translation, } => content.bounds() * *transformation,
Self::Cache { content } => content.bounds(), Self::Cache { content } => content.bounds(),
Self::Custom(custom) => custom.bounds(), Self::Custom(custom) => custom.bounds(),
} }
@ -144,19 +144,19 @@ fn regions<T: Damage>(a: &Primitive<T>, b: &Primitive<T>) -> Vec<Rectangle> {
} }
} }
( (
Primitive::Translate { Primitive::Transform {
translation: translation_a, transformation: transformation_a,
content: content_a, content: content_a,
}, },
Primitive::Translate { Primitive::Transform {
translation: translation_b, transformation: transformation_b,
content: content_b, content: content_b,
}, },
) => { ) => {
if translation_a == translation_b { if transformation_a == transformation_b {
return regions(content_a, content_b) return regions(content_a, content_b)
.into_iter() .into_iter()
.map(|r| r + *translation_a) .map(|r| r * *transformation_a)
.collect(); .collect();
} }
} }

View file

@ -8,6 +8,7 @@ use crate::core::{
}; };
use crate::text::editor; use crate::text::editor;
use crate::text::paragraph; use crate::text::paragraph;
use crate::Transformation;
use std::sync::Arc; use std::sync::Arc;
@ -104,12 +105,12 @@ pub enum Primitive<T> {
/// The content of the clip /// The content of the clip
content: Box<Primitive<T>>, content: Box<Primitive<T>>,
}, },
/// A primitive that applies a translation /// A primitive that applies a [`Transformation`]
Translate { Transform {
/// The translation vector /// The [`Transformation`]
translation: Vector, transformation: Transformation,
/// The primitive to translate /// The primitive to transform
content: Box<Primitive<T>>, content: Box<Primitive<T>>,
}, },
/// A cached primitive. /// A cached primitive.
@ -125,12 +126,12 @@ pub enum Primitive<T> {
} }
impl<T> Primitive<T> { impl<T> Primitive<T> {
/// Creates a [`Primitive::Group`]. /// Groups the current [`Primitive`].
pub fn group(primitives: Vec<Self>) -> Self { pub fn group(primitives: Vec<Self>) -> Self {
Self::Group { primitives } Self::Group { primitives }
} }
/// Creates a [`Primitive::Clip`]. /// Clips the current [`Primitive`].
pub fn clip(self, bounds: Rectangle) -> Self { pub fn clip(self, bounds: Rectangle) -> Self {
Self::Clip { Self::Clip {
bounds, bounds,
@ -138,10 +139,21 @@ impl<T> Primitive<T> {
} }
} }
/// Creates a [`Primitive::Translate`]. /// Translates the current [`Primitive`].
pub fn translate(self, translation: Vector) -> Self { pub fn translate(self, translation: Vector) -> Self {
Self::Translate { Self::Transform {
translation, transformation: Transformation::translate(
translation.x,
translation.y,
),
content: Box::new(self),
}
}
/// Transforms the current [`Primitive`].
pub fn transform(self, transformation: Transformation) -> Self {
Self::Transform {
transformation,
content: Box::new(self), content: Box::new(self),
} }
} }

View file

@ -1,4 +1,6 @@
use glam::{Mat4, Vec3}; use crate::core::{Point, Rectangle, Size, Vector};
use glam::{Mat4, Vec3, Vec4};
use std::ops::Mul; use std::ops::Mul;
/// A 2D transformation matrix. /// A 2D transformation matrix.
@ -6,10 +8,8 @@ use std::ops::Mul;
pub struct Transformation(Mat4); pub struct Transformation(Mat4);
impl Transformation { impl Transformation {
/// Get the identity transformation. /// A [`Transformation`] that preserves whatever is transformed.
pub fn identity() -> Transformation { pub const IDENTITY: Self = Self(Mat4::IDENTITY);
Transformation(Mat4::IDENTITY)
}
/// Creates an orthographic projection. /// Creates an orthographic projection.
#[rustfmt::skip] #[rustfmt::skip]
@ -30,6 +30,26 @@ impl Transformation {
pub fn scale(x: f32, y: f32) -> Transformation { pub fn scale(x: f32, y: f32) -> Transformation {
Transformation(Mat4::from_scale(Vec3::new(x, y, 1.0))) Transformation(Mat4::from_scale(Vec3::new(x, y, 1.0)))
} }
/// The scale factor on the X axis.
pub fn scale_x(&self) -> f32 {
self.0.x_axis.x
}
/// The scale factor on the Y axis.
pub fn scale_y(&self) -> f32 {
self.0.y_axis.y
}
/// The translation on the X axis.
pub fn translation_x(&self) -> f32 {
self.0.w_axis.x
}
/// The translation on the Y axis.
pub fn translation_y(&self) -> f32 {
self.0.w_axis.y
}
} }
impl Mul for Transformation { impl Mul for Transformation {
@ -40,6 +60,56 @@ impl Mul for Transformation {
} }
} }
impl Mul<Transformation> for Point {
type Output = Self;
fn mul(self, transformation: Transformation) -> Self {
let point = transformation
.0
.mul_vec4(Vec4::new(self.x, self.y, 1.0, 1.0));
Point::new(point.x, point.y)
}
}
impl Mul<Transformation> for Vector {
type Output = Self;
fn mul(self, transformation: Transformation) -> Self {
let new_vector = transformation
.0
.mul_vec4(Vec4::new(self.x, self.y, 1.0, 0.0));
Vector::new(new_vector.x, new_vector.y)
}
}
impl Mul<Transformation> for Size {
type Output = Self;
fn mul(self, transformation: Transformation) -> Self {
let new_size = transformation.0.mul_vec4(Vec4::new(
self.width,
self.height,
1.0,
0.0,
));
Size::new(new_size.x, new_size.y)
}
}
impl Mul<Transformation> for Rectangle {
type Output = Self;
fn mul(self, transformation: Transformation) -> Self {
let position = self.position();
let size = self.size();
Self::new(position * transformation, size * transformation)
}
}
impl AsRef<[f32; 16]> for Transformation { impl AsRef<[f32; 16]> for Transformation {
fn as_ref(&self) -> &[f32; 16] { fn as_ref(&self) -> &[f32; 16] {
self.0.as_ref() self.0.as_ref()

View file

@ -3,7 +3,7 @@ use tiny_skia::Size;
use crate::core::{Background, Color, Gradient, Rectangle, Vector}; use crate::core::{Background, Color, Gradient, Rectangle, Vector};
use crate::graphics::backend; use crate::graphics::backend;
use crate::graphics::text; use crate::graphics::text;
use crate::graphics::Viewport; use crate::graphics::{Transformation, Viewport};
use crate::primitive::{self, Primitive}; use crate::primitive::{self, Primitive};
use std::borrow::Cow; use std::borrow::Cow;
@ -106,7 +106,7 @@ impl Backend {
clip_mask, clip_mask,
region, region,
scale_factor, scale_factor,
Vector::ZERO, Transformation::IDENTITY,
); );
} }
@ -146,7 +146,7 @@ impl Backend {
clip_mask: &mut tiny_skia::Mask, clip_mask: &mut tiny_skia::Mask,
clip_bounds: Rectangle, clip_bounds: Rectangle,
scale_factor: f32, scale_factor: f32,
translation: Vector, transformation: Transformation,
) { ) {
match primitive { match primitive {
Primitive::Quad { Primitive::Quad {
@ -164,7 +164,7 @@ impl Backend {
"Quad with non-normal height!" "Quad with non-normal height!"
); );
let physical_bounds = (*bounds + translation) * scale_factor; let physical_bounds = (*bounds * transformation) * scale_factor;
if !clip_bounds.intersects(&physical_bounds) { if !clip_bounds.intersects(&physical_bounds) {
return; return;
@ -173,11 +173,8 @@ impl Backend {
let clip_mask = (!physical_bounds.is_within(&clip_bounds)) let clip_mask = (!physical_bounds.is_within(&clip_bounds))
.then_some(clip_mask as &_); .then_some(clip_mask as &_);
let transform = tiny_skia::Transform::from_translate( let transform = into_transform(transformation)
translation.x, .post_scale(scale_factor, scale_factor);
translation.y,
)
.post_scale(scale_factor, scale_factor);
// Make sure the border radius is not larger than the bounds // Make sure the border radius is not larger than the bounds
let border_width = border let border_width = border
@ -199,7 +196,7 @@ impl Backend {
y: bounds.y + shadow.offset.y - shadow.blur_radius, y: bounds.y + shadow.offset.y - shadow.blur_radius,
width: bounds.width + shadow.blur_radius * 2.0, width: bounds.width + shadow.blur_radius * 2.0,
height: bounds.height + shadow.blur_radius * 2.0, height: bounds.height + shadow.blur_radius * 2.0,
} + translation) } * transformation)
* scale_factor; * scale_factor;
let radii = fill_border_radius let radii = fill_border_radius
@ -451,7 +448,7 @@ impl Backend {
clip_bounds: text_clip_bounds, clip_bounds: text_clip_bounds,
} => { } => {
let physical_bounds = let physical_bounds =
(*text_clip_bounds + translation) * scale_factor; *text_clip_bounds * transformation * scale_factor;
if !clip_bounds.intersects(&physical_bounds) { if !clip_bounds.intersects(&physical_bounds) {
return; return;
@ -462,7 +459,7 @@ impl Backend {
self.text_pipeline.draw_paragraph( self.text_pipeline.draw_paragraph(
paragraph, paragraph,
*position + translation, *position * transformation,
*color, *color,
scale_factor, scale_factor,
pixels, pixels,
@ -476,7 +473,7 @@ impl Backend {
clip_bounds: text_clip_bounds, clip_bounds: text_clip_bounds,
} => { } => {
let physical_bounds = let physical_bounds =
(*text_clip_bounds + translation) * scale_factor; (*text_clip_bounds * transformation) * scale_factor;
if !clip_bounds.intersects(&physical_bounds) { if !clip_bounds.intersects(&physical_bounds) {
return; return;
@ -487,7 +484,7 @@ impl Backend {
self.text_pipeline.draw_editor( self.text_pipeline.draw_editor(
editor, editor,
*position + translation, *position * transformation,
*color, *color,
scale_factor, scale_factor,
pixels, pixels,
@ -507,7 +504,7 @@ impl Backend {
clip_bounds: text_clip_bounds, clip_bounds: text_clip_bounds,
} => { } => {
let physical_bounds = let physical_bounds =
(*text_clip_bounds + translation) * scale_factor; *text_clip_bounds * transformation * scale_factor;
if !clip_bounds.intersects(&physical_bounds) { if !clip_bounds.intersects(&physical_bounds) {
return; return;
@ -518,7 +515,7 @@ impl Backend {
self.text_pipeline.draw_cached( self.text_pipeline.draw_cached(
content, content,
*bounds + translation, *bounds * transformation,
*color, *color,
*size, *size,
*line_height, *line_height,
@ -542,7 +539,7 @@ impl Backend {
}; };
let physical_bounds = let physical_bounds =
(*text_clip_bounds + translation) * scale_factor; *text_clip_bounds * transformation * scale_factor;
if !clip_bounds.intersects(&physical_bounds) { if !clip_bounds.intersects(&physical_bounds) {
return; return;
@ -553,7 +550,7 @@ impl Backend {
self.text_pipeline.draw_raw( self.text_pipeline.draw_raw(
&buffer, &buffer,
*position + translation, *position * transformation,
*color, *color,
scale_factor, scale_factor,
pixels, pixels,
@ -566,7 +563,7 @@ impl Backend {
filter_method, filter_method,
bounds, bounds,
} => { } => {
let physical_bounds = (*bounds + translation) * scale_factor; let physical_bounds = (*bounds * transformation) * scale_factor;
if !clip_bounds.intersects(&physical_bounds) { if !clip_bounds.intersects(&physical_bounds) {
return; return;
@ -575,11 +572,8 @@ impl Backend {
let clip_mask = (!physical_bounds.is_within(&clip_bounds)) let clip_mask = (!physical_bounds.is_within(&clip_bounds))
.then_some(clip_mask as &_); .then_some(clip_mask as &_);
let transform = tiny_skia::Transform::from_translate( let transform = into_transform(transformation)
translation.x, .post_scale(scale_factor, scale_factor);
translation.y,
)
.post_scale(scale_factor, scale_factor);
self.raster_pipeline.draw( self.raster_pipeline.draw(
handle, handle,
@ -602,7 +596,7 @@ impl Backend {
bounds, bounds,
color, color,
} => { } => {
let physical_bounds = (*bounds + translation) * scale_factor; let physical_bounds = (*bounds * transformation) * scale_factor;
if !clip_bounds.intersects(&physical_bounds) { if !clip_bounds.intersects(&physical_bounds) {
return; return;
@ -614,7 +608,7 @@ impl Backend {
self.vector_pipeline.draw( self.vector_pipeline.draw(
handle, handle,
*color, *color,
(*bounds + translation) * scale_factor, (*bounds * transformation) * scale_factor,
pixels, pixels,
clip_mask, clip_mask,
); );
@ -637,7 +631,7 @@ impl Backend {
y: bounds.y(), y: bounds.y(),
width: bounds.width(), width: bounds.width(),
height: bounds.height(), height: bounds.height(),
} + translation) } * transformation)
* scale_factor; * scale_factor;
if !clip_bounds.intersects(&physical_bounds) { if !clip_bounds.intersects(&physical_bounds) {
@ -651,11 +645,8 @@ impl Backend {
path, path,
paint, paint,
*rule, *rule,
tiny_skia::Transform::from_translate( into_transform(transformation)
translation.x, .post_scale(scale_factor, scale_factor),
translation.y,
)
.post_scale(scale_factor, scale_factor),
clip_mask, clip_mask,
); );
} }
@ -671,7 +662,7 @@ impl Backend {
y: bounds.y(), y: bounds.y(),
width: bounds.width(), width: bounds.width(),
height: bounds.height(), height: bounds.height(),
} + translation) } * transformation)
* scale_factor; * scale_factor;
if !clip_bounds.intersects(&physical_bounds) { if !clip_bounds.intersects(&physical_bounds) {
@ -685,11 +676,8 @@ impl Backend {
path, path,
paint, paint,
stroke, stroke,
tiny_skia::Transform::from_translate( into_transform(transformation)
translation.x, .post_scale(scale_factor, scale_factor),
translation.y,
)
.post_scale(scale_factor, scale_factor),
clip_mask, clip_mask,
); );
} }
@ -701,12 +689,12 @@ impl Backend {
clip_mask, clip_mask,
clip_bounds, clip_bounds,
scale_factor, scale_factor,
translation, transformation,
); );
} }
} }
Primitive::Translate { Primitive::Transform {
translation: offset, transformation: new_transformation,
content, content,
} => { } => {
self.draw_primitive( self.draw_primitive(
@ -715,11 +703,11 @@ impl Backend {
clip_mask, clip_mask,
clip_bounds, clip_bounds,
scale_factor, scale_factor,
translation + *offset, transformation * *new_transformation,
); );
} }
Primitive::Clip { bounds, content } => { Primitive::Clip { bounds, content } => {
let bounds = (*bounds + translation) * scale_factor; let bounds = (*bounds * transformation) * scale_factor;
if bounds == clip_bounds { if bounds == clip_bounds {
self.draw_primitive( self.draw_primitive(
@ -728,7 +716,7 @@ impl Backend {
clip_mask, clip_mask,
bounds, bounds,
scale_factor, scale_factor,
translation, transformation,
); );
} else if let Some(bounds) = clip_bounds.intersection(&bounds) { } else if let Some(bounds) = clip_bounds.intersection(&bounds) {
if bounds.x + bounds.width <= 0.0 if bounds.x + bounds.width <= 0.0
@ -749,7 +737,7 @@ impl Backend {
clip_mask, clip_mask,
bounds, bounds,
scale_factor, scale_factor,
translation, transformation,
); );
adjust_clip_mask(clip_mask, clip_bounds); adjust_clip_mask(clip_mask, clip_bounds);
@ -762,7 +750,7 @@ impl Backend {
clip_mask, clip_mask,
clip_bounds, clip_bounds,
scale_factor, scale_factor,
translation, transformation,
); );
} }
} }
@ -780,6 +768,17 @@ fn into_color(color: Color) -> tiny_skia::Color {
.expect("Convert color from iced to tiny_skia") .expect("Convert color from iced to tiny_skia")
} }
fn into_transform(transformation: Transformation) -> tiny_skia::Transform {
tiny_skia::Transform {
sx: transformation.scale_x(),
kx: 0.0,
ky: 0.0,
sy: transformation.scale_y(),
tx: transformation.translation_x(),
ty: transformation.translation_y(),
}
}
fn rounded_rectangle( fn rounded_rectangle(
bounds: Rectangle, bounds: Rectangle,
border_radius: [f32; 4], border_radius: [f32; 4],

View file

@ -3,7 +3,7 @@ use crate::core::{Pixels, Point, Rectangle, Size, Vector};
use crate::graphics::geometry::fill::{self, Fill}; use crate::graphics::geometry::fill::{self, Fill};
use crate::graphics::geometry::stroke::{self, Stroke}; use crate::graphics::geometry::stroke::{self, Stroke};
use crate::graphics::geometry::{Path, Style, Text}; use crate::graphics::geometry::{Path, Style, Text};
use crate::graphics::Gradient; use crate::graphics::{Gradient, Transformation};
use crate::primitive::{self, Primitive}; use crate::primitive::{self, Primitive};
pub struct Frame { pub struct Frame {
@ -181,8 +181,8 @@ impl Frame {
} }
pub fn clip(&mut self, frame: Self, at: Point) { pub fn clip(&mut self, frame: Self, at: Point) {
self.primitives.push(Primitive::Translate { self.primitives.push(Primitive::Transform {
translation: Vector::new(at.x, at.y), transformation: Transformation::translate(at.x, at.y),
content: Box::new(frame.into_primitive()), content: Box::new(frame.into_primitive()),
}); });
} }

View file

@ -8,6 +8,7 @@ use crate::graphics::geometry::{
}; };
use crate::graphics::gradient::{self, Gradient}; use crate::graphics::gradient::{self, Gradient};
use crate::graphics::mesh::{self, Mesh}; use crate::graphics::mesh::{self, Mesh};
use crate::graphics::Transformation;
use crate::primitive::{self, Primitive}; use crate::primitive::{self, Primitive};
use lyon::geom::euclid; use lyon::geom::euclid;
@ -435,7 +436,7 @@ impl Frame {
pub fn clip(&mut self, frame: Frame, at: Point) { pub fn clip(&mut self, frame: Frame, at: Point) {
let size = frame.size(); let size = frame.size();
let primitives = frame.into_primitives(); let primitives = frame.into_primitives();
let translation = Vector::new(at.x, at.y); let transformation = Transformation::translate(at.x, at.y);
let (text, meshes) = primitives let (text, meshes) = primitives
.into_iter() .into_iter()
@ -443,12 +444,12 @@ impl Frame {
self.primitives.push(Primitive::Group { self.primitives.push(Primitive::Group {
primitives: vec![ primitives: vec![
Primitive::Translate { Primitive::Transform {
translation, transformation,
content: Box::new(Primitive::Group { primitives: meshes }), content: Box::new(Primitive::Group { primitives: meshes }),
}, },
Primitive::Translate { Primitive::Transform {
translation, transformation,
content: Box::new(Primitive::Clip { content: Box::new(Primitive::Clip {
bounds: Rectangle::with_size(size), bounds: Rectangle::with_size(size),
content: Box::new(Primitive::Group { content: Box::new(Primitive::Group {

View file

@ -15,7 +15,7 @@ use crate::core::alignment;
use crate::core::{Color, Font, Pixels, Point, Rectangle, Size, Vector}; use crate::core::{Color, Font, Pixels, Point, Rectangle, Size, Vector};
use crate::graphics; use crate::graphics;
use crate::graphics::color; use crate::graphics::color;
use crate::graphics::Viewport; use crate::graphics::{Transformation, Viewport};
use crate::primitive::{self, Primitive}; use crate::primitive::{self, Primitive};
use crate::quad::{self, Quad}; use crate::quad::{self, Quad};
@ -104,7 +104,7 @@ impl<'a> Layer<'a> {
for primitive in primitives { for primitive in primitives {
Self::process_primitive( Self::process_primitive(
&mut layers, &mut layers,
Vector::new(0.0, 0.0), Transformation::IDENTITY,
primitive, primitive,
0, 0,
); );
@ -115,7 +115,7 @@ impl<'a> Layer<'a> {
fn process_primitive( fn process_primitive(
layers: &mut Vec<Self>, layers: &mut Vec<Self>,
translation: Vector, transformation: Transformation,
primitive: &'a Primitive, primitive: &'a Primitive,
current_layer: usize, current_layer: usize,
) { ) {
@ -130,9 +130,10 @@ impl<'a> Layer<'a> {
layer.text.push(Text::Paragraph { layer.text.push(Text::Paragraph {
paragraph: paragraph.clone(), paragraph: paragraph.clone(),
position: *position + translation, position: *position * transformation,
color: *color, color: *color,
clip_bounds: *clip_bounds + translation, clip_bounds: *clip_bounds * transformation,
scale: transformation.scale_y(),
}); });
} }
Primitive::Editor { Primitive::Editor {
@ -145,9 +146,10 @@ impl<'a> Layer<'a> {
layer.text.push(Text::Editor { layer.text.push(Text::Editor {
editor: editor.clone(), editor: editor.clone(),
position: *position + translation, position: *position * transformation,
color: *color, color: *color,
clip_bounds: *clip_bounds + translation, clip_bounds: *clip_bounds * transformation,
scale: transformation.scale_y(),
}); });
} }
Primitive::Text { Primitive::Text {
@ -166,7 +168,7 @@ impl<'a> Layer<'a> {
layer.text.push(Text::Cached(text::Cached { layer.text.push(Text::Cached(text::Cached {
content, content,
bounds: *bounds + translation, bounds: *bounds * transformation,
size: *size, size: *size,
line_height: *line_height, line_height: *line_height,
color: *color, color: *color,
@ -174,7 +176,7 @@ impl<'a> Layer<'a> {
horizontal_alignment: *horizontal_alignment, horizontal_alignment: *horizontal_alignment,
vertical_alignment: *vertical_alignment, vertical_alignment: *vertical_alignment,
shaping: *shaping, shaping: *shaping,
clip_bounds: *clip_bounds + translation, clip_bounds: *clip_bounds * transformation,
})); }));
} }
graphics::Primitive::RawText(graphics::text::Raw { graphics::Primitive::RawText(graphics::text::Raw {
@ -187,9 +189,9 @@ impl<'a> Layer<'a> {
layer.text.push(Text::Raw(graphics::text::Raw { layer.text.push(Text::Raw(graphics::text::Raw {
buffer: buffer.clone(), buffer: buffer.clone(),
position: *position + translation, position: *position * transformation,
color: *color, color: *color,
clip_bounds: *clip_bounds + translation, clip_bounds: *clip_bounds * transformation,
})); }));
} }
Primitive::Quad { Primitive::Quad {
@ -199,12 +201,10 @@ impl<'a> Layer<'a> {
shadow, shadow,
} => { } => {
let layer = &mut layers[current_layer]; let layer = &mut layers[current_layer];
let bounds = *bounds * transformation;
let quad = Quad { let quad = Quad {
position: [ position: [bounds.x, bounds.y],
bounds.x + translation.x,
bounds.y + translation.y,
],
size: [bounds.width, bounds.height], size: [bounds.width, bounds.height],
border_color: color::pack(border.color), border_color: color::pack(border.color),
border_radius: border.radius.into(), border_radius: border.radius.into(),
@ -226,7 +226,7 @@ impl<'a> Layer<'a> {
layer.images.push(Image::Raster { layer.images.push(Image::Raster {
handle: handle.clone(), handle: handle.clone(),
filter_method: *filter_method, filter_method: *filter_method,
bounds: *bounds + translation, bounds: *bounds * transformation,
}); });
} }
Primitive::Svg { Primitive::Svg {
@ -239,7 +239,7 @@ impl<'a> Layer<'a> {
layer.images.push(Image::Vector { layer.images.push(Image::Vector {
handle: handle.clone(), handle: handle.clone(),
color: *color, color: *color,
bounds: *bounds + translation, bounds: *bounds * transformation,
}); });
} }
Primitive::Group { primitives } => { Primitive::Group { primitives } => {
@ -247,7 +247,7 @@ impl<'a> Layer<'a> {
for primitive in primitives { for primitive in primitives {
Self::process_primitive( Self::process_primitive(
layers, layers,
translation, transformation,
primitive, primitive,
current_layer, current_layer,
); );
@ -255,7 +255,7 @@ impl<'a> Layer<'a> {
} }
Primitive::Clip { bounds, content } => { Primitive::Clip { bounds, content } => {
let layer = &mut layers[current_layer]; let layer = &mut layers[current_layer];
let translated_bounds = *bounds + translation; let translated_bounds = *bounds * transformation;
// Only draw visible content // Only draw visible content
if let Some(clip_bounds) = if let Some(clip_bounds) =
@ -266,19 +266,19 @@ impl<'a> Layer<'a> {
Self::process_primitive( Self::process_primitive(
layers, layers,
translation, transformation,
content, content,
layers.len() - 1, layers.len() - 1,
); );
} }
} }
Primitive::Translate { Primitive::Transform {
translation: new_translation, transformation: new_transformation,
content, content,
} => { } => {
Self::process_primitive( Self::process_primitive(
layers, layers,
translation + *new_translation, transformation * *new_transformation,
content, content,
current_layer, current_layer,
); );
@ -286,7 +286,7 @@ impl<'a> Layer<'a> {
Primitive::Cache { content } => { Primitive::Cache { content } => {
Self::process_primitive( Self::process_primitive(
layers, layers,
translation, transformation,
content, content,
current_layer, current_layer,
); );
@ -296,20 +296,15 @@ impl<'a> Layer<'a> {
graphics::Mesh::Solid { buffers, size } => { graphics::Mesh::Solid { buffers, size } => {
let layer = &mut layers[current_layer]; let layer = &mut layers[current_layer];
let bounds = Rectangle::new( let bounds =
Point::new(translation.x, translation.y), Rectangle::with_size(*size) * transformation;
*size,
);
// Only draw visible content // Only draw visible content
if let Some(clip_bounds) = if let Some(clip_bounds) =
layer.bounds.intersection(&bounds) layer.bounds.intersection(&bounds)
{ {
layer.meshes.push(Mesh::Solid { layer.meshes.push(Mesh::Solid {
origin: Point::new( transformation,
translation.x,
translation.y,
),
buffers, buffers,
clip_bounds, clip_bounds,
}); });
@ -318,20 +313,15 @@ impl<'a> Layer<'a> {
graphics::Mesh::Gradient { buffers, size } => { graphics::Mesh::Gradient { buffers, size } => {
let layer = &mut layers[current_layer]; let layer = &mut layers[current_layer];
let bounds = Rectangle::new( let bounds =
Point::new(translation.x, translation.y), Rectangle::with_size(*size) * transformation;
*size,
);
// Only draw visible content // Only draw visible content
if let Some(clip_bounds) = if let Some(clip_bounds) =
layer.bounds.intersection(&bounds) layer.bounds.intersection(&bounds)
{ {
layer.meshes.push(Mesh::Gradient { layer.meshes.push(Mesh::Gradient {
origin: Point::new( transformation,
translation.x,
translation.y,
),
buffers, buffers,
clip_bounds, clip_bounds,
}); });
@ -340,7 +330,7 @@ impl<'a> Layer<'a> {
}, },
primitive::Custom::Pipeline(pipeline) => { primitive::Custom::Pipeline(pipeline) => {
let layer = &mut layers[current_layer]; let layer = &mut layers[current_layer];
let bounds = pipeline.bounds + translation; let bounds = pipeline.bounds * transformation;
if let Some(clip_bounds) = if let Some(clip_bounds) =
layer.bounds.intersection(&bounds) layer.bounds.intersection(&bounds)

View file

@ -1,14 +1,15 @@
//! A collection of triangle primitives. //! A collection of triangle primitives.
use crate::core::{Point, Rectangle}; use crate::core::Rectangle;
use crate::graphics::mesh; use crate::graphics::mesh;
use crate::graphics::Transformation;
/// A mesh of triangles. /// A mesh of triangles.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Mesh<'a> { pub enum Mesh<'a> {
/// A mesh of triangles with a solid color. /// A mesh of triangles with a solid color.
Solid { Solid {
/// The origin of the vertices of the [`Mesh`]. /// The [`Transformation`] for the vertices of the [`Mesh`].
origin: Point, transformation: Transformation,
/// The vertex and index buffers of the [`Mesh`]. /// The vertex and index buffers of the [`Mesh`].
buffers: &'a mesh::Indexed<mesh::SolidVertex2D>, buffers: &'a mesh::Indexed<mesh::SolidVertex2D>,
@ -18,8 +19,8 @@ pub enum Mesh<'a> {
}, },
/// A mesh of triangles with a gradient color. /// A mesh of triangles with a gradient color.
Gradient { Gradient {
/// The origin of the vertices of the [`Mesh`]. /// The [`Transformation`] for the vertices of the [`Mesh`].
origin: Point, transformation: Transformation,
/// The vertex and index buffers of the [`Mesh`]. /// The vertex and index buffers of the [`Mesh`].
buffers: &'a mesh::Indexed<mesh::GradientVertex2D>, buffers: &'a mesh::Indexed<mesh::GradientVertex2D>,
@ -31,11 +32,10 @@ pub enum Mesh<'a> {
impl Mesh<'_> { impl Mesh<'_> {
/// Returns the origin of the [`Mesh`]. /// Returns the origin of the [`Mesh`].
pub fn origin(&self) -> Point { pub fn transformation(&self) -> Transformation {
match self { match self {
Self::Solid { origin, .. } | Self::Gradient { origin, .. } => { Self::Solid { transformation, .. }
*origin | Self::Gradient { transformation, .. } => *transformation,
}
} }
} }

View file

@ -15,6 +15,7 @@ pub enum Text<'a> {
position: Point, position: Point,
color: Color, color: Color,
clip_bounds: Rectangle, clip_bounds: Rectangle,
scale: f32,
}, },
/// An editor. /// An editor.
#[allow(missing_docs)] #[allow(missing_docs)]
@ -23,6 +24,7 @@ pub enum Text<'a> {
position: Point, position: Point,
color: Color, color: Color,
clip_bounds: Rectangle, clip_bounds: Rectangle,
scale: f32,
}, },
/// Some cached text. /// Some cached text.
Cached(Cached<'a>), Cached(Cached<'a>),

View file

@ -319,7 +319,7 @@ impl Uniforms {
impl Default for Uniforms { impl Default for Uniforms {
fn default() -> Self { fn default() -> Self {
Self { Self {
transform: *Transformation::identity().as_ref(), transform: *Transformation::IDENTITY.as_ref(),
scale: 1.0, scale: 1.0,
_padding: [0.0; 3], _padding: [0.0; 3],
} }

View file

@ -98,12 +98,10 @@ impl Layer {
let mut index_offset = 0; let mut index_offset = 0;
for mesh in meshes { for mesh in meshes {
let origin = mesh.origin();
let indices = mesh.indices(); let indices = mesh.indices();
let uniforms = Uniforms::new( let uniforms =
transformation * Transformation::translate(origin.x, origin.y), Uniforms::new(transformation * mesh.transformation());
);
index_offset += index_offset +=
self.index_buffer.write(queue, index_offset, indices); self.index_buffer.write(queue, index_offset, indices);