/ epaint / src / mesh.rs
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  }