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}