stereokit_rust/render_list.rs
1use crate::{
2 StereoKitError,
3 material::{Material, MaterialT},
4 maths::{Matrix, Rect},
5 mesh::{Mesh, MeshT},
6 model::{Model, ModelT},
7 system::{IAsset, RenderClear, RenderLayer, assets_releaseref_threadsafe},
8 tex::{Tex, TexT},
9 util::Color128,
10};
11use std::{
12 self,
13 ffi::{CStr, CString, c_char, c_void},
14 ptr::NonNull,
15};
16
17/// A RenderList is a collection of Draw commands that can be submitted to various surfaces. RenderList.Primary is
18/// where all normal Draw calls get added to, and this RenderList is renderer to primary display surface.
19///
20/// Manually working with a RenderList can be useful for "baking down matrices" or caching a scene of objects. Or
21/// for drawing a separate scene to an offscreen surface, like for thumbnails of Models.
22/// <https://stereokit.net/Pages/StereoKit/RenderList.html>
23///
24/// ### Examples
25/// ```
26/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
27/// use stereokit_rust::{maths::{Vec3, Matrix, Rect}, model::Model, util::Color128,
28/// tex::{Tex, TexType, TexFormat}, material::Material,
29/// mesh::Mesh, render_list::RenderList, system::RenderClear};
30///
31/// let model = Model::from_file("plane.glb", None).unwrap().copy();
32///
33/// let render_tex = Tex::gen_color(Color128::WHITE, 128, 128,
34/// TexType::Rendertarget, TexFormat::RGBA32);
35/// let mut render_mat = Material::unlit().copy();
36/// render_mat.diffuse_tex(&render_tex);
37///
38/// let at = Vec3::new(-2.0, 1.0, 1000.9);
39/// let perspective = Matrix::perspective(45.0, 1.0, 0.01, 1010.0);
40/// let transform_plane = Matrix::r([90.0, 90.0, 145.0]);
41/// let transform_cam = Matrix::look_at(at, Vec3::ZERO, Some(Vec3::new(1.0, 1.0, 1.0)));
42///
43/// let mut render_list = RenderList::new();
44/// render_list.add_model(&model, None, transform_plane, Color128::WHITE, None);
45///
46/// let screen = Mesh::screen_quad();
47///
48/// filename_scr = "screenshots/render_list.jpeg";
49/// test_screenshot!( // !!!! Get a proper main loop !!!!
50/// // The color will change so we redraw every frame
51/// render_list.draw_now( &render_tex,
52/// transform_cam,
53/// perspective,
54/// Some(Color128::new((iter % 100) as f32 * 0.01, 0.3, 0.2, 0.5)),
55/// Some(RenderClear::Color),
56/// Rect::new(0.0, 0.0, 1.0, 1.0),
57/// None,
58/// );
59///
60/// screen.draw(token, &render_mat, Matrix::IDENTITY, None, None);
61/// );
62/// ```
63/// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/render_list.jpeg" alt="screenshot" width="200">
64#[repr(C)]
65#[derive(Debug, PartialEq)]
66pub struct RenderList(pub NonNull<_RenderListT>);
67
68impl Drop for RenderList {
69 fn drop(&mut self) {
70 unsafe { assets_releaseref_threadsafe(self.0.as_ptr() as *mut c_void) };
71 }
72}
73
74impl AsRef<RenderList> for RenderList {
75 fn as_ref(&self) -> &RenderList {
76 self
77 }
78}
79
80/// StereoKit internal type.
81#[repr(C)]
82#[derive(Debug)]
83pub struct _RenderListT {
84 _unused: [u8; 0],
85}
86/// StereoKit ffi type.
87pub type RenderListT = *mut _RenderListT;
88
89unsafe extern "C" {
90 pub fn render_list_find(id: *const c_char) -> RenderListT;
91 pub fn render_list_set_id(render_list: RenderListT, id: *const c_char);
92 pub fn render_list_get_id(render_list: RenderListT) -> *const c_char;
93 pub fn render_get_primary_list() -> RenderListT;
94 pub fn render_list_create() -> RenderListT;
95 pub fn render_list_addref(list: RenderListT);
96 pub fn render_list_release(list: RenderListT);
97 pub fn render_list_clear(list: RenderListT);
98 pub fn render_list_item_count(list: RenderListT) -> i32;
99 pub fn render_list_prev_count(list: RenderListT) -> i32;
100 pub fn render_list_add_mesh(
101 list: RenderListT,
102 mesh: MeshT,
103 material: MaterialT,
104 transform: Matrix,
105 color_linear: Color128,
106 render_layer: RenderLayer,
107 );
108 pub fn render_list_add_model(
109 list: RenderListT,
110 model: ModelT,
111 transform: Matrix,
112 color_linear: Color128,
113 render_layer: RenderLayer,
114 );
115 pub fn render_list_add_model_mat(
116 list: RenderListT,
117 model: ModelT,
118 material_override: MaterialT,
119 transform: Matrix,
120 color_linear: Color128,
121 render_layer: RenderLayer,
122 );
123 pub fn render_list_draw_now(
124 list: RenderListT,
125 to_rendertarget: TexT,
126 camera: Matrix,
127 projection: Matrix,
128 clear_color: Color128,
129 clear: RenderClear,
130 viewport_pct: Rect,
131 layer_filter: RenderLayer,
132 );
133 pub fn render_list_push(list: RenderListT);
134 pub fn render_list_pop();
135
136}
137
138impl Default for RenderList {
139 fn default() -> Self {
140 Self::new()
141 }
142}
143
144impl IAsset for RenderList {
145 // fn id(&mut self, id: impl AsRef<str>) {
146 // self.id(id);
147 // }
148
149 fn get_id(&self) -> &str {
150 self.get_id()
151 }
152}
153
154impl RenderList {
155 /// Creates a new empty RenderList.
156 /// <https://stereokit.net/Pages/StereoKit/RenderList/RenderList.html>
157 ///
158 /// see also [`render_list_create`]
159 /// ### Examples
160 /// ```
161 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
162 /// use stereokit_rust::{maths::Matrix, util::Color128,
163 /// material::Material, mesh::Mesh, render_list::RenderList};
164 ///
165 /// let mut render_list = RenderList::new();
166 /// assert! (render_list.get_id().starts_with("auto/render_list_"));
167 /// assert_eq!(render_list.get_count(), 0);
168 ///
169 /// render_list.add_mesh(Mesh::cube(), Material::unlit(), Matrix::IDENTITY, Color128::WHITE, None);
170 /// assert_eq!(render_list.get_count(), 1);
171 /// ```
172 pub fn new() -> Self {
173 RenderList(NonNull::new(unsafe { render_list_create() }).unwrap())
174 }
175
176 /// Looks for a RenderList matching the given id!
177 /// <https://stereokit.net/Pages/StereoKit/RenderList/Find.html>
178 /// * `id` - The id of the RenderList we are looking for.
179 ///
180 /// see also [`render_list_find`]
181 /// ### Examples
182 /// ```
183 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
184 /// use stereokit_rust::{maths::Matrix, util::Color128,
185 /// material::Material, mesh::Mesh, render_list::RenderList};
186 ///
187 /// let mut render_list = RenderList::new();
188 /// render_list.id("my_render_list");
189 ///
190 /// let same_list = RenderList::find("my_render_list").expect("my_render_list should be found");
191 /// assert_eq!(render_list, same_list);
192 /// ```
193 pub fn find<S: AsRef<str>>(id: S) -> Result<RenderList, StereoKitError> {
194 let c_str = CString::new(id.as_ref())?;
195 let render_list = NonNull::new(unsafe { render_list_find(c_str.as_ptr()) });
196 match render_list {
197 Some(render_list) => Ok(RenderList(render_list)),
198 None => Err(StereoKitError::RenderListFind(id.as_ref().to_owned(), "not found".to_owned())),
199 }
200 }
201
202 /// Creates a clone of the same reference. Basically, the new variable is the same asset. This is what you get by
203 /// calling find() method.
204 /// <https://stereokit.net/Pages/StereoKit/RenderList/Find.html>
205 ///
206 /// see also [`render_list_find`] [`RenderList::find`]
207 /// ### Examples
208 /// ```
209 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
210 /// use stereokit_rust::{maths::Matrix, util::Color128,
211 /// material::Material, mesh::Mesh, render_list::RenderList};
212 ///
213 /// let mut render_list = RenderList::new();
214 ///
215 /// let same_list = render_list.clone_ref();
216 /// assert_eq!(render_list, same_list);
217 /// ```
218 pub fn clone_ref(&self) -> RenderList {
219 RenderList(
220 NonNull::new(unsafe { render_list_find(render_list_get_id(self.0.as_ptr())) })
221 .expect("<asset>::clone_ref failed!"),
222 )
223 }
224
225 /// sets the unique identifier of this asset resource! This can be helpful for debugging,
226 /// managing your assets, or finding them later on!
227 /// <https://stereokit.net/Pages/StereoKit/RenderList/Id.html>
228 ///
229 /// see also [`render_list_set_id`]
230 /// ### Examples
231 /// ```
232 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
233 /// use stereokit_rust::{maths::Matrix, util::Color128,
234 /// material::Material, mesh::Mesh, render_list::RenderList};
235 ///
236 /// let mut render_list = RenderList::new();
237 /// render_list.id("my_render_list");
238 ///
239 /// assert_eq!(render_list.get_id(), "my_render_list");
240 /// ```
241 pub fn id<S: AsRef<str>>(&mut self, id: S) -> &mut Self {
242 let cstr_id = CString::new(id.as_ref()).unwrap();
243 unsafe { render_list_set_id(self.0.as_ptr(), cstr_id.as_ptr()) };
244 self
245 }
246
247 /// Clears out and de-references all Draw items currently in the RenderList.
248 /// <https://stereokit.net/Pages/StereoKit/RenderList/Clear.html>
249 ///
250 /// see also [`render_list_clear`]
251 /// ### Examples
252 /// ```
253 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
254 /// use stereokit_rust::{maths::Matrix, util::Color128,
255 /// material::Material, mesh::Mesh, render_list::RenderList};
256 ///
257 /// let mut render_list = RenderList::new();
258 /// assert! (render_list.get_id().starts_with("auto/render_list_"));
259 /// assert_eq!(render_list.get_count(), 0);
260 ///
261 /// render_list.add_mesh(Mesh::cube(), Material::unlit(), Matrix::IDENTITY, Color128::WHITE, None);
262 /// assert_eq!(render_list.get_count(), 1);
263 /// assert_eq!(render_list.get_prev_count(), 0);
264 ///
265 /// render_list.clear();
266 /// assert_eq!(render_list.get_count(), 0);
267 /// assert_eq!(render_list.get_prev_count(), 1);
268 /// ```
269 pub fn clear(&mut self) -> &mut Self {
270 unsafe { render_list_clear(self.0.as_ptr()) }
271 self
272 }
273
274 /// Add a Mesh/Material to the RenderList. The RenderList will hold a reference to these Assets until the list is
275 /// cleared.
276 /// <https://stereokit.net/Pages/StereoKit/RenderList/Add.html>
277 /// * `mesh` - A valid Mesh you wish to draw.
278 /// * `material` - A Material to apply to the Mesh.
279 /// * `transform` - A transformation Matrix relative to the current Hierarchy.
280 /// * `colorLinear` - A per-instance linear space color value to pass into the shader! Normally this gets used like a
281 /// material tint. If you're adventurous and don't need per-instance colors, this is a great spot to pack in extra
282 /// per-instance data for the shader!
283 /// * `layer` - All visuals are rendered using a layer bit-flag. By default, all layers are rendered, but this can be
284 /// useful for filtering out objects for different rendering purposes! For example: rendering a mesh over the user's
285 /// head from a 3rd person perspective, but filtering it out from the 1st person perspective.
286 ///
287 /// see also [`render_list_add_mesh`]
288 /// ### Examples
289 /// ```
290 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
291 /// use stereokit_rust::{maths::{Vec3, Matrix, Rect}, util::{named_colors, Color128},
292 /// tex::{Tex, TexType, TexFormat}, material::Material,
293 /// mesh::Mesh, render_list::RenderList, system::{RenderClear, RenderLayer}};
294 ///
295 /// let cylinder1 = Mesh::generate_cylinder(0.3, 1.5, [ 0.5, 0.5, 0.0],None);
296 /// let cylinder2 = Mesh::generate_cylinder(0.3, 1.5, [-0.5, 0.5, 0.0],None);
297 /// let cylinder_mat = Material::pbr();
298 ///
299 /// let at = Vec3::new(-80.0, 1.0, 80.0);
300 /// let perspective = Matrix::perspective(45.0, 1.0, 0.01, 120.0);
301 /// let transform_cam = Matrix::look_at(at, Vec3::ZERO, None);
302 ///
303 /// let mut render_list = RenderList::new();
304 /// render_list
305 /// .add_mesh(&cylinder1, &cylinder_mat, Matrix::IDENTITY, named_colors::CYAN, None)
306 /// .add_mesh(&cylinder2, &cylinder_mat, Matrix::IDENTITY, named_colors::FUCHSIA,
307 /// Some(RenderLayer::Layer1));
308 ///
309 /// let render_tex = Tex::gen_color(Color128::WHITE, 128, 128,
310 /// TexType::Rendertarget, TexFormat::RGBA32);
311 /// let mut render_mat = Material::unlit().copy();
312 /// render_mat.diffuse_tex(&render_tex);
313 /// let screen = Mesh::screen_quad();
314 /// render_list.draw_now( &render_tex,
315 /// transform_cam,
316 /// perspective,
317 /// Some(Color128::new(0.99, 0.3, 0.2, 0.5)),
318 /// Some(RenderClear::Color),
319 /// Rect::new(0.0, 0.0, 1.0, 1.0),
320 /// Some(RenderLayer::AllThirdPerson),
321 /// );
322 ///
323 /// filename_scr = "screenshots/render_list_add_mesh.jpeg";
324 /// test_screenshot!( // !!!! Get a proper main loop !!!!
325 /// screen.draw(token, &render_mat, Matrix::IDENTITY, None, None);
326 /// );
327 /// ```
328 /// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/render_list_add_mesh.jpeg" alt="screenshot" width="200">
329 pub fn add_mesh(
330 &mut self,
331 mesh: impl AsRef<Mesh>,
332 material: impl AsRef<Material>,
333 transform: impl Into<Matrix>,
334 color_linear: impl Into<Color128>,
335 layer: Option<RenderLayer>,
336 ) -> &mut Self {
337 let layer = layer.unwrap_or(RenderLayer::Layer0);
338 unsafe {
339 render_list_add_mesh(
340 self.0.as_ptr(),
341 mesh.as_ref().0.as_ptr(),
342 material.as_ref().0.as_ptr(),
343 transform.into(),
344 color_linear.into(),
345 layer,
346 )
347 }
348 self
349 }
350
351 /// Add a Model to the RenderList. The RenderList will hold a reference to these Assets until the list is cleared.
352 /// <https://stereokit.net/Pages/StereoKit/RenderList/Add.html>
353 /// * `model` - A valid Model you wish to draw.
354 /// * `material` - Allows you to override the Material.
355 /// * `transform` - A transformation Matrix relative to the current Hierarchy.
356 /// * `colorLinear` - A per-instance linear space color value to pass into the shader! Normally this gets used like a
357 /// material tint. If you're adventurous and don't need per-instance colors, this is a great spot to pack in extra
358 /// per-instance data for the shader!
359 /// * `layer` - All visuals are rendered using a layer bit-flag. By default, all layers are rendered, but this can be
360 /// useful for filtering out objects for different rendering purposes! For example: rendering a mesh over the user's
361 /// head from a 3rd person perspective, but filtering it out from the 1st person perspective.
362 ///
363 /// see also [`render_list_add_model`] [`render_list_add_model_mat`]
364 /// ### Examples
365 /// ```
366 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
367 /// use stereokit_rust::{maths::{Vec3, Matrix, Rect}, model::Model, util::{named_colors,Color128},
368 /// tex::{Tex, TexType, TexFormat}, material::Material,
369 /// mesh::Mesh, render_list::RenderList, system::{RenderClear, RenderLayer}};
370 ///
371 /// let model = Model::from_file("plane.glb", None).unwrap().copy();
372 ///
373 /// let at = Vec3::new(-2.0, 400.0, 1000.9);
374 /// let perspective = Matrix::perspective(45.0, 1.0, 0.01, 1550.0);
375 /// let transform_plane1 = Matrix::t([ 5.0, 2.0, 0.0]);
376 /// let transform_plane2 = Matrix::t([2.0, -6.0, -10.0]);
377 /// let transform_cam = Matrix::look_at(at, Vec3::ZERO, Some(Vec3::new(0.0, -1.0, 0.0)));
378 ///
379 /// let mut render_list = RenderList::new();
380 /// render_list
381 /// .add_model(&model, None, transform_plane1, named_colors::RED, None)
382 /// .add_model(&model, None, transform_plane2, named_colors::BLUE,
383 /// Some(RenderLayer::Layer1));
384 ///
385 /// let render_tex = Tex::gen_color(Color128::WHITE, 128, 128,
386 /// TexType::Rendertarget, TexFormat::RGBA32);
387 /// let mut render_mat = Material::unlit().copy();
388 /// render_mat.diffuse_tex(&render_tex);
389 /// let screen = Mesh::screen_quad();
390 /// render_list.draw_now( &render_tex,
391 /// transform_cam,
392 /// perspective,
393 /// Some(Color128::new(0.0, 0.3, 0.2, 0.5)),
394 /// Some(RenderClear::Color),
395 /// Rect::new(0.0, 0.0, 1.0, 1.0),
396 /// Some(RenderLayer::AllFirstPerson),
397 /// );
398 ///
399 /// filename_scr = "screenshots/render_list_add_model.jpeg";
400 /// test_screenshot!( // !!!! Get a proper main loop !!!!
401 /// screen.draw(token, &render_mat, Matrix::IDENTITY, None, None);
402 /// );
403 /// ```
404 /// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/render_list_add_model.jpeg" alt="screenshot" width="200">
405 pub fn add_model(
406 &mut self,
407 model: impl AsRef<Model>,
408 material_override: Option<Material>,
409 transform: impl Into<Matrix>,
410 color_linear: impl Into<Color128>,
411 layer: Option<RenderLayer>,
412 ) -> &mut Self {
413 let layer = layer.unwrap_or(RenderLayer::Layer0);
414 match material_override {
415 Some(material) => unsafe {
416 render_list_add_model_mat(
417 self.0.as_ptr(),
418 model.as_ref().0.as_ptr(),
419 material.as_ref().0.as_ptr(),
420 transform.into(),
421 color_linear.into(),
422 layer,
423 )
424 },
425 None => unsafe {
426 render_list_add_model(
427 self.0.as_ptr(),
428 model.as_ref().0.as_ptr(),
429 transform.into(),
430 color_linear.into(),
431 layer,
432 )
433 },
434 }
435 self
436 }
437
438 /// Draws the RenderList to a rendertarget texture immediately. It does _not_ clear the list
439 /// <https://stereokit.net/Pages/StereoKit/RenderList/DrawNow.html>
440 /// * `to_render_target` - The rendertarget texture to draw to.
441 /// * `camera` - A TRS matrix representing the location and orientation of the camera. This matrix gets inverted
442 /// later on, so no need to do it yourself.
443 /// * `projection` - The projection matrix describes how the geometry is flattened onto the draw surface. Normally,
444 /// you'd use Matrix.Perspective, and occasionally Matrix.Orthographic might be helpful as well.
445 /// * `clear_color` * If the `clear` parameter is set to clear the color of `to_render_target`, then this is the color
446 /// it will clear to. `default` would be a transparent black.
447 /// * `clear` - Describes if and how the render_target should be cleared before rendering. Note that clearing the
448 /// target is unaffected by the viewport, so this will clean the entire surface! None is All.
449 /// * `viewport_pct` - Allows you to specify a region of the rendertarget to draw to! This is in normalized
450 /// coordinates, 0-1. If the width of this value is zero, then this will render to the entire texture.
451 /// * `layerFilter` - This is a bit flag that allows you to change which layers StereoKit renders for this
452 /// particular render viewpoint. To change what layers a visual is on, use a Draw method that includes a
453 /// RenderLayer as a parameter.
454 ///
455 /// see also [`render_list_draw_now`]
456 /// ### Examples
457 /// ```
458 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
459 /// use stereokit_rust::{maths::{Vec3, Matrix, Rect}, util::{named_colors, Color128, Color32},
460 /// tex::{Tex, TexType, TexFormat}, material::Material,
461 /// mesh::Mesh, render_list::RenderList, system::{RenderClear, RenderLayer}};
462 ///
463 /// let cylinder1 = Mesh::generate_cylinder(0.3, 1.5, [ 0.5, 0.5, 0.0],None);
464 /// let cylinder2 = Mesh::generate_cylinder(0.3, 1.5, [-0.5, 0.5, 0.0],None);
465 /// let cylinder_mat = Material::pbr().copy();
466 ///
467 /// let render_tex = Tex::gen_color(Color128::WHITE, 128, 128,
468 /// TexType::Rendertarget, TexFormat::RGBA32);
469 /// let mut render_mat = Material::unlit().copy();
470 /// render_mat.diffuse_tex(&render_tex);
471 /// let mut screen = Mesh::generate_cube([1.0, 1.0, 1.0], None);
472 /// let transform_screen = Matrix::t([0.0, 0.0, -1.0]);
473 ///
474 /// let at = Vec3::new(-80.0, 1.0, 80.0);
475 /// let perspective = Matrix::perspective(45.0, 1.0, 0.01, 120.0);
476 /// let transform_cam = Matrix::look_at(at, Vec3::ZERO, None);
477 ///
478 /// let mut render_list = RenderList::new();
479 /// render_list
480 /// .add_mesh(&cylinder1, &cylinder_mat, Matrix::IDENTITY, named_colors::CYAN, None)
481 /// .add_mesh(&cylinder2, &cylinder_mat, Matrix::IDENTITY, named_colors::FUCHSIA,None)
482 /// .add_mesh(&screen, &render_mat, transform_screen, named_colors::GRAY, None);
483 ///
484 /// filename_scr = "screenshots/render_list_draw_now.jpeg";
485 /// test_screenshot!( // !!!! Get a proper main loop !!!!
486 /// screen.draw(token, &render_mat, Matrix::IDENTITY, None, None);
487 /// render_list.draw_now( &render_tex,
488 /// transform_cam,
489 /// perspective,
490 /// None,
491 /// Some(RenderClear::None),
492 /// Rect::new(0.0, 0.0, 1.0, 1.0),
493 /// None
494 /// );
495 /// );
496 /// ```
497 /// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/render_list_draw_now.jpeg" alt="screenshot" width="200">
498 #[allow(clippy::too_many_arguments)]
499 pub fn draw_now(
500 &mut self,
501 to_rendertarget: impl AsRef<Tex>,
502 camera: impl Into<Matrix>,
503 projection: impl Into<Matrix>,
504 clear_color: Option<Color128>,
505 clear: Option<RenderClear>,
506 viewport_pct: Rect,
507 layer_filter: Option<RenderLayer>,
508 ) {
509 let layer_filter = layer_filter.unwrap_or(RenderLayer::all());
510 let clear = clear.unwrap_or(RenderClear::All);
511 let clear_color = clear_color.unwrap_or_default();
512 unsafe {
513 render_list_draw_now(
514 self.0.as_ptr(),
515 to_rendertarget.as_ref().0.as_ptr(),
516 camera.into(),
517 projection.into(),
518 clear_color,
519 clear,
520 viewport_pct,
521 layer_filter,
522 )
523 }
524 }
525
526 /// The default RenderList used by the Renderer for the primary display surface.
527 /// <https://stereokit.net/Pages/StereoKit/RenderList/Primary.html>
528 ///
529 /// see also [`render_get_primary_list`]
530 ///
531 /// ### Examples
532 /// ```
533 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
534 /// use stereokit_rust::render_list::RenderList;
535 ///
536 /// let primary_list = RenderList::primary();
537 /// assert_eq! (primary_list.get_id(),"sk/render/primary_renderlist");
538 /// assert_eq! (primary_list.get_count(), 0);
539 /// ```
540 pub fn primary() -> Self {
541 RenderList(NonNull::new(unsafe { render_get_primary_list() }).unwrap())
542 }
543
544 /// All draw calls that don't specify a render list will get submitted to the active RenderList at the top of the
545 /// stack. By default, that's RenderList.Primary, but you can push your own list onto the stack here to capture draw
546 /// calls, like those done in the UI.
547 /// <https://stereokit.net/Pages/StereoKit/RenderList/Push.html>
548 ///
549 /// see also [`render_list_push`]
550 /// ### Examples
551 /// ```
552 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
553 /// use stereokit_rust::{maths::{Vec3, Matrix}, util::named_colors, material::Material,
554 /// mesh::Mesh, render_list::RenderList};
555 ///
556 /// let cylinder1 = Mesh::generate_cylinder(0.3, 1.5, [ 0.5, 0.5, 0.0],None);
557 /// let cylinder2 = Mesh::generate_cylinder(0.3, 1.5, [-0.5, 0.5, 0.0],None);
558 /// let cylinder_mat = Material::pbr().copy();
559 ///
560 /// let mut render_list = RenderList::new();
561 /// // render_list.add_mesh(&cylinder1, &cylinder_mat, Matrix::IDENTITY, None);
562 ///
563 /// filename_scr = "screenshots/render_list_push.jpeg";
564 /// test_screenshot!( // !!!! Get a proper main loop !!!!
565 /// render_list.push();
566 /// cylinder1.draw(token, &cylinder_mat, Matrix::IDENTITY, Some(named_colors::GOLD.into()), None);
567 /// RenderList::pop();
568 /// cylinder2.draw(token, &cylinder_mat, Matrix::IDENTITY, Some(named_colors::RED.into()), None);
569 /// );
570 /// ```
571 /// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/render_list_push.jpeg" alt="screenshot" width="200">
572 pub fn push(&mut self) {
573 unsafe { render_list_push(self.0.as_ptr()) }
574 }
575
576 /// This removes the current top of the RenderList stack, making the next list as active
577 /// <https://stereokit.net/Pages/StereoKit/RenderList/Pop.html>
578 ///
579 /// see also [`render_list_pop`]
580 /// see example [`RenderList::push`]
581 pub fn pop() {
582 unsafe { render_list_pop() }
583 }
584
585 /// The id of this render list
586 /// <https://stereokit.net/Pages/StereoKit/RenderList/Id.html>
587 ///
588 /// see also [`render_list_get_id`]
589 /// see example [`RenderList::id`]
590 pub fn get_id(&self) -> &str {
591 unsafe { CStr::from_ptr(render_list_get_id(self.0.as_ptr())) }.to_str().unwrap()
592 }
593
594 /// The number of Mesh/Material pairs that have been submitted to the render list so far this frame.
595 /// <https://stereokit.net/Pages/StereoKit/RenderList/Count.html>
596 ///
597 /// see also [`render_list_item_count`]
598 /// ### Examples
599 /// ```
600 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
601 /// use stereokit_rust::{maths::Matrix, util::Color128,
602 /// material::Material, mesh::Mesh, render_list::RenderList};
603 ///
604 /// let mut render_list = RenderList::new();
605 /// assert! (render_list.get_id().starts_with("auto/render_list_"));
606 /// assert_eq!(render_list.get_count(), 0);
607 ///
608 /// render_list.add_mesh(Mesh::cube(), Material::unlit(), Matrix::IDENTITY, Color128::WHITE, None);
609 /// assert_eq!(render_list.get_count(), 1);
610 /// ```
611 pub fn get_count(&self) -> i32 {
612 unsafe { render_list_item_count(self.0.as_ptr()) }
613 }
614
615 /// This is the number of items in the RenderList before it was most recently cleared. If this is a list that is
616 /// drawn and cleared each frame, you can think of this as "last frame's count".
617 /// <https://stereokit.net/Pages/StereoKit/RenderList/PrevCount.html>
618 ///
619 /// see also [`render_list_prev_count`]
620 /// ### Examples
621 /// ```
622 /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
623 /// use stereokit_rust::{maths::Matrix, util::Color128,
624 /// material::Material, mesh::Mesh, render_list::RenderList};
625 ///
626 /// let mut render_list = RenderList::new();
627 /// assert! (render_list.get_id().starts_with("auto/render_list_"));
628 /// assert_eq!(render_list.get_prev_count(), 0);
629 ///
630 /// render_list.add_mesh(Mesh::cube(), Material::unlit(), Matrix::IDENTITY, Color128::WHITE, None);
631 /// assert_eq!(render_list.get_prev_count(), 0);
632 ///
633 /// render_list.clear();
634 /// assert_eq!(render_list.get_count(), 0);
635 /// assert_eq!(render_list.get_prev_count(), 1);
636 /// ```
637 pub fn get_prev_count(&self) -> i32 {
638 unsafe { render_list_prev_count(self.0.as_ptr()) }
639 }
640}