mesh.rs
1 use crate::*; 2 use emath::*; 3 4 /// The 2D vertex type. 5 /// 6 /// Should be friendly to send to GPU as is. 7 #[repr(C)] 8 #[derive(Clone, Copy, Debug, Default, PartialEq)] 9 #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] 10 #[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))] 11 pub struct Vertex { 12 /// Logical pixel coordinates (points). 13 /// (0,0) is the top left corner of the screen. 14 pub pos: Pos2, // 64 bit 15 16 /// Normalized texture coordinates. 17 /// (0, 0) is the top left corner of the texture. 18 /// (1, 1) is the bottom right corner of the texture. 19 pub uv: Pos2, // 64 bit 20 21 /// sRGBA with premultiplied alpha 22 pub color: Color32, // 32 bit 23 } 24 25 /// Textured triangles in two dimensions. 26 #[derive(Clone, Debug, Default, PartialEq)] 27 #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] 28 pub struct Mesh { 29 /// Draw as triangles (i.e. the length is always multiple of three). 30 /// 31 /// If you only support 16-bit indices you can use [`Mesh::split_to_u16`]. 32 /// 33 /// egui is NOT consistent with what winding order it uses, so turn off backface culling. 34 pub indices: Vec<u32>, 35 36 /// The vertex data indexed by `indices`. 37 pub vertices: Vec<Vertex>, 38 39 /// The texture to use when drawing these triangles. 40 pub texture_id: TextureId, 41 // TODO: bounding rectangle 42 } 43 44 impl Mesh { 45 pub fn with_texture(texture_id: TextureId) -> Self { 46 Self { 47 texture_id, 48 ..Default::default() 49 } 50 } 51 52 /// Restore to default state, but without freeing memory. 53 pub fn clear(&mut self) { 54 self.indices.clear(); 55 self.vertices.clear(); 56 self.vertices = Default::default(); 57 } 58 59 pub fn bytes_used(&self) -> usize { 60 std::mem::size_of::<Self>() 61 + self.vertices.len() * std::mem::size_of::<Vertex>() 62 + self.indices.len() * std::mem::size_of::<u32>() 63 } 64 65 /// Are all indices within the bounds of the contained vertices? 66 pub fn is_valid(&self) -> bool { 67 if let Ok(n) = u32::try_from(self.vertices.len()) { 68 self.indices.iter().all(|&i| i < n) 69 } else { 70 false 71 } 72 } 73 74 pub fn is_empty(&self) -> bool { 75 self.indices.is_empty() && self.vertices.is_empty() 76 } 77 78 /// Calculate a bounding rectangle. 79 pub fn calc_bounds(&self) -> Rect { 80 let mut bounds = Rect::NOTHING; 81 for v in &self.vertices { 82 bounds.extend_with(v.pos); 83 } 84 bounds 85 } 86 87 /// Append all the indices and vertices of `other` to `self`. 88 pub fn append(&mut self, other: Mesh) { 89 crate::epaint_assert!(other.is_valid()); 90 91 if self.is_empty() { 92 *self = other; 93 } else { 94 self.append_ref(&other); 95 } 96 } 97 98 /// Append all the indices and vertices of `other` to `self` without 99 /// taking ownership. 100 pub fn append_ref(&mut self, other: &Mesh) { 101 crate::epaint_assert!(other.is_valid()); 102 103 if !self.is_empty() { 104 assert_eq!( 105 self.texture_id, other.texture_id, 106 "Can't merge Mesh using different textures" 107 ); 108 } else { 109 self.texture_id = other.texture_id; 110 } 111 112 let index_offset = self.vertices.len() as u32; 113 self.indices 114 .extend(other.indices.iter().map(|index| index + index_offset)); 115 self.vertices.extend(other.vertices.iter()); 116 } 117 118 #[inline(always)] 119 pub fn colored_vertex(&mut self, pos: Pos2, color: Color32) { 120 crate::epaint_assert!(self.texture_id == TextureId::default()); 121 self.vertices.push(Vertex { 122 pos, 123 uv: WHITE_UV, 124 color, 125 }); 126 } 127 128 /// Add a triangle. 129 #[inline(always)] 130 pub fn add_triangle(&mut self, a: u32, b: u32, c: u32) { 131 self.indices.push(a); 132 self.indices.push(b); 133 self.indices.push(c); 134 } 135 136 /// Make room for this many additional triangles (will reserve 3x as many indices). 137 /// See also `reserve_vertices`. 138 #[inline(always)] 139 pub fn reserve_triangles(&mut self, additional_triangles: usize) { 140 self.indices.reserve(3 * additional_triangles); 141 } 142 143 /// Make room for this many additional vertices. 144 /// See also `reserve_triangles`. 145 #[inline(always)] 146 pub fn reserve_vertices(&mut self, additional: usize) { 147 self.vertices.reserve(additional); 148 } 149 150 /// Rectangle with a texture and color. 151 pub fn add_rect_with_uv(&mut self, rect: Rect, uv: Rect, color: Color32) { 152 #![allow(clippy::identity_op)] 153 154 let idx = self.vertices.len() as u32; 155 self.add_triangle(idx + 0, idx + 1, idx + 2); 156 self.add_triangle(idx + 2, idx + 1, idx + 3); 157 158 self.vertices.push(Vertex { 159 pos: rect.left_top(), 160 uv: uv.left_top(), 161 color, 162 }); 163 self.vertices.push(Vertex { 164 pos: rect.right_top(), 165 uv: uv.right_top(), 166 color, 167 }); 168 self.vertices.push(Vertex { 169 pos: rect.left_bottom(), 170 uv: uv.left_bottom(), 171 color, 172 }); 173 self.vertices.push(Vertex { 174 pos: rect.right_bottom(), 175 uv: uv.right_bottom(), 176 color, 177 }); 178 } 179 180 /// Uniformly colored rectangle. 181 #[inline(always)] 182 pub fn add_colored_rect(&mut self, rect: Rect, color: Color32) { 183 crate::epaint_assert!(self.texture_id == TextureId::default()); 184 self.add_rect_with_uv(rect, [WHITE_UV, WHITE_UV].into(), color); 185 } 186 187 /// This is for platforms that only support 16-bit index buffers. 188 /// 189 /// Splits this mesh into many smaller meshes (if needed) 190 /// where the smaller meshes have 16-bit indices. 191 pub fn split_to_u16(self) -> Vec<Mesh16> { 192 crate::epaint_assert!(self.is_valid()); 193 194 const MAX_SIZE: u32 = 1 << 16; 195 196 if self.vertices.len() < MAX_SIZE as usize { 197 // Common-case optimization: 198 return vec![Mesh16 { 199 indices: self.indices.iter().map(|&i| i as u16).collect(), 200 vertices: self.vertices, 201 texture_id: self.texture_id, 202 }]; 203 } 204 205 let mut output = vec![]; 206 let mut index_cursor = 0; 207 208 while index_cursor < self.indices.len() { 209 let span_start = index_cursor; 210 let mut min_vindex = self.indices[index_cursor]; 211 let mut max_vindex = self.indices[index_cursor]; 212 213 while index_cursor < self.indices.len() { 214 let (mut new_min, mut new_max) = (min_vindex, max_vindex); 215 for i in 0..3 { 216 let idx = self.indices[index_cursor + i]; 217 new_min = new_min.min(idx); 218 new_max = new_max.max(idx); 219 } 220 221 if new_max - new_min < MAX_SIZE { 222 // Triangle fits 223 min_vindex = new_min; 224 max_vindex = new_max; 225 index_cursor += 3; 226 } else { 227 break; 228 } 229 } 230 231 assert!( 232 index_cursor > span_start, 233 "One triangle spanned more than {} vertices", 234 MAX_SIZE 235 ); 236 237 let mesh = Mesh16 { 238 indices: self.indices[span_start..index_cursor] 239 .iter() 240 .map(|vi| u16::try_from(vi - min_vindex).unwrap()) 241 .collect(), 242 vertices: self.vertices[(min_vindex as usize)..=(max_vindex as usize)].to_vec(), 243 texture_id: self.texture_id, 244 }; 245 crate::epaint_assert!(mesh.is_valid()); 246 output.push(mesh); 247 } 248 output 249 } 250 251 /// Translate location by this much, in-place 252 pub fn translate(&mut self, delta: Vec2) { 253 for v in &mut self.vertices { 254 v.pos += delta; 255 } 256 } 257 258 /// Rotate by some angle about an origin, in-place. 259 /// 260 /// Origin is a position in screen space. 261 pub fn rotate(&mut self, rot: Rot2, origin: Pos2) { 262 for v in &mut self.vertices { 263 v.pos = origin + rot * (v.pos - origin); 264 } 265 } 266 } 267 268 // ---------------------------------------------------------------------------- 269 270 /// A version of [`Mesh`] that uses 16-bit indices. 271 /// 272 /// This is produced by [`Mesh::split_to_u16`] and is meant to be used for legacy render backends. 273 pub struct Mesh16 { 274 /// Draw as triangles (i.e. the length is always multiple of three). 275 /// 276 /// egui is NOT consistent with what winding order it uses, so turn off backface culling. 277 pub indices: Vec<u16>, 278 279 /// The vertex data indexed by `indices`. 280 pub vertices: Vec<Vertex>, 281 282 /// The texture to use when drawing these triangles. 283 pub texture_id: TextureId, 284 } 285 286 impl Mesh16 { 287 /// Are all indices within the bounds of the contained vertices? 288 pub fn is_valid(&self) -> bool { 289 if let Ok(n) = u16::try_from(self.vertices.len()) { 290 self.indices.iter().all(|&i| i < n) 291 } else { 292 false 293 } 294 } 295 }