1use crate::*;
2use emath::*;
3
4#[repr(C)]
8#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
9#[cfg(not(feature = "unity"))]
10#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
11#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
12pub struct Vertex {
13 pub pos: Pos2, pub uv: Pos2, pub color: Color32, }
25
26#[repr(C)]
27#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
28#[cfg(feature = "unity")]
29#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
30#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
31pub struct Vertex {
32 pub pos: Pos2, pub color: Color32, pub uv: Pos2, }
44
45#[derive(Clone, Debug, Default, PartialEq, Eq)]
47#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
48pub struct Mesh {
49 pub indices: Vec<u32>,
55
56 pub vertices: Vec<Vertex>,
58
59 pub texture_id: TextureId,
61 }
63
64impl Mesh {
65 pub fn with_texture(texture_id: TextureId) -> Self {
66 Self {
67 texture_id,
68 ..Default::default()
69 }
70 }
71
72 pub fn clear(&mut self) {
74 self.indices.clear();
75 self.vertices.clear();
76 self.vertices = Default::default();
77 }
78
79 pub fn bytes_used(&self) -> usize {
80 std::mem::size_of::<Self>()
81 + self.vertices.len() * std::mem::size_of::<Vertex>()
82 + self.indices.len() * std::mem::size_of::<u32>()
83 }
84
85 pub fn is_valid(&self) -> bool {
87 crate::profile_function!();
88
89 if let Ok(n) = u32::try_from(self.vertices.len()) {
90 self.indices.iter().all(|&i| i < n)
91 } else {
92 false
93 }
94 }
95
96 pub fn is_empty(&self) -> bool {
97 self.indices.is_empty() && self.vertices.is_empty()
98 }
99
100 pub fn calc_bounds(&self) -> Rect {
102 let mut bounds = Rect::NOTHING;
103 for v in &self.vertices {
104 bounds.extend_with(v.pos);
105 }
106 bounds
107 }
108
109 pub fn append(&mut self, other: Self) {
111 crate::profile_function!();
112 debug_assert!(other.is_valid());
113
114 if self.is_empty() {
115 *self = other;
116 } else {
117 self.append_ref(&other);
118 }
119 }
120
121 pub fn append_ref(&mut self, other: &Self) {
124 debug_assert!(other.is_valid());
125
126 if self.is_empty() {
127 self.texture_id = other.texture_id;
128 } else {
129 assert_eq!(
130 self.texture_id, other.texture_id,
131 "Can't merge Mesh using different textures"
132 );
133 }
134
135 let index_offset = self.vertices.len() as u32;
136 self.indices
137 .extend(other.indices.iter().map(|index| index + index_offset));
138 self.vertices.extend(other.vertices.iter());
139 }
140
141 #[inline(always)]
142 pub fn colored_vertex(&mut self, pos: Pos2, color: Color32) {
143 debug_assert!(self.texture_id == TextureId::default());
144 self.vertices.push(Vertex {
145 pos,
146 uv: WHITE_UV,
147 color,
148 });
149 }
150
151 #[inline(always)]
153 pub fn add_triangle(&mut self, a: u32, b: u32, c: u32) {
154 self.indices.push(a);
155 self.indices.push(b);
156 self.indices.push(c);
157 }
158
159 #[inline(always)]
162 pub fn reserve_triangles(&mut self, additional_triangles: usize) {
163 self.indices.reserve(3 * additional_triangles);
164 }
165
166 #[inline(always)]
169 pub fn reserve_vertices(&mut self, additional: usize) {
170 self.vertices.reserve(additional);
171 }
172
173 pub fn add_rect_with_uv(&mut self, rect: Rect, uv: Rect, color: Color32) {
175 #![allow(clippy::identity_op)]
176
177 let idx = self.vertices.len() as u32;
178 self.add_triangle(idx + 0, idx + 1, idx + 2);
179 self.add_triangle(idx + 2, idx + 1, idx + 3);
180
181 self.vertices.push(Vertex {
182 pos: rect.left_top(),
183 uv: uv.left_top(),
184 color,
185 });
186 self.vertices.push(Vertex {
187 pos: rect.right_top(),
188 uv: uv.right_top(),
189 color,
190 });
191 self.vertices.push(Vertex {
192 pos: rect.left_bottom(),
193 uv: uv.left_bottom(),
194 color,
195 });
196 self.vertices.push(Vertex {
197 pos: rect.right_bottom(),
198 uv: uv.right_bottom(),
199 color,
200 });
201 }
202
203 #[inline(always)]
205 pub fn add_colored_rect(&mut self, rect: Rect, color: Color32) {
206 debug_assert!(self.texture_id == TextureId::default());
207 self.add_rect_with_uv(rect, [WHITE_UV, WHITE_UV].into(), color);
208 }
209
210 pub fn split_to_u16(self) -> Vec<Mesh16> {
215 debug_assert!(self.is_valid());
216
217 const MAX_SIZE: u32 = std::u16::MAX as u32;
218
219 if self.vertices.len() <= MAX_SIZE as usize {
220 return vec![Mesh16 {
222 indices: self.indices.iter().map(|&i| i as u16).collect(),
223 vertices: self.vertices,
224 texture_id: self.texture_id,
225 }];
226 }
227
228 let mut output = vec![];
229 let mut index_cursor = 0;
230
231 while index_cursor < self.indices.len() {
232 let span_start = index_cursor;
233 let mut min_vindex = self.indices[index_cursor];
234 let mut max_vindex = self.indices[index_cursor];
235
236 while index_cursor < self.indices.len() {
237 let (mut new_min, mut new_max) = (min_vindex, max_vindex);
238 for i in 0..3 {
239 let idx = self.indices[index_cursor + i];
240 new_min = new_min.min(idx);
241 new_max = new_max.max(idx);
242 }
243
244 let new_span_size = new_max - new_min + 1; if new_span_size <= MAX_SIZE {
246 min_vindex = new_min;
248 max_vindex = new_max;
249 index_cursor += 3;
250 } else {
251 break;
252 }
253 }
254
255 assert!(
256 index_cursor > span_start,
257 "One triangle spanned more than {MAX_SIZE} vertices"
258 );
259
260 let mesh = Mesh16 {
261 indices: self.indices[span_start..index_cursor]
262 .iter()
263 .map(|vi| u16::try_from(vi - min_vindex).unwrap())
264 .collect(),
265 vertices: self.vertices[(min_vindex as usize)..=(max_vindex as usize)].to_vec(),
266 texture_id: self.texture_id,
267 };
268 debug_assert!(mesh.is_valid());
269 output.push(mesh);
270 }
271 output
272 }
273
274 pub fn translate(&mut self, delta: Vec2) {
276 for v in &mut self.vertices {
277 v.pos += delta;
278 }
279 }
280
281 pub fn transform(&mut self, transform: TSTransform) {
283 for v in &mut self.vertices {
284 v.pos = transform * v.pos;
285 }
286 }
287
288 pub fn rotate(&mut self, rot: Rot2, origin: Pos2) {
292 for v in &mut self.vertices {
293 v.pos = origin + rot * (v.pos - origin);
294 }
295 }
296}
297
298pub struct Mesh16 {
304 pub indices: Vec<u16>,
308
309 pub vertices: Vec<Vertex>,
311
312 pub texture_id: TextureId,
314}
315
316impl Mesh16 {
317 pub fn is_valid(&self) -> bool {
319 if let Ok(n) = u16::try_from(self.vertices.len()) {
320 self.indices.iter().all(|&i| i < n)
321 } else {
322 false
323 }
324 }
325}