stereokit_rust/
material.rs

1use crate::StereoKitError;
2use crate::maths::{Bool32T, Matrix, Vec2, Vec3, Vec4};
3use crate::shader::{Shader, ShaderT};
4use crate::system::{IAsset, Log};
5use crate::tex::{Tex, TexT};
6use crate::ui::IdHashT;
7use crate::util::Color128;
8use std::ffi::{CStr, CString, c_char, c_void};
9use std::marker::PhantomData;
10use std::path::Path;
11use std::ptr::NonNull;
12
13/// Also known as ‘alpha’ for those in the know. But there’s actually more than one type of transparency in rendering!
14/// The horrors. We’re keepin’ it fairly simple for now, so you get three options!
15/// <https://stereokit.net/Pages/StereoKit/Transparency.html>
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17#[repr(u32)]
18pub enum Transparency {
19    /// Not actually transparent! This is opaque! Solid! It’s the default option, and it’s the fastest option! Opaque
20    /// objects write to the z-buffer, the occlude pixels behind them, and they can be used as input to important
21    /// Mixed Reality features like Late Stage Reprojection that’ll make your view more stable!
22    None = 1,
23    /// Also known as Alpha To Coverage, this mode uses MSAA samples to create transparency. This works with a z-buffer
24    /// and therefore functionally behaves more like an opaque material, but has a quantized number of "transparent
25    /// values" it supports rather than a full range of  0-255 or 0-1. For 4x MSAA, this will give only 4 different
26    /// transparent values, 8x MSAA only 8, etc. From a performance perspective, MSAA usually is only costly around
27    /// triangle edges, but using this mode, MSAA is used for the whole triangle.
28    MSAA = 2,
29    /// This will blend with the pixels behind it. This is transparent! You may not want to write to the z-buffer, and
30    /// it’s slower than opaque materials.
31    Blend = 3,
32    /// This will straight up add the pixel color to the color buffer! This usually looks -really- glowy, so it makes
33    /// for good particles or lighting effects.
34    Add = 4,
35}
36
37/// Depth test describes how this material looks at and responds to depth information in the zbuffer! The default is
38/// Less, which means if the material pixel’s depth is Less than the existing depth data, (basically, is this in front
39/// of some other object) it will draw that pixel. Similarly, Greater would only draw  the material if it’s ‘behind’
40/// the depth buffer. Always would just draw all the time, and not read from the depth buffer at all.
41/// <https://stereokit.net/Pages/StereoKit/DepthTest.html>
42#[derive(Debug, Copy, Clone, PartialEq, Eq)]
43#[repr(u32)]
44pub enum DepthTest {
45    /// Default behavior, pixels behind the depth buffer will be discarded, and pixels in front of it will be drawn.
46    Less = 0,
47    /// Pixels behind the depth buffer will be discarded, and pixels in front of, or at the depth buffer’s value it
48    /// will be drawn. This could be great for things that might be sitting exactly on a floor or wall.
49    LessOrEq = 1,
50    /// Pixels in front of the zbuffer will be discarded! This is opposite of how things normally work. Great for
51    /// drawing indicators that something is occluded by a wall or other geometry.
52    Greater = 2,
53    /// Pixels in front of (or exactly at) the zbuffer will be discarded! This is opposite of how things normally
54    /// work. Great for drawing indicators that something is occluded by a wall or other geometry.
55    GreaterOrEq = 3,
56    /// Only draw pixels if they’re at exactly the same depth as the zbuffer!
57    Equal = 4,
58    /// Draw any pixel that’s not exactly at the value in the zbuffer.
59    NotEqual = 5,
60    /// Don’t look at the zbuffer at all, just draw everything, always, all the time! At this point, the order at
61    /// which the mesh gets drawn will be super important, so don’t forget about Material.QueueOffset!
62    Always = 6,
63    /// Never draw a pixel, regardless of what’s in the zbuffer. I can think of better ways to do this, but uhh,
64    /// this is here for completeness! Maybe you can find a use for it.
65    Never = 7,
66}
67
68/// Culling is discarding an object from the render pipeline! This enum describes how mesh faces get discarded on the
69/// graphics card. With culling set to none, you can double the number of pixels the GPU ends up drawing, which can
70/// have a big impact on performance. None can be appropriate in cases where the mesh is designed to be ‘double sided’.
71/// Front can also be helpful when you want to flip a mesh ‘inside-out’!
72/// <https://stereokit.net/Pages/StereoKit/Cull.html>
73#[derive(Debug, Copy, Clone, PartialEq, Eq)]
74#[repr(u32)]
75pub enum Cull {
76    /// Discard if the back of the triangle face is pointing towards the camera. This is the default behavior.
77    Back = 0,
78    /// Discard if the front of the triangle face is pointing towards the camera. This is opposite the default behavior.
79    Front = 1,
80    /// No culling at all! Draw the triangle regardless of which way it’s pointing.
81    None = 2,
82}
83
84/// A Material describes the surface of anything drawn on the graphics card! It is typically composed of a Shader, and
85/// shader properties like colors, textures, transparency info, etc.
86///
87/// Items drawn with the same Material can be batched together into a single, fast operation on the graphics card, so
88/// re-using materials can be extremely beneficial for performance!
89/// <https://stereokit.net/Pages/StereoKit/Material.html>
90///
91/// ### Examples
92/// ```
93/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
94/// use stereokit_rust::{maths::Matrix, util::Color128, mesh::Mesh, material::{*}};
95///
96/// let cube = Mesh::cube();
97/// // Create a material with default properties
98/// let mut material_cube = Material::default();
99///
100/// // Set some shader properties
101/// material_cube.color_tint   (Color128::new(1.0, 0.5, 0.3, 1.0))
102///              .transparency (Transparency::MSAA)
103///              .depth_test   (DepthTest::LessOrEq)
104///              .face_cull    (Cull::Front);
105///
106/// filename_scr = "screenshots/materials.jpeg";
107/// test_screenshot!( // !!!! Get a proper main loop !!!!
108///     cube.draw(token, &material_cube, Matrix::IDENTITY, None, None);
109/// );
110/// ```
111/// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/materials.jpeg" alt="screenshot" width="200">
112#[derive(Debug, PartialEq)]
113pub struct Material(pub NonNull<_MaterialT>);
114impl Drop for Material {
115    fn drop(&mut self) {
116        unsafe { material_release(self.0.as_ptr()) }
117    }
118}
119impl AsRef<Material> for Material {
120    fn as_ref(&self) -> &Material {
121        self
122    }
123}
124/// StereoKit internal type.
125#[repr(C)]
126#[derive(Debug)]
127pub struct _MaterialT {
128    _unused: [u8; 0],
129}
130/// StereoKit ffi type.
131pub type MaterialT = *mut _MaterialT;
132
133unsafe extern "C" {
134    pub fn material_find(id: *const c_char) -> MaterialT;
135    pub fn material_create(shader: ShaderT) -> MaterialT;
136    pub fn material_copy(material: MaterialT) -> MaterialT;
137    pub fn material_copy_id(id: *const c_char) -> MaterialT;
138    pub fn material_set_id(material: MaterialT, id: *const c_char);
139    pub fn material_get_id(material: MaterialT) -> *const c_char;
140    pub fn material_addref(material: MaterialT);
141    pub fn material_release(material: MaterialT);
142    pub fn material_set_transparency(material: MaterialT, mode: Transparency);
143    pub fn material_set_cull(material: MaterialT, mode: Cull);
144    pub fn material_set_wireframe(material: MaterialT, wireframe: Bool32T);
145    pub fn material_set_depth_test(material: MaterialT, depth_test_mode: DepthTest);
146    pub fn material_set_depth_write(material: MaterialT, write_enabled: Bool32T);
147    pub fn material_set_depth_clip(material: MaterialT, clip_enabled: Bool32T);
148    pub fn material_set_queue_offset(material: MaterialT, offset: i32);
149    pub fn material_set_chain(material: MaterialT, chain_material: MaterialT);
150    pub fn material_get_transparency(material: MaterialT) -> Transparency;
151    pub fn material_get_cull(material: MaterialT) -> Cull;
152    pub fn material_get_wireframe(material: MaterialT) -> Bool32T;
153    pub fn material_get_depth_test(material: MaterialT) -> DepthTest;
154    pub fn material_get_depth_write(material: MaterialT) -> Bool32T;
155    pub fn material_get_depth_clip(material: MaterialT) -> Bool32T;
156    pub fn material_get_queue_offset(material: MaterialT) -> i32;
157    pub fn material_get_chain(material: MaterialT) -> MaterialT;
158    pub fn material_set_shader(material: MaterialT, shader: ShaderT);
159    pub fn material_get_shader(material: MaterialT) -> ShaderT;
160}
161
162impl IAsset for Material {
163    // fn id(&mut self, id: impl AsRef<str>) {
164    //     self.id(id);
165    // }
166
167    fn get_id(&self) -> &str {
168        self.get_id()
169    }
170}
171
172impl Default for Material {
173    /// The default material! This is used by many models and meshes rendered from within StereoKit. Its shader is
174    /// tuned for high performance, and may change based on system performance characteristics, so it can be great
175    /// to copy this one when creating your own materials! Or if you want to override StereoKit’s default material,
176    /// here’s where you do it!
177    /// <https://stereokit.net/Pages/StereoKit/Material/Default.html>
178    ///
179    /// see also [crate::font::font_find]
180    /// ### Examples
181    /// ```
182    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
183    /// use stereokit_rust::{material::Material};
184    /// let mut material = Material::default();
185    /// assert_eq!(material.get_id(), "default/material");
186    /// ```
187    fn default() -> Self {
188        let c_str = CString::new("default/material").unwrap();
189        Material(NonNull::new(unsafe { material_find(c_str.as_ptr()) }).unwrap())
190    }
191}
192
193impl Material {
194    /// Creates a material from a shader, and uses the shader’s default settings.
195    /// <https://stereokit.net/Pages/StereoKit/Material/Material.html>
196    /// * `shader` - Any valid shader.
197    /// * `id` - If None the id will be set to a default value "auto/asset_???"
198    ///
199    /// see also [`material_create`] [`material_set_id`]
200    /// ### Examples
201    /// ```
202    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
203    /// use stereokit_rust::{maths::{Vec2, Matrix, Vec3}, mesh::Mesh, material::Material, shader::Shader};
204    ///
205    /// // Create Mesh and its material
206    /// let plane = Mesh::generate_plane(Vec2::ONE, Vec3::NEG_Z, Vec3::X, None,  true);
207    /// let mut material_plane = Material::new(Shader::unlit(), Some("my_material_plane"));
208    ///
209    /// test_steps!( // !!!! Get a proper main loop !!!!
210    ///     plane.draw(token, &material_plane,  Matrix::IDENTITY, None, None);
211    /// );
212    /// ```
213    pub fn new(shader: impl AsRef<Shader>, id: Option<&str>) -> Material {
214        let mut mat = Material(NonNull::new(unsafe { material_create(shader.as_ref().0.as_ptr()) }).unwrap());
215        if let Some(id) = id {
216            mat.id(id);
217        }
218        mat
219    }
220
221    /// Loads a Shader asset and creates a Material using it. If the shader fails to load, an error will be returned,
222    /// if so you can use unwrap_or_default() to get the default.
223    /// <https://stereokit.net/Pages/StereoKit/Material/Material.html>
224    /// * `id` - If None the id will be set to a default value "auto/asset_???"
225    /// * `shader_file_name` - The filename of a Shader asset.
226    ///
227    /// see also [`material_create`] [`material_set_id`]
228    /// ### Examples
229    /// ```
230    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
231    /// use stereokit_rust::{maths::{Matrix, Vec3}, mesh::Mesh, material::Material};
232    ///
233    /// // Create Mesh and its material
234    /// let circle = Mesh::generate_circle(1.0, Vec3::NEG_Z, Vec3::X, None,  true);
235    /// let material_circle =
236    ///     Material::from_file("shaders/blinker.hlsl.sks", Some("my_material_circle")).unwrap();
237    ///
238    /// test_steps!( // !!!! Get a proper main loop !!!!
239    ///     circle.draw(token, &material_circle,  Matrix::IDENTITY, None, None);
240    /// );
241    /// ```
242    pub fn from_file(shader_file_name: impl AsRef<Path>, id: Option<&str>) -> Result<Material, StereoKitError> {
243        let shader = Shader::from_file(&shader_file_name);
244        match shader {
245            Ok(shader) => {
246                let mut mat = Material(NonNull::new(unsafe { material_create(shader.as_ref().0.as_ptr()) }).unwrap());
247                if let Some(id) = id {
248                    mat.id(id);
249                }
250                Ok(mat)
251            }
252            Err(err) => Err(StereoKitError::ShaderFile(shader_file_name.as_ref().to_path_buf(), err.to_string())),
253        }
254    }
255
256    /// Creates a new Material asset with the default Material and its properties!
257    /// <https://stereokit.net/Pages/StereoKit/Material/Copy.html>
258    ///
259    /// see also [`material_copy`]
260    pub fn default_copy() -> Material {
261        Material::default().copy()
262    }
263
264    /// Creates a new Material asset with the same shader and properties! Draw calls with the new Material will not
265    /// batch together with this one.
266    /// <https://stereokit.net/Pages/StereoKit/Material/Copy.html>
267    ///
268    /// see also [`material_copy()`]
269    /// ### Examples
270    /// ```
271    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
272    /// use stereokit_rust::{maths::Matrix, util::named_colors, material::Material};
273    ///
274    /// let mut material_blue = Material::default_copy();
275    /// material_blue.metallic_amount(0.63);
276    /// material_blue.color_tint(named_colors::BLUE);
277    /// let mut material_red = material_blue.copy();
278    /// material_red.id("my_red_material").color_tint(named_colors::RED);
279    ///
280    /// assert_eq!(&material_blue.get_all_param_info().get_float("metal"),
281    ///            &material_red.get_all_param_info().get_float("metal"));
282    /// assert_ne!(&material_blue.get_id(), &material_red.get_id());
283    /// assert_ne!(&material_blue.get_all_param_info().get_color("color"),
284    ///            &material_red.get_all_param_info().get_color("color"));
285    /// ```
286    pub fn copy(&self) -> Material {
287        Material(NonNull::new(unsafe { material_copy(self.0.as_ptr()) }).unwrap())
288    }
289
290    /// Creates a new Material asset with the same shader and properties! Draw calls with the new Material will not
291    /// batch together with this one.
292    /// <https://stereokit.net/Pages/StereoKit/Material/Copy.html>
293    /// * `id` - Which material are you looking for?
294    ///
295    /// Returns a new Material asset with the same shader and properties if the id is found.
296    /// see also [`material_copy_id`]
297    /// ### Examples
298    /// ```
299    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
300    /// use stereokit_rust::{util::named_colors, material::Material, shader::Shader};
301    ///
302    /// let mut material = Material::new(Shader::pbr(), Some("my_material"));
303    /// material.roughness_amount(0.42);
304    /// let mut material_red = Material::copy_id("my_material").unwrap();
305    /// material_red.id("my_red_material").color_tint(named_colors::RED);
306    ///
307    /// assert_eq!(&material.get_all_param_info().get_float("roughness"),
308    ///            &material_red.get_all_param_info().get_float("roughness"));
309    /// assert_ne!(&material.get_all_param_info().get_color("color"),
310    ///            &material_red.get_all_param_info().get_color("color"));
311    /// assert_ne!(&material.get_id(), &material_red.get_id());
312    /// ```
313    pub fn copy_id<S: AsRef<str>>(id: S) -> Result<Material, StereoKitError> {
314        let c_str = CString::new(id.as_ref())?;
315        match NonNull::new(unsafe { material_copy_id(c_str.as_ptr()) }) {
316            Some(pt) => Ok(Material(pt)),
317            None => Err(StereoKitError::MaterialFind(id.as_ref().to_owned(), "copy_id".to_owned())),
318        }
319    }
320
321    /// Looks for a Material asset that’s already loaded, matching the given id!
322    /// <https://stereokit.net/Pages/StereoKit/Material/Find.html>
323    /// * `id` - Which material are you looking for ?
324    ///
325    /// see also [`material_find`]
326    /// ### Examples
327    /// ```
328    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
329    /// use stereokit_rust::{util::named_colors,material::Material, shader::Shader};
330    ///
331    /// let mut material = Material::new(Shader::pbr(), Some("my_material"));
332    /// let mut material_red = Material::find("my_material").unwrap();
333    /// material_red.id("my_red_material").color_tint(named_colors::RED);
334    ///
335    /// assert_eq!(&material.get_all_param_info().get_color("color"),
336    ///            &material_red.get_all_param_info().get_color("color"));
337    /// assert_eq!(&material.get_id(),&"my_red_material");
338    /// ```
339    pub fn find<S: AsRef<str>>(id: S) -> Result<Material, StereoKitError> {
340        let c_str = CString::new(id.as_ref())?;
341        let material = NonNull::new(unsafe { material_find(c_str.as_ptr()) });
342        match material {
343            Some(material) => Ok(Material(material)),
344            None => Err(StereoKitError::MaterialFind(id.as_ref().to_owned(), "not found".to_owned())),
345        }
346    }
347
348    /// Creates a clone of the same reference. Basically, the new variable is the same asset. This is what you get by
349    /// calling find() method.
350    /// <https://stereokit.net/Pages/StereoKit/Material/Find.html>
351    ///
352    /// see also [`material_find()`]
353    /// ### Examples
354    /// ```
355    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
356    /// use stereokit_rust::{util::named_colors,material::Material, shader::Shader};
357    ///
358    /// let mut material = Material::new(Shader::pbr(), Some("my_material"));
359    /// let mut material_red = material.clone_ref();
360    /// material_red.id("my_red_material").color_tint(named_colors::RED);
361    ///
362    /// assert_eq!(&material.get_all_param_info().get_color("color"),
363    ///            &material_red.get_all_param_info().get_color("color"));
364    /// assert_eq!(&material.get_id(),&"my_red_material");
365    /// ```
366    pub fn clone_ref(&self) -> Material {
367        Material(
368            NonNull::new(unsafe { material_find(material_get_id(self.0.as_ptr())) })
369                .expect("<asset>::clone_ref failed!"),
370        )
371    }
372
373    /// Non-canonical function of convenience!! Use this for Icons and other Ui Images
374    /// Copy a Material and set a Tex image to its diffuse_tex. If the Tex fails to load, an error will be returned,
375    /// if so you can use unwrap_or_default() to get the default.
376    /// <https://stereokit.net/Pages/StereoKit/Tex/FromFile.html>
377    /// * `tex_file_name` - The file name of the texture to load.
378    /// * `srgb_data` - If true, the texture will be loaded as sRGB data.
379    /// * `priority` - The priority sort order for this asset in the async loading system. Lower values mean loading
380    ///   sooner.
381    ///
382    /// see also [Material::diffuse_tex] [`material_create`] [`material_set_id`]
383    /// ### Examples
384    /// ```
385    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
386    /// use stereokit_rust::material::Material;
387    ///
388    /// let material1 = Material::unlit().copy();
389    /// let material2 = Material::unlit().copy();
390    /// let mut material3 = Material::unlit().tex_file_copy("textures/open_gltf.jpeg", true, None)
391    ///                    .expect("open_gltf.jpeg should load");
392    ///
393    /// assert_eq!(&material1.get_all_param_info().get_texture("diffuse").unwrap().get_id(),
394    ///            &material2.get_all_param_info().get_texture("diffuse").unwrap().get_id());
395    /// assert_ne!(&material2.get_all_param_info().get_texture("diffuse").unwrap().get_id(),
396    ///            &material3.get_all_param_info().get_texture("diffuse").unwrap().get_id());
397    /// ```
398    pub fn tex_file_copy(
399        &mut self,
400        tex_file_name: impl AsRef<Path>,
401        srgb_data: bool,
402        priority: Option<i32>,
403    ) -> Result<Material, StereoKitError> {
404        let tex = Tex::from_file(&tex_file_name, srgb_data, priority);
405        match tex {
406            Ok(tex) => {
407                let mut mat = self.copy();
408                mat.diffuse_tex(tex);
409                Ok(mat)
410            }
411            Err(err) => Err(StereoKitError::TexFile(tex_file_name.as_ref().to_path_buf(), err.to_string())),
412        }
413    }
414
415    /// Non-canonical function of convenience!! Use this for Icons and other Ui Images
416    /// Copy a Material and set a Tex image to its diffuse_tex. If the Tex fails to load, an error will be returned,
417    /// if so you can use unwrap_or_default() to get the default.
418    /// <https://stereokit.net/Pages/StereoKit/Tex/FromFile.html>
419    /// * `tex_file_name` - The file name of the texture to load.
420    /// * `srgb_data` - If true, the texture will be loaded as sRGB data.
421    /// * `priority` - The priority sort order for this asset in the async loading system. Lower values mean loading
422    ///   sooner.
423    ///
424    /// see also [Material::diffuse_tex] [`material_create`] [`material_set_id`]
425    /// ### Examples
426    /// ```
427    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
428    /// use stereokit_rust::{material::Material, tex::Tex};
429    ///
430    /// let material1 = Material::unlit().copy();
431    /// let material2 = Material::unlit().copy();
432    /// let tex = Tex::from_file("textures/open_gltf.jpeg", true, None)
433    ///                    .expect("tex should be created");
434    /// let mut material3 = Material::unlit().tex_copy(tex);
435    ///
436    /// assert_eq!(&material1.get_all_param_info().get_texture("diffuse").unwrap().get_id(),
437    ///            &material2.get_all_param_info().get_texture("diffuse").unwrap().get_id());
438    /// assert_ne!(&material2.get_all_param_info().get_texture("diffuse").unwrap().get_id(),
439    ///            &material3.get_all_param_info().get_texture("diffuse").unwrap().get_id());
440    /// ```
441    pub fn tex_copy(&mut self, tex: impl AsRef<Tex>) -> Material {
442        let mut mat = self.copy();
443        mat.diffuse_tex(tex);
444        mat
445    }
446
447    /// Set a new id to the material.
448    /// <https://stereokit.net/Pages/StereoKit/Material/Id.html>
449    ///
450    /// see also [`material_set_id`]
451    /// ### Examples
452    /// ```
453    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
454    /// use stereokit_rust::{material::Material, shader::Shader};
455    ///
456    /// let mut material = Material::new(Shader::pbr(), Some("my_material"));
457    /// assert_eq!(material.get_id(), "my_material");
458    ///
459    /// material.id("my_new_material");
460    /// assert_eq!(material.get_id(), "my_new_material");
461    /// ```
462    pub fn id<S: AsRef<str>>(&mut self, id: S) -> &mut Self {
463        let c_str = CString::new(id.as_ref()).unwrap();
464        unsafe { material_set_id(self.0.as_ptr(), c_str.as_ptr()) };
465        self
466    }
467
468    /// Overrides the Shader this material uses.
469    /// <https://stereokit.net/Pages/StereoKit/Material/Shader.html>
470    ///
471    /// see also [`material_set_shader`]
472    /// ### Examples
473    /// ```
474    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to init sk !!!!
475    /// use stereokit_rust::{material::Material, shader::Shader};
476    ///
477    /// let mut material = Material::new(Shader::pbr(), Some("my_material"));
478    /// assert_eq!(material.get_shader().get_id(), Shader::pbr().get_id());
479    ///
480    /// material.shader(Shader::unlit());
481    /// assert_eq!(material.get_shader().get_id(), Shader::unlit().get_id());
482    /// ```
483    pub fn shader(&mut self, shader: impl AsRef<Shader>) -> &mut Self {
484        unsafe { material_set_shader(self.0.as_ptr(), shader.as_ref().0.as_ptr()) };
485        self
486    }
487
488    /// Non canonical shader parameter to indicate a border size if the shader have one (especially for [`Material::ui_box`])
489    /// <https://stereokit.net/Pages/StereoKit/MatParamName.html>
490    ///
491    /// see also [`material_set_param_id`]
492    /// ### Examples
493    /// ```
494    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
495    /// use stereokit_rust::material::Material;
496    ///
497    /// let mut material = Material::ui_box();
498    /// material.border_size(0.0428);
499    ///
500    /// assert_eq!(material.get_all_param_info().get_float("border_size"), 0.0428);
501    /// # use stereokit_rust::util::Hash;
502    /// # assert_eq!(Hash::string("border_size"), 12300782195362451721);
503    /// ```
504    pub fn border_size(&mut self, time: f32) -> &mut Self {
505        let ptr: *const f32 = &time;
506        unsafe {
507            material_set_param_id(self.0.as_ptr(), 12300782195362451721, MaterialParam::Float, ptr as *const c_void);
508        }
509        self
510    }
511
512    /// In clip shaders, this is the cutoff value below which pixels are discarded.
513    /// Typically, the diffuse/albedo’s alpha component is sampled for comparison here. This represents the float param ‘cutoff’.
514    /// <https://stereokit.net/Pages/StereoKit/MatParamName.html>
515    ///
516    /// see also [`material_set_param_id`]
517    /// ### Examples
518    /// ```
519    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to init sk !!!!
520    /// use stereokit_rust::{material::Material};
521    ///
522    /// let mut material = Material::pbr_clip().copy();
523    /// material.clip_cutoff(0.53);
524    /// assert_eq!(material.get_all_param_info().get_float("cutoff"), 0.53);
525    /// # use stereokit_rust::util::Hash;
526    /// # assert_eq!(Hash::string("cutoff"), 9874215895386126464);
527    /// ```
528    pub fn clip_cutoff(&mut self, cutoff: f32) -> &mut Self {
529        let ptr: *const f32 = &cutoff;
530        unsafe {
531            material_set_param_id(self.0.as_ptr(), 9874215895386126464, MaterialParam::Float, ptr as *const c_void);
532        }
533        self
534    }
535
536    /// A per-material color tint, behavior could vary from shader to shader, but often this is just multiplied against
537    /// the diffuse texture right at the start. This represents the Color param ‘color’.
538    /// <https://stereokit.net/Pages/StereoKit/MatParamName.html>
539    ///
540    /// see also [`material_set_param_id`]
541    /// ### Examples
542    /// ```
543    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to init sk !!!!
544    /// use stereokit_rust::{material::Material, util::named_colors};
545    ///
546    /// let mut material = Material::unlit().copy();
547    /// material.color_tint(named_colors::RED);
548    /// assert_eq!(material.get_all_param_info().get_color("color"), named_colors::RED.into());
549    /// # use stereokit_rust::util::Hash;
550    /// # assert_eq!(Hash::string("color"), 8644027876048135736);
551    /// ```    
552    pub fn color_tint(&mut self, color: impl Into<Color128>) -> &mut Self {
553        let ptr: *const Color128 = &color.into();
554        unsafe {
555            material_set_param_id(self.0.as_ptr(), 8644027876048135736, MaterialParam::Color128, ptr as *const c_void);
556        }
557        self
558    }
559
560    /// The primary color texture for the shader! Diffuse, Albedo, ‘The Texture’, or whatever you want to call it, this
561    /// is usually the base color that the shader works with. This represents the texture param ‘diffuse’.
562    /// <https://stereokit.net/Pages/StereoKit/MatParamName.html>
563    ///
564    /// see also [`Material::tex_file_copy`]
565    /// see also [`material_set_param_id`]
566    /// ### Examples
567    /// ```
568    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
569    /// use stereokit_rust::{material::Material, tex::Tex};
570    ///
571    /// let mut material = Material::unlit().copy();
572    /// let default_tex = material.get_all_param_info().get_texture("diffuse").unwrap();
573    ///
574    /// let tex = Tex::from_file("textures/open_gltf.jpeg", true, None)
575    ///                    .expect("tex should be created");
576    /// material.diffuse_tex(&tex);
577    ///
578    /// assert_eq!(&material.get_all_param_info().get_texture("diffuse").unwrap().get_id(),
579    ///            &tex.get_id());
580    /// assert_ne!(&default_tex.get_id(),
581    ///            &tex.get_id());
582    /// # use stereokit_rust::util::Hash;
583    /// # assert_eq!(Hash::string("diffuse"), 17401384459118377917);
584    /// ```
585    pub fn diffuse_tex(&mut self, texture: impl AsRef<Tex>) -> &mut Self {
586        unsafe {
587            material_set_param_id(
588                self.0.as_ptr(),
589                17401384459118377917,
590                MaterialParam::Texture,
591                texture.as_ref().0.as_ptr() as *const c_void,
592            );
593        }
594        self
595    }
596
597    /// A multiplier for emission values sampled from the emission texture. The default emission texture in SK shaders is
598    /// white, and the default value for this parameter is 0,0,0,0. This represents the Color param ‘emission_factor’.
599    /// <https://stereokit.net/Pages/StereoKit/MatParamName.html>
600    ///
601    /// see also [`Material::emission_tex`]
602    /// see also [`material_set_param_id`]
603    /// ### Examples
604    /// ```
605    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to init sk !!!!
606    /// use stereokit_rust::{material::Material, util::named_colors};
607    ///
608    /// let mut material = Material::pbr().copy();
609    /// material.emission_factor(named_colors::RED);
610    /// assert_eq!(material.get_all_param_info().get_color("emission_factor"), named_colors::RED.into());
611    /// # use stereokit_rust::util::Hash;
612    /// # assert_eq!(Hash::string("emission_factor"), 5248711978018327020);
613    /// ```  
614    pub fn emission_factor(&mut self, color: impl Into<Color128>) -> &mut Self {
615        let ptr: *const Color128 = &color.into();
616        unsafe {
617            material_set_param_id(self.0.as_ptr(), 5248711978018327020, MaterialParam::Color128, ptr as *const c_void);
618        }
619        self
620    }
621
622    /// This texture is unaffected by lighting, and is frequently just added in on top of the material’s final color!
623    /// Tends to look really glowy. This represents the texture param ‘emission’.
624    /// <https://stereokit.net/Pages/StereoKit/MatParamName.html>
625    ///
626    /// see also [`Material::emission_factor`]
627    /// see also [`material_set_param_id`]
628    /// ### Examples
629    /// ```
630    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
631    /// use stereokit_rust::{util::named_colors, material::Material, tex::Tex};
632    ///
633    /// let mut material = Material::pbr_clip().tex_file_copy("textures/water/bump_large.ktx2", true, Some(0)).unwrap();
634    ///
635    /// let tex = Tex::from_file("textures/water/bump_large_inverse.ktx2", true, None)
636    ///                    .expect("tex should be created");
637    /// material.emission_tex(&tex).emission_factor(named_colors::RED);
638    ///
639    /// assert_eq!(&material.get_all_param_info().get_texture("emission").unwrap().get_id(),
640    ///            &tex.get_id());
641    /// # use stereokit_rust::util::Hash;
642    /// # assert_eq!(Hash::string("emission"), 17756472659261185998);
643    /// ```
644    pub fn emission_tex(&mut self, texture: impl AsRef<Tex>) -> &mut Self {
645        unsafe {
646            material_set_param_id(
647                self.0.as_ptr(),
648                17756472659261185998,
649                MaterialParam::Texture,
650                texture.as_ref().0.as_ptr() as *const c_void,
651            );
652        }
653        self
654    }
655
656    /// For physically based shader, this is a multiplier to scale the metallic properties of the material.
657    /// This represents the float param ‘metallic’.
658    /// <https://stereokit.net/Pages/StereoKit/MatParamName.html>
659    ///
660    /// see also [`Material::metal_tex`]
661    /// see also [`material_set_param_id`]
662    /// ### Examples
663    /// ```
664    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to init sk !!!!
665    /// use stereokit_rust::{material::Material, util::named_colors};
666    ///
667    /// let mut material = Material::pbr().copy();
668    /// material.metallic_amount(0.68);
669    /// assert_eq!(material.get_all_param_info().get_float("metallic"), 0.68);
670    /// # use stereokit_rust::util::Hash;
671    /// # assert_eq!(Hash::string("metallic"), 16113330016842241480);
672    /// ```  
673    pub fn metallic_amount(&mut self, amount: f32) -> &mut Self {
674        let ptr: *const f32 = &amount;
675        unsafe {
676            material_set_param_id(self.0.as_ptr(), 16113330016842241480, MaterialParam::Float, ptr as *const c_void);
677        }
678        self
679    }
680
681    /// For physically based shaders, metal is a texture that encodes metallic and roughness data into the ‘B’ and ‘G’
682    /// channels, respectively. This represents the texture param ‘metal’.
683    /// <https://stereokit.net/Pages/StereoKit/MatParamName.html>
684    ///
685    /// see also [`Material::metallic_amount`]
686    /// see also [`material_set_param_id`]
687    /// ### Examples
688    /// ```
689    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
690    /// use stereokit_rust::{material::Material, tex::Tex};
691    ///
692    /// let mut material = Material::pbr_clip().tex_file_copy("textures/parquet2/parquet2.ktx2", true, Some(0)).unwrap();
693    ///
694    /// let tex = Tex::from_file("textures/parquet2/parquet2metal.ktx2", true, None)
695    ///                    .expect("tex should be created");
696    /// material.metal_tex(&tex).metallic_amount(0.68);
697    ///
698    /// assert_eq!(&material.get_all_param_info().get_texture("metal").unwrap().get_id(),
699    ///            &tex.get_id());
700    /// # use stereokit_rust::util::Hash;
701    /// # assert_eq!(Hash::string("metal"), 4582786214424138428);
702    /// ```
703    pub fn metal_tex(&mut self, texture: impl AsRef<Tex>) -> &mut Self {
704        unsafe {
705            material_set_param_id(
706                self.0.as_ptr(),
707                4582786214424138428,
708                MaterialParam::Texture,
709                texture.as_ref().0.as_ptr() as *const c_void,
710            );
711        }
712        self
713    }
714
715    /// The ‘normal map’ texture for the material! This texture contains information about the direction of the
716    /// material’s surface, which is used to calculate lighting, and make surfaces look like they have more detail than
717    /// they actually do. Normals are in Tangent Coordinate Space, and the RGB values map to XYZ values. This represents
718    /// the texture param ‘normal’.
719    /// <https://stereokit.net/Pages/StereoKit/MatParamName.html>
720    ///
721    /// see also [`material_set_param_id`]
722    /// ### Examples
723    /// ```
724    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
725    /// use stereokit_rust::{material::Material, tex::Tex};
726    ///
727    /// let mut material = Material::from_file("shaders/water_pbr2.hlsl.sks", None).unwrap();
728    ///
729    /// let tex = Tex::from_file("textures/water/bump_large.ktx2", true, None)
730    ///                    .expect("tex should be created");
731    /// material.normal_tex(&tex);
732    ///
733    /// assert_eq!(&material.get_all_param_info().get_texture("normal").unwrap().get_id(),
734    ///            &tex.get_id());
735    /// # use stereokit_rust::util::Hash;
736    /// # assert_eq!(Hash::string("normal"), 6991063326977151602);
737    /// ```
738    pub fn normal_tex(&mut self, texture: impl AsRef<Tex>) -> &mut Self {
739        unsafe {
740            material_set_param_id(
741                self.0.as_ptr(),
742                6991063326977151602,
743                MaterialParam::Texture,
744                texture.as_ref().0.as_ptr() as *const c_void,
745            );
746        }
747        self
748    }
749
750    /// Used by physically based shaders, this can be used for baked ambient occlusion lighting, or to remove specular
751    /// reflections from areas that are surrounded by geometry that would likely block reflections. This represents the
752    /// texture param ‘occlusion’.
753    /// <https://stereokit.net/Pages/StereoKit/MatParamName.html>
754    ///
755    /// see also [`material_set_param_id`]
756    /// ### Examples
757    /// ```
758    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
759    /// use stereokit_rust::{material::Material, tex::Tex};
760    ///
761    /// let mut material = Material::pbr().tex_file_copy("textures/parquet2/parquet2.ktx2", true, None).unwrap();
762    ///
763    /// let tex = Tex::from_file("textures/parquet2/parquet2ao.ktx2", true, None)
764    ///                    .expect("tex should be created");
765    /// material.occlusion_tex(&tex);
766    ///
767    /// assert_eq!(&material.get_all_param_info().get_texture("occlusion").unwrap().get_id(),
768    ///            &tex.get_id());
769    /// # use stereokit_rust::util::Hash;
770    /// # assert_eq!(Hash::string("occlusion"), 10274420935108893154);
771    /// ```
772    pub fn occlusion_tex(&mut self, texture: impl AsRef<Tex>) -> &mut Self {
773        unsafe {
774            material_set_param_id(
775                self.0.as_ptr(),
776                10274420935108893154,
777                MaterialParam::Texture,
778                texture.as_ref().0.as_ptr() as *const c_void,
779            );
780        }
781        self
782    }
783
784    /// For physically based shader, this is a multiplier to scale the roughness properties of the material.
785    /// This represents the float param ‘roughness’.
786    /// <https://stereokit.net/Pages/StereoKit/MatParamName.html>
787    ///
788    /// see also [`material_set_param_id`]
789    /// ### Examples
790    /// ```
791    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
792    /// use stereokit_rust::material::Material;
793    ///
794    /// let mut material = Material::pbr().copy();
795    /// material.roughness_amount(0.78);
796    ///
797    /// assert_eq!(material.get_all_param_info().get_float("roughness"), 0.78);
798    /// # use stereokit_rust::util::Hash;
799    /// # assert_eq!(Hash::string("roughness"), 14293098357166276437);
800    /// ```
801    pub fn roughness_amount(&mut self, amount: f32) -> &mut Self {
802        let ptr: *const f32 = &amount;
803        unsafe {
804            material_set_param_id(self.0.as_ptr(), 14293098357166276437, MaterialParam::Float, ptr as *const c_void);
805        }
806        self
807    }
808
809    /// Not necessarily present in all shaders, this multiplies the UV coordinates of the mesh, so that the texture will repeat.
810    /// This is great for tiling textures! This represents the float param ‘tex_scale’.
811    /// <https://stereokit.net/Pages/StereoKit/MatParamName.html>
812    ///
813    /// see also [`material_set_param`]
814    #[deprecated(since = "0.40.0", note = "please use `tex_transform` instead")]
815    pub fn tex_scale(&mut self, scale: f32) -> &mut Self {
816        let ptr: *const f32 = &scale;
817        unsafe {
818            let cstr = &CString::new("tex_scale").unwrap();
819            material_set_param(self.0.as_ptr(), cstr.as_ptr(), MaterialParam::Float, ptr as *const c_void);
820        }
821        self
822    }
823
824    /// Non canonical shader parameter to indicate a time multiplier if the shader have one (water, blinker ...)
825    /// <https://stereokit.net/Pages/StereoKit/MatParamName.html>
826    ///
827    /// see also [`material_set_param_id`]
828    /// ### Examples
829    /// ```
830    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
831    /// use stereokit_rust::material::Material;
832    ///
833    /// let mut material = Material::from_file("shaders/water_pbr2.hlsl.sks", None).unwrap();
834    /// material.time(0.38);
835    ///
836    /// assert_eq!(material.get_all_param_info().get_float("time"), 0.38);
837    /// # use stereokit_rust::util::Hash;
838    /// # assert_eq!(Hash::string("time"), 2185518981507421060);
839    /// ```
840    pub fn time(&mut self, time: f32) -> &mut Self {
841        let ptr: *const f32 = &time;
842        unsafe {
843            material_set_param_id(self.0.as_ptr(), 2185518981507421060, MaterialParam::Float, ptr as *const c_void);
844        }
845        self
846    }
847
848    /// Not necessarily present in all shaders, this transforms the UV coordinates of the mesh, so that the texture can
849    /// repeat and scroll. XY components are offset, and ZW components are scale.
850    ///  
851    /// This represents the float param 'tex_trans'.
852    /// <https://stereokit.net/Pages/StereoKit/MatParamName.html>
853    ///
854    /// see also [`material_set_param_id`]
855    /// ### Examples
856    /// ```
857    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
858    /// use stereokit_rust::{maths::Vec4, material::Material};
859    ///
860    /// let mut material = Material::unlit().copy();
861    /// material.tex_transform(Vec4::ONE * 5.5);
862    ///
863    /// assert_eq!(material.get_all_param_info().get_vector4("tex_trans"), Vec4::ONE * 5.5);
864    /// # use stereokit_rust::util::Hash;
865    /// # assert_eq!(Hash::string("tex_trans"), 11548192078170871263);
866    /// ```
867    pub fn tex_transform(&mut self, transform: impl Into<Vec4>) -> &mut Self {
868        let ptr: *const Vec4 = &transform.into();
869        unsafe {
870            material_set_param_id(self.0.as_ptr(), 11548192078170871263, MaterialParam::Float, ptr as *const c_void);
871        }
872        self
873    }
874
875    //--- Others parameters
876
877    /// What type of transparency does this Material use? Default is None. Transparency has an impact on performance,
878    /// and draw order.
879    /// Check the [`Transparency`] enum for details.
880    /// <https://stereokit.net/Pages/StereoKit/Material/Transparency.html>
881    ///
882    /// see also [`material_set_transparency`]
883    /// ### Examples
884    /// ```
885    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
886    /// use stereokit_rust::{maths::{Vec3, Matrix, Quat}, util::{named_colors,Color32},
887    ///                      mesh::Mesh, material::{Material, Transparency}};
888    ///
889    /// // Creating Meshes and their materials
890    /// let cube = Mesh::generate_cube(Vec3::ONE * 0.8, None);
891    /// let sphere = Mesh::generate_sphere(1.4, None);
892    ///
893    /// let mut material_sphere = Material::pbr().copy();
894    /// material_sphere.color_tint(named_colors::BLUE).transparency(Transparency::Add);
895    ///
896    /// let material_cube = Material::pbr().copy();
897    /// let cube_transform = Matrix::r(Quat::from_angles(40.0, 50.0, 20.0));
898    ///
899    /// assert_eq!(material_sphere.get_transparency(), Transparency::Add);
900    /// assert_eq!(material_cube.get_transparency(), Transparency::None);
901    /// filename_scr = "screenshots/material_transparency.jpeg";
902    /// test_screenshot!( // !!!! Get a proper main loop !!!!
903    ///     cube.draw(token, &material_cube, cube_transform, None, None);
904    ///     sphere.draw(token, &material_sphere, Matrix::IDENTITY, None, None);
905    /// );
906    /// ```
907    /// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/material_transparency.jpeg" alt="screenshot" width="200">
908    pub fn transparency(&mut self, mode: Transparency) -> &mut Self {
909        unsafe { material_set_transparency(self.0.as_ptr(), mode) };
910        self
911    }
912
913    /// How should this material cull faces?
914    /// <https://stereokit.net/Pages/StereoKit/Material/FaceCull.html>
915    ///
916    /// see also [`material_set_cull`]
917    /// ### Examples
918    /// ```
919    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
920    /// use stereokit_rust::{maths::{Vec3, Matrix}, util::{named_colors,Color32},
921    ///                      mesh::Mesh, material::{Material, Cull}};
922    ///
923    /// // Creating Meshes and their materials
924    /// let cube1 = Mesh::generate_cube(Vec3::ONE * 1.0, None);
925    /// let cube2 = Mesh::generate_cube(Vec3::ONE * 0.4, None);
926    ///
927    /// let mut material_cube1 = Material::pbr().copy();
928    /// material_cube1.face_cull(Cull::Front).color_tint(named_colors::RED);
929    ///
930    /// let mut material_cube2 = Material::pbr().copy();
931    /// assert_eq!(material_cube2.get_face_cull(), Cull::Back);
932    /// material_cube2.face_cull(Cull::None).color_tint(named_colors::GREEN);
933    ///
934    /// assert_eq!(material_cube1.get_face_cull(), Cull::Front);
935    /// assert_eq!(material_cube2.get_face_cull(), Cull::None);
936    ///
937    /// filename_scr = "screenshots/material_face_cull.jpeg";
938    /// test_screenshot!( // !!!! Get a proper main loop !!!!
939    ///     cube1.draw(token, &material_cube1,  Matrix::IDENTITY, None, None);
940    ///     cube2.draw(token, &material_cube2,  Matrix::IDENTITY, None, None);
941    /// );
942    /// ```
943    /// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/material_face_cull.jpeg" alt="screenshot" width="200">
944    pub fn face_cull(&mut self, mode: Cull) -> &mut Self {
945        unsafe { material_set_cull(self.0.as_ptr(), mode) };
946        self
947    }
948
949    /// Should this material draw only the edges/wires of the mesh? This can be useful for debugging, and even some
950    /// kinds of visualization work.
951    ///
952    /// Note that this may not work on some mobile OpenGL systems like Quest.
953    /// <https://stereokit.net/Pages/StereoKit/Material/Wireframe.html>
954    ///
955    /// see also [`material_set_wireframe`]
956    /// ### Examples
957    /// ```
958    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
959    /// use stereokit_rust::{util::{named_colors,Color32},material::Material};
960    ///
961    /// let mut material_cube = Material::pbr().copy();
962    /// assert_eq!(material_cube.get_wireframe(), false);
963    /// material_cube.wireframe(true).color_tint(named_colors::CYAN);
964    /// assert_eq!(material_cube.get_wireframe(), true);
965    /// ```
966    pub fn wireframe(&mut self, wireframe: bool) -> &mut Self {
967        unsafe { material_set_wireframe(self.0.as_ptr(), wireframe as Bool32T) };
968        self
969    }
970
971    /// How does this material interact with the ZBuffer? Generally [DepthTest::Less] would be normal behavior: don’t draw
972    /// objects that are occluded. But this can also be used to achieve some interesting effects, like you could use
973    /// [DepthTest::Greater] to draw a glow that
974    /// indicates an object is behind something.
975    /// <https://stereokit.net/Pages/StereoKit/Material/DepthTest.html>
976    ///
977    /// see also [`material_set_depth_test`]
978    /// ### Examples
979    /// ```
980    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
981    /// use stereokit_rust::{ util::{named_colors,Color32}, material::{Material, DepthTest}};
982    ///
983    /// let mut material_cube = Material::pbr().copy();
984    /// assert_eq!(material_cube.get_depth_test(), DepthTest::Less);
985    /// material_cube.depth_test(DepthTest::Greater).color_tint(named_colors::CYAN);
986    /// assert_eq!(material_cube.get_depth_test(), DepthTest::Greater);
987    /// ```
988    pub fn depth_test(&mut self, depth_test_mode: DepthTest) -> &mut Self {
989        unsafe { material_set_depth_test(self.0.as_ptr(), depth_test_mode) };
990        self
991    }
992
993    /// Should this material write to the ZBuffer? For opaque objects, this generally should be true. But transparent
994    /// objects writing to the ZBuffer can be problematic and cause draw order issues. Note that turning this off can
995    /// mean that this material won’t get properly accounted for when the MR system is performing late stage
996    /// reprojection. Not writing to the buffer can also be faster! :)
997    /// <https://stereokit.net/Pages/StereoKit/Material/DepthWrite.html>
998    ///
999    /// see also [`material_set_depth_write`]
1000    /// ### Examples
1001    /// ```
1002    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1003    /// use stereokit_rust::{util::{named_colors,Color32},material::Material};
1004    ///
1005    /// let mut material_cube = Material::pbr().copy();
1006    /// assert_eq!(material_cube.get_depth_write(), true);
1007    /// material_cube.depth_write(false).color_tint(named_colors::CYAN);
1008    /// assert_eq!(material_cube.get_depth_write(), false);
1009    /// ```
1010    pub fn depth_write(&mut self, write_enabled: bool) -> &mut Self {
1011        unsafe { material_set_depth_write(self.0.as_ptr(), write_enabled as Bool32T) };
1012        self
1013    }
1014
1015    /// Should the near/far depth plane clip (discard) what we're drawing? This defaults to true, and should almost
1016    /// always be true! However, it can be useful to set this to false for occasions like shadow map rendering, where
1017    /// near/far clip planes are really critical, and out of clip objects are still useful to have.
1018    /// <https://stereokit.net/Pages/StereoKit/Material.html>
1019    ///
1020    /// see also [`material_set_depth_clip`] [`Material::get_depth_clip`]
1021    /// ### Examples
1022    /// ```
1023    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1024    /// use stereokit_rust::material::Material;
1025    /// let mut material = Material::pbr().copy();
1026    /// assert_eq!(material.get_depth_clip(), false);
1027    /// material.depth_clip(false);
1028    /// assert_eq!(material.get_depth_clip(), false);
1029    /// ```
1030    pub fn depth_clip(&mut self, clip_enabled: bool) -> &mut Self {
1031        unsafe { material_set_depth_clip(self.0.as_ptr(), clip_enabled as Bool32T) };
1032        self
1033    }
1034
1035    /// This property will force this material to draw earlier or later in the draw queue. Positive values make it draw
1036    /// later, negative makes it earlier. This can be helpful for tweaking performance! If you know an object is always
1037    /// going to be close to the user and likely to obscure lots of objects (like hands), drawing it earlier can mean
1038    /// objects behind it get discarded much faster! Similarly, objects that are far away (skybox!) can be pushed
1039    /// towards the back of the queue, so they’re more likely to be discarded early.
1040    /// <https://stereokit.net/Pages/StereoKit/Material/QueueOffset.html>
1041    ///
1042    /// see also [`material_set_queue_offset`]
1043    /// ### Examples
1044    /// ```
1045    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1046    /// use stereokit_rust::{util::{named_colors,Color32},material::Material};
1047    ///
1048    /// let mut material_cube = Material::pbr().copy();
1049    /// assert_eq!(material_cube.get_queue_offset(), 0);
1050    /// material_cube.queue_offset(8).color_tint(named_colors::CYAN);
1051    /// assert_eq!(material_cube.get_queue_offset(), 8);
1052    /// ```
1053    pub fn queue_offset(&mut self, offset: i32) -> &mut Self {
1054        unsafe { material_set_queue_offset(self.0.as_ptr(), offset) };
1055        self
1056    }
1057
1058    /// Allows you to chain Materials together in a form of multi-pass rendering! Any time the Material is used, the
1059    /// chained Materials will also be used to draw the same item.
1060    /// <https://stereokit.net/Pages/StereoKit/Material/Chain.html>
1061    ///
1062    /// see also [`material_set_chain`]
1063    /// ### Examples
1064    /// ```
1065    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1066    /// use stereokit_rust::material::Material;
1067    ///
1068    /// let mut material_cube = Material::pbr().copy();
1069    /// assert!(material_cube.get_chain().is_none());
1070    ///
1071    /// let mut material_to_chain = Material::ui_quadrant().copy();
1072    /// material_to_chain.id("material_to_chain");
1073    /// material_cube.chain(&material_to_chain);
1074    /// assert_eq!(material_cube.get_chain().unwrap().get_id(), material_to_chain.get_id());
1075    /// ```
1076    pub fn chain(&mut self, chained_material: &Material) -> &mut Self {
1077        unsafe { material_set_chain(self.0.as_ptr(), chained_material.0.as_ptr()) };
1078        self
1079    }
1080
1081    /// Get the [`Material::id`] of the material.
1082    /// <https://stereokit.net/Pages/StereoKit/Material/Id.html>
1083    ///
1084    /// see also [`material_get_id`]
1085    ///
1086    /// see example in [`Material::id`]
1087    pub fn get_id(&self) -> &str {
1088        unsafe { CStr::from_ptr(material_get_id(self.0.as_ptr())) }.to_str().unwrap()
1089    }
1090
1091    /// Get the [`Material::shader`] of the material.
1092    /// <https://stereokit.net/Pages/StereoKit/Material/Shader.html>
1093    ///
1094    /// see also [`material_get_shader`]
1095    ///
1096    /// see example in [`Material::shader`]
1097    pub fn get_shader(&self) -> Shader {
1098        unsafe { Shader(NonNull::new(material_get_shader(self.0.as_ptr())).unwrap()) }
1099    }
1100
1101    /// Get the [`Material::transparency`] of the material.
1102    /// <https://stereokit.net/Pages/StereoKit/Material/Transparency.html>
1103    ///
1104    /// see also [`material_get_transparency`]
1105    ///
1106    /// see example in [`Material::transparency`]
1107    pub fn get_transparency(&self) -> Transparency {
1108        unsafe { material_get_transparency(self.0.as_ptr()) }
1109    }
1110
1111    /// Get the [`Material::face_cull`] of the material.
1112    /// <https://stereokit.net/Pages/StereoKit/Material/FaceCull.html>
1113    ///
1114    /// see also [`material_get_cull`]
1115    ///
1116    /// see example in [`Material::face_cull`]
1117    pub fn get_face_cull(&self) -> Cull {
1118        unsafe { material_get_cull(self.0.as_ptr()) }
1119    }
1120
1121    /// Get the [`Material::wireframe`] of the material.
1122    /// <https://stereokit.net/Pages/StereoKit/Material/Wireframe.html>
1123    ///
1124    /// see also [`material_get_wireframe`]
1125    ///
1126    /// see example in [`Material::wireframe`]
1127    pub fn get_wireframe(&self) -> bool {
1128        unsafe { material_get_wireframe(self.0.as_ptr()) != 0 }
1129    }
1130
1131    /// Get the [`Material::depth_test`] of the material.
1132    /// <https://stereokit.net/Pages/StereoKit/Material/DepthTest.html>
1133    ///
1134    /// see also [`material_get_depth_test`]
1135    ///
1136    /// see example in [`Material::depth_test`]
1137    pub fn get_depth_test(&self) -> DepthTest {
1138        unsafe { material_get_depth_test(self.0.as_ptr()) }
1139    }
1140
1141    /// Get the [`Material::depth_write`] of the material.
1142    /// <https://stereokit.net/Pages/StereoKit/Material/DepthWrite.html>
1143    ///
1144    /// see also [`material_get_depth_write`]
1145    ///
1146    /// see example in [`Material::depth_write`]
1147    pub fn get_depth_write(&self) -> bool {
1148        unsafe { material_get_depth_write(self.0.as_ptr()) != 0 }
1149    }
1150
1151    /// Get the [`Material::depth_clip`] state of the material.
1152    /// <https://stereokit.net/Pages/StereoKit/Material.html>
1153    ///
1154    /// see also [`material_get_depth_clip`]
1155    ///
1156    /// see example in [`Material::depth_clip`]
1157    pub fn get_depth_clip(&self) -> bool {
1158        unsafe { material_get_depth_clip(self.0.as_ptr()) != 0 }
1159    }
1160
1161    /// Get the [`Material::queue_offset`] of the material.
1162    /// <https://stereokit.net/Pages/StereoKit/Material/QueueOffset.html>
1163    ///
1164    /// see also [`material_get_queue_offset`]
1165    ///
1166    /// see example in [`Material::queue_offset`]
1167    pub fn get_queue_offset(&self) -> i32 {
1168        unsafe { material_get_queue_offset(self.0.as_ptr()) }
1169    }
1170
1171    /// Get the [`Material::chain`] of the material.
1172    /// <https://stereokit.net/Pages/StereoKit/Material/Chain.html>
1173    ///
1174    /// see also [`material_get_chain`]
1175    ///
1176    /// see example in [`Material::chain`]
1177    pub fn get_chain(&self) -> Option<Material> {
1178        unsafe { NonNull::new(material_get_chain(self.0.as_ptr())).map(Material) }
1179    }
1180
1181    /// Get All param infos.
1182    /// <https://stereokit.net/Pages/StereoKit/Material/GetAllParamInfo.html>
1183    ///
1184    /// see also [`ParamInfos`] [`ParamInfo`]
1185    /// ### Examples
1186    /// ```
1187    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1188    /// use stereokit_rust::{material::{Material, MaterialParam}, shader::Shader};
1189    ///
1190    /// let material = Material::new(Shader::pbr(), Some("my_material"));
1191    /// let param_infos = material.get_all_param_info();
1192    /// assert_ne!(param_infos.get_count(), 0);
1193    /// for param in param_infos {
1194    ///    match param.name.as_str()  {
1195    ///        "diffuse" | "emission" | "metal" | "occlusion"  
1196    ///             => assert_eq!(param.type_info, MaterialParam::Texture),
1197    ///        "color" | "emission_factor"  
1198    ///             => assert_eq!(param.type_info, MaterialParam::Color128),
1199    ///        "metallic" | "roughness"  
1200    ///             => assert_eq!(param.type_info, MaterialParam::Float),
1201    ///        "tex_trans"  
1202    ///             => assert_eq!(param.type_info, MaterialParam::Vec4),
1203    ///        _ => {}
1204    ///    }
1205    /// }
1206    /// ```
1207    pub fn get_all_param_info(&self) -> ParamInfos<'_> {
1208        ParamInfos::from(self)
1209    }
1210
1211    /// The default Physically Based Rendering material! This is used by StereoKit anytime a mesh or model has metallic
1212    /// or roughness properties, or needs to look more realistic. Its shader may change based on system performance
1213    /// characteristics, so it can be great to copy this one when creating your own materials! Or if you want to
1214    /// override StereoKit’s default PBR behavior, here’s where you do it! Note that the shader used by default here is
1215    /// much more costly than Default.Material.
1216    ///  <https://stereokit.net/Pages/StereoKit/Material/PBR.html>
1217    /// ### Examples
1218    /// ```
1219    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1220    /// use stereokit_rust::{material::Material};
1221    /// let mut material = Material::pbr();
1222    /// assert_eq!(material.get_id(), "default/material_pbr");
1223    /// ```
1224    pub fn pbr() -> Self {
1225        Self::find("default/material_pbr").unwrap()
1226    }
1227
1228    /// Same as MaterialPBR, but it uses a discard clip for transparency.
1229    /// <https://stereokit.net/Pages/StereoKit/Material/PBRClip.html>
1230    /// ### Examples
1231    /// ```
1232    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1233    /// use stereokit_rust::{material::Material};
1234    /// let mut material = Material::pbr_clip();
1235    /// assert_eq!(material.get_id(), "default/material_pbr_clip");
1236    /// ```
1237    pub fn pbr_clip() -> Self {
1238        Self::find("default/material_pbr_clip").unwrap()
1239    }
1240
1241    /// The default unlit material! This is used by StereoKit any time a mesh or model needs to be rendered with an
1242    /// unlit surface. Its shader may change based on system performance characteristics, so it can be great to copy
1243    /// this one when creating your own materials! Or if you want to override StereoKit’s default unlit behavior,
1244    /// here’s where you do it!
1245    /// <https://stereokit.net/Pages/StereoKit/Material/Unlit.html>
1246    /// ### Examples
1247    /// ```
1248    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1249    /// use stereokit_rust::{material::Material};
1250    /// let mut material = Material::unlit();
1251    /// assert_eq!(material.get_id(), "default/material_unlit");
1252    /// ```
1253    pub fn unlit() -> Self {
1254        Self::find("default/material_unlit").unwrap()
1255    }
1256
1257    /// The default unlit material with alpha clipping! This is used by StereoKit for unlit content with transparency,
1258    /// where completely transparent pixels are discarded. This means less alpha blending, and fewer visible alpha
1259    /// blending issues! In particular, this is how Sprites are drawn. Its shader may change based on system
1260    /// performance characteristics, so it can be great to copy this one when creating your own materials!
1261    /// Or if you want to override StereoKit’s default unlit clipped behavior, here’s where you do it!
1262    /// <https://stereokit.net/Pages/StereoKit/Material/UnlitClip.html>
1263    /// ### Examples
1264    /// ```
1265    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1266    /// use stereokit_rust::{material::Material};
1267    /// let mut material = Material::unlit_clip();
1268    /// assert_eq!(material.get_id(), "default/material_unlit_clip");
1269    /// ```
1270    pub fn unlit_clip() -> Self {
1271        Self::find("default/material_unlit_clip").unwrap()
1272    }
1273
1274    /// The material used by cubemap
1275    /// <https://stereokit.net/Pages/StereoKit/Material.html>
1276    /// ### Examples
1277    /// ```
1278    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1279    /// use stereokit_rust::{material::Material};
1280    /// let mut material = Material::equirect();
1281    /// assert_eq!(material.get_id(), "default/equirect_convert");
1282    /// ```
1283    pub fn equirect() -> Self {
1284        Self::find("default/equirect_convert").unwrap()
1285    }
1286
1287    /// The material used by font
1288    /// <https://stereokit.net/Pages/StereoKit/Material.html>
1289    /// ### Examples
1290    /// ```
1291    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1292    /// use stereokit_rust::{material::Material};
1293    /// let mut material = Material::font();
1294    /// assert_eq!(material.get_id(), "default/material_font");
1295    /// ```
1296    pub fn font() -> Self {
1297        Self::find("default/material_font").unwrap()
1298    }
1299
1300    /// The material used for hands
1301    /// <https://stereokit.net/Pages/StereoKit/Material.html>
1302    /// ### Examples
1303    /// ```
1304    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1305    /// use stereokit_rust::{material::Material};
1306    /// let mut material = Material::hand();
1307    /// assert_eq!(material.get_id(), "default/material_hand");
1308    /// ```
1309    pub fn hand() -> Self {
1310        Self::find("default/material_hand").unwrap()
1311    }
1312
1313    /// The material used by the UI! By default, it uses a shader that creates a ‘finger shadow’ that shows how close
1314    /// the finger
1315    /// is to the UI.
1316    /// <https://stereokit.net/Pages/StereoKit/Material/UI.html>
1317    /// ### Examples
1318    /// ```
1319    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1320    /// use stereokit_rust::{material::Material};
1321    /// let mut material = Material::ui();
1322    /// assert_eq!(material.get_id(), "default/material_ui");
1323    /// ```
1324    pub fn ui() -> Self {
1325        Self::find("default/material_ui").unwrap()
1326    }
1327
1328    /// A material for indicating interaction volumes! It renders a border around the edges of the UV coordinates that
1329    /// will ‘grow’ on proximity to the user’s finger. It will discard pixels outside of that border, but will also
1330    /// show the finger shadow. This is meant to be an opaque material, so it works well for depth LSR. This material
1331    /// works best on cube-like meshes where each face has UV coordinates from 0-1.
1332    /// Shader Parameters: color - color border_size - meters border_size_grow - meters border_affect_radius - meters
1333    /// <https://stereokit.net/Pages/StereoKit/Material/UIBox.html>
1334    /// ### Examples
1335    /// ```
1336    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1337    /// use stereokit_rust::{material::Material};
1338    /// let mut material = Material::ui_box();
1339    /// assert_eq!(material.get_id(), "default/material_ui_box");
1340    /// ```
1341    pub fn ui_box() -> Self {
1342        Self::find("default/material_ui_box").unwrap()
1343    }
1344
1345    /// The material used by the UI for Quadrant Sized UI elements. See UI.QuadrantSizeMesh for additional details.
1346    /// By default, it uses a shader that creates a ‘finger shadow’ that shows how close the finger is to the UI.
1347    /// <https://stereokit.net/Pages/StereoKit/Material.html>
1348    /// ### Examples
1349    /// ```
1350    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1351    /// use stereokit_rust::{material::Material};
1352    /// let mut material = Material::ui_quadrant();
1353    /// assert_eq!(material.get_id(), "default/material_ui_quadrant");
1354    /// ```
1355    pub fn ui_quadrant() -> Self {
1356        Self::find("default/material_ui_quadrant").unwrap()
1357    }
1358
1359    /// The material used by the UI for Aura, an extra space and visual element that goes around Window elements to make
1360    /// them easier to grab
1361    /// <https://stereokit.net/Pages/StereoKit/Material.html>
1362    /// ### Examples
1363    /// ```
1364    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1365    /// use stereokit_rust::{material::Material};
1366    /// let mut material = Material::ui_aura();
1367    /// assert_eq!(material.get_id(), "default/material_ui_aura");
1368    /// ```
1369    pub fn ui_aura() -> Self {
1370        Self::find("default/material_ui_aura").unwrap()
1371    }
1372}
1373
1374/// Infos of a Material.  This includes all global shader variables and textures.
1375/// Warning, you have to be cautious when settings some infos
1376/// <https://stereokit.net/Pages/StereoKit/Material/GetAllParamInfo.html>
1377///
1378/// see also [`Material::get_all_param_info`] [ParamInfo]
1379/// ### Examples
1380/// ```
1381/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1382/// use stereokit_rust::{material::{Material, MaterialParam, Cull},
1383///                      mesh::Mesh, maths::{Vec3, Vec4, Matrix}};
1384///
1385/// let cube = Mesh::cube();
1386/// let mut material_cube = Material::from_file("shaders/brick_pbr.hlsl.sks", None).unwrap();
1387/// material_cube.face_cull(Cull::Front).tex_transform(Vec4::new(0.0, 0.0, 0.04, 0.04));
1388/// let mut param_infos = material_cube.get_all_param_info();
1389/// assert!(param_infos.has_param("line_color", MaterialParam::Vec3), "line_color is missing");
1390/// assert_eq!(param_infos.get_float("edge_pos"), 1.5);
1391///
1392/// // Change of unusual values that are not listed in Material
1393/// param_infos .set_float("edge_pos", 0.5)
1394///             .set_vector3("line_color", Vec3::new(0.54, 0.54, 0.20));
1395///
1396/// filename_scr = "screenshots/param_infos.jpeg";
1397/// test_screenshot!( // !!!! Get a proper main loop !!!!
1398///     cube.draw(token, &material_cube, Matrix::IDENTITY, None, None);
1399/// );
1400/// ```
1401/// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/param_infos.jpeg" alt="screenshot" width="200">
1402pub struct ParamInfos<'a> {
1403    material: &'a Material,
1404    index: i32,
1405}
1406
1407unsafe extern "C" {
1408    pub fn material_set_float(material: MaterialT, name: *const c_char, value: f32);
1409    pub fn material_set_vector2(material: MaterialT, name: *const c_char, value: Vec2);
1410    pub fn material_set_vector3(material: MaterialT, name: *const c_char, value: Vec3);
1411    pub fn material_set_color(material: MaterialT, name: *const c_char, color_gamma: Color128);
1412    pub fn material_set_vector4(material: MaterialT, name: *const c_char, value: Vec4);
1413    // Deprecated: pub fn material_set_vector(material: MaterialT, name: *const c_char, value: Vec4);
1414    pub fn material_set_int(material: MaterialT, name: *const c_char, value: i32);
1415    pub fn material_set_int2(material: MaterialT, name: *const c_char, value1: i32, value2: i32);
1416    pub fn material_set_int3(material: MaterialT, name: *const c_char, value1: i32, value2: i32, value3: i32);
1417    pub fn material_set_int4(
1418        material: MaterialT,
1419        name: *const c_char,
1420        value1: i32,
1421        value2: i32,
1422        value3: i32,
1423        value4: i32,
1424    );
1425    pub fn material_set_bool(material: MaterialT, name: *const c_char, value: Bool32T);
1426    pub fn material_set_uint(material: MaterialT, name: *const c_char, value: u32);
1427    pub fn material_set_uint2(material: MaterialT, name: *const c_char, value1: u32, value2: u32);
1428    pub fn material_set_uint3(material: MaterialT, name: *const c_char, value1: u32, value2: u32, value3: u32);
1429    pub fn material_set_uint4(
1430        material: MaterialT,
1431        name: *const c_char,
1432        value1: u32,
1433        value2: u32,
1434        value3: u32,
1435        value4: u32,
1436    );
1437    pub fn material_set_matrix(material: MaterialT, name: *const c_char, value: Matrix);
1438    pub fn material_set_texture(material: MaterialT, name: *const c_char, value: TexT) -> Bool32T;
1439    pub fn material_set_texture_id(material: MaterialT, id: u64, value: TexT) -> Bool32T;
1440    pub fn material_get_float(material: MaterialT, name: *const c_char) -> f32;
1441    pub fn material_get_vector2(material: MaterialT, name: *const c_char) -> Vec2;
1442    pub fn material_get_vector3(material: MaterialT, name: *const c_char) -> Vec3;
1443    pub fn material_get_color(material: MaterialT, name: *const c_char) -> Color128;
1444    pub fn material_get_vector4(material: MaterialT, name: *const c_char) -> Vec4;
1445    pub fn material_get_int(material: MaterialT, name: *const c_char) -> i32;
1446    pub fn material_get_bool(material: MaterialT, name: *const c_char) -> Bool32T;
1447    pub fn material_get_uint(material: MaterialT, name: *const c_char) -> u32;
1448    pub fn material_get_matrix(material: MaterialT, name: *const c_char) -> Matrix;
1449    pub fn material_get_texture(material: MaterialT, name: *const c_char) -> TexT;
1450    pub fn material_has_param(material: MaterialT, name: *const c_char, type_: MaterialParam) -> Bool32T;
1451    pub fn material_set_param(material: MaterialT, name: *const c_char, type_: MaterialParam, value: *const c_void);
1452    pub fn material_set_param_id(material: MaterialT, id: IdHashT, type_: MaterialParam, value: *const c_void);
1453    pub fn material_get_param(
1454        material: MaterialT,
1455        name: *const c_char,
1456        type_: MaterialParam,
1457        out_value: *mut c_void,
1458    ) -> Bool32T;
1459    pub fn material_get_param_id(material: MaterialT, id: u64, type_: MaterialParam, out_value: *mut c_void)
1460    -> Bool32T;
1461    pub fn material_get_param_info(
1462        material: MaterialT,
1463        index: i32,
1464        out_name: *mut *mut c_char,
1465        out_type: *mut MaterialParam,
1466    );
1467    pub fn material_get_param_count(material: MaterialT) -> i32;
1468
1469}
1470
1471/// TODO: v0.4 This may need significant revision? What type of data does this material parameter need?
1472/// This is used to tell the shader how large the data is, and where to attach it to on the shader.
1473/// <https://stereokit.net/Pages/StereoKit/MaterialParam.html>
1474#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1475#[repr(u32)]
1476pub enum MaterialParam {
1477    /// This data type is not currently recognized. Please report your case on GitHub Issues!
1478    Unknown = 0,
1479    /// A single 32 bit float value
1480    Float = 1,
1481    /// A color value described by 4 floating point values. Memory-wise this is
1482    /// the same as a Vector4, but in the shader this variable has a ':color'
1483    /// tag applied to it using StereoKits's shader info syntax, indicating it's
1484    /// a color value. Color values for shaders should be in linear space, not
1485    /// gamma.
1486    Color128 = 2,
1487    /// A 2 component vector composed of floating point values
1488    Vec2 = 3,
1489    /// A 3 component vector composed of floating point values
1490    Vec3 = 4,
1491    /// A 4 component vector composed of floating point values
1492    Vec4 = 5,
1493    /// A 4x4 matrix of floats.
1494    Matrix = 6,
1495    /// Texture information!
1496    Texture = 7,
1497    /// An i32, or 1 component array composed of i32 values
1498    Int = 8,
1499    /// A 2 component array composed of i32 values
1500    Int2 = 9,
1501    /// A 3 component array composed of i32 values
1502    Int3 = 10,
1503    /// A 4 component array composed of i32 values
1504    Int4 = 11,
1505    /// A u32, or 1 component array composed of u32 values
1506    UInt = 12,
1507    /// A 2 component array composed of u32 values
1508    UInt2 = 13,
1509    /// A 3 component array composed of u32 values
1510    UInt3 = 14,
1511    /// A 4 component array composed of u32 values
1512    UInt4 = 15,
1513}
1514
1515impl Iterator for ParamInfos<'_> {
1516    type Item = ParamInfo;
1517
1518    /// get all the param info
1519    ///
1520    /// see also [`material_get_param_info`] [`material_get_param_count`] [`material_get_param`]
1521    fn next(&mut self) -> Option<Self::Item> {
1522        self.index += 1;
1523        let count = unsafe { material_get_param_count(self.material.0.as_ptr()) };
1524        if self.index < count {
1525            let res = self.material_get_param_info(self.index);
1526            match res {
1527                Some((name, type_info)) => Some(ParamInfo::new(name, type_info)),
1528                None => {
1529                    //error
1530                    Log::err(format!(
1531                        "Unable to get info {:?}/{:?} for material {:?}",
1532                        self.index,
1533                        count,
1534                        self.material.get_id()
1535                    ));
1536                    None
1537                }
1538            }
1539        } else {
1540            None
1541        }
1542    }
1543}
1544
1545impl<'a> ParamInfos<'a> {
1546    /// helper to get the infos with only a material
1547    /// <https://stereokit.net/Pages/StereoKit/Material/GetAllParamInfo.html>
1548    /// * `material` - the material to get the param info from.
1549    ///
1550    /// see also [`Material::get_all_param_info`]
1551    /// ### Examples
1552    /// ```
1553    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1554    /// use stereokit_rust::material::{Material, MaterialParam, ParamInfos};
1555    ///
1556    /// let mut material_cube = Material::from_file("shaders/brick_pbr.hlsl.sks", None).unwrap();
1557    /// let mut param_infos = ParamInfos::from(&material_cube);
1558    /// assert!(param_infos.has_param("line_color", MaterialParam::Vec3), "line_color is missing");
1559    /// assert_eq!(param_infos.get_float("edge_pos"), 1.5);
1560    /// ```
1561    pub fn from(material: &'a Material) -> ParamInfos<'a> {
1562        ParamInfos { material, index: -1 }
1563    }
1564
1565    /// Only way to see if a shader has a given parameter if you do not iterate over parameters.
1566    /// <https://stereokit.net/Pages/StereoKit/Material.html>
1567    /// * `name`: The name of the parameter to check for.
1568    ///
1569    /// see also [`material_has_param`]
1570    /// ### Examples
1571    /// ```
1572    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1573    /// use stereokit_rust::material::{Material, MaterialParam, ParamInfos};
1574    ///
1575    /// let mut material_cube = Material::from_file("shaders/brick_pbr.hlsl.sks", None).unwrap();
1576    /// let mut param_infos = ParamInfos::from(&material_cube);
1577    /// assert!(param_infos.has_param("line_color", MaterialParam::Vec3), "line_color is missing");
1578    /// assert!(param_infos.has_param("edge_pos", MaterialParam::Float),   "edge_pos is missing");
1579    /// ```
1580    pub fn has_param<S: AsRef<str>>(&self, name: S, type_: MaterialParam) -> bool {
1581        unsafe {
1582            let cstr = &CString::new(name.as_ref()).unwrap_or_default();
1583            material_has_param(self.material.0.as_ptr(), cstr.as_ptr(), type_) != 0
1584        }
1585    }
1586
1587    /// This allows you to set more complex shader data types such as structs. Note the SK doesn’t guard against setting
1588    /// data of the wrong size here, so pay extra attention to the size of your data here, and ensure it matched up with
1589    /// the shader! Consider using [`ParamInfos::set_data_with_id`] if you have to change the data type often (i.e. in
1590    /// the main loop).
1591    /// <https://stereokit.net/Pages/StereoKit/Material/SetData.html>
1592    /// * `name` - The name of the parameter to set
1593    /// * `type_info` - The type of the data being set.
1594    /// * `value` - A pointer to the data being set.
1595    ///
1596    /// see also [`material_set_param`] [`ParamInfos::set_data_with_id`]
1597    ///    # Safety
1598    ///    Be sure of the data you want to modify this way.
1599    ///
1600    /// ### Examples
1601    /// ```
1602    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1603    /// use stereokit_rust::material::{Material, MaterialParam};
1604    ///
1605    /// let mut material = Material::from_file("shaders/brick_pbr.hlsl.sks", None).unwrap();
1606    /// let mut param_infos = material.get_all_param_info();
1607    /// // an odd way to do : material.color_tint(...);
1608    /// let mut new_color: std::vec::Vec<f32>  = vec![1.0, 0.5, 0.2, 1.0];
1609    /// unsafe{
1610    ///     param_infos.set_data("color", MaterialParam::Color128,
1611    ///                          new_color.as_ptr() as *mut std::ffi::c_void);
1612    /// }
1613    /// assert_eq!( param_infos.get_color("color"),
1614    ///             util::Color128::new(1.0, 0.5, 0.2, 1.0));
1615    /// ```
1616    pub unsafe fn set_data<S: AsRef<str>>(
1617        &mut self,
1618        name: S,
1619        type_info: MaterialParam,
1620        value: *mut c_void,
1621    ) -> &mut Self {
1622        unsafe {
1623            let cstr = &CString::new(name.as_ref()).unwrap_or_default();
1624            material_set_param(self.material.0.as_ptr(), cstr.as_ptr(), type_info, value)
1625        };
1626        self
1627    }
1628
1629    /// Add an info value (identified with an id) to the shader of this material. Be sure of using a pointer 'value'
1630    /// corresponding to the right type 'type_info'
1631    /// <https://stereokit.net/Pages/StereoKit/Material/SetData.html>
1632    /// * `id` - the hash_fnv64_string value of the name of the parameter.
1633    /// * `type_info` - the type of the parameter you want to set.
1634    /// * `value` - a pointer to the data you want to set.
1635    ///
1636    /// see also [`material_set_param_id`] [`ParamInfos::set_data`]
1637    ///    # Safety
1638    ///    Be sure of the data you want to modify this way.
1639    ///
1640    /// ### Examples
1641    /// ```
1642    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1643    /// use stereokit_rust::{material::{Material, MaterialParam, Cull},
1644    ///                      mesh::Mesh, maths::{Vec3, Vec4, Matrix}, util::Hash};
1645    ///
1646    /// let cube = Mesh::cube();
1647    /// let mut material_cube = Material::from_file("shaders/brick_pbr.hlsl.sks", None).unwrap();
1648    /// material_cube.face_cull(Cull::Front).tex_transform(Vec4::new(0.0, 0.0, 0.04, 0.04));
1649    /// let mut param_infos = material_cube.get_all_param_info();
1650    /// // an odd way to do : material.color_tint(...);
1651    /// let mut new_color: std::vec::Vec<f32>  = vec![0.2, 0.2, 0.9, 1.0];
1652    /// let hash_color = Hash::string("color");
1653    ///
1654    /// filename_scr = "screenshots/param_infos_with_id.jpeg";
1655    /// test_screenshot!( // !!!! Get a proper main loop !!!!
1656    ///     unsafe{
1657    ///         param_infos.set_data_with_id(hash_color, MaterialParam::Color128,
1658    ///                          new_color.as_ptr() as *mut std::ffi::c_void);
1659    ///     }
1660    ///     cube.draw(token, &material_cube, Matrix::IDENTITY, None, None);
1661    /// );
1662    /// ```
1663    /// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/param_infos_with_id.jpeg" alt="screenshot" width="200">
1664    pub unsafe fn set_data_with_id(&mut self, id: IdHashT, type_info: MaterialParam, value: *mut c_void) -> &mut Self {
1665        unsafe { material_set_param_id(self.material.0.as_ptr(), id, type_info, value) };
1666        self
1667    }
1668
1669    /// Sets a shader parameter with the given name to the provided value. If no parameter is found, nothing happens,
1670    /// and the value is not set!
1671    /// <https://stereokit.net/Pages/StereoKit/Material/SetBool.html>
1672    /// * `name` - Name of the shader parameter.
1673    /// * `value` - The new value to set.
1674    ///
1675    /// see also [`material_set_bool`]
1676    /// ### Examples
1677    /// ```
1678    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1679    /// use stereokit_rust::material::{Material, MaterialParam};
1680    ///
1681    /// let mut material = Material::from_file("shaders/brick_pbr.hlsl.sks", None).unwrap();
1682    /// let mut param_infos = material.get_all_param_info();
1683    /// param_infos.set_bool("use_occlusion", true);
1684    ///
1685    /// assert_eq!( param_infos.get_bool("use_occlusion"),true);
1686    /// ```
1687    pub fn set_bool<S: AsRef<str>>(&mut self, name: S, value: bool) -> &mut Self {
1688        unsafe {
1689            let cstr = &CString::new(name.as_ref()).unwrap_or_default();
1690            material_set_bool(self.material.0.as_ptr(), cstr.as_ptr(), value as Bool32T)
1691        };
1692        self
1693    }
1694
1695    /// Sets a shader parameter with the given name to the provided value. If no parameter is found, nothing happens,
1696    /// and the value is not set!
1697    /// <https://stereokit.net/Pages/StereoKit/Material/SetColor.html>
1698    /// * `name` - Name of the shader parameter.
1699    /// * `color_gamma` - The gamma space color for the shader to use.
1700    ///
1701    /// see also [`material_set_color`]
1702    /// ### Examples
1703    /// ```
1704    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1705    /// use stereokit_rust::{material::{Material, MaterialParam},util::Color128};
1706    ///
1707    /// let mut material = Material::from_file("shaders/brick_pbr.hlsl.sks", None).unwrap();
1708    /// let mut param_infos = material.get_all_param_info();
1709    /// let new_color = Color128::new(1.0, 0.5, 0.2, 1.0);
1710    /// // same as Material::color_tint(new_color);
1711    /// param_infos.set_color("color", new_color);  
1712    ///
1713    /// assert_eq!( param_infos.get_color("color"),new_color.to_linear() );
1714    /// ```
1715    pub fn set_color<S: AsRef<str>>(&mut self, name: S, color_gamma: impl Into<Color128>) -> &mut Self {
1716        unsafe {
1717            let cstr = &CString::new(name.as_ref()).unwrap_or_default();
1718            material_set_color(self.material.0.as_ptr(), cstr.as_ptr(), color_gamma.into())
1719        };
1720        self
1721    }
1722
1723    /// Sets a shader parameter with the given name to the provided value. If no parameter is found, nothing happens,
1724    /// and the value is not set!
1725    /// <https://stereokit.net/Pages/StereoKit/Material/SetFloat.html>
1726    /// * `name` - The name of the parameter to set.
1727    /// * `value` - The value to set for the parameter.
1728    ///
1729    /// see also [`material_set_float`]
1730    /// ### Examples
1731    /// ```
1732    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1733    /// use stereokit_rust::material::{Material, MaterialParam};
1734    ///
1735    /// let mut material = Material::from_file("shaders/brick_pbr.hlsl.sks", None).unwrap();
1736    /// let mut param_infos = material.get_all_param_info();
1737    /// param_infos.set_float("edge_pos", 0.18);
1738    ///
1739    /// assert_eq!( param_infos.get_float("edge_pos"), 0.18);
1740    /// ```
1741    pub fn set_float<S: AsRef<str>>(&mut self, name: S, value: f32) -> &mut Self {
1742        unsafe {
1743            let cstr = &CString::new(name.as_ref()).unwrap_or_default();
1744            material_set_float(self.material.0.as_ptr(), cstr.as_ptr(), value)
1745        };
1746        self
1747    }
1748
1749    /// Sets a shader parameter with the given name to the provided value. If no parameter is found, nothing happens,
1750    /// and the value is not set!
1751    /// <https://stereokit.net/Pages/StereoKit/Material/SetInt.html>
1752    /// * `name` - the name of the parameter to set
1753    /// * `value` - up to 4 integer values
1754    ///
1755    /// see also [`material_set_int`]
1756    /// see also [`material_set_int2`]
1757    /// see also [`material_set_int3`]
1758    /// see also [`material_set_int4`]
1759    /// ### Examples
1760    /// ```
1761    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1762    /// use stereokit_rust::material::{Material, MaterialParam};
1763    ///
1764    /// let mut material = Material::from_file("shaders/brick_pbr.hlsl.sks", None).unwrap();
1765    /// let mut param_infos = material.get_all_param_info();
1766    /// let new_factors = vec![302,50,20,10];
1767    /// param_infos.set_int("size_factors", new_factors.as_slice());
1768    ///
1769    /// assert_eq!( param_infos.get_int_vector("size_factors", MaterialParam::Int4).unwrap(), new_factors);
1770    /// ```
1771    pub fn set_int<S: AsRef<str>>(&mut self, name: S, values: &[i32]) -> &mut Self {
1772        unsafe {
1773            let cstr = &CString::new(name.as_ref()).unwrap_or_default();
1774            match values.len() {
1775                1 => material_set_int(self.material.0.as_ptr(), cstr.as_ptr(), values[0]),
1776                2 => material_set_int2(self.material.0.as_ptr(), cstr.as_ptr(), values[0], values[1]),
1777                3 => material_set_int3(self.material.0.as_ptr(), cstr.as_ptr(), values[0], values[1], values[2]),
1778                4 => material_set_int4(
1779                    self.material.0.as_ptr(),
1780                    cstr.as_ptr(),
1781                    values[0],
1782                    values[1],
1783                    values[2],
1784                    values[3],
1785                ),
1786                _ => {}
1787            }
1788        };
1789        self
1790    }
1791
1792    /// Sets a shader parameter with the given name to the provided value. If no parameter is found, nothing happens,
1793    /// and the value is not set! Warning, this may work on Int values as you can see in the examples.
1794    /// <https://stereokit.net/Pages/StereoKit/Material/SetUInt.html>
1795    /// * `name` - the name of the parameter to set
1796    /// * `value` : up to 4 unsigned integer values
1797    ///
1798    /// see also [`material_set_uint`]
1799    /// see also [`material_set_uint2`]
1800    /// see also [`material_set_uint3`]
1801    /// see also [`material_set_uint4`]
1802    /// ### Examples
1803    /// ```
1804    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1805    /// use stereokit_rust::material::{Material, MaterialParam};
1806    ///
1807    /// let mut material = Material::from_file("shaders/brick_pbr.hlsl.sks", None).unwrap();
1808    /// let mut param_infos = material.get_all_param_info();
1809    /// assert_eq!( param_infos.get_uint_vector("size_factors", MaterialParam::UInt4).unwrap(), vec![300, 4294967196, 50, 25]);
1810    /// let new_factors = vec![303,502,201,100];
1811    /// param_infos.set_uint("size_factors", new_factors.as_slice());
1812    ///
1813    /// assert!( param_infos.has_param("size_factors", MaterialParam::UInt4),"size_factors should be here");
1814    /// assert_eq!( param_infos.get_uint_vector("size_factors", MaterialParam::UInt4).unwrap(), new_factors);
1815    /// ```
1816    pub fn set_uint<S: AsRef<str>>(&mut self, name: S, values: &[u32]) -> &mut Self {
1817        unsafe {
1818            let cstr = &CString::new(name.as_ref()).unwrap_or_default();
1819            match values.len() {
1820                1 => material_set_uint(self.material.0.as_ptr(), cstr.as_ptr(), values[0]),
1821                2 => material_set_uint2(self.material.0.as_ptr(), cstr.as_ptr(), values[0], values[1]),
1822                3 => material_set_uint3(self.material.0.as_ptr(), cstr.as_ptr(), values[0], values[1], values[2]),
1823                4 => material_set_uint4(
1824                    self.material.0.as_ptr(),
1825                    cstr.as_ptr(),
1826                    values[0],
1827                    values[1],
1828                    values[2],
1829                    values[3],
1830                ),
1831                _ => {}
1832            }
1833        };
1834        self
1835    }
1836
1837    /// Sets a shader parameter with the given name to the provided value. If no parameter is found, nothing happens,
1838    /// and the value is not set!
1839    /// <https://stereokit.net/Pages/StereoKit/Material/SetMatrix.html>
1840    /// * `name` - The name of the parameter to set.
1841    /// * `value` - The [Matrix] to set for the parameter.
1842    ///
1843    /// see also [`material_set_matrix`]
1844    /// ### Examples
1845    /// ```
1846    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1847    /// use stereokit_rust::{material::{Material, MaterialParam}, maths::{Vec3, Matrix}};
1848    ///
1849    /// let mut material = Material::from_file("shaders/brick_pbr.hlsl.sks", None).unwrap();
1850    /// let mut param_infos = material.get_all_param_info();
1851    /// assert_eq!( param_infos.get_matrix("useless"), Matrix::NULL );
1852    /// let new_matrix = Matrix::t( Vec3::new(1.0, 2.0, 3.0));
1853    /// param_infos.set_matrix("useless", new_matrix);
1854    ///
1855    /// assert!( param_infos.has_param("useless", MaterialParam::Matrix),"size_factors should be here");
1856    /// assert_eq!( param_infos.get_matrix("useless"), new_matrix);
1857    /// ```
1858    pub fn set_matrix<S: AsRef<str>>(&mut self, name: S, value: impl Into<Matrix>) -> &mut Self {
1859        unsafe {
1860            let cstr = &CString::new(name.as_ref()).unwrap_or_default();
1861            material_set_matrix(self.material.0.as_ptr(), cstr.as_ptr(), value.into())
1862        };
1863        self
1864    }
1865
1866    /// Sets a shader parameter with the given name to the provided value. If no parameter is found, nothing happens,
1867    /// and the value is not set!
1868    /// <https://stereokit.net/Pages/StereoKit/Material/SetTexture.html>
1869    /// * `name` - the name of the parameter to set
1870    /// * `value` - the [Tex] to set for the parameter
1871    ///
1872    /// see also [`material_set_texture`]
1873    /// ### Examples
1874    /// ```
1875    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1876    /// use stereokit_rust::{material::{Material, MaterialParam}, tex::{Tex}};
1877    ///
1878    /// let mut material = Material::from_file("shaders/brick_pbr.hlsl.sks", None).unwrap();
1879    /// let mut param_infos = material.get_all_param_info();
1880    /// assert_ne!( param_infos.get_texture("metal").unwrap(), Tex::default() );
1881    /// let metal_tex = Tex::from_file("textures/open_gltf.jpeg", true, None)
1882    ///                    .expect("tex should be created");
1883    /// param_infos.set_texture("metal", &metal_tex);
1884    /// assert_eq!( param_infos.get_texture("metal").unwrap(), metal_tex );
1885    /// ```
1886    pub fn set_texture<S: AsRef<str>>(&mut self, name: S, value: impl AsRef<Tex>) -> &mut Self {
1887        unsafe {
1888            let cstr = &CString::new(name.as_ref()).unwrap_or_default();
1889            material_set_texture(self.material.0.as_ptr(), cstr.as_ptr(), value.as_ref().0.as_ptr())
1890        };
1891        self
1892    }
1893
1894    /// Sets a shader parameter with the given name to the provided value. If no parameter is found, nothing happens,
1895    /// and the value is not set!
1896    /// <https://stereokit.net/Pages/StereoKit/Material/SetVector.html>
1897    /// * `name` - the name of the parameter to set
1898    /// * `value` - the [Vec2] to set for the parameter
1899    ///
1900    /// see also [`material_set_vector2`]
1901    /// ### Examples
1902    /// ```
1903    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1904    /// use stereokit_rust::{material::{Material, MaterialParam}, maths::Vec2};
1905    ///
1906    /// let mut material = Material::from_file("shaders/brick_pbr.hlsl.sks", None).unwrap();
1907    /// let mut param_infos = material.get_all_param_info();
1908    /// assert_eq!( param_infos.get_vector2("edge_limit"), Vec2::new(0.1, 0.9) );
1909    /// let new_vec2 = Vec2::new(0.15, 0.85);
1910    /// param_infos.set_vector2("edge_limit", new_vec2);
1911    /// assert_eq!( param_infos.get_vector2("edge_limit"), new_vec2);
1912    /// ```
1913    pub fn set_vector2<S: AsRef<str>>(&mut self, name: S, value: impl Into<Vec2>) -> &mut Self {
1914        unsafe {
1915            let cstr = &CString::new(name.as_ref()).unwrap_or_default();
1916            material_set_vector2(self.material.0.as_ptr(), cstr.as_ptr(), value.into())
1917        };
1918        self
1919    }
1920
1921    /// Sets a shader parameter with the given name to the provided value. If no parameter is found, nothing happens,
1922    /// and the value is not set!
1923    /// <https://stereokit.net/Pages/StereoKit/Material/SetVector.html>
1924    /// * `name` - the name of the parameter to set
1925    /// * `value` - the [Vec3] to set for the parameter
1926    ///
1927    /// see also [`material_set_vector2`]
1928    /// ### Examples
1929    /// ```
1930    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1931    /// use stereokit_rust::{material::{Material, MaterialParam}, maths::Vec3};
1932    ///
1933    /// let mut material = Material::from_file("shaders/brick_pbr.hlsl.sks", None).unwrap();
1934    /// let mut param_infos = material.get_all_param_info();
1935    /// assert_eq!( param_infos.get_vector3("line_color"), Vec3::new(0.84, 0.84, 0.84) );
1936    /// let new_vec3 = Vec3::new(0.75, 0.75, 0.75);
1937    /// param_infos.set_vector3("line_color", new_vec3);
1938    /// assert_eq!( param_infos.get_vector3("line_color"), new_vec3);
1939    /// ```
1940    pub fn set_vector3<S: AsRef<str>>(&mut self, name: S, value: impl Into<Vec3>) -> &mut Self {
1941        unsafe {
1942            let cstr = &CString::new(name.as_ref()).unwrap_or_default();
1943            material_set_vector3(self.material.0.as_ptr(), cstr.as_ptr(), value.into())
1944        };
1945        self
1946    }
1947
1948    /// Sets a shader parameter with the given name to the provided value. If no parameter is found, nothing happens,
1949    /// and the value is not set!
1950    /// <https://stereokit.net/Pages/StereoKit/Material/SetVector.html>
1951    /// * `name`- The name of the parameter to set.
1952    /// * `value` - the [Vec4] to set for the parameter
1953    ///
1954    /// see also [`material_set_vector4`]
1955    /// ### Examples
1956    /// ```
1957    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1958    /// use stereokit_rust::{material::Material, maths::Vec4};
1959    ///
1960    /// let mut material = Material::from_file("shaders/brick_pbr.hlsl.sks", None).unwrap();
1961    /// let mut param_infos = material.get_all_param_info();
1962    /// assert_eq!( param_infos.get_vector4("tex_trans"), Vec4::new(0.0, 0.0, 0.1,0.1) );
1963    ///
1964    /// let new_vec4 = Vec4::new(0.0, 0.0, 0.75, 0.75);
1965    /// // same as material.tex_transform(new_vec4)
1966    /// param_infos.set_vector4("tex_trans", new_vec4);
1967    /// assert_eq!( param_infos.get_vector4("tex_trans"), new_vec4);
1968    /// ```
1969    pub fn set_vector4<S: AsRef<str>>(&mut self, name: S, value: impl Into<Vec4>) -> &mut Self {
1970        unsafe {
1971            let cstr = &CString::new(name.as_ref()).unwrap_or_default();
1972            material_set_vector4(self.material.0.as_ptr(), cstr.as_ptr(), value.into())
1973        };
1974        self
1975    }
1976
1977    /// Get the name and type of the info at given index
1978    fn material_get_param_info(&self, index: i32) -> Option<(&str, MaterialParam)> {
1979        let name_info = CString::new("H").unwrap().into_raw() as *mut *mut c_char;
1980        let mut type_info = MaterialParam::Unknown;
1981        unsafe { material_get_param_info(self.material.0.as_ptr(), index, name_info, &mut type_info) }
1982        let name_info = unsafe { CStr::from_ptr(*name_info).to_str().unwrap() };
1983        Some((name_info, type_info))
1984    }
1985
1986    /// Gets the value of a shader parameter with the given name. If no parameter is found, a default value of ‘false’
1987    /// will be returned.
1988    /// <https://stereokit.net/Pages/StereoKit/Material/GetBool.html>
1989    /// * `name` - The name of the shader parameter to get.
1990    ///
1991    /// see also [`material_get_bool`]
1992    /// see example in [`ParamInfos::set_bool`]
1993    pub fn get_bool<S: AsRef<str>>(&self, name: S) -> bool {
1994        unsafe {
1995            let cstr = &CString::new(name.as_ref()).unwrap_or_default();
1996            material_get_bool(self.material.0.as_ptr(), cstr.as_ptr()) != 0
1997        }
1998    }
1999
2000    /// Gets the value of a shader parameter with the given name. If no parameter is found, a default value of ‘0’ will
2001    /// be returned.
2002    /// <https://stereokit.net/Pages/StereoKit/Material/GetFloat.html>
2003    /// * `name` - The name of the shader parameter to get.
2004    ///
2005    /// see also [`material_get_float`]
2006    /// see example in [`ParamInfos::set_float`]
2007    pub fn get_float<S: AsRef<str>>(&self, name: S) -> f32 {
2008        unsafe {
2009            let cstr = &CString::new(name.as_ref()).unwrap_or_default();
2010            material_get_float(self.material.0.as_ptr(), cstr.as_ptr())
2011        }
2012    }
2013
2014    /// Gets the value of a shader parameter with the given name. If no parameter is found, a default value of
2015    /// Vec2::ZERO will be returned.
2016    /// <https://stereokit.net/Pages/StereoKit/Material/GetVector2.html>
2017    /// * `name` - The name of the shader parameter to get.
2018    ///
2019    /// see also [`material_get_vector2`]
2020    /// see example in [`ParamInfos::set_vector2`]
2021    pub fn get_vector2<S: AsRef<str>>(&self, name: S) -> Vec2 {
2022        unsafe {
2023            let cstr = &CString::new(name.as_ref()).unwrap_or_default();
2024            material_get_vector2(self.material.0.as_ptr(), cstr.as_ptr())
2025        }
2026    }
2027
2028    /// Gets the value of a shader parameter with the given name. If no parameter is found, a default value of
2029    /// Vec3::ZERO will be returned.
2030    /// <https://stereokit.net/Pages/StereoKit/Material/GetVector3.html>
2031    /// * `name` - The name of the shader parameter to get.
2032    ///
2033    /// see also [`material_get_vector3`]
2034    /// see example in [`ParamInfos::set_vector3`]
2035    pub fn get_vector3<S: AsRef<str>>(&self, name: S) -> Vec3 {
2036        unsafe {
2037            let cstr = &CString::new(name.as_ref()).unwrap_or_default();
2038            material_get_vector3(self.material.0.as_ptr(), cstr.as_ptr())
2039        }
2040    }
2041
2042    /// Gets the value of a shader parameter with the given name. If no parameter is found, a default value of
2043    /// Vec4::ZERO will be returned.
2044    /// <https://stereokit.net/Pages/StereoKit/Material/GetVector4.html>
2045    /// * `name` - The name of the shader parameter to get.
2046    ///
2047    /// see also [`material_get_vector4`]
2048    /// see example in [`ParamInfos::set_vector4`]
2049    pub fn get_vector4<S: AsRef<str>>(&self, name: S) -> Vec4 {
2050        unsafe {
2051            let cstr = &CString::new(name.as_ref()).unwrap_or_default();
2052            material_get_vector4(self.material.0.as_ptr(), cstr.as_ptr())
2053        }
2054    }
2055
2056    /// Gets the value of a shader parameter with the given name. If no parameter is found, a default value of
2057    /// Color128::WHITE will be returned. Warning: This function returns a gamma color.
2058    /// <https://stereokit.net/Pages/StereoKit/Material/GetColor.html>
2059    /// * `name` - The name of the shader parameter to get.
2060    ///
2061    /// see also [`material_get_color`]
2062    /// see example in [`ParamInfos::set_color`]
2063    pub fn get_color<S: AsRef<str>>(&self, name: S) -> Color128 {
2064        unsafe {
2065            let cstr = &CString::new(name.as_ref()).unwrap_or_default();
2066            material_get_color(self.material.0.as_ptr(), cstr.as_ptr())
2067        }
2068    }
2069
2070    /// Gets the value of a shader parameter with the given name. If no parameter is found, a default value of ‘0’ will
2071    /// be returned.
2072    /// <https://stereokit.net/Pages/StereoKit/Material/GetInt.html>
2073    /// * `name` - The name of the shader parameter to get.
2074    ///
2075    /// see also [`material_get_int]
2076    /// see example in [`ParamInfos::set_int`]
2077    pub fn get_int<S: AsRef<str>>(&self, name: S) -> i32 {
2078        unsafe {
2079            let cstr = &CString::new(name.as_ref()).unwrap_or_default();
2080            material_get_int(self.material.0.as_ptr(), cstr.as_ptr())
2081        }
2082    }
2083
2084    /// Get int vector using unsafe material_get_param function
2085    /// * `name` - The name of the shader parameter to get.
2086    /// * `type_info` - The type of the shader parameter to get: Int, Int2, Int3 or Int4
2087    ///
2088    /// see example in [`ParamInfos::set_int`]
2089    pub fn get_int_vector<S: AsRef<str>>(&self, name: S, type_info: MaterialParam) -> Option<Vec<i32>> {
2090        if let Some(out_value) = self.get_data(name, type_info) {
2091            match type_info {
2092                MaterialParam::Int => Some(unsafe { std::ptr::read(out_value as *const [i32; 1]).to_vec() }),
2093                MaterialParam::Int2 => Some(unsafe { std::ptr::read(out_value as *const [i32; 2]).to_vec() }),
2094                MaterialParam::Int3 => Some(unsafe { std::ptr::read(out_value as *const [i32; 3]).to_vec() }),
2095                MaterialParam::Int4 => Some(unsafe { std::ptr::read(out_value as *const [i32; 4]).to_vec() }),
2096                _ => None,
2097            }
2098        } else {
2099            None
2100        }
2101    }
2102
2103    /// Gets the value of a shader parameter with the given name. If no parameter is found, a default value of ‘0’ will
2104    /// be returned.
2105    /// <https://stereokit.net/Pages/StereoKit/Material/GetUInt.html>
2106    /// * `name` - The name of the shader parameter to get.
2107    ///
2108    /// see also [`material_get_uint`]
2109    /// see example in [`ParamInfos::set_uint`]
2110    pub fn get_uint<S: AsRef<str>>(&self, name: S) -> u32 {
2111        unsafe {
2112            let cstr = &CString::new(name.as_ref()).unwrap_or_default();
2113            material_get_uint(self.material.0.as_ptr(), cstr.as_ptr())
2114        }
2115    }
2116
2117    /// Get uint vector using unsafe material_get_param function
2118    /// * `name` - The name of the shader parameter to get.
2119    /// * type_info - The type of the shader parameter to get: UInt, UInt2, UInt3, UInt4.
2120    ///
2121    /// see example in [`ParamInfos::set_uint`]
2122    pub fn get_uint_vector<S: AsRef<str>>(&self, name: S, type_info: MaterialParam) -> Option<Vec<u32>> {
2123        if let Some(out_value) = self.get_data(name, type_info) {
2124            match type_info {
2125                MaterialParam::UInt => Some(unsafe { std::ptr::read(out_value as *const [u32; 1]).to_vec() }),
2126                MaterialParam::UInt2 => Some(unsafe { std::ptr::read(out_value as *const [u32; 2]).to_vec() }),
2127                MaterialParam::UInt3 => Some(unsafe { std::ptr::read(out_value as *const [u32; 3]).to_vec() }),
2128                MaterialParam::UInt4 => Some(unsafe { std::ptr::read(out_value as *const [u32; 4]).to_vec() }),
2129                _ => None,
2130            }
2131        } else {
2132            None
2133        }
2134    }
2135
2136    /// Gets the value of a shader parameter with the given name. If no parameter is found, a default value of
2137    /// Matrix.Identity will be returned.
2138    /// <https://stereokit.net/Pages/StereoKit/Material/GetMatrix.html>
2139    /// * `name` - The name of the parameter to get.
2140    ///
2141    /// see also [`material_get_matrix`]
2142    /// see example in [`ParamInfos::set_matrix`]
2143    pub fn get_matrix<S: AsRef<str>>(&self, name: S) -> Matrix {
2144        unsafe {
2145            let cstr = &CString::new(name.as_ref()).unwrap_or_default();
2146            material_get_matrix(self.material.0.as_ptr(), cstr.as_ptr())
2147        }
2148    }
2149
2150    /// Gets the value of a shader parameter with the given name. If no parameter is found,None will be returned.
2151    /// <https://stereokit.net/Pages/StereoKit/Material/GetTexture.html>
2152    /// * `name` - The name of the parameter to get.
2153    ///
2154    /// see also [`material_get_texture`]
2155    /// see example in [`ParamInfos::set_texture`]
2156    pub fn get_texture<S: AsRef<str>>(&self, name: S) -> Option<Tex> {
2157        NonNull::new(unsafe {
2158            let cstr = &CString::new(name.as_ref()).unwrap_or_default();
2159            material_get_texture(self.material.0.as_ptr(), cstr.as_ptr())
2160        })
2161        .map(Tex)
2162    }
2163
2164    /// Get an info value of the shader of this material
2165    /// <https://stereokit.net/Pages/StereoKit/Material.html>
2166    /// * `name` - The name of the parameter to get.
2167    /// * `type_info` - The type of the parameter to get.
2168    ///
2169    /// see also [`ParamInfo`] [`material_get_param`]
2170    /// ### Examples
2171    /// ```
2172    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2173    /// use stereokit_rust::material::{Material, MaterialParam};
2174    ///
2175    /// let mut material = Material::from_file("shaders/brick_pbr.hlsl.sks", None).unwrap();
2176    /// let mut param_infos = material.get_all_param_info();
2177    /// if let Some(out_value) = param_infos.get_data("size_factors", MaterialParam::Int4) {
2178    ///     let vec4 = unsafe { std::ptr::read(out_value as *const [i32; 4]).to_vec() };
2179    ///     assert_eq!( vec4, vec![300,-100,50,25] );
2180    /// } else { panic!("Failed to size_factors Int4");}
2181    /// ```
2182    /// see [`ParamInfos::set_data`]
2183    pub fn get_data<S: AsRef<str>>(&self, name: S, type_info: MaterialParam) -> Option<*mut c_void> {
2184        let out_value = CString::new("H").unwrap().into_raw() as *mut c_void;
2185        let cstr = &CString::new(name.as_ref()).unwrap();
2186        if unsafe { material_get_param(self.material.0.as_ptr(), cstr.as_ptr(), type_info, out_value) } != 0 {
2187            Some(out_value)
2188        } else {
2189            None
2190        }
2191    }
2192
2193    /// Get an info value (identified with an id) of the shader of this material
2194    /// <https://stereokit.net/Pages/StereoKit/Material.html>
2195    /// * `id` - the [`crate::util::Hash::string`] value of the name of the parameter.
2196    /// * `type_info` - the type of the parameter.
2197    ///
2198    /// Returns a pointer to the value that will be filled in if the parameter is found.
2199    /// see also [`ParamInfo`] [`material_get_param_id`] [`ParamInfos::set_data_with_id`]
2200    pub fn get_data_with_id(&self, id: IdHashT, type_info: MaterialParam) -> Option<*mut c_void> {
2201        let out_value = CString::new("H").unwrap().into_raw() as *mut c_void;
2202        if unsafe { material_get_param_id(self.material.0.as_ptr(), id, type_info, out_value) } != 0 {
2203            Some(out_value)
2204        } else {
2205            None
2206        }
2207    }
2208
2209    /// Get the number of infos for this node
2210    /// <https://stereokit.net/Pages/StereoKit/Material/ParamCount.html>
2211    ///
2212    /// see also [`material_get_param_count`]
2213    /// ### Examples
2214    /// ```
2215    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2216    /// use stereokit_rust::material::Material;
2217    ///
2218    /// let mut material = Material::unlit();
2219    /// let mut param_infos = material.get_all_param_info();
2220    /// assert_eq!( param_infos.get_count(), 3);
2221    /// ```
2222    pub fn get_count(&self) -> i32 {
2223        unsafe { material_get_param_count(self.material.0.as_ptr()) }
2224    }
2225
2226    /// Get the string value of the given ParamInfo
2227    /// ### Examples
2228    /// ```
2229    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2230    /// use stereokit_rust::material::Material;
2231    ///
2232    /// let mut material = Material::unlit();
2233    /// let mut param_infos_iter = material.get_all_param_info();
2234    /// let mut param_infos = material.get_all_param_info();
2235    /// for param in param_infos_iter {
2236    ///     match (param.get_name()) {
2237    ///         "color" =>
2238    ///             assert_eq!(param_infos.string_of(&param), "r:1, g:1, b:1, a:1"),
2239    ///         "tex_trans" =>
2240    ///             assert_eq!(param_infos.string_of(&param), "[x:0, y:0, z:1, w:1]"),
2241    ///         "diffuse" =>
2242    ///             assert_eq!(param_infos.string_of(&param), "Texture data..."),
2243    ///        otherwise =>
2244    ///             panic!("Unknown param type: {}", otherwise)
2245    ///     }
2246    /// }
2247    /// ```
2248    pub fn string_of(&self, info: &ParamInfo) -> String {
2249        match info.get_type() {
2250            MaterialParam::Unknown => "Unknown".into(),
2251            MaterialParam::Float => self.get_float(info.get_name()).to_string(),
2252            MaterialParam::Color128 => self.get_color(info.get_name()).to_string(),
2253            MaterialParam::Vec2 => self.get_vector2(info.get_name()).to_string(),
2254            MaterialParam::Vec3 => self.get_vector3(info.get_name()).to_string(),
2255            MaterialParam::Vec4 => self.get_vector4(info.get_name()).to_string(),
2256            MaterialParam::Matrix => self.get_matrix(info.get_name()).to_string(),
2257            MaterialParam::Texture => "Texture data...".to_string(),
2258            MaterialParam::Int => self.get_int(info.get_name()).to_string(),
2259            MaterialParam::Int2 => format!("{:?}", self.get_int_vector(info.get_name(), MaterialParam::Int2)),
2260            MaterialParam::Int3 => format!("{:?}", self.get_int_vector(info.get_name(), MaterialParam::Int3)),
2261            MaterialParam::Int4 => format!("{:?}", self.get_int_vector(info.get_name(), MaterialParam::Int4)),
2262            MaterialParam::UInt => self.get_color(info.get_name()).to_string(),
2263            MaterialParam::UInt2 => format!("{:?}", self.get_int_vector(info.get_name(), MaterialParam::UInt2)),
2264            MaterialParam::UInt3 => format!("{:?}", self.get_int_vector(info.get_name(), MaterialParam::UInt3)),
2265            MaterialParam::UInt4 => format!("{:?}", self.get_int_vector(info.get_name(), MaterialParam::UInt4)),
2266        }
2267    }
2268}
2269
2270/// One Info of a Material. This is only useful for [`Material::get_all_param_info`] iterator.
2271/// <https://stereokit.net/Pages/StereoKit/Material/GetAllParamInfo.html>
2272///
2273/// see also [ParamInfos] [`Material::get_all_param_info`]
2274pub struct ParamInfo {
2275    pub name: String,
2276    pub type_info: MaterialParam,
2277}
2278
2279impl ParamInfo {
2280    /// Create a new ParamInfo with the given name and type info. There is no reason to use this method as you can
2281    /// get values from [`Material`] get_???? methods
2282    /// [`Material::get_all_param_info`] iterator
2283    pub fn new<S: AsRef<str>>(name: S, type_info: MaterialParam) -> ParamInfo {
2284        ParamInfo { name: name.as_ref().to_string(), type_info }
2285    }
2286
2287    /// Get the name of the shader parameter
2288    pub fn get_name(&self) -> &str {
2289        self.name.as_str()
2290    }
2291
2292    /// Get the type of the shader parameter
2293    pub fn get_type(&self) -> MaterialParam {
2294        self.type_info
2295    }
2296}
2297
2298unsafe extern "C" {
2299    pub fn material_buffer_create(size: i32) -> MaterialBufferT;
2300    pub fn material_buffer_addref(buffer: MaterialBufferT);
2301    pub fn material_buffer_set_data(buffer: MaterialBufferT, buffer_data: *const c_void);
2302    pub fn material_buffer_release(buffer: MaterialBufferT);
2303}
2304
2305/// This is a chunk of memory that will get bound to all shaders at a particular register slot. StereoKit uses this to
2306/// provide engine values to the shader, and you can also use this to drive graphical shader systems of your own!
2307///
2308/// For example, if your application has a custom lighting system, fog, wind, or some other system that multiple shaders
2309/// might need to refer to, this is the perfect tool to use.
2310///
2311/// The type ‘T’ for this buffer must be a struct that uses the #[repr(C)] attribute for
2312/// proper copying. It should also match the layout of your equivalent cbuffer in the shader file. Note that shaders
2313/// often have specific byte alignment requirements!
2314/// <https://stereokit.net/Pages/StereoKit/MaterialBuffer.html>
2315///
2316/// ### Examples
2317/// ```
2318/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2319/// use stereokit_rust::material::MaterialBuffer;
2320///
2321/// // This struct must mirror the layout of the cbuffer in your shader.
2322/// // #[repr(C)] ensures a predictable memory layout.
2323/// #[repr(C)]
2324/// #[derive(Clone, Copy, Debug, Default)]
2325/// struct Globals {
2326///     time: f32,
2327///     wind: [f32; 3], // Example of packing a vec3
2328///     // Alignment padding if your shader expects 16-byte alignment for next values.
2329/// }
2330///
2331/// // Create the GPU buffer once.
2332/// let buffer = MaterialBuffer::<Globals>::new();
2333///
2334/// // Update data you want the shader(s) to read.
2335/// let mut globals = Globals { time: 1.234, wind: [0.1, 0.2, 0.3], ..Default::default() };
2336///
2337/// // Upload to GPU so every shader using this global slot can access it.
2338/// buffer.set(&mut globals as *mut _);
2339///
2340/// // In your shader, declare a matching cbuffer bound to the slot you
2341/// // bind this MaterialBuffer to (see Renderer::set_global_buffer in StereoKit).
2342/// ```
2343pub struct MaterialBuffer<T> {
2344    _material_buffer: MaterialBufferT,
2345    phantom: PhantomData<T>,
2346}
2347/// StereoKit internal type.
2348#[repr(C)]
2349#[derive(Debug)]
2350pub struct _MaterialBufferT {
2351    _unused: [u8; 0],
2352}
2353/// StereoKit ffi type.
2354pub type MaterialBufferT = *mut _MaterialBufferT;
2355
2356impl<T> Drop for MaterialBuffer<T> {
2357    fn drop(&mut self) {
2358        unsafe { material_buffer_release(self._material_buffer) }
2359    }
2360}
2361
2362impl<T> AsRef<MaterialBuffer<T>> for MaterialBuffer<T> {
2363    fn as_ref(&self) -> &MaterialBuffer<T> {
2364        self
2365    }
2366}
2367
2368impl<T> Default for MaterialBuffer<T> {
2369    fn default() -> Self {
2370        Self::new()
2371    }
2372}
2373impl<T> MaterialBuffer<T> {
2374    /// Create a new global MaterialBuffer that can be bound to a register slot id via Renderer.SetGlobalBuffer. All
2375    /// shaders will have access to the data provided via this instance's `Set`.
2376    /// <https://stereokit.net/Pages/StereoKit/MaterialBuffer/MaterialBuffer.html>
2377    ///
2378    /// see also [`material_buffer_create`]
2379    pub fn new() -> MaterialBuffer<T> {
2380        let size = std::mem::size_of::<T>();
2381        let mat_buffer = unsafe { material_buffer_create(size as i32) };
2382        MaterialBuffer { _material_buffer: mat_buffer, phantom: PhantomData }
2383    }
2384
2385    /// This will upload your data to the GPU for shaders to use.
2386    /// <https://stereokit.net/Pages/StereoKit/MaterialBuffer/Set.html>
2387    ///
2388    /// see also [`material_buffer_set_data`]
2389    pub fn set(&self, in_data: *mut T) {
2390        unsafe { material_buffer_set_data(self._material_buffer, in_data as *const c_void) };
2391    }
2392
2393    /// Internal: returns raw pointer for FFI binding usage (Renderer::set_global_buffer).
2394    pub(crate) fn as_ptr(&self) -> MaterialBufferT {
2395        self._material_buffer
2396    }
2397}