rootvg_image/
primitive.rs1use bytemuck::{Pod, Zeroable};
2use rootvg_core::math::{Angle, Point, Rect, Scale, Size, Transform, Vector};
3
4use crate::texture::RcTexture;
5
6#[derive(Debug, Clone, PartialEq)]
7pub struct ImagePrimitive {
8 pub texture: RcTexture,
9 pub vertex: ImageVertex,
10}
11
12impl ImagePrimitive {
13 pub fn new(texture: RcTexture, position: Point) -> Self {
14 let size = texture.size();
15
16 Self {
17 texture,
18 vertex: ImageVertex {
19 position: position.into(),
20 size: [size.width as f32, size.height as f32],
21 ..Default::default()
22 },
23 }
24 }
25
26 pub fn builder(texture: RcTexture) -> ImagePrimitiveBuilder {
27 ImagePrimitiveBuilder::new(texture)
28 }
29
30 pub fn position(&self) -> Point {
31 Point::new(self.vertex.position[0], self.vertex.position[1])
32 }
33
34 pub fn set_position(&mut self, position: Point) {
35 self.vertex.position = position.into();
36 }
37}
38
39pub struct ImagePrimitiveBuilder {
40 primitive: ImagePrimitive,
41}
42
43impl ImagePrimitiveBuilder {
44 pub fn new(texture: RcTexture) -> Self {
45 Self {
46 primitive: ImagePrimitive::new(texture, Point::default()),
47 }
48 }
49
50 pub fn position(mut self, position: Point) -> Self {
52 self.primitive.vertex.position = position.into();
53 self
54 }
55
56 pub fn scale(mut self, scale_x: Scale, scale_y: Scale) -> Self {
57 self.primitive.vertex.size[0] *= scale_x.0;
58 self.primitive.vertex.size[1] *= scale_y.0;
59 self
60 }
61
62 pub fn rotation(mut self, angle: Angle, origin_normal: Point) -> Self {
63 let transform = Transform::translation(-origin_normal.x, -origin_normal.y)
64 .then_rotate(angle)
65 .then_translate(Vector::new(origin_normal.x, origin_normal.y));
66
67 self.primitive.vertex.transform = transform.to_array();
68 self.primitive.vertex.has_transform = 1;
69 self
70 }
71
72 pub fn transform(mut self, transform: Transform) -> Self {
73 self.primitive.vertex.transform = transform.to_array();
74 self.primitive.vertex.has_transform = 1;
75 self
76 }
77
78 pub fn unnormalized_uv_rect(mut self, uv_rect: Rect) -> Self {
79 let normal_uv_rect = normalized_uv_rect(
80 uv_rect,
81 Size::new(self.primitive.vertex.size[0], self.primitive.vertex.size[1]),
82 );
83
84 self.primitive.vertex.normalized_uv_pos = normal_uv_rect.origin.into();
85 self.primitive.vertex.normalized_uv_size = normal_uv_rect.size.into();
86 self
87 }
88
89 pub fn normalized_uv_rect(mut self, uv_rect: Rect) -> Self {
90 self.primitive.vertex.normalized_uv_pos = uv_rect.origin.into();
91 self.primitive.vertex.normalized_uv_size = uv_rect.size.into();
92 self
93 }
94
95 pub fn build(self) -> ImagePrimitive {
96 self.primitive
97 }
98}
99
100impl From<ImagePrimitiveBuilder> for ImagePrimitive {
101 fn from(i: ImagePrimitiveBuilder) -> Self {
102 i.build()
103 }
104}
105
106#[repr(C)]
107#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)]
108pub struct ImageVertex {
109 pub position: [f32; 2],
112
113 pub size: [f32; 2],
115
116 pub normalized_uv_pos: [f32; 2],
121
122 pub normalized_uv_size: [f32; 2],
126
127 pub transform: [f32; 6],
132
133 pub has_transform: u32,
140}
141
142impl Default for ImageVertex {
143 fn default() -> Self {
144 Self {
145 position: [0.0; 2],
146 size: [0.0; 2],
147 normalized_uv_pos: [0.0; 2],
148 normalized_uv_size: [1.0; 2],
149 transform: [0.0; 6],
150 has_transform: 0,
151 }
152 }
153}
154
155fn normalized_uv_rect(uv_rect: Rect, texture_size: Size) -> Rect {
156 Rect::new(
157 Point::new(
158 uv_rect.origin.x / texture_size.width,
159 uv_rect.origin.y / texture_size.height,
160 ),
161 Size::new(
162 uv_rect.size.width / texture_size.width,
163 uv_rect.size.height / texture_size.height,
164 ),
165 )
166}