stereokit_rust/mesh.rs
1use crate::{
2 StereoKitError,
3 material::{Cull, Material, MaterialT},
4 maths::{Bool32T, Bounds, Matrix, Ray, Vec2, Vec3, Vec4},
5 sk::MainThreadToken,
6 system::{IAsset, RenderLayer},
7 util::{Color32, Color128},
8};
9use std::{
10 ffi::{CStr, CString, c_char},
11 ptr::{NonNull, slice_from_raw_parts_mut},
12};
13
14/// This represents a single vertex in a Mesh, all StereoKit Meshes currently use this exact layout!
15/// It’s good to fill out all values of a Vertex explicitly, as default values for the normal (0,0,0) and color
16/// (0,0,0,0) will cause your mesh to appear completely black, or even transparent in most shaders!
17/// <https://stereokit.net/Pages/StereoKit/Vertex.html>
18///
19/// ### Examples
20/// ```
21/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
22/// use stereokit_rust::{maths::{Vec3, Vec2, Matrix}, util::Color32, mesh::{Mesh,Vertex}, material::Material};
23///
24/// // Creating vertices with all fields specified
25/// let vertices = [
26/// Vertex::new(Vec3::ZERO,Vec3::UP,None, Some(Color32::rgb(0, 0, 255))),
27/// Vertex::new(Vec3::X, Vec3::UP,Some(Vec2::X),Some(Color32::rgb(255, 0, 0))),
28/// Vertex::new(Vec3::Y, Vec3::UP,Some(Vec2::Y),Some(Color32::rgb(0,255, 0))),
29/// ];
30/// let indices = [0, 1, 2, 2, 1, 0];
31/// let mut mesh = Mesh::new();
32/// mesh.id("most_basic_mesh").keep_data(true).set_data(&vertices, &indices, true);
33/// let material = Material::pbr();
34///
35/// filename_scr = "screenshots/basic_mesh.jpeg";
36/// test_screenshot!( // !!!! Get a proper main loop !!!!
37/// mesh.draw(token, &material, Matrix::IDENTITY, None, None);
38/// );
39/// ```
40/// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/basic_mesh.jpeg" alt="screenshot" width="200">
41#[derive(Default, Debug, Copy, Clone, PartialEq)]
42#[repr(C)]
43pub struct Vertex {
44 /// Position of the vertex, in model space coordinates.
45 pub pos: Vec3,
46 /// The normal of this vertex, or the direction the vertex is facing. Preferably normalized.
47 pub norm: Vec3,
48 /// The texture coordinates at this vertex.
49 pub uv: Vec2,
50 /// The color of the vertex. If you aren’t using it, set it to white.
51 pub col: Color32,
52}
53
54impl Vertex {
55 /// Create a new Vertex.
56 /// <https://stereokit.net/Pages/StereoKit/Vertex/Vertex.html>
57 /// * `position` - Location of the vertex, this is typically meters in model space.
58 /// * `normal` - The direction the Vertex is facing. Never leave this as zero, or your lighting may turn out black!
59 /// A good default value if you don’t know what to put here is (0,1,0), but a Mesh composed entirely of this value
60 /// will have flat lighting.
61 /// * `texture_coordinate` - If None, set the value to Vec2::ZERO
62 /// * `color` - If None, set the value to Color32::WHITE
63 ///
64 /// ### Examples
65 /// ```
66 /// use stereokit_rust::{maths::{Vec3, Vec2}, mesh::Vertex, util::Color32};
67 ///
68 /// let vertex = Vertex::new([0.0, 0.0, 0.0], [0.0, 1.0, 0.0], None, None);
69 /// let vertex_bis = Vertex{
70 /// pos: Vec3::new(0.0, 0.0, 0.0),
71 /// norm: Vec3::new(0.0, 1.0, 0.0),
72 /// uv: Vec2::ZERO,
73 /// col: Color32::WHITE};
74 /// assert_eq!(vertex, vertex_bis);
75 ///
76 /// let vertex = Vertex::new([0.0, 0.0, 0.0], [0.0, 0.0, 0.0],
77 /// Some(Vec2::ZERO), Some(Color32::BLACK_TRANSPARENT) );
78 /// let vertex_default = Vertex::default();
79 /// assert_eq!(vertex, vertex_default);
80 /// ```
81 pub fn new<V: Into<Vec3>>(
82 position: V,
83 normal: V,
84 texture_coordinate: Option<Vec2>,
85 color: Option<Color32>,
86 ) -> Self {
87 let texture_coordinate = texture_coordinate.unwrap_or(Vec2::ZERO);
88 let color = color.unwrap_or(Color32::WHITE);
89 Self { pos: position.into(), norm: normal.into(), uv: texture_coordinate, col: color }
90 }
91}
92
93/// Mesh index data
94/// <https://stereokit.net/Pages/StereoKit/Mesh.html>
95pub type Inds = u32;
96
97/// For performance sensitive areas, or places dealing with large chunks of memory, it can be faster to get a reference
98/// to that memory rather than copying it! However, if this isn’t explicitly stated, it isn’t necessarily clear what’s
99/// happening. So this enum allows us to visibly specify what type of memory reference is occurring.
100/// <https://stereokit.net/Pages/StereoKit/Memory.html>
101#[derive(Debug, Copy, Clone, PartialEq, Eq)]
102#[repr(u32)]
103pub enum Memory {
104 /// The chunk of memory involved here is a reference that is still managed or used by StereoKit! You should not free
105 /// it, and be extremely cautious about modifying it.
106 Reference = 0,
107 /// This memory is now yours and you must free it yourself! Memory has been allocated, and the data has been copied
108 /// over to it. Pricey! But safe.
109 Copy = 1,
110}
111
112/// A Mesh is a single collection of triangular faces with extra surface information to enhance rendering! StereoKit
113/// meshes are composed of a list of vertices, and a list of indices to connect the vertices into faces. Nothing more
114/// than that is stored here, so typically meshes are combined with Materials, or added to Models in order to draw them.
115///
116/// Mesh vertices are composed of a position, a normal (direction of the vert), a uv coordinate (for mapping a texture
117/// to the mesh’s surface), and a 32 bit color containing red, green, blue, and alpha (transparency).
118///
119/// Mesh indices are stored as unsigned ints, so you can have a mesh with a fudgeton of verts! 4 billion or so :)
120/// <https://stereokit.net/Pages/StereoKit/Mesh.html>
121///
122/// ### Examples
123/// ```
124/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
125/// use stereokit_rust::{maths::{Vec3, Matrix, Quat}, util::{named_colors,Color32},
126/// mesh::Mesh, material::Material};
127///
128/// // Create Meshes
129/// let cube = Mesh::generate_cube(Vec3::ONE * 0.8, None);
130/// let sphere = Mesh::generate_sphere(1.0, None);
131///
132/// let material_cube = Material::pbr().copy();
133/// let mut material_sphere = Material::pbr().copy();
134/// material_sphere.color_tint(named_colors::GREEN);
135/// let cube_transform = Matrix::r([40.0, 50.0, 20.0]);
136///
137/// filename_scr = "screenshots/meshes.jpeg";
138/// test_screenshot!( // !!!! Get a proper main loop !!!!
139/// cube.draw(token, &material_cube, cube_transform, None, None);
140/// sphere.draw(token, &material_sphere, Matrix::IDENTITY, None, None);
141/// );
142/// ```
143/// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/meshes.jpeg" alt="screenshot" width="200">
144#[derive(Debug, PartialEq)]
145pub struct Mesh(pub NonNull<_MeshT>);
146impl Drop for Mesh {
147 fn drop(&mut self) {
148 unsafe { mesh_release(self.0.as_ptr()) }
149 }
150}
151impl AsRef<Mesh> for Mesh {
152 fn as_ref(&self) -> &Mesh {
153 self
154 }
155}
156
157/// StereoKit internal type.
158#[repr(C)]
159#[derive(Debug)]
160pub struct _MeshT {
161 _unused: [u8; 0],
162}
163/// StereoKit ffi type.
164pub type MeshT = *mut _MeshT;
165
166/// StereoKit ffi type.
167pub type VindT = u32;
168
169unsafe extern "C" {
170 pub fn mesh_find(name: *const c_char) -> MeshT;
171 pub fn mesh_create() -> MeshT;
172 pub fn mesh_copy(mesh: MeshT) -> MeshT;
173 pub fn mesh_set_id(mesh: MeshT, id: *const c_char);
174 pub fn mesh_get_id(mesh: MeshT) -> *const c_char;
175 pub fn mesh_addref(mesh: MeshT);
176 pub fn mesh_release(mesh: MeshT);
177 pub fn mesh_draw(mesh: MeshT, material: MaterialT, transform: Matrix, color_linear: Color128, layer: RenderLayer);
178 pub fn mesh_set_keep_data(mesh: MeshT, keep_data: Bool32T);
179 pub fn mesh_get_keep_data(mesh: MeshT) -> Bool32T;
180 pub fn mesh_set_data(
181 mesh: MeshT,
182 in_arr_vertices: *const Vertex,
183 vertex_count: i32,
184 in_arr_indices: *const VindT,
185 index_count: i32,
186 calculate_bounds: Bool32T,
187 );
188 pub fn mesh_set_verts(mesh: MeshT, in_arr_vertices: *const Vertex, vertex_count: i32, calculate_bounds: Bool32T);
189 pub fn mesh_get_verts(
190 mesh: MeshT,
191 out_arr_vertices: *mut *mut Vertex,
192 out_vertex_count: *mut i32,
193 reference_mode: Memory,
194 );
195 pub fn mesh_get_vert_count(mesh: MeshT) -> i32;
196 pub fn mesh_set_inds(mesh: MeshT, in_arr_indices: *const VindT, index_count: i32);
197 pub fn mesh_get_inds(
198 mesh: MeshT,
199 out_arr_indices: *mut *mut VindT,
200 out_index_count: *mut i32,
201 reference_mode: Memory,
202 );
203 pub fn mesh_get_ind_count(mesh: MeshT) -> i32;
204 pub fn mesh_set_draw_inds(mesh: MeshT, index_count: i32);
205 pub fn mesh_set_bounds(mesh: MeshT, bounds: *const Bounds);
206 pub fn mesh_get_bounds(mesh: MeshT) -> Bounds;
207 pub fn mesh_has_skin(mesh: MeshT) -> Bool32T;
208 pub fn mesh_set_skin(
209 mesh: MeshT,
210 in_arr_bone_ids_4: *const u16,
211 bone_id_4_count: i32,
212 in_arr_bone_weights: *const Vec4,
213 bone_weight_count: i32,
214 bone_resting_transforms: *const Matrix,
215 bone_count: i32,
216 );
217 pub fn mesh_update_skin(mesh: MeshT, in_arr_bone_transforms: *const Matrix, bone_count: i32);
218 pub fn mesh_ray_intersect(
219 mesh: MeshT,
220 model_space_ray: Ray,
221 cull_mode: Cull,
222 out_pt: *mut Ray,
223 out_start_inds: *mut u32,
224 ) -> Bool32T;
225 pub fn mesh_ray_intersect_bvh(
226 mesh: MeshT,
227 model_space_ray: Ray,
228 cull_mode: Cull,
229 out_pt: *mut Ray,
230 out_start_inds: *mut u32,
231 ) -> Bool32T;
232 pub fn mesh_get_triangle(
233 mesh: MeshT,
234 triangle_index: u32,
235 out_a: *mut Vertex,
236 out_b: *mut Vertex,
237 out_c: *mut Vertex,
238 ) -> Bool32T;
239 pub fn mesh_gen_plane(
240 dimensions: Vec2,
241 plane_normal: Vec3,
242 plane_top_direction: Vec3,
243 subdivisions: i32,
244 double_sided: Bool32T,
245 ) -> MeshT;
246 pub fn mesh_gen_circle(
247 diameter: f32,
248 plane_normal: Vec3,
249 plane_top_direction: Vec3,
250 spokes: i32,
251 double_sided: Bool32T,
252 ) -> MeshT;
253 pub fn mesh_gen_cube(dimensions: Vec3, subdivisions: i32) -> MeshT;
254 pub fn mesh_gen_sphere(diameter: f32, subdivisions: i32) -> MeshT;
255 pub fn mesh_gen_rounded_cube(dimensions: Vec3, edge_radius: f32, subdivisions: i32) -> MeshT;
256 pub fn mesh_gen_cylinder(diameter: f32, depth: f32, direction: Vec3, subdivisions: i32) -> MeshT;
257 pub fn mesh_gen_cone(diameter: f32, depth: f32, direction: Vec3, subdivisions: i32) -> MeshT;
258}
259
260impl IAsset for Mesh {
261 // fn id(&mut self, id: impl AsRef<str>) {
262 // self.id(id);
263 // }
264
265 fn get_id(&self) -> &str {
266 self.get_id()
267 }
268}
269
270impl Default for Mesh {
271 /// Creates an empty Mesh asset. Use SetVerts and SetInds to add data to it!
272 /// <https://stereokit.net/Pages/StereoKit/Mesh/Mesh.html>
273 ///
274 /// see also: [`Vertex`] [`Mesh::new`]
275 fn default() -> Self {
276 Self::new()
277 }
278}
279
280impl Mesh {
281 /// Creates an empty Mesh asset. Use SetVerts and SetInds to add data to it!
282 /// <https://stereokit.net/Pages/StereoKit/Mesh/Mesh.html>
283 ///
284 /// see also [`mesh_create`] [`Mesh::default`]
285 ///
286 /// ### Examples
287 /// ```
288 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
289 /// use stereokit_rust::mesh::Mesh;
290 ///
291 /// // Create Meshes
292 /// let mesh = Mesh::new();
293 ///
294 /// assert_eq!(mesh.get_inds().len(), 0);
295 /// assert_eq!(mesh.get_verts().len(), 0);
296 /// ```
297 pub fn new() -> Mesh {
298 Mesh(NonNull::new(unsafe { mesh_create() }).unwrap())
299 }
300
301 /// Generates a plane with an arbitrary orientation that is optionally subdivided, pre-sized to the given
302 /// dimensions. UV coordinates start at the top left indicated with plane_top_direction.
303 ///
304 /// NOTE: This generates a completely new Mesh asset on the GPU, and is best done during 'initialization' of your
305 /// app/scene. You may also be interested in using the pre-generated `Mesh.Quad` asset if it already meets your
306 /// needs.
307 /// <https://stereokit.net/Pages/StereoKit/Mesh/GeneratePlane.html>
308 /// * `dimension` - How large is this plane on the XZ axis, in meters?
309 /// * `plane_normal` - What is the normal of the surface this plane is generated on?
310 /// * `plane_top_direction` - A normal defines the plane, but this is technically a rectangle on the plane. So which
311 /// direction is up? It's important for UVs, but doesn't need to be exact. This function takes the planeNormal as
312 /// law, and uses this vector to find the right and up vectors via cross-products.
313 /// * `subdivisions` - Use this to add extra slices of vertices across the plane. This can be useful for some types of
314 /// vertex-based effects! None is 0.
315 /// * `double_sided` - Should both sides of the plane be rendered?
316 ///
317 /// Returns a plane mesh, pre-sized to the given dimensions.
318 /// see also [`mesh_gen_plane`]
319 /// ### Examples
320 /// ```
321 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
322 /// use stereokit_rust::mesh::Mesh;
323 ///
324 /// // Create Meshes
325 /// let mesh = Mesh::generate_plane([1.0, 1.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], None, false);
326 /// assert_eq!(mesh.get_ind_count(), 6);
327 /// assert_eq!(mesh.get_vert_count(), 4);
328 ///
329 /// let mesh = Mesh::generate_plane([1.0, 1.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], None, true);
330 /// assert_eq!(mesh.get_ind_count(), 12);
331 /// assert_eq!(mesh.get_vert_count(), 8);
332 ///
333 /// let mesh = Mesh::generate_plane([1.0, 1.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], Some(1), true);
334 /// assert_eq!(mesh.get_ind_count(), 48);
335 /// assert_eq!(mesh.get_vert_count(), 18);
336 /// ```
337 pub fn generate_plane<V: Into<Vec3>>(
338 dimensions: impl Into<Vec2>,
339 plane_normal: V,
340 plane_top_direction: V,
341 subdivisions: Option<i32>,
342 double_sided: bool,
343 ) -> Mesh {
344 let subdivisions = subdivisions.unwrap_or(0);
345 Mesh(
346 NonNull::new(unsafe {
347 mesh_gen_plane(
348 dimensions.into(),
349 plane_normal.into(),
350 plane_top_direction.into(),
351 subdivisions,
352 double_sided as Bool32T,
353 )
354 })
355 .unwrap(),
356 )
357 }
358
359 /// Generates a plane on the XZ axis facing up that is optionally subdivided, pre-sized to the given dimensions. UV
360 /// coordinates start at 0,0 at the -X,-Z corner, and go to 1,1 at the +X,+Z corner!
361 ///
362 /// NOTE: This generates a completely new Mesh asset on the GPU, and is best done during 'initialization' of your
363 /// app/scene. You may also be interested in using the pre-generated `Mesh.Quad` asset if it already meets your
364 /// needs.
365 /// <https://stereokit.net/Pages/StereoKit/Mesh/GeneratePlane.html>
366 /// * `dimension` - How large is this plane on the XZ axis, in meters?
367 /// * `subdivisions` - Use this to add extra slices of vertices across the plane. This can be useful for some types of
368 /// vertex-based effects! None is 0.
369 /// * `double_sided` - Should both sides of the plane be rendered?
370 ///
371 /// Returns a plane mesh, pre-sized to the given dimensions.
372 /// see also [`mesh_gen_plane`]
373 /// ### Examples
374 /// ```
375 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
376 /// use stereokit_rust::{mesh::{Mesh, Vertex}, maths::{Vec2, Vec3}};
377 ///
378 /// // Create Meshes
379 /// let mesh = Mesh::generate_plane_up([1.0, 1.0], None, false);
380 /// let mesh_b = Mesh::generate_plane([1.0, 1.0], [0.0, 1.0, 0.0], [0.0, 0.0, -1.0], None, false);
381 /// assert_eq!(mesh.get_verts(), mesh_b.get_verts());
382 /// assert_eq!(mesh.get_inds(), mesh_b.get_inds());
383 /// assert_eq!(mesh.get_ind_count(), 6);
384 /// assert_eq!(mesh.get_vert_count(), 4);
385 /// let vertices0 = [
386 /// Vertex::new([-0.5, 0.0,-0.5].into(),Vec3::UP,Some(Vec2::ZERO), None),
387 /// Vertex::new([ 0.5, 0.0,-0.5].into(),Vec3::UP,Some(Vec2::X) , None),
388 /// Vertex::new([-0.5, 0.0, 0.5].into(),Vec3::UP,Some(Vec2::Y) , None),
389 /// Vertex::new([ 0.5, 0.0, 0.5].into(),Vec3::UP,Some(Vec2::ONE) , None),
390 /// ];
391 /// assert_eq!(mesh.get_verts(), vertices0);
392 ///
393 /// let mesh = Mesh::generate_plane_up([1.0, 1.0], None, true);
394 /// assert_eq!(mesh.get_inds().len(), 12);
395 /// assert_eq!(mesh.get_verts().len(), 8);
396 ///
397 /// let mesh = Mesh::generate_plane_up([1.0, 1.0], Some(1), true);
398 /// assert_eq!(mesh.get_inds().len(), 48);
399 /// assert_eq!(mesh.get_verts().len(), 18);
400 /// ```
401 pub fn generate_plane_up(dimensions: impl Into<Vec2>, subdivisions: Option<i32>, double_sided: bool) -> Mesh {
402 let subdivisions = subdivisions.unwrap_or(0);
403 Mesh(
404 NonNull::new(unsafe {
405 mesh_gen_plane(dimensions.into(), Vec3::UP, Vec3::FORWARD, subdivisions, double_sided as Bool32T)
406 })
407 .unwrap(),
408 )
409 }
410
411 /// Generates a circle with an arbitrary orientation that is pre-sized to the given diameter. UV coordinates start
412 /// at the top left indicated with 'plane_top_direction' and correspond to a unit circle centered at 0.5, 0.5.
413 ///
414 /// NOTE: This generates a completely new Mesh asset on the GPU, and is best done during 'initialization' of your
415 /// app/scene.
416 /// <https://stereokit.net/Pages/StereoKit/Mesh/GenerateCircle.html>
417 /// * `diameter` - The diameter of the circle in meters, or 2*radius. This is the full length from one side to the
418 /// other.
419 /// * `plane_normal` - What is the normal of the surface this circle is generated on?
420 /// * `plane_top_direction` - A normal defines the plane, but this is technically a rectangle on the plane. So which
421 /// direction is up? It's important for UVs, but doesn't need to be exact. This function takes the plane_normal as
422 /// law, and uses this vector to find the right and up vectors via cross-products.
423 /// * `spokes` - How many vertices compose the circumference of the circle? Clamps to a minimum of 3. More is smoother,
424 /// but less performant. if None has default value of 16.
425 /// * `double_sided` - Should both sides of the circle be rendered?
426 ///
427 /// Returns A circle mesh, pre-sized to the given dimensions.
428 ///
429 /// see also [`mesh_gen_circle`]
430 /// ### Examples
431 /// ```
432 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
433 /// use stereokit_rust::mesh::Mesh;
434 ///
435 /// // Create Meshes
436 /// let mesh = Mesh::generate_circle(1.0, [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], None, false);
437 /// assert_eq!(mesh.get_ind_count(), 42);
438 /// assert_eq!(mesh.get_vert_count(), 16);
439 ///
440 /// let mesh = Mesh::generate_circle(1.0, [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], None, true);
441 /// assert_eq!(mesh.get_inds().len(), 84);
442 /// assert_eq!(mesh.get_verts().len(), 32);
443 ///
444 /// let mesh = Mesh::generate_circle(1.0, [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], Some(1), true);
445 /// assert_eq!(mesh.get_inds().len(), 6);
446 /// assert_eq!(mesh.get_verts().len(), 6);
447 /// ```
448 pub fn generate_circle<V: Into<Vec3>>(
449 diameter: f32,
450 plane_normal: V,
451 plane_top_direction: V,
452 spokes: Option<i32>,
453 double_sided: bool,
454 ) -> Mesh {
455 let spokes = spokes.unwrap_or(16);
456 Mesh(
457 NonNull::new(unsafe {
458 mesh_gen_circle(
459 diameter,
460 plane_normal.into(),
461 plane_top_direction.into(),
462 spokes,
463 double_sided as Bool32T,
464 )
465 })
466 .unwrap(),
467 )
468 }
469
470 /// Generates a circle on the XZ axis facing up that is pre-sized to the given diameter. UV coordinates correspond
471 /// to a unit circle centered at 0.5, 0.5! That is, the right-most point on the circle has UV coordinates 1, 0.5
472 /// and the top-most point has UV coordinates 0.5, 1.
473 ///
474 /// NOTE: This generates a completely new Mesh asset on the GPU, and is best done during 'initialization' of your
475 /// app/scene.
476 /// <https://stereokit.net/Pages/StereoKit/Mesh/GenerateCircle.html>
477 /// * `diameter` - The diameter of the circle in meters, or 2*radius. This is the full length from one side to the
478 /// other.
479 /// * `spokes` - How many vertices compose the circumference of the circle? Clamps to a minimum of 3. More is smoother,
480 /// but less performant. if None has default value of 16.
481 /// * `double_sided` - Should both sides of the circle be rendered?
482 ///
483 /// Returns A circle mesh, pre-sized to the given dimensions.
484 /// see also [`mesh_gen_circle`]
485 /// ### Examples
486 /// ```
487 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
488 /// use stereokit_rust::mesh::Mesh;
489 ///
490 /// // Create Meshes
491 /// let mesh = Mesh::generate_circle_up(1.0 , None, false);
492 /// let mesh_b = Mesh::generate_circle(1.0, [0.0, 1.0, 0.0], [0.0, 0.0, -1.0], None, false);
493 /// assert_eq!(mesh.get_verts(), mesh_b.get_verts());
494 /// assert_eq!(mesh.get_inds(), mesh_b.get_inds());
495 /// assert_eq!(mesh.get_ind_count(), 42);
496 /// assert_eq!(mesh.get_vert_count(), 16);
497 ///
498 /// let mesh = Mesh::generate_circle_up(1.0 , None, true);
499 /// assert_eq!(mesh.get_inds().len(), 84);
500 /// assert_eq!(mesh.get_verts().len(), 32);
501 ///
502 /// let mesh = Mesh::generate_circle_up(1.0 , Some(1), true);
503 /// assert_eq!(mesh.get_inds().len(), 6);
504 /// assert_eq!(mesh.get_verts().len(), 6);
505 /// ```
506 pub fn generate_circle_up(diameter: f32, spokes: Option<i32>, double_sided: bool) -> Mesh {
507 let spokes = spokes.unwrap_or(16);
508 Mesh(
509 NonNull::new(unsafe {
510 mesh_gen_circle(diameter, Vec3::UP, Vec3::FORWARD, spokes, double_sided as Bool32T)
511 })
512 .unwrap(),
513 )
514 }
515
516 /// Generates a flat-shaded cube mesh, pre-sized to the given dimensions. UV coordinates are projected flat on each
517 /// face, 0,0 -> 1,1.
518 ///
519 /// NOTE: This generates a completely new Mesh asset on the GPU, and is best done during 'initialization' of your
520 /// app/scene. You may also be interested in using the pre-generated Mesh::cube() asset if it already meets your
521 /// needs.
522 /// <https://stereokit.net/Pages/StereoKit/Mesh/GenerateCube.html>
523 /// * `dimension` - How large is this cube on each axis, in meters?
524 /// * `subdivisions` - Use this to add extra slices of vertices across the cube's faces. This can be useful for some
525 /// types of vertex-based effects! None is 0.
526 ///
527 /// Returns a flat-shaded cube mesh, pre-sized to the given dimensions.
528 /// see also [`mesh_gen_circle`]
529 /// ### Examples
530 /// ```
531 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
532 /// use stereokit_rust::mesh::Mesh;
533 ///
534 /// // Create Meshes
535 /// let mesh = Mesh::generate_cube([1.0, 1.0, 1.0], None);
536 /// assert_eq!(mesh.get_ind_count(), 36);
537 /// assert_eq!(mesh.get_vert_count(), 24);
538 ///
539 /// let mesh = Mesh::generate_cube([1.0, 1.0, 1.0], Some(1));
540 /// assert_eq!(mesh.get_inds().len(), 144);
541 /// assert_eq!(mesh.get_verts().len(), 54);
542 /// ```
543 pub fn generate_cube(dimensions: impl Into<Vec3>, subdivisions: Option<i32>) -> Mesh {
544 let subdivisions = subdivisions.unwrap_or(0);
545 Mesh(NonNull::new(unsafe { mesh_gen_cube(dimensions.into(), subdivisions) }).unwrap())
546 }
547
548 /// Generates a cube mesh with rounded corners, pre-sized to the given dimensions. UV coordinates are 0,0 -> 1,1 on
549 /// each face, meeting at the middle of the rounded corners.
550 ///
551 /// NOTE: This generates a completely new Mesh asset on the GPU, and is best done during 'initialization' of your
552 /// app/scene.
553 /// <https://stereokit.net/Pages/StereoKit/Mesh/GenerateRoundedCube.html>
554 /// * `dimension` - How large is this cube on each axis, in meters?
555 /// * `edge_radius` - Radius of the corner rounding, in meters.
556 /// * `subdivisions` -How many subdivisions should be used for creating the corners? A larger value results in
557 /// smoother corners, but can decrease performance.! None is 4.
558 ///
559 /// Returns a cube mesh with rounded corners, pre-sized to the given dimensions
560 /// see also [`mesh_gen_rounded_cube`]
561 /// ### Examples
562 /// ```
563 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
564 /// use stereokit_rust::mesh::Mesh;
565 ///
566 /// // Create Meshes
567 /// let mesh = Mesh::generate_rounded_cube([1.0, 1.0, 1.0], 0.1, None);
568 /// assert_eq!(mesh.get_ind_count(), 900);
569 /// assert_eq!(mesh.get_vert_count(), 216);
570 ///
571 /// let mesh = Mesh::generate_rounded_cube([1.0, 1.0, 1.0], 0.1, Some(1));
572 /// assert_eq!(mesh.get_inds().len(), 324);
573 /// assert_eq!(mesh.get_verts().len(), 96);
574 ///
575 /// let mesh = Mesh::generate_rounded_cube([1.0, 1.0, 1.0], 0.2, Some(1));
576 /// assert_eq!(mesh.get_inds().len(), 324);
577 /// assert_eq!(mesh.get_verts().len(), 96);
578 /// ```
579 pub fn generate_rounded_cube(dimensions: impl Into<Vec3>, edge_radius: f32, subdivisions: Option<i32>) -> Mesh {
580 let subdivisions = subdivisions.unwrap_or(4);
581 Mesh(NonNull::new(unsafe { mesh_gen_rounded_cube(dimensions.into(), edge_radius, subdivisions) }).unwrap())
582 }
583
584 /// Generates a sphere mesh, pre-sized to the given diameter, created by sphereifying a subdivided cube! UV
585 /// coordinates are taken from the initial unspherified cube.
586 ///
587 /// NOTE: This generates a completely new Mesh asset on the GPU, and is best done during 'initialization' of your
588 /// app/scene. You may also be interested in using the pre-generated `Mesh::sphere()` asset if it already meets your
589 /// needs.
590 /// <https://stereokit.net/Pages/StereoKit/Mesh/GenerateSphere.html>
591 /// * `diameter` - The diameter of the sphere in meters, or 2*radius. This is the full length from one side to the other.
592 /// * `subdivisions` - How many times should the initial cube be subdivided? None is 4.
593 ///
594 /// Returns - A sphere mesh, pre-sized to the given diameter, created by sphereifying a subdivided cube! UV
595 /// coordinates are taken from the initial unspherified cube.
596 /// see also [`mesh_gen_sphere`]
597 /// ### Examples
598 /// ```
599 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
600 /// use stereokit_rust::mesh::Mesh;
601 ///
602 /// // Create Meshes
603 /// let mesh = Mesh::generate_sphere(1.0 , None);
604 /// assert_eq!(mesh.get_ind_count(), 900);
605 /// assert_eq!(mesh.get_vert_count(), 216);
606 ///
607 ///
608 /// let mesh = Mesh::generate_sphere(1.0 , Some(1));
609 /// assert_eq!(mesh.get_inds().len(), 144);
610 /// assert_eq!(mesh.get_verts().len(), 54);
611 /// ```
612 pub fn generate_sphere(diameter: f32, subdivisions: Option<i32>) -> Mesh {
613 let subdivisions = subdivisions.unwrap_or(4);
614 Mesh(NonNull::new(unsafe { mesh_gen_sphere(diameter, subdivisions) }).unwrap())
615 }
616
617 /// Generates a cylinder mesh, pre-sized to the given diameter and depth, UV coordinates are from a flattened top
618 /// view right now. Additional development is needed for making better UVs for the edges.
619 ///
620 /// NOTE: This generates a completely new Mesh asset on the GPU, and is best done during 'initialization' of your
621 /// app/scene.
622 /// <https://stereokit.net/Pages/StereoKit/Mesh/GenerateCylinder.html>
623 /// * `diameter` - Diameter of the circular part of the cylinder in meters. Diameter is 2*radius.
624 /// * `depth` - How tall is this cylinder, in meters?
625 /// * `direction` - What direction do the circular surfaces face? This is the surface normal for the top, it does not
626 /// need to be normalized.
627 /// * `subdivisions` - How many vertices compose the edges of the cylinder? More is smoother, but less performant.
628 /// None is 16.
629 ///
630 /// Returns a cylinder mesh, pre-sized to the given diameter and depth, UV coordinates are from a flattened top view
631 /// right now.
632 /// see also [`mesh_gen_cylinder`]
633 /// ### Examples
634 /// ```
635 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
636 /// use stereokit_rust::mesh::Mesh;
637 ///
638 /// // Create Meshes
639 /// let mesh = Mesh::generate_cylinder(1.0, 1.0, [0.0, 1.0, 0.0], None);
640 /// assert_eq!(mesh.get_ind_count(), 192);
641 /// assert_eq!(mesh.get_vert_count(), 70);
642 ///
643 /// let mesh = Mesh::generate_cylinder(1.0, 1.0, [0.0, 1.0, 0.0], Some(1));
644 /// assert_eq!(mesh.get_inds().len(), 12);
645 /// assert_eq!(mesh.get_verts().len(), 10);
646 /// ```
647 pub fn generate_cylinder(diameter: f32, depth: f32, direction: impl Into<Vec3>, subdivisions: Option<i32>) -> Mesh {
648 let subdivisions = subdivisions.unwrap_or(16);
649 Mesh(NonNull::new(unsafe { mesh_gen_cylinder(diameter, depth, direction.into(), subdivisions) }).unwrap())
650 }
651
652 /// Finds the Mesh with the matching id, and returns a reference to it. If no Mesh is found, it returns
653 /// StereoKitError::MeshFind.
654 /// <https://stereokit.net/Pages/StereoKit/Mesh/Find.html>
655 /// * `id` - The id of the Mesh to find.
656 ///
657 /// see also [`mesh_find`]
658 /// ### Examples
659 /// ```
660 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
661 /// use stereokit_rust::mesh::Mesh;
662 ///
663 /// // Create Meshes
664 /// let mut mesh = Mesh::generate_circle_up(1.0 , None, false);
665 /// mesh.id("my_circle");
666 ///
667 /// let same_mesh = Mesh::find("my_circle").expect("Mesh should be here");
668 ///
669 /// assert_eq!(mesh, same_mesh);
670 /// ```
671 pub fn find<S: AsRef<str>>(id: S) -> Result<Mesh, StereoKitError> {
672 let cstr = CString::new(id.as_ref())?;
673 match NonNull::new(unsafe { mesh_find(cstr.as_ptr()) }) {
674 Some(mesh) => Ok(Mesh(mesh)),
675 None => Err(StereoKitError::MeshFind(id.as_ref().to_owned())),
676 }
677 }
678
679 /// Creates a clone of the same reference. Basically, the new variable is the same asset. This is what you get by
680 /// calling find() method.
681 /// <https://stereokit.net/Pages/StereoKit/Mesh/Find.html>
682 ///
683 /// see also [`mesh_find()`]
684 /// ### Examples
685 /// ```
686 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
687 /// use stereokit_rust::mesh::Mesh;
688 ///
689 /// // Create Meshes
690 /// let mesh = Mesh::generate_circle_up(1.0 , None, false);
691 /// let not_same_mesh = Mesh::generate_circle_up(1.0 , None, false);
692 ///
693 /// let same_mesh = mesh.clone_ref();
694 ///
695 /// assert_eq!(mesh, same_mesh);
696 /// assert_ne!(mesh, not_same_mesh);
697 /// ```
698 pub fn clone_ref(&self) -> Mesh {
699 Mesh(NonNull::new(unsafe { mesh_find(mesh_get_id(self.0.as_ptr())) }).expect("<asset>::clone_ref failed!"))
700 }
701
702 /// Sets the unique identifier of this asset resource! This can be helpful for debugging, managing your assets, or
703 /// finding them later on!
704 /// <https://stereokit.net/Pages/StereoKit/Mesh/Id.html>
705 /// * `id` - The unique identifier for this asset! Be sure it's unique!
706 ///
707 /// see also [`mesh_set_id`]
708 /// ### Examples
709 /// ```
710 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
711 /// use stereokit_rust::mesh::Mesh;
712 ///
713 /// // Create Meshes
714 /// let mut mesh = Mesh::generate_circle_up(1.0 , None, false);
715 /// assert!(mesh.get_id().starts_with("auto/mesh_"));
716 /// mesh.id("my_circle");
717 ///
718 /// assert_eq!(mesh.get_id(), "my_circle");
719 /// ```
720 pub fn id<S: AsRef<str>>(&mut self, id: S) -> &mut Self {
721 let cstr = CString::new(id.as_ref()).unwrap();
722 unsafe { mesh_set_id(self.0.as_ptr(), cstr.as_ptr()) };
723 self
724 }
725
726 /// This is a bounding box that encapsulates the Mesh! It's used for collision, visibility testing, UI layout, and
727 /// probably other things. While it's normally calculated from the mesh vertices, you can also override this to
728 /// suit your needs.
729 /// <https://stereokit.net/Pages/StereoKit/Mesh/Bounds.html>
730 /// * `bounds` - The bounding box to set.
731 ///
732 /// see also [`mesh_set_bounds`]
733 /// ### Examples
734 /// ```
735 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
736 /// use stereokit_rust::{maths::{Vec3, Matrix, Bounds},
737 /// mesh::Mesh, material::Material, util::named_colors};
738 ///
739 /// let mut sphere = Mesh::generate_sphere(1.0, None);
740 /// let material_sphere = Material::pbr();
741 /// let transform = Matrix::IDENTITY;
742 ///
743 /// let cube = Mesh::cube();
744 /// let mut material_before = Material::ui_box();
745 /// material_before.color_tint(named_colors::GOLD)
746 /// .border_size(0.025);
747 ///
748 /// let mut material_after = material_before.copy();
749 /// material_after.color_tint(named_colors::RED);
750 ///
751 /// let bounds = sphere.get_bounds();
752 /// let transform_before = Matrix::t_s( bounds.center, bounds.dimensions);
753 ///
754 /// sphere.bounds( Bounds::bounds_centered(Vec3::ONE * 0.7));
755 /// let new_bounds = sphere.get_bounds();
756 /// let transform_after = Matrix::t_s( new_bounds.center, new_bounds.dimensions);
757 ///
758 /// filename_scr = "screenshots/mesh_bounds.jpeg";
759 /// test_screenshot!( // !!!! Get a proper main loop !!!!
760 /// sphere.draw(token, &material_sphere, transform, None, None);
761 /// cube.draw( token, &material_before, transform_before, None, None);
762 /// cube.draw( token, &material_after, transform_after, None, None);
763 /// );
764 /// ```
765 /// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/mesh_bounds.jpeg" alt="screenshot" width="200">
766 pub fn bounds(&mut self, bounds: impl AsRef<Bounds>) -> &mut Self {
767 unsafe { mesh_set_bounds(self.0.as_ptr(), bounds.as_ref() as *const Bounds) };
768 self
769 }
770
771 /// Should StereoKit keep the mesh data on the CPU for later access, or collision detection? Defaults to true. If you
772 /// set this to false before setting data, the data won't be stored. If you call this after setting data, that
773 /// stored data will be freed! If you set this to true again later on, it will not contain data until it's set again.
774 /// <https://stereokit.net/Pages/StereoKit/Mesh/KeepData.html>
775 ///
776 /// see also [`mesh_set_keep_data`]
777 /// ### Examples
778 /// ```
779 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
780 /// use stereokit_rust::{mesh::Mesh, maths::Bounds};
781 ///
782 /// // Create Meshes
783 /// let mut mesh = Mesh::generate_circle_up(1.0 , None, false);
784 /// assert_eq!(mesh.get_keep_data(), true);
785 /// assert_ne!(mesh.get_bounds(), Bounds::default());
786 ///
787 /// mesh.keep_data(false);
788 /// assert_eq!(mesh.get_keep_data(), false);
789 /// mesh.keep_data(true);
790 /// assert_eq!(mesh.get_keep_data(), true);
791 /// ```
792 pub fn keep_data(&mut self, keep_data: bool) -> &mut Self {
793 unsafe { mesh_set_keep_data(self.0.as_ptr(), keep_data as Bool32T) };
794 self
795 }
796
797 /// Assigns the vertices and indices for this Mesh! This will create a vertex buffer and index buffer object on the
798 /// graphics card. If you're calling this a second time, the buffers will be marked as dynamic and re-allocated. If
799 /// you're calling this a third time, the buffer will only re-allocate if the buffer is too small, otherwise it just
800 /// copies in the data!
801 ///
802 /// Remember to set all the relevant values! Your material will often show black if the Normals or Colors are left
803 /// at their default values.
804 ///
805 /// Calling SetData is slightly more efficient than calling SetVerts and SetInds separately.
806 /// <https://stereokit.net/Pages/StereoKit/Mesh/SetData.html>
807 /// * `vertices` - An array of vertices to add to the mesh. Remember to set all the relevant values! Your material
808 /// will often show black if the Normals or Colors are left at their default values.
809 /// * `indices` - A list of face indices, must be a multiple of 3. Each index represents a vertex from the provided
810 /// vertex array.
811 /// * `calculate_bounds` - If true, this will also update the Mesh's bounds based on the vertices provided. Since this
812 /// does require iterating through all the verts with some logic, there is performance cost to doing this. If
813 /// you're updating a mesh frequently or need all the performance you can get, setting this to false is a nice way
814 /// to gain some speed!
815 ///
816 /// see also [`mesh_set_data`]
817 /// see example[`Vertex`]
818 pub fn set_data(&mut self, vertices: &[Vertex], indices: &[u32], calculate_bounds: bool) -> &mut Self {
819 unsafe {
820 mesh_set_data(
821 self.0.as_ptr(),
822 vertices.as_ptr(),
823 vertices.len() as i32,
824 indices.as_ptr(),
825 indices.len() as i32,
826 calculate_bounds as Bool32T,
827 )
828 };
829 self
830 }
831
832 /// Assigns the vertices for this Mesh! This will create a vertex buffer object on the graphics card. If you're
833 /// calling this a second time, the buffer will be marked as dynamic and re-allocated. If you're calling this a
834 /// third time, the buffer will only re-allocate if the buffer is too small, otherwise it just copies in the data!
835 ///
836 /// Remember to set all the relevant values! Your material will often show black if the Normals or Colors are left
837 /// at their default values.
838 /// <https://stereokit.net/Pages/StereoKit/Mesh/SetVerts.html>
839 /// * `vertices` - An array of vertices to add to the mesh. Remember to set all the relevant values! Your material
840 /// will often show black if the Normals or Colors are left at their default values.
841 /// * `calculate_bounds` - If true, this will also update the Mesh's bounds based on the vertices provided. Since this
842 /// does require iterating through all the verts with some logic, there is performance cost to doing this. If
843 /// you're updating a mesh frequently or need all the performance you can get, setting this to false is a nice way
844 /// to gain some speed!
845 ///
846 /// see also [`mesh_set_verts`] [`Vertex`] [`Mesh::set_data`]
847 /// ### Examples
848 /// ```
849 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
850 /// use stereokit_rust::{maths::{Vec2, Vec3, Matrix, Bounds}, mesh::{Mesh, Vertex},
851 /// material::Material, util::named_colors};
852 ///
853 /// let material = Material::pbr();
854 /// let mut square = Mesh::new();
855 /// square.set_verts(&[
856 /// Vertex::new([-1.0, -1.0, 0.0].into(), Vec3::UP, None, Some(named_colors::BLUE)),
857 /// Vertex::new([ 1.0, -1.0, 0.0].into(), Vec3::UP, Some(Vec2::X), None),
858 /// Vertex::new([-1.0, 1.0, 0.0].into(), Vec3::UP, Some(Vec2::Y), None),
859 /// Vertex::new([ 1.0, 1.0, 0.0].into(), Vec3::UP, Some(Vec2::ONE), Some(named_colors::YELLOW)),
860 /// ], true)
861 /// .set_inds(&[0, 1, 2, 2, 1, 3]);
862 ///
863 /// filename_scr = "screenshots/mesh_set_verts.jpeg";
864 /// test_screenshot!( // !!!! Get a proper main loop !!!!
865 /// square.draw(token, &material , Matrix::IDENTITY, None, None);
866 /// );
867 /// ```
868 /// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/mesh_set_verts.jpeg" alt="screenshot" width="200">
869 pub fn set_verts(&mut self, vertices: &[Vertex], calculate_bounds: bool) -> &mut Self {
870 unsafe {
871 mesh_set_verts(self.0.as_ptr(), vertices.as_ptr(), vertices.len() as i32, calculate_bounds as Bool32T)
872 };
873 self
874 }
875
876 /// Assigns the face indices for this Mesh! Faces are always triangles, there are only ever three indices per face.
877 /// This function will create a index buffer object on the graphics card. If you're calling this a second time, the
878 /// buffer will be marked as dynamic and re-allocated. If you're calling this a third time, the buffer will only
879 /// re-allocate if the buffer is too small, otherwise it just copies in the data!
880 /// <https://stereokit.net/Pages/StereoKit/Mesh/SetInds.html>
881 /// * `indices` - A list of face indices, must be a multiple of 3. Each index represents a vertex from the array
882 /// assigned using SetVerts.
883 ///
884 /// see also [`mesh_set_inds`] [`Vertex`] [`Mesh::set_data`]
885 /// ### Examples
886 /// ```
887 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
888 /// use stereokit_rust::{maths::{Vec2, Vec3, Matrix, Bounds}, mesh::{Mesh, Vertex},
889 /// material::Material, util::named_colors};
890 ///
891 /// let material = Material::pbr();
892 /// let mut sphere = Mesh::generate_sphere(1.5, Some(16));
893 ///
894 /// // Let's remove half of the triangles.
895 /// let indices = sphere.get_inds();
896 /// let mut new_indices = vec![];
897 /// let mut iter = 0;
898 /// for i in 0..indices.len() {
899 /// if iter < 3 {
900 /// new_indices.push(indices[i]);
901 /// } else if iter == 5 {
902 /// iter = -1;
903 /// }
904 /// iter += 1;
905 /// }
906 ///
907 /// sphere.set_inds(&new_indices);
908 ///
909 /// filename_scr = "screenshots/mesh_set_inds.jpeg";
910 /// test_screenshot!( // !!!! Get a proper main loop !!!!
911 /// sphere.draw(token, &material , Matrix::IDENTITY, Some(named_colors::PINK.into()), None);
912 /// );
913 /// ```
914 /// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/mesh_set_inds.jpeg" alt="screenshot" width="200">
915 pub fn set_inds(&mut self, indices: &[u32]) -> &mut Self {
916 unsafe { mesh_set_inds(self.0.as_ptr(), indices.as_ptr(), indices.len() as i32) };
917 self
918 }
919
920 /// Adds a mesh to the render queue for this frame! If the Hierarchy has a transform on it, that transform is
921 /// combined with the Matrix provided here.
922 /// <https://stereokit.net/Pages/StereoKit/Mesh/Draw.html>
923 /// * `material` - A Material to apply to the Mesh.
924 /// * `transform` - A Matrix that will transform the mesh from Model Space into the current Hierarchy Space.
925 /// * `color_linear` - A per-instance linear space color value to pass into the shader! Normally this gets used like a
926 /// material tint. If you're adventurous and don't need per-instance colors, this is a great spot to pack in
927 /// extra per-instance data for the shader! If None has default value of WHITE
928 /// * `layer` - All visuals are rendered using a layer bit-flag. By default, all layers are rendered, but this can be
929 /// useful for filtering out objects for different rendering purposes! For example: rendering a mesh over the
930 /// user's head from a 3rd person perspective, but filtering it out from the 1st person perspective.If None has
931 /// default value of Layer0
932 ///
933 /// see also [`mesh_draw`]
934 /// ### Examples
935 /// ```
936 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
937 /// use stereokit_rust::{maths::{Vec2, Vec3, Matrix, Bounds}, mesh::{Mesh, Vertex},
938 /// material::Material, util::named_colors, system::RenderLayer};
939 ///
940 /// let material = Material::pbr();
941 /// let cylinder1 = Mesh::generate_cylinder(0.25, 1.5, Vec3::ONE, None);
942 /// let cylinder2 = Mesh::generate_cylinder(0.25, 1.5, [-0.5, 0.5, 0.5], None);
943 /// let cylinder3 = Mesh::generate_cylinder(0.25, 1.2, [0.0, -0.5, 0.5], None);
944 ///
945 /// filename_scr = "screenshots/mesh_draw.jpeg";
946 /// test_screenshot!( // !!!! Get a proper main loop !!!!
947 /// cylinder1.draw(token, &material , Matrix::IDENTITY, None, None);
948 /// cylinder2.draw(token, &material , Matrix::IDENTITY, Some(named_colors::RED.into()),
949 /// Some(RenderLayer::Layer1));
950 /// cylinder3.draw(token, &material , Matrix::IDENTITY, Some(named_colors::GREEN.into()),
951 /// Some(RenderLayer::ThirdPerson));
952 /// );
953 /// ```
954 /// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/mesh_draw.jpeg" alt="screenshot" width="200">
955 pub fn draw(
956 &self,
957 _token: &MainThreadToken,
958 material: impl AsRef<Material>,
959 transform: impl Into<Matrix>,
960 color_linear: Option<Color128>,
961 layer: Option<RenderLayer>,
962 ) {
963 let color_linear: Color128 = color_linear.unwrap_or(Color128::WHITE);
964 let layer = layer.unwrap_or(RenderLayer::Layer0);
965 unsafe { mesh_draw(self.0.as_ptr(), material.as_ref().0.as_ptr(), transform.into(), color_linear, layer) }
966 }
967
968 /// Gets the unique identifier of this asset resource! This can be helpful for debugging, managing your assets, or
969 /// finding them later on!
970 /// <https://stereokit.net/Pages/StereoKit/Mesh/id.html>
971 ///
972 /// see also [`mesh_get_id`]
973 /// see example in [`Mesh::id`]
974 pub fn get_id(&self) -> &str {
975 unsafe { CStr::from_ptr(mesh_get_id(self.0.as_ptr())) }.to_str().unwrap()
976 }
977 /// This is a bounding box that encapsulates the Mesh! It's used for collision, visibility testing, UI layout, and
978 /// probably other things. While it's normally calculated from the mesh vertices, you can also override this to
979 /// suit your needs.
980 /// <https://stereokit.net/Pages/StereoKit/Mesh/Bounds.html>
981 ///
982 /// see also [`mesh_get_bounds`]
983 /// see example in [`Mesh::bounds`]
984 pub fn get_bounds(&self) -> Bounds {
985 unsafe { mesh_get_bounds(self.0.as_ptr()) }
986 }
987
988 /// Should StereoKit keep the mesh data on the CPU for later access, or collision detection? Defaults to true. If you
989 /// set this to false before setting data, the data won't be stored. If you call this after setting data, that
990 /// stored data will be freed! If you set this to true again later on, it will not contain data until it's set again.
991 /// <https://stereokit.net/Pages/StereoKit/Mesh/KeepData.html>
992 ///
993 /// see also [`mesh_get_keep_data`]
994 /// see example in [`Mesh::keep_data`]
995 pub fn get_keep_data(&self) -> bool {
996 unsafe { mesh_get_keep_data(self.0.as_ptr()) != 0 }
997 }
998
999 /// Get the number of indices stored in this Mesh! This is available to you regardless of whether or not keep_data
1000 /// is set.
1001 /// <https://stereokit.net/Pages/StereoKit/Mesh/IndCount.html>
1002 ///
1003 /// see also [`mesh_get_ind_count`]
1004 pub fn get_ind_count(&self) -> i32 {
1005 unsafe { mesh_get_ind_count(self.0.as_ptr()) }
1006 }
1007
1008 /// Get the number of vertices stored in this Mesh! This is available to you regardless of whether or not keep_data
1009 /// is set.
1010 /// <https://stereokit.net/Pages/StereoKit/Mesh/VertCount.html>
1011 ///
1012 /// see also [`mesh_get_vert_count`]
1013 pub fn get_vert_count(&self) -> i32 {
1014 unsafe { mesh_get_vert_count(self.0.as_ptr()) }
1015 }
1016
1017 /// This marshalls the Mesh's index data into an array. If keep_data is false, then the Mesh is **not** storing
1018 /// indices on the CPU, and this information will **not** be available.
1019 ///
1020 /// Due to the way marshalling works, this is **not** a cheap function!
1021 /// <https://stereokit.net/Pages/StereoKit/Mesh/GetInds.html>
1022 /// Returns - An array of indices representing the Mesh, or null if keep_data is false.
1023 ///
1024 /// see also [Mesh::get_inds_copy] [`mesh_get_inds`]
1025 /// see example in [`Mesh::set_inds`]
1026 pub fn get_inds(&self) -> &[u32] {
1027 let inds_ptr = CString::new("H").unwrap().into_raw() as *mut *mut u32;
1028 let mut inds_len = 0;
1029 unsafe {
1030 mesh_get_inds(self.0.as_ptr(), inds_ptr, &mut inds_len, Memory::Reference);
1031 &mut *slice_from_raw_parts_mut(*inds_ptr, inds_len as usize)
1032 }
1033 }
1034
1035 /// Get the indices by value
1036 /// This marshalls the Mesh's index data into an array. If keep_data is false, then the Mesh is **not** storing
1037 /// indices on the CPU, and this information will **not** be available.
1038 ///
1039 /// Due to the way marshalling works, this is **not** a cheap function!
1040 /// <https://stereokit.net/Pages/StereoKit/Mesh/GetInds.html>
1041 ///
1042 /// see also [Mesh::get_inds] [`mesh_get_inds`]
1043 pub fn get_inds_copy(&self) -> Vec<u32> {
1044 self.get_inds().to_vec()
1045 }
1046
1047 /// This marshalls the Mesh's vertex data into an array. If keep_data is false, then the Mesh is **not** storing
1048 /// verts
1049 /// on the CPU, and this information will **not** be available.
1050 ///
1051 /// Due to the way marshalling works, this is **not** a cheap function!
1052 /// <https://stereokit.net/Pages/StereoKit/Mesh/GetVerts.html>
1053 ///
1054 /// see also [Mesh::get_verts_copy] [`mesh_get_verts`]
1055 /// see example in [`Mesh::set_verts`]
1056 pub fn get_verts(&self) -> &[Vertex] {
1057 let verts_pointer = CString::new("H").unwrap().into_raw() as *mut *mut Vertex;
1058 let mut verts_len = 0;
1059 unsafe {
1060 mesh_get_verts(self.0.as_ptr(), verts_pointer, &mut verts_len, Memory::Reference);
1061 &mut *slice_from_raw_parts_mut(*verts_pointer, verts_len as usize)
1062 }
1063 }
1064
1065 /// Get the vertices by value
1066 /// This marshalls the Mesh's vertex data into an array. If keep_data is false, then the Mesh is **not** storing
1067 /// verts
1068 /// on the CPU, and this information will **not** be available.
1069 ///
1070 /// Due to the way marshalling works, this is **not** a cheap function!
1071 /// <https://stereokit.net/Pages/StereoKit/Mesh/GetVerts.html>
1072 ///
1073 /// see also [Mesh::get_verts] [`mesh_get_verts`]
1074 pub fn get_verts_copy(&self) -> Vec<Vertex> {
1075 self.get_verts().to_vec()
1076 }
1077
1078 /// Retrieves the vertices associated with a particular triangle on the Mesh.
1079 /// <https://stereokit.net/Pages/StereoKit/Mesh/GetTriangle.html>
1080 /// * `triangle_index` - Starting index of the triangle, should be a multiple of 3.
1081 ///
1082 /// Returns an array of 3 vertices if triangle index was valid.
1083 /// see also [`mesh_get_triangle`]
1084 /// ### Examples
1085 /// ```
1086 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1087 /// use stereokit_rust::{maths::{Vec2, Vec3, Matrix, Bounds}, mesh::{Mesh, Vertex},
1088 /// material::Material, util::named_colors, system::RenderLayer};
1089 ///
1090 /// let material = Material::pbr();
1091 /// let plane = Mesh::generate_plane_up(Vec2::ONE, None, false);
1092 /// assert_eq!(plane.get_vert_count(), 4, "plane should have 4 vertices");
1093 /// assert_eq!(plane.get_ind_count(), 6, "plane should have 6 indices");
1094 ///
1095 /// let triangle0 = plane.get_triangle(0 * 3).expect("triangle 0 should exist");
1096 /// let triangle1 = plane.get_triangle(1 * 3).expect("triangle 1 should exist");
1097 /// //assert!(plane.get_triangle(5).is_some(), "triangle 5 should exist");
1098 /// assert!(plane.get_triangle(2 * 3).is_none(), "triangle 6 should not exist");
1099 ///
1100 /// let vertices0 = [
1101 /// Vertex::new([ 0.5, 0.0, 0.5].into(),Vec3::UP,Some(Vec2::ONE) , None),
1102 /// Vertex::new([ 0.5, 0.0,-0.5].into(),Vec3::UP,Some(Vec2::X) , None),
1103 /// Vertex::new([-0.5, 0.0,-0.5].into(),Vec3::UP,Some(Vec2::ZERO), None),
1104 /// ];
1105 /// assert_eq!(triangle0, vertices0);
1106 ///
1107 /// let vertices1 = [
1108 /// Vertex::new([-0.5, 0.0, 0.5].into(),Vec3::UP,Some(Vec2::Y) , None),
1109 /// Vertex::new([ 0.5, 0.0, 0.5].into(),Vec3::UP,Some(Vec2::ONE) , None),
1110 /// Vertex::new([-0.5, 0.0,-0.5].into(),Vec3::UP,Some(Vec2::ZERO), None),
1111 /// ];
1112 /// assert_eq!(triangle1, vertices1);
1113 /// ```
1114 pub fn get_triangle(&self, triangle_index: u32) -> Option<[Vertex; 3]> {
1115 let mut v_a = Vertex::default();
1116 let mut v_b = Vertex::default();
1117 let mut v_c = Vertex::default();
1118 let out_a: *mut Vertex = &mut v_a;
1119 let out_b: *mut Vertex = &mut v_b;
1120 let out_c: *mut Vertex = &mut v_c;
1121 unsafe {
1122 match mesh_get_triangle(self.0.as_ptr(), triangle_index, out_a, out_b, out_c) != 0 {
1123 true => Some([v_a, v_b, v_c]),
1124 false => None,
1125 }
1126 }
1127 }
1128
1129 /// Checks the intersection point of a ray and this Mesh with collision data stored on the CPU. A mesh without
1130 /// collision data will always return None. Ray must be in model space, intersection point will be in model
1131 /// space too. You can use the inverse of the mesh’s world transform matrix to bring the ray into model space,
1132 /// see the example in the docs!
1133 /// <https://stereokit.net/Pages/StereoKit/Mesh/Intersect.html>
1134 /// * `model_space_ray` - Ray must be in model space, the intersection point will be in model space too. You can use the
1135 /// inverse of the mesh's world transform matrix to bring the ray into model space, see the example in the docs!
1136 /// * `cull` - If None has default value of Cull::Back.
1137 ///
1138 /// Returns a tuple with
1139 /// - The intersection point of the ray and the mesh, if an intersection occurs. This is in model space, and must
1140 /// be transformed back into world space later.
1141 /// - The indice of the mesh where the intersection occurs.
1142 ///
1143 /// see also [`mesh_ray_intersect`] [`Ray::intersect_mesh`]
1144 /// ### Examples
1145 /// ```
1146 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1147 /// use stereokit_rust::{maths::{Vec3, Matrix, Quat, Ray}, system::Lines,
1148 /// util::{named_colors}, mesh::Mesh, material::{Material, Cull}};
1149 ///
1150 /// // Create Meshes
1151 /// let cube = Mesh::generate_cube(Vec3::ONE * 0.8, None);
1152 /// let sphere = Mesh::generate_sphere(1.0, Some(4));
1153 ///
1154 /// let material = Material::pbr().copy();
1155 /// let transform = Matrix::r(Quat::from_angles(40.0, 50.0, 20.0));
1156 /// let inv = transform.get_inverse();
1157 ///
1158 /// let ray = Ray::new([-1.0, 2.0, 2.5 ], [1.0, -2.0, -2.25]);
1159 /// let inv_ray = inv.transform_ray(ray);
1160 ///
1161 /// let (contact_cube, ind_cube) = cube.intersect( inv_ray, Some(Cull::Back))
1162 /// .expect("Ray should touch cube");
1163 /// assert_eq!(ind_cube, 12);
1164 ///
1165 /// let transform_contact_cube = Matrix::t_s(
1166 /// transform.transform_point(contact_cube), Vec3::ONE * 0.1);
1167 ///
1168 /// filename_scr = "screenshots/mesh_intersect.jpeg";
1169 /// test_screenshot!( // !!!! Get a proper main loop !!!!
1170 /// cube.draw(token, &material, transform, Some(named_colors::CYAN.into()), None);
1171 /// Lines::add_ray(token, ray, 2.2, named_colors::WHITE, None, 0.02);
1172 /// sphere.draw(token, &material, transform_contact_cube, Some(named_colors::YELLOW.into()), None );
1173 /// );
1174 /// ```
1175 /// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/mesh_intersect.jpeg" alt="screenshot" width="200">
1176 #[inline]
1177 pub fn intersect(&self, model_space_ray: Ray, cull: Option<Cull>) -> Option<(Vec3, VindT)> {
1178 model_space_ray.intersect_mesh(self, cull)
1179 }
1180
1181 /// Checks the intersection point of a Ray and this Mesh with collision data stored on the CPU. A mesh without
1182 /// collision data will always return false. Ray must be in model space, intersection point will be in model
1183 /// space too. You can use the inverse of the mesh’s world transform matrix to bring the ray into model space,
1184 /// see the example in the docs!
1185 /// <https://stereokit.net/Pages/StereoKit/Mesh/Intersect.html>
1186 /// * `model_space_ray` - Ray must be in model space, the intersection point will be in model space too. You can use the
1187 /// inverse of the mesh's world transform matrix to bring the ray into model space, see the example in the docs!
1188 /// * `cull` - If None has default value of Cull::Back.
1189 /// * `out_model_space_ray` -The intersection point and surface direction of the ray and the mesh, if an intersection
1190 /// occurs. This is in model space, and must be transformed back into world space later. Direction is not
1191 /// guaranteed to be normalized, especially if your own model->world transform contains scale/skew in it.
1192 /// * `out_start_inds` - The index of the first index of the triangle that was hit
1193 ///
1194 /// Returns true if an intersection occurs.
1195 /// see also [`mesh_ray_intersect`] [`Ray::intersect_mesh`] [`Mesh::intersect`]
1196 /// ### Examples
1197 /// ```
1198 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1199 /// use stereokit_rust::{maths::{Vec3, Matrix, Quat, Ray}, system::Lines,
1200 /// util::{named_colors}, mesh::Mesh, material::{Material, Cull}};
1201 ///
1202 /// // Create Meshes
1203 /// let cube = Mesh::generate_cube(Vec3::ONE * 0.8, None);
1204 /// let sphere = Mesh::generate_sphere(1.0, Some(4));
1205 ///
1206 /// let material = Material::pbr().copy();
1207 /// let transform = Matrix::r(Quat::from_angles(40.0, 50.0, 20.0));
1208 /// let inv = transform.get_inverse();
1209 ///
1210 /// let ray = Ray::new([-3.0, 2.0, 0.5 ], [3.0, -2.0, -0.25]);
1211 /// let inv_ray = inv.transform_ray(ray);
1212 ///
1213 /// let (mut contact_sphere_ray, mut ind_sphere) = (Ray::default(), 0u32);
1214 /// assert!(sphere.intersect_to_ptr(inv_ray, Some(Cull::Front),
1215 /// &mut contact_sphere_ray, &mut ind_sphere)
1216 /// ,"Ray should touch sphere");
1217 ///
1218 /// let (mut contact_cube_ray, mut ind_cube) = (Ray::default(), 0u32);
1219 /// assert!( cube.intersect_to_ptr(
1220 /// inv_ray, Some(Cull::Back),
1221 /// &mut contact_cube_ray, &mut ind_cube)
1222 /// ,"Ray should touch cube");
1223 ///
1224 /// assert_eq!(ind_sphere, 672);
1225 /// assert_eq!(ind_cube, 9);
1226 ///
1227 /// assert_eq!(transform.transform_ray(contact_sphere_ray),
1228 /// Ray { position: Vec3 { x: 0.36746234, y: -0.244975, z: 0.21937825 },
1229 /// direction: Vec3 { x: 0.58682406, y: -0.6427875, z: 0.49240398 }});
1230 /// assert_eq!(transform.transform_ray(contact_cube_ray),
1231 /// Ray { position: Vec3 { x: -0.39531866, y: 0.26354572, z: 0.2829433 },
1232 /// direction: Vec3 { x: -0.77243483, y: -0.2620026, z: 0.57853174 } });
1233 /// ```
1234 #[inline]
1235 #[allow(clippy::not_unsafe_ptr_arg_deref)]
1236 pub fn intersect_to_ptr(
1237 &self,
1238 ray: Ray,
1239 cull: Option<Cull>,
1240 out_model_space_ray: *mut Ray,
1241 out_start_inds: *mut u32,
1242 ) -> bool {
1243 ray.intersect_mesh_to_ptr(self, cull, out_model_space_ray, out_start_inds)
1244 }
1245
1246 /// A cube with dimensions of (1,1,1), this is equivalent to Mesh.GenerateCube(Vec3.One).
1247 /// <https://stereokit.net/Pages/StereoKit/Mesh/Cube.html>
1248 ///
1249 /// ### Examples
1250 /// ```
1251 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1252 /// use stereokit_rust::mesh::Mesh;
1253 ///
1254 /// // Get the mesh
1255 /// let mesh = Mesh::cube();
1256 /// assert_eq!(mesh.get_id(), "default/mesh_cube");
1257 /// ```
1258 pub fn cube() -> Self {
1259 Mesh::find("default/mesh_cube").unwrap()
1260 }
1261
1262 /// A default quad mesh, 2 triangles, 4 verts, from (-0.5,-0.5,0) to (0.5,0.5,0) and facing forward on the Z axis
1263 /// (0,0,-1). White vertex colors, and UVs from (1,1) at vertex (-0.5,-0.5,0) to (0,0) at vertex (0.5,0.5,0).
1264 /// <https://stereokit.net/Pages/StereoKit/Mesh/Quad.html>
1265 ///
1266 /// ### Examples
1267 /// ```
1268 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1269 /// use stereokit_rust::mesh::Mesh;
1270 ///
1271 /// // Get the mesh
1272 /// let mesh = Mesh::screen_quad();
1273 /// assert_eq!(mesh.get_id(), "default/mesh_screen_quad");
1274 /// ```
1275 pub fn screen_quad() -> Self {
1276 Mesh::find("default/mesh_screen_quad").unwrap()
1277 }
1278
1279 // see screen_quad instead ! TODO: Why this ?
1280 // <https://stereokit.net/Pages/StereoKit/Mesh/Quad.html>
1281 // pub fn quad() -> Self {
1282 // Mesh::find("default/mesh_quad").unwrap()
1283 // }
1284
1285 /// A sphere mesh with a diameter of 1. This is equivalent to Mesh.GenerateSphere(1,4).
1286 /// <https://stereokit.net/Pages/StereoKit/Mesh/Sphere.html>
1287 ///
1288 /// ### Examples
1289 /// ```
1290 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1291 /// use stereokit_rust::mesh::Mesh;
1292 ///
1293 /// // Get the mesh
1294 /// let mesh = Mesh::sphere();
1295 /// assert_eq!(mesh.get_id(), "default/mesh_sphere");
1296 /// ```
1297 pub fn sphere() -> Self {
1298 Mesh::find("default/mesh_sphere").unwrap()
1299 }
1300
1301 /// A clone mesh of the left hand
1302 /// <https://stereokit.net/Pages/StereoKit/Mesh.html>
1303 ///
1304 /// ### Examples
1305 /// ```
1306 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1307 /// use stereokit_rust::mesh::Mesh;
1308 ///
1309 /// // Get the mesh
1310 /// let mesh = Mesh::left_hand();
1311 /// assert_eq!(mesh.get_id(), "default/mesh_lefthand");
1312 /// ```
1313 /// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/left_hand.jpeg" alt="screenshot" width="200">
1314 pub fn left_hand() -> Self {
1315 Mesh::find("default/mesh_lefthand").unwrap()
1316 }
1317
1318 /// A clone mesh of the right hand
1319 /// <https://stereokit.net/Pages/StereoKit/Mesh.html>
1320 ///
1321 /// ### Examples
1322 /// ```
1323 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1324 /// use stereokit_rust::mesh::Mesh;
1325 ///
1326 /// // Get the mesh
1327 /// let mesh = Mesh::right_hand();
1328 /// assert_eq!(mesh.get_id(), "default/mesh_righthand");
1329 /// ```
1330 pub fn right_hand() -> Self {
1331 Mesh::find("default/mesh_righthand").unwrap()
1332 }
1333}