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(¶m), "r:1, g:1, b:1, a:1"),
2239 /// "tex_trans" =>
2240 /// assert_eq!(param_infos.string_of(¶m), "[x:0, y:0, z:1, w:1]"),
2241 /// "diffuse" =>
2242 /// assert_eq!(param_infos.string_of(¶m), "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}