stereokit_rust/
tex.rs

1use crate::{
2    StereoKitError,
3    maths::{Bool32T, Vec3},
4    system::{AssetState, IAsset, Log, render_get_skylight, render_get_skytex, render_set_skylight, render_set_skytex},
5    util::{Color32, Color128, Gradient, GradientKey, GradientT, SphericalHarmonics},
6};
7use std::{
8    ffi::{CStr, CString, c_char, c_void},
9    mem::size_of,
10    path::{Path, PathBuf},
11    ptr::{NonNull, null_mut},
12};
13
14bitflags::bitflags! {
15    /// Textures come in various types and flavors! These are bit-flags
16    /// that tell StereoKit what type of texture we want; and how the application
17    /// might use it!
18    /// <https://stereokit.net/Pages/StereoKit/TexType.html>
19    ///
20    /// see also [`Tex`]
21    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
22    #[repr(C)]
23    pub struct TexType: u32 {
24        /// A standard color image; without any generated mip-maps.
25        const ImageNomips = 1 << 0;
26        /// A size sided texture that's used for things like skyboxes;
27        /// environment maps; and reflection probes. It behaves like a texture
28        /// array with 6 textures.
29        const Cubemap = 1 << 1;
30        /// This texture can be rendered to! This is great for textures
31        /// that might be passed in as a target to Renderer.Blit; or other
32        /// such situations.
33        const Rendertarget = 1 << 2;
34        /// This texture contains depth data; not color data!
35        const Depth = 1 << 3;
36        /// This texture will generate mip-maps any time the contents
37        /// change. Mip-maps are a list of textures that are each half the
38        /// size of the one before them! This is used to prevent textures from
39        /// 'sparkling' or aliasing in the distance.
40        const Mips = 1 << 4;
41        /// This texture's data will be updated frequently from the
42        /// CPU (not renders)! This ensures the graphics card stores it
43        /// someplace where writes are easy to do quickly.
44        const Dynamic = 1 << 5;
45        /// A standard color image that also generates mip-maps
46        /// automatically.
47        const Image = Self::ImageNomips.bits() | Self::Mips.bits();
48    }
49}
50impl TexType {
51    pub fn as_u32(&self) -> u32 {
52        self.bits()
53    }
54}
55/// What type of color information will the texture contain? A
56/// good default here is Rgba32.
57/// <https://stereokit.net/Pages/StereoKit/TexFormat.html>
58///
59/// see also [`Tex`] [`crate::system::Renderer`]
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61#[repr(u32)]
62pub enum TexFormat {
63    /// A default zero value for TexFormat! Uninitialized formats will get this value and **** **** up so you know to
64    /// assign it properly :)
65    None = 0,
66    /// Red/Green/Blue/Transparency data channels, at 8 bits per-channel in sRGB color space. This is what you'll
67    /// want most of the time you're dealing with color images! Matches well with the Color32 struct! If you're
68    /// storing normals, rough/metal, or anything else, use Rgba32Linear.
69    RGBA32 = 1,
70    /// Red/Green/Blue/Transparency data channels, at 8 bits per-channel in linear color space. This is what you'll
71    /// want most of the time you're dealing with color data! Matches well with the Color32 struct.
72    RGBA32Linear = 2,
73    /// Blue/Green/Red/Transparency data channels, at 8 bits per-channel in sRGB color space. This is a common swapchain
74    /// format  on Windows.
75    BGRA32 = 3,
76    /// Blue/Green/Red/Transparency data channels, at 8 bits per-channel in linear color space. This is a common
77    /// swapchain format on Windows.
78    BGRA32Linear = 4,
79    /// Red/Green/Blue data channels, with 11 bits for R and G, and 10 bits for blue. This is a great presentation format
80    /// for high bit depth displays that still fits in 32 bits! This format has no alpha channel.
81    RG11B10 = 5,
82    /// Red/Green/Blue/Transparency data channels, with 10 bits for R, G, and B, and 2 for alpha. This is a great
83    /// presentation format for high bit depth displays that still fits in 32 bits, and also includes at least a bit of
84    /// transparency!
85    RGB10A2 = 6,
86    /// Red/Green/Blue/Transparency data channels, at 16 bits per-channel! This is not common, but you might encounter
87    /// it with raw photos, or HDR images.  The u postfix indicates that the raw color data is stored as an unsigned
88    /// 16 bit integer, which is then normalized into the 0, 1 floating point range on the GPU.
89    RGBA64U = 7,
90    /// Red/Green/Blue/Transparency data channels, at 16 bits per-channel! This is not common, but you might encounter
91    /// it with raw photos, or HDR images. The s postfix indicates that the raw color data is stored as a signed 16 bit
92    /// integer, which is then normalized into the -1, +1 floating point range on the GPU.
93    RGBA64S = 8,
94    /// Red/Green/Blue/Transparency data channels, at 16 bits per-channel! This is not common, but you might encounter
95    /// it with raw photos, or HDR images. The f postfix indicates that the raw color data is stored as 16 bit floats,
96    /// which may be tricky to work with in most languages.
97    RGBA64F = 9,
98    /// Red/Green/Blue/Transparency data channels at 32 bits per-channel! Basically 4 floats per color, which is bonkers
99    /// expensive. Don't use this unless you know -exactly- what you're doing.
100    RGBA128 = 10,
101    /// A single channel of data, with 8 bits per-pixel! This can be great when you're only using one channel, and want
102    /// to reduce memory usage. Values in the shader are always 0.0-1.0.
103    R8 = 11,
104    /// A single channel of data, with 16 bits per-pixel! This is a good format for height maps, since it stores a fair
105    /// bit of information in it. Values in the shader are always 0.0-1.0.
106    /// TODO: remove during major version update, prefer s, f, or u postfixed versions of this format, this item is the
107    /// same as  r16u.
108    //R16 = 12,
109    /// A single channel of data, with 16 bits per-pixel! This is a good format for height maps, since it stores a fair
110    /// bit of information in it. The u postfix indicates that the raw color data is stored as an unsigned 16 bit
111    /// integer, which is then normalized into the 0, 1 floating point range on the GPU.
112    R16u = 12,
113    /// A single channel of data, with 16 bits per-pixel! This is a good format for height maps, since it stores a fair
114    /// bit of information in it. The s postfix indicates that the raw color data is stored as a signed 16 bit integer,
115    /// which is then normalized into the -1, +1 floating point range on the GPU.
116    R16s = 13,
117    /// A single channel of data, with 16 bits per-pixel! This is a good format for height maps, since it stores a fair
118    /// bit of information in it. The f postfix indicates that the raw color data is stored as 16 bit floats, which may
119    /// be tricky to work with in most languages.
120    R16f = 14,
121    /// A single channel of data, with 32 bits per-pixel! This basically treats each pixel as a generic float, so you
122    /// can do all sorts of strange and interesting things with this.
123    R32 = 15,
124    /// A depth data format, 24 bits for depth data, and 8 bits to store stencil information! Stencil data can be used
125    /// for things like clipping effects, deferred rendering, or shadow effects.
126    DepthStencil = 16,
127    /// 32 bits of data per depth value! This is pretty detailed, and is excellent for experiences that have a very far
128    /// view distance.
129    Depth32 = 17,
130    /// 16 bits of depth is not a lot, but it can be enough if your far clipping plane is pretty close. If you're seeing
131    /// lots of flickering where two objects overlap, you either need to bring your far clip in, or switch to 32/24 bit
132    /// depth.
133    Depth16 = 18,
134    /// A double channel of data that supports 8 bits for the red channel and 8 bits for the green channel.
135    R8G8 = 19,
136}
137
138/// How does the shader grab pixels from the texture? Or more
139/// specifically, how does the shader grab colors between the provided
140/// pixels? If you'd like an in-depth explanation of these topics, check
141/// out [this exploration of texture filtering]
142/// <https://medium.com/@bgolus/sharper-mipmapping-using-shader-based-supersampling-ed7aadb47bec>
143/// by graphics wizard Ben Golus.
144/// <https://stereokit.net/Pages/StereoKit/TexSample.html>
145///
146/// see also [`Tex`]
147#[derive(Debug, Clone, Copy, PartialEq, Eq)]
148#[repr(u32)]
149pub enum TexSample {
150    /// Use a linear blend between adjacent pixels, this creates a smooth, blurry look when texture resolution is too
151    /// low.
152    Linear = 0,
153    /// Choose the nearest pixel's color! This makes your texture look like pixel art if you're too close.
154    Point = 1,
155    /// This helps reduce texture blurriness when a surface is viewed at an extreme angle!
156    Anisotropic = 2,
157}
158
159/// What happens when the shader asks for a texture coordinate
160/// that's outside the texture?? Believe it or not, this happens plenty
161/// often!
162///<https://stereokit.net/Pages/StereoKit/TexAddress.html>
163///
164/// see also [`Tex`]
165#[derive(Debug, Clone, Copy, PartialEq, Eq)]
166#[repr(u32)]
167pub enum TexAddress {
168    /// Wrap the UV coordinate around to the other side of the texture! This is basically like a looping texture, and
169    /// is an excellent default. If you can see weird bits of color at the edges of your texture, this may be due to
170    /// Wrap blending the color with the other side of the texture, Clamp may be better in such cases.
171    Wrap = 0,
172    /// Clamp the UV coordinates to the edge of the texture! This'll create color streaks that continue to forever. This
173    /// is actually really great for non-looping textures that you know will always be accessed on the 0-1 range.
174    Clamp = 1,
175    /// Like Wrap, but it reflects the image each time! Who needs this? I'm not sure!! But the graphics card can do it,
176    /// so now you can too!
177    Mirror = 2,
178}
179
180/// This is the texture asset class! This encapsulates 2D images, texture arrays, cubemaps, and rendertargets! It can
181/// load any image format that stb_image can, (jpg, png, tga, bmp, psd, gif, hdr, pic, ktx2) plus more later on, and you
182/// can also create textures procedurally.
183/// <https://stereokit.net/Pages/StereoKit/Tex.html>
184///
185/// ### Examples
186/// ```
187/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
188/// use stereokit_rust::{maths::{Vec3, Matrix, Quat}, util::{named_colors,Color32},
189///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
190///
191/// let tex_left = Tex::from_file("textures/open_gltf.jpeg", true, None)
192///                    .expect("tex_left should be created");
193///
194/// let mut tex_right = Tex::gen_color(named_colors::RED, 1, 1, TexType::Image, TexFormat::RGBA32);
195///
196/// let mut tex_back = Tex::gen_particle(128, 128, 0.2, None);
197///
198/// let mut tex_floor = Tex::new(TexType::Image, TexFormat::RGBA32, None);
199///
200/// let plane_mesh = Mesh::generate_plane_up([1.0,1.0], None, true);
201/// let material_left  = Material::pbr().tex_copy(tex_left);
202/// let material_right = Material::pbr().tex_copy(tex_right);
203/// let material_back  = Material::unlit_clip().tex_copy(tex_back);
204/// let material_floor = Material::pbr().tex_copy(tex_floor);
205///
206/// let transform_left  = Matrix::t_r([-0.5, 0.0, 0.0], [0.0, 0.0, 90.0]);
207/// let transform_right = Matrix::t_r([ 0.5, 0.0, 0.0], [0.0, 0.0,-90.0]);
208/// let transform_back  = Matrix::t_r([ 0.0, 0.0,-0.5], [90.0, 0.0, 0.0]);
209/// let transform_floor = Matrix::t(  [0.0, -0.5, 0.0]);
210///
211/// filename_scr = "screenshots/tex.jpeg";
212/// test_screenshot!( // !!!! Get a proper main loop !!!!
213///     plane_mesh.draw(token, &material_left,  transform_left,  None, None);
214///     plane_mesh.draw(token, &material_right, transform_right, None, None);
215///     plane_mesh.draw(token, &material_back,  transform_back,  None, None);
216///     plane_mesh.draw(token, &material_floor, transform_floor, None, None);
217/// );
218/// ```
219/// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/tex.jpeg" alt="screenshot" width="200">
220#[repr(C)]
221#[derive(Debug, PartialEq)]
222pub struct Tex(pub NonNull<_TexT>);
223
224impl Drop for Tex {
225    fn drop(&mut self) {
226        unsafe { tex_release(self.0.as_ptr()) };
227    }
228}
229
230impl AsRef<Tex> for Tex {
231    fn as_ref(&self) -> &Tex {
232        self
233    }
234}
235
236/// StereoKit internal type.
237#[repr(C)]
238#[derive(Debug)]
239pub struct _TexT {
240    _unused: [u8; 0],
241}
242
243/// StereoKit ffi type.
244pub type TexT = *mut _TexT;
245
246unsafe impl Send for Tex {}
247unsafe impl Sync for Tex {}
248
249unsafe extern "C" {
250    pub fn tex_find(id: *const c_char) -> TexT;
251    pub fn tex_create(type_: TexType, format: TexFormat) -> TexT;
252    pub fn tex_create_rendertarget(
253        width: i32,
254        height: i32,
255        msaa: i32,
256        color_format: TexFormat,
257        depth_format: TexFormat,
258    ) -> TexT;
259    pub fn tex_create_color32(in_arr_data: *mut Color32, width: i32, height: i32, srgb_data: Bool32T) -> TexT;
260    pub fn tex_create_color128(in_arr_data: *mut Color128, width: i32, height: i32, srgb_data: Bool32T) -> TexT;
261    pub fn tex_create_mem(data: *mut c_void, data_size: usize, srgb_data: Bool32T, load_priority: i32) -> TexT;
262    pub fn tex_create_file(file_utf8: *const c_char, srgb_data: Bool32T, load_priority: i32) -> TexT;
263    pub fn tex_create_file_arr(
264        in_arr_files: *mut *const c_char,
265        file_count: i32,
266        srgb_data: Bool32T,
267        load_priority: i32,
268    ) -> TexT;
269    pub fn tex_create_cubemap_file(cubemap_file: *const c_char, srgb_data: Bool32T, load_priority: i32) -> TexT;
270    pub fn tex_create_cubemap_files(
271        in_arr_cube_face_file_xxyyzz: *mut *const c_char,
272        srgb_data: Bool32T,
273        load_priority: i32,
274    ) -> TexT;
275    pub fn tex_copy(texture: TexT, type_: TexType, format: TexFormat) -> TexT;
276    pub fn tex_gen_mips(texture: TexT) -> Bool32T;
277    pub fn tex_set_id(texture: TexT, id: *const c_char);
278    pub fn tex_get_id(texture: TexT) -> *const c_char;
279    pub fn tex_set_fallback(texture: TexT, fallback: TexT);
280    pub fn tex_set_surface(
281        texture: TexT,
282        native_surface: *mut c_void,
283        type_: TexType,
284        native_fmt: i64,
285        width: i32,
286        height: i32,
287        surface_count: i32,
288        multisample: i32,
289        framebuffer_multisample: i32,
290        owned: Bool32T,
291    );
292    pub fn tex_get_surface(texture: TexT) -> *mut c_void;
293    pub fn tex_addref(texture: TexT);
294    pub fn tex_release(texture: TexT);
295    pub fn tex_asset_state(texture: TexT) -> AssetState;
296    pub fn tex_on_load(
297        texture: TexT,
298        asset_on_load_callback: ::std::option::Option<unsafe extern "C" fn(texture: TexT, context: *mut c_void)>,
299        context: *mut c_void,
300    );
301    pub fn tex_on_load_remove(
302        texture: TexT,
303        asset_on_load_callback: ::std::option::Option<unsafe extern "C" fn(texture: TexT, context: *mut c_void)>,
304    );
305    pub fn tex_set_colors(texture: TexT, width: i32, height: i32, data: *mut c_void);
306    pub fn tex_set_color_arr(
307        texture: TexT,
308        width: i32,
309        height: i32,
310        data: *mut *mut c_void,
311        data_count: i32,
312        out_sh_lighting_info: *mut SphericalHarmonics,
313        multisample: i32,
314    );
315    pub fn tex_set_mem(
316        texture: TexT,
317        data: *mut c_void,
318        data_size: usize,
319        srgb_data: Bool32T,
320        blocking: Bool32T,
321        priority: i32,
322    );
323    pub fn tex_add_zbuffer(texture: TexT, format: TexFormat);
324    pub fn tex_set_zbuffer(texture: TexT, depth_texture: TexT);
325    pub fn tex_get_zbuffer(texture: TexT) -> TexT;
326    pub fn tex_get_data(texture: TexT, out_data: *mut c_void, out_data_size: usize, mip_level: i32);
327    pub fn tex_gen_color(color: Color128, width: i32, height: i32, type_: TexType, format: TexFormat) -> TexT;
328    pub fn tex_gen_particle(width: i32, height: i32, roundness: f32, gradient_linear: GradientT) -> TexT;
329    pub fn tex_gen_cubemap(
330        gradient: GradientT,
331        gradient_dir: Vec3,
332        resolution: i32,
333        out_sh_lighting_info: *mut SphericalHarmonics,
334    ) -> TexT;
335    pub fn tex_gen_cubemap_sh(
336        lookup: *const SphericalHarmonics,
337        face_size: i32,
338        light_spot_size_pct: f32,
339        light_spot_intensity: f32,
340    ) -> TexT;
341    pub fn tex_get_format(texture: TexT) -> TexFormat;
342    pub fn tex_get_width(texture: TexT) -> i32;
343    pub fn tex_get_height(texture: TexT) -> i32;
344    pub fn tex_set_sample(texture: TexT, sample: TexSample);
345    pub fn tex_get_sample(texture: TexT) -> TexSample;
346    pub fn tex_set_address(texture: TexT, address_mode: TexAddress);
347    pub fn tex_get_address(texture: TexT) -> TexAddress;
348    pub fn tex_set_anisotropy(texture: TexT, anisotropy_level: i32);
349    pub fn tex_get_anisotropy(texture: TexT) -> i32;
350    pub fn tex_get_mips(texture: TexT) -> i32;
351    pub fn tex_set_loading_fallback(loading_texture: TexT);
352    pub fn tex_set_error_fallback(error_texture: TexT);
353    pub fn tex_get_cubemap_lighting(cubemap_texture: TexT) -> SphericalHarmonics;
354}
355
356impl IAsset for Tex {
357    // fn id(&mut self, id: impl AsRef<str>) {
358    //     self.id(id);
359    // }
360
361    fn get_id(&self) -> &str {
362        self.get_id()
363    }
364}
365
366impl Default for Tex {
367    /// A Default texture may be asked when a Tex creation or find returned an error. [`Tex::error()`] is a good default
368    /// value.
369    fn default() -> Self {
370        Self::error()
371    }
372}
373
374impl Tex {
375    /// Sets up an empty texture container! Fill it with data using SetColors next! Creates a default unique asset Id.
376    /// <https://stereokit.net/Pages/StereoKit/Tex/Tex.html>
377    /// * `texture_type` - What type of texture is it? Just a 2D Image? A Cubemap? Should it have mip-maps?
378    /// * `format` - What information is the texture composed of? 32 bit colors, 64 bit colors, etc.
379    /// * `id` - A unique asset Id for this texture, this is used to find the texture later on, and to reference it.
380    ///   if
381    ///
382    /// see also [`tex_create`]
383    /// ### Examples
384    /// ```
385    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
386    /// use stereokit_rust::{maths::{Vec3, Matrix}, util::{named_colors, Color32, Color128},
387    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
388    ///
389    /// let plane_mesh = Mesh::generate_plane_up([1.0,1.0], None, true);
390    ///
391    /// let mut color_dots = [named_colors::CYAN; 128 * 128];
392    /// let mut tex_left = Tex::new(TexType::Image, TexFormat::RGBA32, Some("tex_left_ID"));
393    /// tex_left.set_colors32(128, 128, &color_dots);
394    ///
395    /// let mut color_dots = [Color128::new(0.5, 0.75, 0.25, 1.0); 128 * 128];
396    /// let mut tex_right = Tex::new(TexType::Image, TexFormat::RGBA128, None);
397    /// tex_right.set_colors128(128, 128, &color_dots);
398    ///
399    /// let material_left  = Material::pbr().tex_copy(tex_left);
400    /// let material_right = Material::pbr().tex_copy(tex_right);
401    ///
402    /// let transform_left  = Matrix::t_r([-0.5, 0.0, 0.0], [0.0,-45.0, 90.0]);
403    /// let transform_right = Matrix::t_r([ 0.5, 0.0, 0.0], [0.0, 45.0,-90.0]);
404    ///
405    /// test_steps!( // !!!! Get a proper main loop !!!!
406    ///     plane_mesh.draw(token, &material_left,  transform_left,  None, None);
407    ///     plane_mesh.draw(token, &material_right, transform_right, None, None);
408    /// );
409    /// ```
410    pub fn new(texture_type: TexType, format: TexFormat, id: Option<&str>) -> Tex {
411        let tex = Tex(NonNull::new(unsafe { tex_create(texture_type, format) }).unwrap());
412        if let Some(id) = id {
413            let c_str = CString::new(id).unwrap();
414            unsafe { tex_set_id(tex.0.as_ptr(), c_str.as_ptr()) };
415        }
416        tex
417    }
418
419    /// Loads an image file stored in memory directly into a texture! Supported formats are: jpg, png, tga, bmp, psd,
420    /// gif, hdr, pic, ktx2.
421    /// Asset Id will be the same as the filename.
422    /// <https://stereokit.net/Pages/StereoKit/Tex/FromMemory.html>
423    /// * `data` - The binary data of an image file, this is NOT a raw RGB color array!
424    /// * `srgb_data` - Is this image color data in sRGB format, or is it normal/metal/rough/data that’s not for direct
425    ///   display? sRGB colors get converted to linear color space on the graphics card, so getting this right can have
426    ///   a big impact on visuals.
427    /// * `priority` - The priority sort order for this asset in the async loading system. Lower values mean loading
428    ///   sooner. If None will be set to 10
429    ///
430    /// see also [`tex_create_mem`]
431    /// ### Examples
432    /// ```
433    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
434    /// use stereokit_rust::{maths::{Vec3, Matrix},
435    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
436    ///
437    /// let plane_mesh = Mesh::generate_plane_up([1.0,1.0], None, true);
438    ///
439    /// let left_data  = std::include_bytes!("../assets/textures/open_gltf.jpeg");
440    /// let right_data = std::include_bytes!("../assets/textures/log_viewer.jpeg");
441    ///
442    /// let tex_left  = Tex::from_memory(left_data, true, None)
443    ///                          .expect("open_gltf.jpeg should be loaded");
444    /// let tex_right = Tex::from_memory(right_data, true, None)
445    ///                          .expect("open_gltf.jpeg should be loaded");
446    ///
447    /// let material_left  = Material::pbr().tex_copy(tex_left);
448    /// let material_right = Material::pbr().tex_copy(tex_right);
449    ///
450    /// let transform_left  = Matrix::t_r([-0.5, 0.0, 0.0], [0.0,-45.0, 90.0]);
451    /// let transform_right = Matrix::t_r([ 0.5, 0.0, 0.0], [0.0, 45.0,-90.0]);
452    ///
453    /// test_steps!( // !!!! Get a proper main loop !!!!
454    ///     plane_mesh.draw(token, &material_left,  transform_left,  None, None);
455    ///     plane_mesh.draw(token, &material_right, transform_right, None, None);
456    /// );
457    /// ```
458    pub fn from_memory(data: &[u8], srgb_data: bool, priority: Option<i32>) -> Result<Tex, StereoKitError> {
459        let priority = priority.unwrap_or(10);
460        Ok(Tex(NonNull::new(unsafe {
461            tex_create_mem(data.as_ptr() as *mut c_void, data.len(), srgb_data as Bool32T, priority)
462        })
463        .ok_or(StereoKitError::TexMemory)?))
464    }
465
466    /// Loads an image file directly into a texture! Supported formats are: jpg, png, tga, bmp, psd, gif, hdr, pic, ktx2.
467    /// Asset Id will be the same as the filename.
468    /// <https://stereokit.net/Pages/StereoKit/Tex/FromFile.html>
469    /// * `file_utf8` - An absolute filename, or a filename relative to the assets folder. Supports jpg, png, tga, bmp,
470    ///   psd, gif, hdr, pic, ktx2.
471    /// * `srgb_data` - Is this image color data in sRGB format, or is it normal/metal/rough/data that’s not for direct
472    ///   display? sRGB colors get converted to linear color space on the graphics card, so getting this right can have
473    ///   a big impact on visuals.
474    /// * `priority` - The priority sort order for this asset in the async loading system. Lower values mean loading
475    ///   sooner. If None will be set to 10
476    ///
477    /// see also [`tex_create_file`] [`Tex::get_asset_state`] [`crate::material::Material::tex_file_copy`]
478    /// ### Examples
479    /// ```
480    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
481    /// use stereokit_rust::{maths::{Vec3, Matrix}, system::AssetState,
482    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
483    ///
484    /// let plane_mesh = Mesh::generate_plane_up([1.0,1.0], None, true);
485    ///
486    /// let tex_left  = Tex::from_file("textures/open_gltf.jpeg", true, Some(9999))
487    ///                          .expect("tex_left should be created");
488    /// let tex_right = Tex::from_file("textures/log_viewer.jpeg", true, Some(9999))
489    ///                          .expect("tex_right should be created");
490    /// let tex_floor = Tex::from_file("not a file so we'll have error tex", true, Some(9999))
491    ///                          .expect("tex_error should be loaded");
492    ///
493    /// let material_left  = Material::pbr().tex_copy(&tex_left);
494    /// let material_right = Material::pbr().tex_copy(&tex_right);
495    /// let material_floor = Material::pbr().tex_copy(&tex_floor);
496    ///
497    /// let transform_left  = Matrix::t_r([-0.5, 0.0, 0.0], [0.0,-45.0, 90.0]);
498    /// let transform_right = Matrix::t_r([ 0.5, 0.0, 0.0], [0.0, 45.0,-90.0]);
499    /// let transform_floor = Matrix::t(  [0.0, -0.5, 0.0]);
500    ///
501    /// filename_scr = "screenshots/tex_from_file.jpeg";
502    /// test_screenshot!( // !!!! Get a proper main loop !!!!
503    ///
504    ///     // We ensure to have the Tex loaded for the screenshot.
505    ///     if    tex_left.get_asset_state()  != AssetState::Loaded
506    ///        || tex_right.get_asset_state() != AssetState::Loaded { iter -= 1; }
507    ///
508    ///     plane_mesh.draw(token, &material_left,  transform_left,  None, None);
509    ///     plane_mesh.draw(token, &material_right, transform_right, None, None);
510    ///     plane_mesh.draw(token, &material_floor, transform_floor, None, None);
511    /// );
512    /// assert_eq!(tex_left.get_asset_state(),  AssetState::Loaded);
513    /// assert_eq!(tex_right.get_asset_state(), AssetState::Loaded);
514    /// assert_eq!(tex_floor.get_asset_state(), AssetState::NotFound);
515    /// ```
516    /// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/tex_from_file.jpeg" alt="screenshot" width="200">
517    pub fn from_file(
518        file_utf8: impl AsRef<Path>,
519        srgb_data: bool,
520        priority: Option<i32>,
521    ) -> Result<Tex, StereoKitError> {
522        let priority = priority.unwrap_or(10);
523        let path_buf = file_utf8.as_ref().to_path_buf();
524        let c_str = CString::new(
525            path_buf
526                .clone()
527                .to_str()
528                .ok_or(StereoKitError::TexFile(path_buf.clone(), "CString conversion".to_string()))?,
529        )?;
530        Ok(Tex(NonNull::new(unsafe { tex_create_file(c_str.as_ptr(), srgb_data as Bool32T, priority) })
531            .ok_or(StereoKitError::TexFile(path_buf, "tex_create failed".to_string()))?))
532    }
533
534    /// Loads an array of image files directly into a single array texture! Array textures are often useful for shader
535    /// effects, layering, material merging, weird stuff, and will generally need a specific shader to support it.
536    /// Supported formats are: jpg, png, tga, bmp, psd, gif, hdr, pic, ktx2. Asset Id will be the hash of all the
537    /// filenames merged consecutively.
538    /// <https://stereokit.net/Pages/StereoKit/Tex/FromFiles.html>
539    /// * `files_utf8` - An absolute filenames, or filenames relative to the assets folder. Supports jpg, png, tga, bmp,
540    ///   psd, gif, hdr, pic, ktx2.
541    /// * `srgb_data` - Is this image color data in sRGB format, or is it normal/metal/rough/data that’s not for direct
542    ///   display? sRGB colors get converted to linear color space on the graphics card, so getting this right can have
543    ///   a big impact on visuals.
544    /// * `priority` - The priority sort order for this asset in the async loading system. Lower values mean loading
545    ///   sooner. If None will be set to 10    
546    ///
547    /// see also [`tex_create_file`]
548    /// ### Examples
549    /// ```
550    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
551    /// use stereokit_rust::{maths::{Vec3, Matrix},
552    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
553    ///
554    /// let plane_mesh = Mesh::generate_plane_up([1.0,1.0], None, true);
555    ///
556    /// let tex  = Tex::from_files(&["textures/open_gltf.jpeg",
557    ///                                   "textures/log_viewer.jpeg"], true, Some(100))
558    ///                    .expect("tex should be created");
559    ///
560    /// let material  = Material::pbr().tex_copy(tex);
561    ///
562    /// let transform  = Matrix::t_r([-0.5, 0.0, 0.0], [0.0, -45.0, 90.0]);
563    ///
564    /// test_steps!( // !!!! Get a proper main loop !!!!
565    ///     plane_mesh.draw(token, &material,  transform,  None, None);
566    /// );
567    /// ```
568    pub fn from_files<P: AsRef<Path>>(
569        files_utf8: &[P],
570        srgb_data: bool,
571        priority: Option<i32>,
572    ) -> Result<Tex, StereoKitError> {
573        let priority = priority.unwrap_or(10);
574        let mut c_files = Vec::new();
575        for path in files_utf8 {
576            let path = path.as_ref();
577            let path_buf = path.to_path_buf();
578            let c_str =
579                CString::new(path.to_str().ok_or(StereoKitError::TexCString(path_buf.to_str().unwrap().to_owned()))?)?;
580            c_files.push(c_str);
581        }
582        let mut c_files_ptr = Vec::new();
583        for str in c_files.iter() {
584            c_files_ptr.push(str.as_ptr());
585        }
586        let in_arr_files_cstr = c_files_ptr.as_mut_slice().as_mut_ptr();
587        let tex = Tex(NonNull::new(unsafe {
588            tex_create_file_arr(in_arr_files_cstr, files_utf8.len() as i32, srgb_data as Bool32T, priority)
589        })
590        .ok_or(StereoKitError::TexFile(
591            PathBuf::from(r"one_of_many_files"),
592            "tex_create_file_arr failed".to_string(),
593        ))?);
594        Ok(tex)
595    }
596
597    /// Creates a texture and sets the texture’s pixels using a color array! This will be an image of type TexType.Image,
598    /// and a format of TexFormat.Rgba32 or TexFormat.Rgba32Linear depending on the value of the sRGBData parameter.
599    /// <https://stereokit.net/Pages/StereoKit/Tex/FromColors.html>
600    /// * `colors` - An array of 32 bit colors, should be a length of width*height.
601    /// * `width` - Width in pixels of the texture. Powers of two are generally best!
602    /// * `height` - Height in pixels of the texture. Powers of two are generally best!
603    /// * `srgb_data` - s this image color data in sRGB format, or is it normal/metal/rough/data that’s not for direct
604    ///   display? sRGB colors get converted to linear color space on the graphics card, so getting this right can have
605    ///   a big impact on visuals.
606    ///
607    /// see also [`tex_create_color32`] [`Tex::gen_color`]
608    /// ### Examples
609    /// ```
610    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
611    /// use stereokit_rust::{maths::{Vec3, Matrix}, util::{named_colors, Color32},
612    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
613    ///
614    /// let plane_mesh = Mesh::generate_plane_up([1.0,1.0], None, true);
615    ///
616    /// let color_dots = [named_colors::RED; 128 * 128];
617    /// let tex = Tex::from_color32(&color_dots, 128, 128, true)
618    ///                            .expect("Tex should be created");
619    ///
620    /// let material  = Material::pbr().tex_copy(tex);
621    ///
622    /// let transform  = Matrix::t_r([-0.5, 0.0, 0.0], [0.0, -45.0, 90.0]);
623    ///
624    /// test_steps!( // !!!! Get a proper main loop !!!!
625    ///     plane_mesh.draw(token, &material,  transform,  None, None);
626    /// );
627    /// ```
628    pub fn from_color32(
629        colors: &[Color32],
630        width: usize,
631        height: usize,
632        srgb_data: bool,
633    ) -> Result<Tex, StereoKitError> {
634        if width * height != { colors }.len() {
635            return Err(StereoKitError::TexColor(
636                format!("{}x{} differ from {}", height, width, { colors }.len()),
637                "tex_create_color32 failed".to_string(),
638            ));
639        }
640        Ok(Tex(NonNull::new(unsafe {
641            tex_create_color32(colors.as_ptr() as *mut Color32, width as i32, height as i32, srgb_data as i32)
642        })
643        .ok_or(StereoKitError::TexColor(
644            format!("{height}x{width}"),
645            "tex_create_color32 failed".to_string(),
646        ))?))
647    }
648
649    /// Creates a texture and sets the texture’s pixels using a color array! Color values are converted to 32 bit colors,
650    /// so this means a memory allocation and conversion. Prefer the Color32 overload for performance, or create an empty
651    /// Texture and use SetColors for more flexibility. This will be an image of type TexType.Image, and a format of
652    /// TexFormat. Rgba32 or TexFormat.Rgba32Linear depending on the value of the sRGBData parameter.
653    /// <https://stereokit.net/Pages/StereoKit/Tex/FromColors.html>
654    /// * `colors` - An array of 128 bit colors, should be a length of width*height.
655    /// * `width` - Width in pixels of the texture. Powers of two are generally best!
656    /// * `height` - Height in pixels of the texture. Powers of two are generally best!
657    /// * `srgb_data` - s this image color data in sRGB format, or is it normal/metal/rough/data that’s not for direct
658    ///   display? sRGB colors get converted to linear color space on the graphics card, so getting this right can have
659    ///   a big impact on visuals.
660    ///
661    /// Important: The color conversion from 128 to 32 may crash if the data do not contains color128.
662    ///
663    /// see also [`tex_create_color128`] [`Tex::gen_color()`]
664    /// ### Examples
665    /// ```
666    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
667    /// use stereokit_rust::{maths::{Vec3, Matrix}, util::{named_colors, Color128},
668    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
669    ///
670    /// let plane_mesh = Mesh::generate_plane_up([1.0,1.0], None, true);
671    ///
672    /// let color_dots = [Color128::new(0.1, 0.2, 0.5, 1.0); 128 * 128];
673    /// let tex = Tex::from_color128(&color_dots, 128, 128, true)
674    ///                            .expect("Tex should be created");
675    ///
676    /// let material  = Material::pbr().tex_copy(tex);
677    ///
678    /// let transform  = Matrix::t_r([-0.5, 0.0, 0.0], [0.0, -45.0, 90.0]);
679    ///
680    /// test_steps!( // !!!! Get a proper main loop !!!!
681    ///     plane_mesh.draw(token, &material,  transform,  None, None);
682    /// );
683    /// ```
684    pub fn from_color128(
685        colors: &[Color128],
686        width: usize,
687        height: usize,
688        srgb_data: bool,
689    ) -> Result<Tex, StereoKitError> {
690        if width * height != { colors }.len() {
691            return Err(StereoKitError::TexColor(
692                format!("{}x{} differ from {}", height, width, { colors }.len()),
693                "tex_create_color128 failed".to_string(),
694            ));
695        }
696        Ok(Tex(NonNull::new(unsafe {
697            tex_create_color128(colors.as_ptr() as *mut Color128, width as i32, height as i32, srgb_data as i32)
698        })
699        .ok_or(StereoKitError::TexColor(
700            format!("{height}x{width}"),
701            "tex_create_color128 failed".to_string(),
702        ))?))
703    }
704
705    /// This will assemble a texture ready for rendering to! It creates a render target texture with no mip maps and a
706    /// depth buffer attached.
707    /// <https://stereokit.net/Pages/StereoKit/Tex/RenderTarget.html>
708    /// * `width` - in pixels
709    /// * `height` - in pixels
710    /// * `multisample` - Multisample level, or MSAA. This should be 1, 2, 4, 8, or 16. The results will have moother
711    ///   edges with higher values, but will cost more RAM and time to render. Note that GL platforms cannot trivially
712    ///   draw a multisample > 1 texture in a shader. If this is None, the default is 1.
713    /// * `color_format` - The format of the color surface. If this is None, the default is RGBA32.
714    /// * `depth_format` - The format of the depth buffer. If this is TexFormat::None, no depth buffer will be attached
715    ///   to this. If this is None, the default is Depth16.
716    ///   rendertarget.
717    ///
718    /// see also [`tex_create_rendertarget`]
719    ///
720    /// see also [`tex_get_data`]
721    /// ### Examples
722    /// ```
723    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
724    /// use stereokit_rust::{maths::{Vec3, Matrix}, util::{named_colors, Color32},
725    ///                      system::Renderer,
726    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
727    ///
728    /// let plane_mesh = Mesh::generate_plane_up([1.0,1.0], None, true);
729    ///
730    /// let tex = Tex::render_target(128, 128, Some(2), Some(TexFormat::RGBA32), None)
731    ///                            .expect("Tex should be created");
732    ///
733    /// let material  = Material::pbr().tex_copy(&tex);
734    ///
735    /// let transform  = Matrix::t_r([-0.5, 0.0, 0.0], [0.0, -45.0, 90.0]);
736    ///
737    /// Renderer::blit(&tex, &material);
738    /// ```
739    pub fn render_target(
740        width: usize,
741        height: usize,
742        multisample: Option<i32>,
743        color_format: Option<TexFormat>,
744        depth_format: Option<TexFormat>,
745    ) -> Result<Tex, StereoKitError> {
746        let multisample = multisample.unwrap_or(1);
747        let color_format = color_format.unwrap_or(TexFormat::RGBA32);
748        let depth_format = depth_format.unwrap_or(TexFormat::Depth16);
749        Ok(Tex(NonNull::new(unsafe {
750            tex_create_rendertarget(width as i32, height as i32, multisample, color_format, depth_format)
751        })
752        .ok_or(StereoKitError::TexRenderTarget(
753            format!("{height}x{width}"),
754            "tex_create_rendertarget failed".to_string(),
755        ))?))
756    }
757
758    /// This generates a solid color texture of the given dimensions. Can be quite nice for creating placeholder textures!
759    /// Make sure to match linear/gamma colors with the correct format.
760    /// <https://stereokit.net/Pages/StereoKit/Tex/GenColor.html>
761    /// * `color` - The color to use for the texture. This is interpreted slightly differently based on what TexFormat
762    ///   gets used.
763    /// * `width` - Width of the final texture, in pixels.
764    /// * `height` - Height of the final texture, in pixels.
765    /// * `tex_type` - Not all types here are applicable, but TexType.Image or TexType::ImageNomips are good options here.
766    /// * `format` - Not all formats are supported, but this does support a decent range. The provided color is
767    ///   interpreted slightly different depending on this format.
768    ///
769    /// see also [`tex_gen_color`]
770    /// ### Examples
771    /// ```
772    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
773    /// use stereokit_rust::{maths::{Vec3, Matrix}, util::{named_colors, Color128},
774    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
775    ///
776    /// let plane_mesh = Mesh::generate_plane_up([1.0,1.0], None, true);
777    ///
778    /// let tex_err = Tex::gen_color(named_colors::RED, 128, 128, TexType::Image, TexFormat::RGBA32);
779    /// Tex::set_error_fallback(&tex_err);
780    ///
781    /// let tex =  Tex::gen_color(Color128::new(0.1, 0.2, 0.5, 1.0), 128, 128, TexType::Image, TexFormat::RGBA128);
782    ///
783    /// let material  = Material::pbr().tex_copy(tex);
784    ///
785    /// let transform  = Matrix::t_r([-0.5, 0.0, 0.0], [0.0, -45.0, 90.0]);
786    ///
787    /// test_steps!( // !!!! Get a proper main loop !!!!
788    ///     plane_mesh.draw(token, &material,  transform,  None, None);
789    /// );
790    /// ```
791    pub fn gen_color(color: impl Into<Color128>, width: i32, height: i32, tex_type: TexType, format: TexFormat) -> Tex {
792        Tex(NonNull::new(unsafe { tex_gen_color(color.into(), width, height, tex_type, format) }).unwrap())
793    }
794
795    /// Generates a ‘radial’ gradient that works well for particles, blob shadows, glows, or various other things.
796    /// The roundness can be used to change the shape from round, ‘1’, to star-like, ‘0’. Default color is transparent white to opaque white,
797    /// but this can be configured by providing a Gradient of your own.
798    /// <https://stereokit.net/Pages/StereoKit/Tex/GenParticle.html>
799    /// * `width` - Width of the final texture, in pixels.
800    /// * `height` - Height of the final texture, in pixels.
801    /// * `gradient_linear` : A color gradient that starts with the background/outside at 0, and progresses to the center
802    ///   at 1. If None, will use a white gradient.
803    ///
804    /// see also [`tex_gen_particle`]
805    /// ### Examples
806    /// ```
807    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
808    /// use stereokit_rust::{maths::{Vec3, Matrix, Quat},
809    ///                      util::{named_colors, Gradient, GradientKey, Color128},
810    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
811    ///
812    /// let mut keys = [
813    ///     GradientKey::new(Color128::BLACK_TRANSPARENT, 0.0),
814    ///     GradientKey::new(named_colors::RED, 0.1),
815    ///     GradientKey::new(named_colors::CYAN, 0.4),
816    ///     GradientKey::new(named_colors::YELLOW, 0.5),
817    ///     GradientKey::new(Color128::BLACK, 0.7)];
818    ///
819    /// let tex_back  = Tex::gen_particle(128, 128, 0.15, Some(Gradient::new(Some(&keys))));
820    /// let tex_floor = Tex::gen_particle(128, 128, 0.3, Some(Gradient::new(Some(&keys))));
821    /// let tex_right = Tex::gen_particle(128, 128, 0.6, Some(Gradient::new(Some(&keys))));
822    /// let tex_left  = Tex::gen_particle(128, 128, 0.9, Some(Gradient::new(Some(&keys))));
823    ///
824    /// let plane_mesh = Mesh::generate_plane_up([1.0,1.0], None, true);
825    /// let material_left  = Material::unlit_clip().tex_copy(tex_left);
826    /// let material_right = Material::unlit_clip().tex_copy(tex_right);
827    /// let material_back  = Material::unlit_clip().tex_copy(tex_back);
828    /// let material_floor = Material::unlit_clip().tex_copy(tex_floor);
829    ///
830    /// let transform_left  = Matrix::t_r([-0.5, 0.0, 0.0], [0.0, 0.0, 90.0]);
831    /// let transform_right = Matrix::t_r([ 0.5, 0.0, 0.0], [0.0, 0.0, -90.0]);
832    /// let transform_back  = Matrix::t_r([ 0.0, 0.0,-0.5], [90.0, 0.0, 0.0]);
833    /// let transform_floor = Matrix::t(  [0.0, -0.5, 0.0]);
834    ///
835    /// filename_scr = "screenshots/tex_gen_particle.jpeg";
836    /// test_screenshot!( // !!!! Get a proper main loop !!!!
837    ///     plane_mesh.draw(token, &material_left,  transform_left,  None, None);
838    ///     plane_mesh.draw(token, &material_right, transform_right, None, None);
839    ///     plane_mesh.draw(token, &material_back,  transform_back,  None, None);
840    ///     plane_mesh.draw(token, &material_floor, transform_floor, None, None);
841    /// );
842    /// ```
843    /// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/tex_gen_particle.jpeg" alt="screenshot" width="200">
844    pub fn gen_particle(width: i32, height: i32, roundness: f32, gradient_linear: Option<Gradient>) -> Tex {
845        let gradient_linear = match gradient_linear {
846            Some(gl) => gl,
847            None => {
848                let keys: [GradientKey; 2] = [
849                    GradientKey { color: [1.0, 1.0, 1.0, 0.0].into(), position: 0.0 },
850                    GradientKey { color: Color128::WHITE, position: 1.0 },
851                ];
852                Gradient::new(Some(&keys))
853            }
854        };
855        Tex(NonNull::new(unsafe { tex_gen_particle(width, height, roundness, gradient_linear.0.as_ptr()) }).unwrap())
856    }
857
858    /// This is the texture that all Tex objects will fall back to by default if they are still loading. Assigning a
859    /// texture here that isn’t fully loaded will cause the app to block until it is loaded.
860    /// <https://stereokit.net/Pages/StereoKit/Tex/SetLoadingFallback.html>
861    ///
862    /// see also [`tex_set_loading_fallback`]
863    /// ### Examples
864    /// ```
865    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
866    /// use stereokit_rust::{maths::{Vec3, Matrix}, util::{named_colors, Color128},
867    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
868    ///
869    /// let tex_loading = Tex::gen_color(named_colors::GREEN, 128, 128, TexType::Image, TexFormat::RGBA32);
870    /// Tex::set_loading_fallback(&tex_loading);
871    ///
872    /// let tex = Tex::new(TexType::Image, TexFormat::RGBA32, None);
873    /// let material  = Material::pbr().tex_copy(tex);
874    /// let plane_mesh = Mesh::generate_plane_up([1.0,1.0], None, true);
875    /// let transform_floor = Matrix::t(  [0.0, -0.5, 0.0]);
876    ///
877    /// test_steps!( // !!!! Get a proper main loop !!!!
878    ///     plane_mesh.draw(token, &material,  transform_floor,  None, None);
879    /// );
880    /// ```
881    pub fn set_loading_fallback<T: AsRef<Tex>>(fallback: T) {
882        unsafe { tex_set_loading_fallback(fallback.as_ref().0.as_ptr()) };
883    }
884
885    /// This is the texture that all Tex objects with errors will fall back to. Assigning a texture here that isn’t
886    /// fully loaded will cause the app to block until it is loaded.
887    /// <https://stereokit.net/Pages/StereoKit/Tex/SetErrorFallback.html>
888    ///
889    /// see also [`tex_set_error_fallback`]
890    /// ### Examples
891    /// ```
892    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
893    /// use stereokit_rust::{maths::{Vec3, Matrix}, util::{named_colors, Color128},
894    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
895    ///
896    /// let tex_err = Tex::gen_color(named_colors::RED, 128, 128, TexType::Image, TexFormat::RGBA32);
897    /// Tex::set_error_fallback(&tex_err);
898    ///
899    /// let tex = Tex::from_file("file that doesn't exist", true, None)
900    ///                    .expect("tex should be created");
901    /// let material  = Material::pbr().tex_copy(tex);
902    /// let plane_mesh = Mesh::generate_plane_up([1.0,1.0], None, true);
903    /// let transform_floor = Matrix::t(  [0.0, -0.5, 0.0]);
904    ///
905    /// test_steps!( // !!!! Get a proper main loop !!!!
906    ///     plane_mesh.draw(token, &material,  transform_floor,  None, None);
907    /// );
908    /// ```
909    pub fn set_error_fallback<T: AsRef<Tex>>(fallback: T) {
910        unsafe { tex_set_error_fallback(fallback.as_ref().0.as_ptr()) };
911    }
912
913    /// Looks for a Material asset that’s already loaded, matching the given id!
914    /// <https://stereokit.net/Pages/StereoKit/Tex/Find.html>
915    /// * `id` - The id of the texture to find.
916    ///
917    /// see also [`tex_find`]
918    /// ### Examples
919    /// ```
920    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
921    /// use stereokit_rust::{maths::{Vec3, Matrix}, util::{named_colors, Color128},
922    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
923    ///
924    /// let mut tex_blue = Tex::gen_color(named_colors::BLUE, 1, 1, TexType::Image, TexFormat::RGBA32);
925    /// assert!(tex_blue.get_id().starts_with("auto/tex_"));
926    /// tex_blue.id("my_tex_blue");
927    /// let same_tex_blue = Tex::find("my_tex_blue").expect("my_tex_blue should be found");
928    /// assert_eq!(tex_blue, same_tex_blue);
929    ///
930    /// let tex = Tex::from_file("textures/open_gltf.jpeg", true, None)
931    ///                    .expect("tex should be created");
932    /// assert_eq!(tex.get_id(), "textures/open_gltf.jpeg");
933    /// let same_tex = Tex::find("textures/open_gltf.jpeg")
934    ///                    .expect("same_tex should be found");
935    /// assert_eq!(tex, same_tex);
936    /// ```
937    pub fn find<S: AsRef<str>>(id: S) -> Result<Tex, StereoKitError> {
938        let c_str = CString::new(id.as_ref()).map_err(|_| StereoKitError::TexCString(id.as_ref().into()))?;
939        Ok(Tex(
940            NonNull::new(unsafe { tex_find(c_str.as_ptr()) }).ok_or(StereoKitError::TexFind(id.as_ref().into()))?
941        ))
942    }
943
944    /// Get a copy of the texture
945    /// <https://stereokit.net/Pages/StereoKit/Tex.html>
946    /// * `tex_type` - Type of the copy. If None has default value of TexType::Image.
947    /// * `tex_format` - Format of the copy - If None has default value of TexFormat::None.
948    ///
949    /// see also [`tex_copy`]
950    /// ### Examples
951    /// ```
952    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
953    /// use stereokit_rust::{maths::{Vec3, Matrix}, util::{Color32, Color128},
954    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
955    ///
956    ///
957    /// let tex_blue = Tex::gen_color(Color32::new(64, 32, 255, 255), 1, 1,
958    ///                               TexType::Image, TexFormat::RGBA32Linear);
959    ///
960    /// let tex_copy = tex_blue.copy(None, Some(TexFormat::RGBA32))
961    ///                             .expect("copy should be done");
962    /// let mut color_data = [Color32::WHITE; 1];
963    /// assert!(tex_copy.get_color_data::<Color32>(&mut color_data, 0));
964    /// //TODO: windows assert_eq!(color_data[0], Color32 { r: 64, g: 32, b: 255, a: 255 });
965    /// //TODO: linux   assert_eq!(color_data[0], Color32 { r: 137, g: 99, b: 255, a: 255 });
966    ///
967    /// let tex_copy = tex_blue.copy(Some(TexType::Image), Some(TexFormat::RGBA128))
968    ///                             .expect("copy should be done");
969    /// let mut color_data = [Color128::WHITE; 1];
970    /// assert!(tex_copy.get_color_data::<Color128>(&mut color_data, 0));
971    /// //TODO: windows assert_eq!(color_data[0], Color128 { r: 0.0, g: 0.0, b: 0.0, a: 0.0 });
972    /// //TODO: linux   assert_eq!(color_data[0], Color128 { r: 0.2509804, g: 0.1254902, b: 1.0, a:1.0 });
973    /// ```
974    pub fn copy(&self, tex_type: Option<TexType>, tex_format: Option<TexFormat>) -> Result<Tex, StereoKitError> {
975        let type_ = tex_type.unwrap_or(TexType::Image);
976        let format = tex_format.unwrap_or(TexFormat::None);
977        Ok(Tex(NonNull::new(unsafe { tex_copy(self.0.as_ptr(), type_, format) })
978            .ok_or(StereoKitError::TexCopy(self.get_id().into()))?))
979    }
980
981    /// Creates a clone of the same reference. Basically, the new variable is the same asset. This is what you get by
982    /// calling find() method.
983    /// <https://stereokit.net/Pages/StereoKit/Tex/Find.html>
984    ///
985    /// see also [`tex_find()`]
986    /// ### Examples
987    /// ```
988    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
989    /// use stereokit_rust::{maths::{Vec3, Matrix}, util::{named_colors, Color128},
990    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
991    ///
992    /// let mut tex_blue = Tex::gen_color(named_colors::BLUE, 1, 1, TexType::Image, TexFormat::RGBA32);
993    /// assert!(tex_blue.get_id().starts_with("auto/tex_"));
994    /// let same_tex_blue = tex_blue.clone_ref();
995    /// assert_eq!(tex_blue, same_tex_blue);
996    ///
997    /// let tex = Tex::from_file("textures/open_gltf.jpeg", true, None)
998    ///                    .expect("tex should be created");
999    /// assert_eq!(tex.get_id(), "textures/open_gltf.jpeg");
1000    /// let same_tex = tex.clone_ref();
1001    /// assert_eq!(tex, same_tex);
1002    /// ```
1003    pub fn clone_ref(&self) -> Tex {
1004        Tex(NonNull::new(unsafe { tex_find(tex_get_id(self.0.as_ptr())) }).expect("<asset>::clone_ref failed!"))
1005    }
1006
1007    /// Set a new id to the texture.
1008    /// <https://stereokit.net/Pages/StereoKit/Tex/Id.html>
1009    ///
1010    /// see also [`tex_set_id`]
1011    /// ### Examples
1012    /// ```
1013    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1014    /// use stereokit_rust::{maths::{Vec3, Matrix}, util::{named_colors, Color128},
1015    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
1016    ///
1017    /// let mut tex_blue = Tex::gen_color(named_colors::BLUE, 1, 1, TexType::Image, TexFormat::RGBA32);
1018    /// assert!(tex_blue.get_id().starts_with("auto/tex_"));
1019    /// tex_blue.id("my_tex_blue");
1020    /// assert_eq!(tex_blue.get_id(), "my_tex_blue");
1021    ///
1022    /// let mut tex = Tex::from_file("textures/open_gltf.jpeg", true, None)
1023    ///                        .expect("tex should be created");
1024    /// assert_eq!(tex.get_id(), "textures/open_gltf.jpeg");
1025    /// tex_blue.id("my_tex_image");
1026    /// assert_eq!(tex_blue.get_id(), "my_tex_image");
1027    /// ```
1028    pub fn id<S: AsRef<str>>(&mut self, id: S) -> &mut Self {
1029        let c_str = CString::new(id.as_ref()).unwrap();
1030        unsafe { tex_set_id(self.0.as_ptr(), c_str.as_ptr()) };
1031        self
1032    }
1033
1034    /// Only applicable if this texture is a rendertarget! This creates and attaches a zbuffer surface to the texture
1035    /// for use when rendering to it.
1036    /// <https://stereokit.net/Pages/StereoKit/Tex/AddZBuffer.html>
1037    /// * `depth_format` - The format of the depth texture, must be a depth format type!
1038    ///
1039    /// see also [`tex_add_zbuffer`] [`Tex::set_zbuffer`]
1040    /// ### Examples
1041    /// ```
1042    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1043    /// use stereokit_rust::{maths::{Vec3, Matrix}, util::{named_colors, Color32},
1044    ///                      system::Renderer,
1045    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
1046    ///
1047    ///
1048    /// let mut tex = Tex::render_target(128, 128, Some(2), Some(TexFormat::RGBA32),
1049    ///                                  Some(TexFormat::None))
1050    ///                            .expect("Tex should be created");
1051    /// assert_eq!(tex.get_zbuffer(), None);
1052    ///
1053    /// tex.add_zbuffer(TexFormat::Depth16);
1054    /// assert_ne!(tex.get_zbuffer(), None);
1055    ///
1056    /// let plane_mesh = Mesh::generate_plane_up([1.0,1.0], None, true);
1057    /// let material  = Material::pbr().tex_copy(&tex);
1058    /// let transform  = Matrix::t_r([-0.5, 0.0, 0.0], [0.0, -45.0, 90.0]);
1059    ///
1060    /// Renderer::blit(&tex, &material);
1061    /// ```
1062    pub fn add_zbuffer(&mut self, depth_format: TexFormat) -> &mut Self {
1063        unsafe { tex_add_zbuffer(self.0.as_ptr(), depth_format) };
1064        self
1065    }
1066
1067    /// Loads an image file stored in memory directly into the created texture! Supported formats are: jpg, png, tga,
1068    /// bmp, psd, gif, hdr, pic, ktx2. This method introduces a blocking boolean parameter, which allows you to specify
1069    /// whether this method blocks until the image fully loads! The default case is to have it as part of the
1070    /// asynchronous asset pipeline, in which the Asset Id will
1071    /// be the same as the filename.
1072    /// <https://stereokit.net/Pages/StereoKit/Tex/SetMemory.html>
1073    /// * `data` - The binary data of an image file, this is NOT a raw RGB color array!
1074    /// * `srgb_data` - Is this image color data in sRGB format, or is it normal/metal/rough/data that’s not for direct
1075    ///   display? sRGB colors get converted to linear color space on the graphics card, so getting this right can have
1076    ///   a big impact on visuals.
1077    /// * `blocking` - Will this method wait for the image to load. By default, we try to load it asynchronously.
1078    /// * `priority` - The priority sort order for this asset in the async loading system. Lower values mean loading
1079    ///   sooner. If None will be set to 10
1080    ///
1081    /// see also [`tex_set_mem`] [`Tex::from_memory`]
1082    /// ### Examples
1083    /// ```
1084    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1085    /// use stereokit_rust::{maths::{Vec3, Matrix},
1086    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
1087    ///
1088    /// let image_data = std::include_bytes!("../assets/textures/open_gltf.jpeg");
1089    /// let mut tex = Tex::new(TexType::Image, TexFormat::RGBA32, None);
1090    ///
1091    /// tex.set_memory(image_data, true, false, Some(0));
1092    ///
1093    /// let plane_mesh = Mesh::generate_plane_up([1.0,1.0], None, true);
1094    /// let material  = Material::pbr().tex_copy(tex);
1095    /// let transform_floor = Matrix::t([0.0, -0.5, 0.0]);
1096    ///
1097    /// test_steps!( // !!!! Get a proper main loop !!!!
1098    ///     plane_mesh.draw(token, &material, transform_floor, None, None);
1099    /// );
1100    /// ```
1101    pub fn set_memory(&mut self, data: &[u8], srgb_data: bool, blocking: bool, priority: Option<i32>) -> &mut Self {
1102        let priority = priority.unwrap_or(10);
1103        unsafe {
1104            tex_set_mem(
1105                self.0.as_ptr(),
1106                data.as_ptr() as *mut c_void,
1107                data.len(),
1108                srgb_data as Bool32T,
1109                blocking as Bool32T,
1110                priority,
1111            )
1112        };
1113        self
1114    }
1115
1116    /// Set the texture’s pixels using a pointer to a chunk of memory! This is great if you’re pulling in some color
1117    /// data from native code, and don’t want to pay the cost of trying to marshal that data around.
1118    /// The data should contains width*height*(TextureFormat size) bytes.
1119    /// Warning: The check width*height*(TextureFormat size) upon the size of the data values must be done before
1120    /// calling this function.
1121    /// Warning: The color data type must be compliant with the format of the texture.
1122    /// <https://stereokit.net/Pages/StereoKit/Tex/SetColors.html>
1123    /// * `width` - Width in pixels of the texture. Powers of two are generally best!
1124    /// * `height` - Height in pixels of the texture. Powers of two are generally best!
1125    /// * `data` - A pointer to a chunk of memory containing color data! Should be widthheightsize_of_texture_format
1126    ///   bytes large. Color data should definitely match the format provided when constructing the texture!
1127    ///
1128    /// # Safety
1129    /// The data pointer must be a valid array for the size of the texture.
1130    ///
1131    /// see also [`tex_set_colors`]
1132    /// ### Examples
1133    /// ```
1134    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1135    /// use stereokit_rust::{maths::{Vec3, Matrix}, util::{named_colors, Color32},
1136    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
1137    ///
1138    /// let mut color_dots = [named_colors::CYAN; 16 * 16];
1139    /// let mut tex = Tex::new(TexType::Image, TexFormat::RGBA32, None);
1140    ///
1141    /// unsafe { tex.set_colors(16, 16, color_dots.as_mut_ptr() as *mut std::os::raw::c_void); }
1142    ///
1143    /// let check_dots = [Color32::WHITE; 16 * 16];
1144    /// assert!(tex.get_color_data::<Color32>(&check_dots, 0));
1145    /// assert_eq!(check_dots, color_dots);
1146    /// ```
1147    pub unsafe fn set_colors(&mut self, width: usize, height: usize, data: *mut std::os::raw::c_void) -> &mut Self {
1148        unsafe { tex_set_colors(self.0.as_ptr(), width as i32, height as i32, data) };
1149        self
1150    }
1151
1152    /// Set the texture’s pixels using a color array! This function should only be called on textures with a format of
1153    /// Rgba32 or Rgba32Linear. You can call this as many times as you’d like, even with different widths and heights.
1154    /// Calling this multiple times will mark it as dynamic on the graphics card. Calling this function can also result
1155    /// in building mip-maps, which has a non-zero cost: use TexType.ImageNomips when creating the Tex to avoid this.
1156    /// <https://stereokit.net/Pages/StereoKit/Tex/SetColors.html>
1157    /// * `width` - Width in pixels of the texture. Powers of two are generally best!
1158    /// * `height` - Height in pixels of the texture. Powers of two are generally best!
1159    /// * `data` - An array of 32 bit colors, should be a length of width*height.
1160    ///
1161    /// Warning, instead of [`Tex::set_colors`], this call may not be done if the asset is not loaded
1162    /// (see [`Tex::get_asset_state`]) or the size is inconsistent or the format is incompatible.
1163    ///
1164    /// see also [`tex_set_colors`]
1165    /// ### Examples
1166    /// ```
1167    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1168    /// use stereokit_rust::{maths::{Vec3, Matrix}, util::{named_colors, Color32},
1169    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
1170    ///
1171    /// let mut color_dots = [named_colors::CYAN; 16 * 16];
1172    /// let mut tex = Tex::new(TexType::Image, TexFormat::RGBA32, None);
1173    ///
1174    /// tex.set_colors32(16, 16, &color_dots);
1175    ///
1176    /// let check_dots = [Color32::WHITE; 16 * 16];
1177    /// assert!(tex.get_color_data::<Color32>(&check_dots, 0));
1178    /// assert_eq!(check_dots, color_dots);
1179    /// ```
1180    pub fn set_colors32(&mut self, width: usize, height: usize, data: &[Color32]) -> &mut Self {
1181        match self.get_format() {
1182            Some(TexFormat::RGBA32) => (),
1183            Some(TexFormat::RGBA32Linear) => (),
1184            Some(_) => {
1185                Log::err(format!(
1186                    "The format of the texture {} is not compatible with Tex::set_colors32",
1187                    self.get_id()
1188                ));
1189                return self;
1190            }
1191            None => {
1192                Log::err(format!("The texture {} is not loaded during Tex::set_colors32", self.get_id()));
1193                return self;
1194            }
1195        }
1196        if width * height != data.len() {
1197            Log::err(format!(
1198                "{}x{} differ from {} in Tex::set_color32 for texture {}",
1199                height,
1200                width,
1201                data.len(),
1202                self.get_id()
1203            ));
1204            return self;
1205        }
1206        unsafe {
1207            tex_set_colors(self.0.as_ptr(), width as i32, height as i32, data.as_ptr() as *mut std::os::raw::c_void)
1208        };
1209        self
1210    }
1211
1212    /// Set the texture’s pixels using a color array! This function should only be called on textures with a format of
1213    /// Rgba128. You can call this as many times as you’d like, even with different widths and heights. Calling this
1214    /// multiple times will mark it as dynamic on the graphics card.
1215    /// Calling this function can also result in building mip-maps, which has a non-zero cost: use TexType.ImageNomips
1216    /// when creating the Tex to avoid this.
1217    /// <https://stereokit.net/Pages/StereoKit/Tex/SetColors.html>
1218    /// * `width` - Width in pixels of the texture. Powers of two are generally best!
1219    /// * `height` - Height in pixels of the texture. Powers of two are generally best!
1220    /// * `data` - An array of 128 bit colors, should be a length of width*height.
1221    ///
1222    /// Warning, instead of [`Tex::set_colors`], this call may not be done if the asset is not loaded
1223    /// (see [`Tex::get_asset_state`]) or the size is inconsistent or the format is incompatible.
1224    ///
1225    /// see also [`tex_set_colors`]
1226    /// ### Examples
1227    /// ```
1228    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1229    /// use stereokit_rust::{maths::{Vec3, Matrix}, util::{named_colors, Color128},
1230    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
1231    ///
1232    /// let mut color_dots = [Color128{r: 0.25, g: 0.125, b: 1.0, a: 1.0}; 16 * 16];
1233    /// let mut tex = Tex::new(TexType::Image, TexFormat::RGBA128, None);
1234    ///
1235    /// tex.set_colors128(16, 16, &color_dots);
1236    ///
1237    /// let check_dots = [Color128::BLACK; 16 * 16];
1238    /// assert!(tex.get_color_data::<Color128>(&check_dots, 0));
1239    /// assert_eq!(check_dots, color_dots);
1240    /// ```
1241    pub fn set_colors128(&mut self, width: usize, height: usize, data: &[Color128]) -> &mut Self {
1242        match self.get_format() {
1243            Some(TexFormat::RGBA128) => (),
1244            Some(_) => {
1245                Log::err(format!(
1246                    "The format of the texture {} is not compatible with Tex::set_colors128",
1247                    self.get_id()
1248                ));
1249                return self;
1250            }
1251            None => {
1252                Log::err(format!("The texture {} is not loaded during Tex::set_colors128", self.get_id()));
1253                return self;
1254            }
1255        }
1256        if width * height != data.len() {
1257            Log::err(format!(
1258                "{}x{} differ from {} for Tex::set_color128 for texture {}",
1259                height,
1260                width,
1261                data.len(),
1262                self.get_id()
1263            ));
1264            return self;
1265        }
1266        unsafe {
1267            tex_set_colors(self.0.as_ptr(), width as i32, height as i32, data.as_ptr() as *mut std::os::raw::c_void)
1268        };
1269        self
1270    }
1271
1272    /// Set the texture’s pixels using a scalar array for channel R !  This function should only be called on textures
1273    /// with a format of R8. You can call this as many times as you’d like, even with different widths and heights.
1274    /// Calling this multiple times will mark it as dynamic on the graphics card. Calling this function can also result
1275    /// in building mip-maps, which has a non-zero cost: use TexType.ImageNomips when creating the Tex to avoid this.
1276    /// <https://stereokit.net/Pages/StereoKit/Tex/SetColors.html>
1277    /// * `width` - Width in pixels of the texture. Powers of two are generally best!
1278    /// * `height` - Height in pixels of the texture. Powers of two are generally best!
1279    /// * `data` - An array of 8 bit values, should be a length of width*height.
1280    ///
1281    /// Warning, instead of [`Tex::set_colors`], this call may not be done if the asset is not loaded
1282    /// (see [`Tex::get_asset_state`]) or the size is inconsistent or the format is incompatible.
1283    ///
1284    /// see also [`tex_set_colors`]
1285    /// ### Examples
1286    /// ```
1287    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1288    /// use stereokit_rust::{maths::{Vec3, Matrix},
1289    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
1290    ///
1291    /// let mut color_dots = [125u8; 16 * 16];
1292    /// let mut tex = Tex::new(TexType::Image, TexFormat::R8, None);
1293    ///
1294    /// tex.set_colors_r8(16, 16, &color_dots);
1295    ///
1296    /// let check_dots = [0u8; 16 * 16];
1297    /// assert!(tex.get_color_data::<u8>(&check_dots, 0));
1298    /// assert_eq!(check_dots, color_dots);
1299    /// ```
1300    pub fn set_colors_r8(&mut self, width: usize, height: usize, data: &[u8]) -> &mut Self {
1301        match self.get_format() {
1302            Some(TexFormat::R8) => (),
1303            Some(_) => {
1304                Log::err(format!(
1305                    "The format of the texture {} is not compatible with Tex::set_colors_r8",
1306                    self.get_id()
1307                ));
1308                return self;
1309            }
1310            None => {
1311                Log::err(format!("The texture {} is not loaded during Tex::set_colors_r8", self.get_id()));
1312                return self;
1313            }
1314        }
1315        if width * height != data.len() {
1316            Log::err(format!(
1317                "{}x{} differ from {} for Tex::set_color_r8 for texture {}",
1318                height,
1319                width,
1320                data.len(),
1321                self.get_id()
1322            ));
1323            return self;
1324        }
1325        unsafe {
1326            tex_set_colors(self.0.as_ptr(), width as i32, height as i32, data.as_ptr() as *mut std::os::raw::c_void)
1327        };
1328        self
1329    }
1330
1331    /// Non canonical function !!
1332    /// Set the texture’s pixels using an u8 array !  This function should only be called for all textures format
1333    /// with a format of R8. You can call this as many times as you’d like, even with different widths and heights.
1334    /// Calling this multiple times will mark it as dynamic on the graphics card. Calling this function can also result
1335    /// in building mip-maps, which has a non-zero cost: use TexType.ImageNomips when creating the Tex to avoid this.
1336    /// <https://stereokit.net/Pages/StereoKit/Tex/SetColors.html>
1337    /// * `width` - Width in pixels of the texture. Powers of two are generally best!
1338    /// * `height` - Height in pixels of the texture. Powers of two are generally best!
1339    /// * `data` - An array of 8 bit values, should be a length of width*height.
1340    /// * `color_size` - number of byte for a pixel used by the format of this texture
1341    ///
1342    /// Warning, instead of [`Tex::set_colors`], this call may not be done if the asset is not loaded
1343    /// (see [`Tex::get_asset_state`]) or the size is inconsistent or the format is incompatible.
1344    ///
1345    /// see also [`tex_set_colors`]
1346    /// ### Examples
1347    /// ```
1348    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1349    /// use stereokit_rust::{maths::{Vec3, Matrix}, util::{named_colors, Color32},
1350    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
1351    ///
1352    /// let mut color_dots = [127u8; 16 * 16 * 4];
1353    /// let mut tex = Tex::new(TexType::Image, TexFormat::RGBA32, None);
1354    ///
1355    /// tex.set_colors_u8(16, 16, &color_dots, 4);
1356    ///
1357    /// let check_dots = [Color32::BLACK; 16 * 16];
1358    /// assert!(tex.get_color_data::<Color32>(&check_dots, 0));
1359    /// assert_eq!(check_dots[0],Color32{r:127,g:127,b:127,a:127});
1360    /// ```
1361    pub fn set_colors_u8(&mut self, width: usize, height: usize, data: &[u8], color_size: usize) -> &mut Self {
1362        if width * height * color_size != data.len() {
1363            Log::err(format!(
1364                "{}x{}x{} differ from {} for Tex::set_color_u8 for texture {}",
1365                height,
1366                width,
1367                color_size,
1368                data.len(),
1369                self.get_id()
1370            ));
1371            return self;
1372        }
1373        unsafe {
1374            tex_set_colors(self.0.as_ptr(), width as i32, height as i32, data.as_ptr() as *mut std::os::raw::c_void)
1375        };
1376        self
1377    }
1378
1379    /// Set the texture’s pixels using a scalar array for channel R ! This function should only be called on textures
1380    /// with a format of R16u. You can call this as many times as you’d like, even with different widths and heights.
1381    /// Calling this multiple times will mark it as dynamic on the graphics card. Calling this function can also result
1382    /// in building mip-maps, which has a non-zero cost: use TexType.ImageNomips when creating the Tex to avoid this.
1383    /// <https://stereokit.net/Pages/StereoKit/Tex/SetColors.html>
1384    /// * `width` - Width in pixels of the texture. Powers of two are generally best!
1385    /// * `height` - Height in pixels of the texture. Powers of two are generally best!
1386    /// * `data` - An array of 16 bit values, should be a length of width*height.
1387    ///
1388    /// Warning, instead of [`Tex::set_colors`], this call may not be done if the asset is not loaded
1389    /// (see [`Tex::get_asset_state`]) or the size is inconsistent or the format is incompatible.
1390    ///
1391    /// see also [`tex_set_colors`]
1392    /// ### Examples
1393    /// ```
1394    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1395    /// use stereokit_rust::{maths::{Vec3, Matrix},
1396    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
1397    ///
1398    /// let mut color_dots = [256u16; 16 * 16];
1399    /// let mut tex = Tex::new(TexType::Image, TexFormat::R16u, None);
1400    ///
1401    /// tex.set_colors_r16(16, 16, &color_dots);
1402    ///
1403    /// let check_dots = [0u16; 16 * 16];
1404    /// assert!(tex.get_color_data::<u16>(&check_dots, 0));
1405    /// assert_eq!(check_dots, color_dots);
1406    /// ```
1407    pub fn set_colors_r16(&mut self, width: usize, height: usize, data: &[u16]) -> &mut Self {
1408        match self.get_format() {
1409            Some(TexFormat::R16u) => (),
1410            Some(_) => {
1411                Log::err(format!(
1412                    "The format of the texture {} is not compatible with Tex::set_colors_r16",
1413                    self.get_id()
1414                ));
1415                return self;
1416            }
1417            None => {
1418                Log::err(format!("The texture {} is not loaded during Tex::set_colors_r16", self.get_id()));
1419                return self;
1420            }
1421        }
1422        if width * height != data.len() {
1423            Log::err(format!(
1424                "{}x{} differ from {} for Tex::set_color_r16 for texture {}",
1425                height,
1426                width,
1427                data.len(),
1428                self.get_id()
1429            ));
1430            return self;
1431        }
1432        unsafe {
1433            tex_set_colors(self.0.as_ptr(), width as i32, height as i32, data.as_ptr() as *mut std::os::raw::c_void)
1434        };
1435        self
1436    }
1437
1438    /// Set the texture’s pixels using a scalar array! This function should only be called on textures with a format of
1439    /// R32. You can call this as many times as you’d like, even with different widths and heights. Calling this
1440    /// multiple times will mark it as dynamic on the graphics card. Calling this function can also result in building
1441    /// mip-maps, which has a non-zero cost: use TexType.ImageNomips when creating the Tex to avoid this.
1442    /// <https://stereokit.net/Pages/StereoKit/Tex/SetColors.html>
1443    /// * `width` - Width in pixels of the texture. Powers of two are generally best!
1444    /// * `height` - Height in pixels of the texture. Powers of two are generally best!
1445    /// * `data` - An array of 32 bit values, should be a length of width*height.
1446    ///
1447    /// Warning, instead of [`Tex::set_colors`], this call may not be done if the asset is not loaded
1448    /// (see [`Tex::get_asset_state`]) or the size is inconsistent or the format is incompatible.
1449    ///
1450    /// see also [`tex_set_colors`]
1451    /// ### Examples
1452    /// ```
1453    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1454    /// use stereokit_rust::{maths::{Vec3, Matrix},
1455    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
1456    ///
1457    /// let mut color_dots = [0.13f32; 16 * 16];
1458    /// let mut tex = Tex::new(TexType::Image, TexFormat::R32, None);
1459    ///
1460    /// tex.set_colors_r32(16, 16, &color_dots);
1461    ///
1462    /// let check_dots = [0.0f32; 16 * 16];
1463    /// assert!(tex.get_color_data::<f32>(&check_dots, 0));
1464    /// assert_eq!(check_dots, color_dots);
1465    /// ```
1466    pub fn set_colors_r32(&mut self, width: usize, height: usize, data: &[f32]) -> &mut Self {
1467        match self.get_format() {
1468            Some(TexFormat::R32) => (),
1469            Some(_) => {
1470                Log::err(format!(
1471                    "The format of the texture {} is not compatible with Tex::set_colors_r32",
1472                    self.get_id()
1473                ));
1474                return self;
1475            }
1476            None => {
1477                Log::err(format!("The texture {} is not loaded during Tex::set_colors_r32", self.get_id()));
1478                return self;
1479            }
1480        }
1481        if width * height != data.len() {
1482            Log::err(format!(
1483                "{}x{} differ from {} for Tex::set_color_r32 for texture {}",
1484                height,
1485                width,
1486                data.len(),
1487                self.get_id()
1488            ));
1489            return self;
1490        }
1491        unsafe {
1492            tex_set_colors(self.0.as_ptr(), width as i32, height as i32, data.as_ptr() as *mut std::os::raw::c_void)
1493        };
1494        self
1495    }
1496
1497    /// This allows you to attach a z/depth buffer from a rendertarget texture. This texture _must_ be a
1498    /// rendertarget to set this, and the zbuffer texture _must_ be a depth format (or null). For no-rendertarget
1499    /// textures, this will always be None.
1500    /// <https://stereokit.net/Pages/StereoKit/Tex/SetZBuffer.html>
1501    /// * `tex` - TODO: None may crash the program
1502    ///
1503    /// see also [`tex_set_zbuffer`] [`Tex::add_zbuffer`]
1504    /// ### Examples
1505    /// ```
1506    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1507    /// use stereokit_rust::{maths::{Vec3, Matrix}, util::{named_colors, Color32},
1508    ///                      system::Renderer,
1509    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
1510    ///
1511    ///
1512    /// let mut tex = Tex::render_target(128, 128, Some(2), Some(TexFormat::RGBA32),
1513    ///                                  Some(TexFormat::Depth16))
1514    ///                            .expect("Tex should be created");
1515    ///
1516    /// let zbuffer = tex.get_zbuffer().expect("Tex should have a zbuffer");
1517    ///
1518    /// let mut tex2 = Tex::render_target(128, 128, Some(2), Some(TexFormat::RGBA32),
1519    ///                                  Some(TexFormat::None))
1520    ///                            .expect("Tex2 should be created");
1521    /// tex2.set_zbuffer(Some(zbuffer));
1522    /// assert_ne!(tex2.get_zbuffer(), None);
1523    ///
1524    /// //tex2.set_zbuffer(None);
1525    /// //assert_eq!(tex2.get_zbuffer(), None);
1526    /// ```
1527    pub fn set_zbuffer(&mut self, tex: Option<Tex>) -> &mut Self {
1528        if let Some(tex) = tex {
1529            unsafe { tex_set_zbuffer(self.0.as_ptr(), tex.0.as_ptr()) }
1530        } else {
1531            unsafe { tex_set_zbuffer(self.0.as_ptr(), null_mut()) }
1532        }
1533        self
1534    }
1535
1536    /// This function is dependent on the graphics backend! It will take a texture resource for the current graphics
1537    /// backend (D3D or GL) and wrap it in a StereoKit texture for use within StereoKit. This is a bit of an advanced
1538    /// feature.
1539    /// # Safety
1540    /// native_surface must be a valid pointer to a texture resource for the current graphics backend.
1541    /// <https://stereokit.net/Pages/StereoKit/Tex/SetNativeSurface.html>
1542    /// * `native_surface` - For D3D, this should be an ID3D11Texture2D*, and for GL, this should be a uint32_t from a
1543    ///   glGenTexture call, coerced into the IntPtr.
1544    /// * `tex_type` - The image flags that tell SK how to treat the texture, this should match up with the settings the
1545    ///   texture was originally created with. If SK can figure the appropriate settings, it may override the value
1546    ///   provided here.
1547    /// * `native_fmt` - The texture’s format using the graphics backend’s value, not SK’s. This should match up with
1548    ///   the settings the texture was originally created with. If SK can figure the appropriate settings, it may
1549    ///   override the value provided here. 0 is a valide default value.
1550    /// * `width` - Width of the texture. This should match up with the settings the texture was originally created
1551    ///   with. If SK can figure the appropriate settings, it may override the value provided here. 0 is a valide default
1552    ///   value.
1553    /// * `height` - Height of the texture. This should match up with the settings the texture was originally created
1554    ///   with. If SK can figure the appropriate settings, it may override the value provided here. 0 is a valide default
1555    ///   value.
1556    /// * `surface_count` - Texture array surface count. This should match up with the settings the texture was
1557    ///   originally created with. If SK can figure the appropriate settings, it may override the value provided here.
1558    ///   1 is a valide default value.
1559    /// * `owned` - Should ownership of this texture resource be passed on to StereoKit? If so, StereoKit may delete
1560    ///   it when it’s finished with it. True is a valide default value, if this is not desired, pass in false.
1561    ///
1562    /// see also [`tex_set_surface`]
1563    /// ### Examples
1564    /// ```
1565    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1566    /// # use stereokit_rust::{tex::{Tex, TexFormat, TexType}};
1567    /// # use std::ptr::null_mut;
1568    ///
1569    /// let mut tex = Tex::new(TexType::Image, TexFormat::RGBA32, None);
1570    /// let native_surface = tex.get_native_surface();
1571    /// unsafe { tex.set_native_surface(native_surface, TexType::Image, 0, 1, 1, 1, false); }
1572    /// ```
1573    #[allow(clippy::too_many_arguments)]
1574    pub unsafe fn set_native_surface(
1575        &mut self,
1576        native_surface: *mut std::os::raw::c_void,
1577        tex_type: TexType,
1578        native_fmt: i64,
1579        width: i32,
1580        height: i32,
1581        surface_count: i32,
1582        owned: bool,
1583    ) -> &mut Self {
1584        unsafe {
1585            tex_set_surface(
1586                self.0.as_ptr(),
1587                native_surface,
1588                tex_type,
1589                native_fmt,
1590                width,
1591                height,
1592                surface_count,
1593                1,
1594                1,
1595                owned as Bool32T,
1596            )
1597        };
1598        self
1599    }
1600
1601    /// Set the texture’s size without providing any color data. In most cases, you should probably just call SetColors
1602    /// instead, but this can be useful if you’re adding color data some other way, such as when blitting or rendering
1603    /// to it.
1604    /// <https://stereokit.net/Pages/StereoKit/Tex/SetSize.html>
1605    ///
1606    /// see also [`tex_set_colors`]
1607    /// ### Examples
1608    /// ```
1609    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1610    /// use stereokit_rust::{maths::{Vec3, Matrix}, util::{named_colors, Color32},
1611    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
1612    ///
1613    /// let mut tex = Tex::new(TexType::Image, TexFormat::RGBA32, None);
1614    ///
1615    /// assert_eq!(tex.get_width(), Some(0));
1616    /// assert_eq!(tex.get_height(), Some(0));
1617    ///
1618    /// tex.set_size(16, 16);
1619    /// assert_eq!(tex.get_width(), Some(16));
1620    /// assert_eq!(tex.get_height(), Some(16));
1621    ///
1622    /// let check_dots = [Color32::BLACK; 16 * 16];
1623    /// assert!(tex.get_color_data::<Color32>(&check_dots, 0));
1624    /// ```
1625    pub fn set_size(&mut self, width: usize, height: usize) -> &mut Self {
1626        unsafe { tex_set_colors(self.0.as_ptr(), width as i32, height as i32, null_mut()) };
1627        self
1628    }
1629
1630    /// This will override the default fallback texture that gets used before the Tex has finished loading. This is
1631    /// useful for textures with a specific purpose where the normal fallback texture would appear strange, such as a
1632    /// metal/rough map.
1633    /// <https://stereokit.net/Pages/StereoKit/Tex/FallbackOverride.html>
1634    ///
1635    /// see also [`tex_set_fallback`] [`Tex::set_loading_fallback`]
1636    /// ### Examples
1637    /// ```
1638    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1639    /// use stereokit_rust::{maths::{Vec3, Matrix}, util::{named_colors, Color128},
1640    ///                      tex::{Tex, TexFormat, TexType}, mesh::Mesh, material::Material};
1641    ///
1642    /// let tex_fallback = Tex::gen_color(named_colors::VIOLET, 128, 128, TexType::Image, TexFormat::RGBA32);
1643    /// let mut tex = Tex::new(TexType::Image, TexFormat::RGBA32, None);
1644    /// tex.fallback_override(&tex_fallback);
1645    ///
1646    /// let tex = Tex::new(TexType::Image, TexFormat::RGBA32, Some("tex_left_ID"));
1647    /// let tex_metal = Tex::from_file("textures/parquet2/parquet2metal.ktx2", true, Some(9999))
1648    ///                          .expect("Metal tex should be created");
1649    /// let mut material  = Material::pbr().tex_copy(tex);
1650    /// material.metal_tex(&tex_metal);
1651    /// let plane_mesh = Mesh::generate_plane_up([1.0,1.0], None, true);
1652    /// let transform_floor = Matrix::t(  [0.0, -0.5, 0.0]);
1653    ///
1654    /// test_steps!( // !!!! Get a proper main loop !!!!
1655    ///     plane_mesh.draw(token, &material,  transform_floor,  None, None);
1656    /// );
1657    /// ```
1658    pub fn fallback_override<T: AsRef<Tex>>(&mut self, fallback: T) -> &mut Self {
1659        unsafe { tex_set_fallback(self.0.as_ptr(), fallback.as_ref().0.as_ptr()) };
1660        self
1661    }
1662
1663    /// When sampling a texture that’s stretched, or shrunk beyond its screen size, how do we handle figuring out which
1664    /// color to grab from the texture? Default is Linear.
1665    /// <https://stereokit.net/Pages/StereoKit/Tex/SampleMode.html>
1666    ///
1667    /// see also [`tex_set_sample`]
1668    /// ### Examples
1669    /// ```
1670    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1671    /// use stereokit_rust::{util::named_colors,
1672    ///                      tex::{Tex, TexFormat, TexType, TexSample}};
1673    ///
1674    /// let mut tex = Tex::gen_color(named_colors::VIOLET, 128, 128, TexType::Image, TexFormat::RGBA32);
1675    /// assert_eq!(tex.get_sample_mode(), TexSample::Linear);
1676    /// tex.sample_mode(TexSample::Anisotropic);
1677    /// assert_eq!(tex.get_sample_mode(), TexSample::Anisotropic);
1678    /// ```
1679    pub fn sample_mode(&mut self, sample: TexSample) -> &mut Self {
1680        unsafe { tex_set_sample(self.0.as_ptr(), sample) };
1681        self
1682    }
1683
1684    //// When looking at a UV texture coordinate on this texture, how do we handle values larger than 1, or less than zero?
1685    /// Do we Wrap to the other side? Clamp it between 0-1, or just keep Mirroring back and forth? Wrap is the default.
1686    /// <https://stereokit.net/Pages/StereoKit/Tex/AddressMode.html>
1687    ///
1688    /// see also [`tex_set_address`]
1689    /// ### Examples
1690    /// ```
1691    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1692    /// use stereokit_rust::{util::named_colors,
1693    ///                      tex::{Tex, TexFormat, TexType, TexAddress}};
1694    ///
1695    /// let mut tex = Tex::gen_color(named_colors::VIOLET, 128, 128, TexType::Image, TexFormat::RGBA32);
1696    /// assert_eq!(tex.get_address_mode(), TexAddress::Wrap);
1697    /// tex.address_mode(TexAddress::Mirror);
1698    /// assert_eq!(tex.get_address_mode(), TexAddress::Mirror);
1699    /// ```
1700    pub fn address_mode(&mut self, address_mode: TexAddress) -> &mut Self {
1701        unsafe { tex_set_address(self.0.as_ptr(), address_mode) };
1702        self
1703    }
1704
1705    /// When SampleMode is set to Anisotropic, this is the number of samples the GPU takes to figure out the correct color.
1706    /// Default is 4, and 16 is pretty high.
1707    /// <https://stereokit.net/Pages/StereoKit/Tex/Anisoptropy.html>
1708    /// <https://stereokit.net/Pages/StereoKit/Tex/Anisotropy.html>
1709    ///
1710    /// see also [`tex_set_anisotropy`]
1711    /// ### Examples
1712    /// ```
1713    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1714    /// use stereokit_rust::{util::named_colors,
1715    ///                      tex::{Tex, TexFormat, TexType, TexSample}};
1716    ///
1717    /// let mut tex = Tex::gen_color(named_colors::VIOLET, 128, 128, TexType::Image, TexFormat::RGBA32);
1718    /// assert_eq!(tex.get_sample_mode(), TexSample::Linear);
1719    /// assert_eq!(tex.get_anisotropy(), 4);
1720    ///
1721    /// tex.sample_mode(TexSample::Anisotropic).anisotropy(10);
1722    ///
1723    /// assert_eq!(tex.get_anisotropy(), 10);
1724    /// ```
1725    pub fn anisotropy(&mut self, anisotropy_level: i32) -> &mut Self {
1726        unsafe { tex_set_anisotropy(self.0.as_ptr(), anisotropy_level) };
1727        self
1728    }
1729
1730    /// Gets the unique identifier of this asset resource! This can be helpful for debugging, managing your assets, or
1731    /// finding them later on!
1732    /// <https://stereokit.net/Pages/StereoKit/Tex/Id.html>
1733    ///
1734    /// see also [`tex_get_id`]
1735    /// see example in [`Tex::id`]
1736    pub fn get_id(&self) -> &str {
1737        unsafe { CStr::from_ptr(tex_get_id(self.0.as_ptr())) }.to_str().unwrap()
1738    }
1739
1740    /// Textures are loaded asyncronously, so this tells you the current state of this texture! This also can tell if
1741    /// an error occured, and what type of error it may have been.
1742    /// <https://stereokit.net/Pages/StereoKit/Tex/AssetState.html>
1743    ///
1744    /// see also [`tex_asset_state`]
1745    /// ### Examples
1746    /// ```
1747    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1748    /// use stereokit_rust::{util::named_colors, system::AssetState,
1749    ///                      tex::{Tex, TexFormat, TexType}};
1750    ///
1751    /// let tex = Tex::gen_color(named_colors::VIOLET, 128, 128,
1752    ///                          TexType::Image, TexFormat::RGBA32);
1753    /// assert_eq!(tex.get_asset_state(), AssetState::Loaded);
1754    ///
1755    /// let tex_icon = Tex::from_file("icons/checked.png", true, None)
1756    ///                         .expect("Tex_icon should be created");
1757    /// assert_ne!(tex_icon.get_asset_state(), AssetState::NotFound);
1758    ///
1759    /// let tex_not_icon = Tex::from_file("icccons/checddked.png", true, None)
1760    ///                             .expect("Tex_not_icon should be created");
1761    /// assert_ne!(tex_not_icon.get_asset_state(), AssetState::Loaded);    
1762    ///
1763    /// test_steps!( // !!!! Get a proper main loop !!!!
1764    ///     // We ensure to have the Tex loaded.
1765    ///     if    tex_icon.get_asset_state()     != AssetState::Loaded
1766    ///        || tex_not_icon.get_asset_state() == AssetState::Loading { iter -= 1; }     
1767    /// );
1768    /// assert_eq!(tex_icon.get_asset_state(),     AssetState::Loaded);    
1769    /// assert_eq!(tex_not_icon.get_asset_state(), AssetState::NotFound);    
1770    /// assert_eq!(tex_not_icon.get_width(),  None);
1771    /// assert_eq!(tex_not_icon.get_height(), None);
1772    /// ```
1773    pub fn get_asset_state(&self) -> AssetState {
1774        unsafe { tex_asset_state(self.0.as_ptr()) }
1775    }
1776
1777    /// The StereoKit format this texture was initialized with. This will be a blocking call if AssetState is less than
1778    /// LoadedMeta so None will be return instead
1779    /// <https://stereokit.net/Pages/StereoKit/Tex/Format.html>
1780    ///
1781    /// see also [`tex_get_format`]
1782    /// ### Examples
1783    /// ```
1784    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1785    /// use stereokit_rust::{util::named_colors, system::AssetState,
1786    ///                      tex::{Tex, TexFormat, TexType}};
1787    ///
1788    /// let tex = Tex::gen_color(named_colors::VIOLET, 128, 128,
1789    ///                          TexType::Image, TexFormat::RGBA128);
1790    /// assert_eq!(tex.get_format(), Some(TexFormat::RGBA128));
1791    ///
1792    /// let tex_icon = Tex::from_file("icons/checked.png", true, None)
1793    ///                         .expect("Tex_icon should be created");
1794    ///
1795    /// let tex_not_icon = Tex::from_file("icccons/checddked.png", true, None)
1796    ///                             .expect("Tex_not_icon should be created");
1797    ///
1798    /// test_steps!( // !!!! Get a proper main loop !!!!
1799    ///     // We ensure to have the Tex loaded.
1800    ///     if    tex_icon.get_asset_state()     != AssetState::Loaded
1801    ///        || tex_not_icon.get_asset_state() == AssetState::Loading { iter -= 1; }     
1802    /// );
1803    /// assert_eq!(tex_icon.get_format(), Some(TexFormat::RGBA32));
1804    /// assert_eq!(tex_not_icon.get_format(), None);   
1805    /// ```
1806    pub fn get_format(&self) -> Option<TexFormat> {
1807        match self.get_asset_state() {
1808            AssetState::Loaded => (),
1809            AssetState::LoadedMeta => (),
1810            AssetState::None => (),
1811            _ => return None,
1812        }
1813        Some(unsafe { tex_get_format(self.0.as_ptr()) })
1814    }
1815
1816    /// This allows you to retreive a z/depth buffer from a rendertarget texture. This texture _must_ be a
1817    /// rendertarget to set this, and the zbuffer texture _must_ be a depth format (or null). For no-rendertarget
1818    /// textures, this will always be null.
1819    /// <https://stereokit.net/Pages/StereoKit/Tex/GetZBuffer.html>
1820    ///
1821    /// see also [`tex_get_zbuffer`]
1822    /// see example in [`Tex::set_zbuffer`]
1823    pub fn get_zbuffer(&self) -> Option<Tex> {
1824        NonNull::new(unsafe { tex_get_zbuffer(self.0.as_ptr()) }).map(Tex)
1825    }
1826
1827    /// This will return the texture’s native resource for use with external libraries. For D3D, this will be an
1828    /// ID3D11Texture2D*, and for GL, this will be a uint32_t from a glGenTexture call, coerced into the IntPtr. This
1829    /// call will block execution until the texture is loaded, if it is not already.
1830    /// <https://stereokit.net/Pages/StereoKit/Tex/GetNativeSurface.html>
1831    ///
1832    /// see also [`tex_get_surface`]
1833    /// see example in [`Tex::set_native_surface`]
1834    pub fn get_native_surface(&self) -> *mut c_void {
1835        unsafe { tex_get_surface(self.0.as_ptr()) }
1836    }
1837
1838    /// The width of the texture, in pixels. This will be a blocking call if AssetState is less than LoadedMeta so None
1839    /// will be return instead
1840    /// <https://stereokit.net/Pages/StereoKit/Tex/Width.html>
1841    ///
1842    /// see also [`tex_get_width`]
1843    /// see example in [`Tex::set_size`] [`Tex::get_asset_state`]
1844    pub fn get_width(&self) -> Option<usize> {
1845        match self.get_asset_state() {
1846            AssetState::Loaded => (),
1847            AssetState::LoadedMeta => (),
1848            AssetState::None => (),
1849            _ => return None,
1850        }
1851        Some(unsafe { tex_get_width(self.0.as_ptr()) } as usize)
1852    }
1853
1854    /// The height of the texture, in pixels. This will be a blocking call if AssetState is less than LoadedMeta so None
1855    /// will be return instead
1856    /// <https://stereokit.net/Pages/StereoKit/Tex/Height.html>
1857    ///
1858    /// see also [`tex_get_height`]
1859    /// see example in [`Tex::set_size`] [`Tex::get_asset_state`]
1860    pub fn get_height(&self) -> Option<usize> {
1861        match self.get_asset_state() {
1862            AssetState::Loaded => (),
1863            AssetState::LoadedMeta => (),
1864            AssetState::None => (),
1865            _ => return None,
1866        }
1867        Some(unsafe { tex_get_height(self.0.as_ptr()) } as usize)
1868    }
1869
1870    /// Non-canon function which returns a tuple made of (width, heigh, size) of the corresponding texture.
1871    ///
1872    /// use `mip` < 0 for textures using [`TexType::ImageNomips`]
1873    ///
1874    /// use `mip` >=0 to retrieve the info about one MIP of the texture
1875    ///
1876    /// the size corresponding to the mip texture and the width and height of this mip texture
1877    /// This will be a blocking call if AssetState is less than LoadedMeta so None will be return instead
1878    ///
1879    /// ### Examples
1880    /// ```
1881    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1882    /// use stereokit_rust::{util::{named_colors, Color32}, system::AssetState,
1883    ///                      tex::{Tex, TexFormat, TexType}};
1884    ///
1885    /// let mut color_dots = [named_colors::CYAN; 16 * 16];
1886    /// let mut tex = Tex::new(TexType::Image, TexFormat::RGBA32, None);
1887    /// tex.set_colors32(16, 16, &color_dots);
1888    ///
1889    /// let check_dots = [Color32::WHITE; 16 * 16];
1890    /// assert!(tex.get_color_data::<Color32>(&check_dots, 0));
1891    /// assert_eq!(check_dots, color_dots);
1892    ///
1893    /// let (width, height, size) = tex.get_data_infos(0).expect("tex should be loaded");
1894    /// assert_eq!(width, 16);
1895    /// assert_eq!(height, 16);
1896    /// assert_eq!(size, 256);
1897    ///
1898    /// let (width, height, size) = tex.get_data_infos(1).expect("tex should be loaded");
1899    /// assert_eq!(width, 8);
1900    /// assert_eq!(height, 8);
1901    /// assert_eq!(size, 64);
1902    ///
1903    /// let tex_icon = Tex::from_file("icons/checked.png", true, None)
1904    ///                        .expect("Tex_icon should be created");
1905    /// test_steps!( // !!!! Get a proper main loop !!!!
1906    ///     // We ensure to have the Tex loaded.
1907    ///     if    tex_icon.get_asset_state()     != AssetState::Loaded { iter -= 1; }
1908    /// );
1909    /// assert_eq!(tex_icon.get_data_infos(0), Some((128, 128, 16384)));
1910    /// ```
1911    pub fn get_data_infos(&self, mip: i8) -> Option<(usize, usize, usize)> {
1912        match self.get_asset_state() {
1913            AssetState::Loaded => (),
1914            AssetState::LoadedMeta => (),
1915            AssetState::None => (),
1916            _ => {
1917                Log::err(format!("Texture {} not loaded. Function tex_get_data_info failed!", self.get_id()));
1918                return None;
1919            }
1920        }
1921        let mut width = unsafe { tex_get_width(self.0.as_ptr()) } as usize;
1922        let mut height = unsafe { tex_get_height(self.0.as_ptr()) } as usize;
1923        let size_test;
1924        let mut mips_test = unsafe { tex_get_mips(self.0.as_ptr()) } as usize;
1925
1926        if mip >= mips_test as i8 {
1927            Log::err(format!(
1928                "Texture {} has only {} mips. Index {} is too high. Function tex_get_data_info failed!",
1929                self.get_id(),
1930                mips_test,
1931                mip
1932            ));
1933            return None;
1934        }
1935
1936        let deux: usize = 2;
1937        if mip <= 0 {
1938            size_test = width * height;
1939        } else {
1940            mips_test = deux.pow(mip as u32);
1941            width /= mips_test;
1942            height /= mips_test;
1943
1944            size_test = width * height;
1945        }
1946        Some((width, height, size_test))
1947    }
1948
1949    /// Retrieve the color data of the texture from the GPU. This can be a very slow operation,
1950    /// so use it cautiously. The out_data pointer must correspond to an array with the correct size.
1951    /// <https://stereokit.net/Pages/StereoKit/Tex/GetColorData.html>
1952    /// * mip_level - Retrieves the color data for a specific mip-mapping level. This function will log a fail and
1953    ///   return a black array if an invalid mip-level is provided.
1954    ///
1955    /// The function [`Tex::get_data_infos`] may help you to shape the right receiver.
1956    ///
1957    /// see also [`tex_get_data`]
1958    /// ### Examples
1959    /// ```
1960    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1961    /// use stereokit_rust::{util::{named_colors, Color32, Color128},
1962    ///                      tex::{Tex, TexFormat, TexType}};
1963    ///
1964    /// let mut tex = Tex::gen_color(named_colors::CYAN, 8 , 8, TexType::Image, TexFormat::RGBA32);
1965    ///
1966    /// let check_dots = [Color32::WHITE; 8 * 8];
1967    /// assert!(tex.get_color_data::<Color32>(&check_dots, 0));
1968    /// assert_eq!(check_dots[5], named_colors::CYAN);
1969    ///
1970    /// let mut tex = Tex::gen_color(named_colors::MAGENTA, 8 , 8, TexType::Image, TexFormat::RGBA128);
1971    ///
1972    /// let check_dots = [Color128::WHITE; 8 * 8];
1973    /// assert!(tex.get_color_data::<Color128>(&check_dots, 0));
1974    /// assert_eq!(check_dots[5], named_colors::MAGENTA.into());
1975    /// ```
1976    pub fn get_color_data<T>(&self, color_data: &[T], mut mip_level: i8) -> bool {
1977        let size_of_color = std::mem::size_of_val(color_data);
1978        let (width, height, size_test) = match self.get_data_infos(mip_level) {
1979            Some(value) => value,
1980            None => return false,
1981        };
1982        if size_test * size_of::<T>() != size_of_color {
1983            Log::err(format!(
1984                "Size of the Tex {} is {}x{}/mip={} when size of the given buffer is {} instead of {}. Function Tex::get_color failed!",
1985                self.get_id(),
1986                height,
1987                width,
1988                mip_level,
1989                size_of_color,
1990                size_test * size_of::<T>(),
1991            ));
1992            return false;
1993        }
1994
1995        if mip_level < 0 {
1996            mip_level = 0
1997        }
1998        unsafe {
1999            tex_get_data(
2000                self.0.as_ptr(),
2001                color_data.as_ptr() as *mut std::os::raw::c_void,
2002                size_of_color,
2003                mip_level as i32,
2004            )
2005        };
2006
2007        true
2008    }
2009
2010    /// Non canonical function!
2011    /// Retrieve the color data of the texture from the GPU. This can be a very slow operation,
2012    /// so use it cautiously. The out_data pointer must correspond to an u8 array with the correct size.
2013    /// <https://stereokit.net/Pages/StereoKit/Tex/GetColorData.html>
2014    /// * `color_size`: number of bytes of the color (Color32: 4, Color128: 16 ...)
2015    /// * `mip_level` - Retrieves the color data for a specific mip-mapping level. This function will log a fail and
2016    ///   return a black array if an invalid mip-level is provided.
2017    ///
2018    /// The function [`Tex::get_data_infos`] may help you to shape the right receiver.
2019    ///
2020    /// see also [`tex_get_data`]
2021    /// ### Examples
2022    /// ```
2023    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2024    /// use stereokit_rust::{util::{named_colors, Color32},
2025    ///                      tex::{Tex, TexFormat, TexType}};
2026    ///
2027    /// let mut tex = Tex::gen_color(named_colors::CYAN, 8 , 8, TexType::Image, TexFormat::RGBA32);
2028    ///
2029    /// let mut check_dots = [0u8; 8 * 8 * 4];
2030    /// assert!(tex.get_color_data_u8(&mut check_dots, 4, 0));
2031    /// assert_eq!(check_dots[5*4], named_colors::CYAN.r);
2032    /// assert_eq!(check_dots[5*4+1], named_colors::CYAN.g);
2033    /// assert_eq!(check_dots[5*4+2], named_colors::CYAN.b);
2034    /// assert_eq!(check_dots[5*4+3], named_colors::CYAN.a);
2035    /// ```
2036    pub fn get_color_data_u8(&self, color_data: &[u8], color_size: usize, mut mip_level: i8) -> bool {
2037        let size_of_color = std::mem::size_of_val(color_data);
2038        let (width, height, size_test) = match self.get_data_infos(mip_level) {
2039            Some(value) => value,
2040            None => return false,
2041        };
2042
2043        if size_test * color_size != size_of_color {
2044            Log::err(format!(
2045                "Size of the Tex {} is {}x{}/mip={} when size of the given buffer is {} instead of {}. Function Tex::get_color_data_u8 failed!",
2046                self.get_id(),
2047                height,
2048                width,
2049                mip_level,
2050                size_of_color,
2051                size_test * color_size,
2052            ));
2053            return false;
2054        }
2055
2056        if mip_level < 0 {
2057            mip_level = 0
2058        }
2059        unsafe {
2060            tex_get_data(
2061                self.0.as_ptr(),
2062                color_data.as_ptr() as *mut std::os::raw::c_void,
2063                size_of_color,
2064                mip_level as i32,
2065            )
2066        };
2067
2068        true
2069    }
2070
2071    /// When sampling a texture that’s stretched, or shrunk beyond its screen size, how do we handle figuring out which
2072    /// color to grab from the texture? Default is Linear.
2073    /// <https://stereokit.net/Pages/StereoKit/Tex/SampleMode.html>
2074    ///
2075    /// see also [`tex_get_sample`]
2076    /// see example in [`Tex::sample_mode`]
2077    pub fn get_sample_mode(&self) -> TexSample {
2078        unsafe { tex_get_sample(self.0.as_ptr()) }
2079    }
2080
2081    /// When looking at a UV texture coordinate on this texture, how do we handle values larger than 1, or less than
2082    /// zero? Do we Wrap to the other side? Clamp it between 0-1, or just keep Mirroring back and forth? Wrap is the
2083    /// default.
2084    /// <https://stereokit.net/Pages/StereoKit/Tex/AddressMode.html>
2085    ///
2086    /// see also [`tex_get_address`]
2087    /// see example in [`Tex::address_mode`]
2088    pub fn get_address_mode(&self) -> TexAddress {
2089        unsafe { tex_get_address(self.0.as_ptr()) }
2090    }
2091
2092    /// When SampleMode is set to Anisotropic, this is the number of samples the GPU takes to figure out the correct
2093    /// color. Default is 4, and 16 is pretty high.
2094    /// <https://stereokit.net/Pages/StereoKit/Tex/Anisoptropy.html>
2095    /// <https://stereokit.net/Pages/StereoKit/Tex/Anisotropy.html>
2096    ///
2097    /// see also [`tex_get_anisotropy`]
2098    /// see example in [`Tex::anisotropy`]
2099    pub fn get_anisotropy(&self) -> i32 {
2100        unsafe { tex_get_anisotropy(self.0.as_ptr()) }
2101    }
2102
2103    /// The number of mip-map levels this texture has. This will be 1 if the texture doesn’t have mip mapping enabled.
2104    /// This will be a blocking call if AssetState is less than LoadedMeta so None will be return instead.
2105    /// <https://stereokit.net/Pages/StereoKit/Tex/Mips.html>
2106    ///
2107    /// see also [`tex_get_mips`]
2108    /// ### Examples
2109    /// ```
2110    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2111    /// use stereokit_rust::{util::named_colors, system::AssetState,
2112    ///                      tex::{Tex, TexFormat, TexType}};
2113    ///
2114    /// let tex_nomips = Tex::gen_color(named_colors::VIOLET, 128, 128,
2115    ///                                 TexType::ImageNomips, TexFormat::RGBA32);
2116    ///
2117    /// let tex = Tex::gen_color(named_colors::VIOLET, 128, 128,
2118    ///                          TexType::Image, TexFormat::RGBA32);
2119    ///
2120    /// let tex_icon = Tex::from_file("icons/checked.png", true, None)
2121    ///                         .expect("Tex_icon should be created");
2122    /// // TODO: assert_eq!(tex_icon.get_mips(), None);
2123    ///
2124    /// let tex_not_icon = Tex::from_file("Not an icon file", true, None)
2125    ///                             .expect("Tex_not_icon should be created");
2126    /// assert_eq!(tex_not_icon.get_mips(), None);
2127    ///
2128    /// test_steps!( // !!!! Get a proper main loop !!!!
2129    ///     // We ensure to have the Tex loaded.
2130    ///     if    tex_icon.get_asset_state()     != AssetState::Loaded
2131    ///        || tex_not_icon.get_asset_state() == AssetState::Loading { iter -= 1; }
2132    /// );
2133    /// assert_eq!(tex_nomips.get_mips(), Some(1));
2134    /// // TODO: assert_eq!(tex.get_mips(), Some(8));
2135    /// // TODO: assert_eq!(tex_icon.get_mips(), Some(8));
2136    /// assert_eq!(tex_not_icon.get_mips(), None);
2137    /// ```
2138    pub fn get_mips(&self) -> Option<i32> {
2139        match self.get_asset_state() {
2140            AssetState::Loaded => (),
2141            AssetState::LoadedMeta => (),
2142            AssetState::None => (),
2143            _ => return None,
2144        }
2145        Some(unsafe { tex_get_mips(self.0.as_ptr()) })
2146    }
2147
2148    /// ONLY valid for cubemap textures! This will calculate a spherical harmonics representation of the cubemap for use
2149    /// with StereoKit’s lighting. First call may take a frame  or two of time, but subsequent calls will pull from a
2150    /// cached value.
2151    /// <https://stereokit.net/Pages/StereoKit/Tex/CubemapLighting.html>
2152    ///
2153    /// see also [`tex_get_cubemap_lighting`] use instead [`SHCubemap`]
2154    /// ### Examples
2155    /// ```
2156    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2157    /// use stereokit_rust::{util::named_colors, maths::Vec3,
2158    ///                      tex::{Tex, TexFormat, TexType}};
2159    ///
2160    /// let tex = Tex::gen_color(named_colors::VIOLET, 128, 128,
2161    ///                          TexType::Cubemap, TexFormat::RGBA32);
2162    ///
2163    /// // Cubemap must be created with SHCubemap static methods.
2164    /// let sh_cubemap = tex.get_cubemap_lighting();
2165    /// assert_eq!(sh_cubemap.sh.coefficients[2], Vec3::ZERO);
2166    /// assert_eq!(sh_cubemap.sh.coefficients[5], Vec3::ZERO);
2167    /// ```
2168    pub fn get_cubemap_lighting(&self) -> SHCubemap {
2169        SHCubemap {
2170            sh: unsafe { tex_get_cubemap_lighting(self.0.as_ptr()) },
2171            tex: Tex(NonNull::new(unsafe { tex_find(tex_get_id(self.0.as_ptr())) }).unwrap()),
2172        }
2173    }
2174
2175    /// Default 2x2 black opaque texture, this is the texture referred to as ‘black’ in the shader texture defaults.
2176    /// <https://stereokit.net/Pages/StereoKit/Tex/Black.html>
2177    ///
2178    /// ### Examples
2179    /// ```
2180    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2181    /// use stereokit_rust::tex::Tex;
2182    ///
2183    /// let tex= Tex::black();
2184    /// assert_eq!(tex.get_id(), "default/tex_black");
2185    /// ```
2186    pub fn black() -> Self {
2187        Self::find("default/tex_black").unwrap()
2188    }
2189
2190    /// This is a white checkered grid texture used to easily add visual features to materials. By default, this is used
2191    /// for the loading fallback texture for all Tex objects.
2192    /// <https://stereokit.net/Pages/StereoKit/Tex/DevTex.html>
2193    ///
2194    /// ### Examples
2195    /// ```
2196    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2197    /// use stereokit_rust::tex::Tex;
2198    ///
2199    /// let tex = Tex::dev_tex();
2200    /// assert_eq!(tex.get_id(), "default/tex_devtex");
2201    /// ```
2202    pub fn dev_tex() -> Self {
2203        Self::find("default/tex_devtex").unwrap()
2204    }
2205
2206    /// This is a red checkered grid texture used to indicate some sort of error has occurred. By default, this is used
2207    /// for the error fallback texture for all Tex objects.
2208    /// <https://stereokit.net/Pages/StereoKit/Tex/Error.html>
2209    ///
2210    /// ### Examples
2211    /// ```
2212    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2213    /// use stereokit_rust::tex::Tex;
2214    ///
2215    /// let tex = Tex::error();
2216    /// assert_eq!(tex.get_id(), "default/tex_error");
2217    /// ```
2218    pub fn error() -> Self {
2219        Self::find("default/tex_error").unwrap()
2220    }
2221
2222    /// Default 2x2 flat normal texture, this is a normal that faces out from the, face, and has a color value of
2223    /// (0.5,0.5,1). This is the texture referred to as ‘flat’ in the shader texture defaults.
2224    /// <https://stereokit.net/Pages/StereoKit/Tex/Flat.html>
2225    ///
2226    /// ### Examples
2227    /// ```
2228    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2229    /// use stereokit_rust::tex::Tex;
2230    ///
2231    /// let tex = Tex::flat();
2232    /// assert_eq!(tex.get_id(), "default/tex_flat");
2233    /// ```
2234    pub fn flat() -> Self {
2235        Self::find("default/tex_flat").unwrap()
2236    }
2237
2238    /// Default 2x2 middle gray (0.5,0.5,0.5) opaque texture, this is the texture referred to as ‘gray’ in the shader
2239    /// texture defaults.
2240    /// <https://stereokit.net/Pages/StereoKit/Tex/Gray.html>
2241    ///
2242    /// ### Examples
2243    /// ```
2244    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2245    /// use stereokit_rust::tex::Tex;
2246    ///
2247    /// let tex = Tex::gray();
2248    /// assert_eq!(tex.get_id(), "default/tex_gray");
2249    /// ```
2250    pub fn gray() -> Self {
2251        Self::find("default/tex_gray").unwrap()
2252    }
2253
2254    /// Default 2x2 roughness color (1,1,0,1) texture, this is the texture referred to as ‘rough’ in the shader texture
2255    /// defaults.
2256    /// <https://stereokit.net/Pages/StereoKit/Tex/Rough.html>
2257    ///
2258    /// ### Examples
2259    /// ```
2260    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2261    /// use stereokit_rust::tex::Tex;
2262    ///
2263    /// let tex = Tex::rough();
2264    /// assert_eq!(tex.get_id(), "default/tex_rough");
2265    /// ```
2266    pub fn rough() -> Self {
2267        Self::find("default/tex_rough").unwrap()
2268    }
2269
2270    /// Default 2x2 white opaque texture, this is the texture referred to as ‘white’ in the shader texture defaults.
2271    /// <https://stereokit.net/Pages/StereoKit/Tex/White.html>
2272    ///
2273    /// ### Examples
2274    /// ```
2275    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2276    /// use stereokit_rust::tex::Tex;
2277    ///
2278    /// let tex = Tex::white();
2279    /// assert_eq!(tex.get_id(), "default/tex");
2280    /// ```
2281    pub fn white() -> Self {
2282        Self::find("default/tex").unwrap()
2283    }
2284
2285    // /// The equirectangular texture used for the default dome
2286    // /// <https://stereokit.net/Pages/StereoKit/Tex.html>
2287    // pub fn cubemap() -> Self {
2288    //     Self::find("default/tex_cubemap").unwrap()
2289    // }
2290}
2291
2292/// fluent syntax for Texture cubemap
2293/// <https://stereokit.net/Pages/StereoKit/Tex.html>
2294///
2295/// see also [`Tex`] [`crate::util::SphericalHarmonics`]
2296/// ### Examples
2297/// ```
2298/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2299/// use stereokit_rust::{maths::Vec3, tex::SHCubemap, system::AssetState};
2300///
2301/// let sh_cubemap = SHCubemap::from_cubemap("hdri/sky_dawn.hdr", true, 9999)
2302///                                .expect("Cubemap should be created");
2303///
2304/// sh_cubemap.render_as_sky();
2305/// assert_eq!(sh_cubemap.tex.get_asset_state(), AssetState::Loaded);
2306///
2307/// let tex = sh_cubemap.tex;
2308///
2309/// filename_scr = "screenshots/sh_cubemap.jpeg";
2310/// test_screenshot!( // !!!! Get a proper main loop !!!!
2311///     if tex.get_asset_state() != AssetState::Loaded {iter -= 1}
2312/// );
2313/// ```
2314/// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/sh_cubemap.jpeg" alt="screenshot" width="200">
2315#[derive(Debug)]
2316pub struct SHCubemap {
2317    pub sh: SphericalHarmonics,
2318    pub tex: Tex,
2319}
2320
2321impl SHCubemap {
2322    /// Creates a cubemap texture from a single equirectangular image! You know, the ones that look like an unwrapped
2323    /// globe with the poles all stretched out. It uses some fancy shaders and texture blitting to create 6 faces from
2324    /// the equirectangular image.
2325    /// <https://stereokit.net/Pages/StereoKit/Tex/FromCubemapEquirectangular.html>
2326    ///
2327    /// see also [`tex_create_cubemap_file`]
2328    #[deprecated(since = "0.40.0", note = "please use `from_cubemap` instead")]
2329    pub fn from_cubemap_equirectangular(
2330        equirectangular_file_utf8: impl AsRef<Path>,
2331        srgb_data: bool,
2332        priority: i32,
2333    ) -> Result<SHCubemap, StereoKitError> {
2334        Self::from_cubemap(equirectangular_file_utf8, srgb_data, priority)
2335    }
2336
2337    /// Creates a cubemap texture from a single file! This will load KTX2 files with 6 surfaces, or convert
2338    /// equirectangular images into cubemap images. KTX2 files are the _fastest_ way to load a cubemap, but
2339    /// equirectangular images can be acquired quite easily!
2340    ///
2341    /// Equirectangular images look like an unwrapped globe with the poles all stretched out, and are sometimes referred
2342    /// to as HDRIs.
2343    /// <https://stereokit.net/Pages/StereoKit/Tex/FromCubemap.html>
2344    /// * `cubemap_file` - Filename of the cubemap image.
2345    /// * `srgb_data` - Is this image color data in sRGB format, or is it normal/metal/rough/data that's not for direct
2346    ///   display? sRGB colors get converted to linear color space on the graphics card, so getting this right can have
2347    ///   a big impact on visuals.
2348    /// * `load_priority` - The priority sort order for this asset in the async loading system. Lower values mean loading
2349    ///   sooner.
2350    ///
2351    /// see also [`tex_create_cubemap_file`]
2352    /// ### Examples
2353    /// ```
2354    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2355    /// use stereokit_rust::{maths::Vec3, tex::SHCubemap, system::AssetState};
2356    ///
2357    /// let sh_cubemap = SHCubemap::from_cubemap("hdri/sky_dawn.hdr", true, 9999)
2358    ///                                .expect("Cubemap should be created");
2359    /// sh_cubemap.render_as_sky();
2360    ///
2361    /// assert_ne!(sh_cubemap.sh.coefficients[0], Vec3::ZERO);
2362    /// assert_ne!(sh_cubemap.sh.coefficients[8], Vec3::ZERO);
2363    ///
2364    /// let tex = sh_cubemap.tex;
2365    ///
2366    /// test_steps!( // !!!! Get a proper main loop !!!!
2367    ///     if tex.get_asset_state() != AssetState::Loaded {iter -= 1}
2368    /// );
2369    /// assert_eq!(tex.get_asset_state(), AssetState::Loaded);
2370    /// ```
2371    pub fn from_cubemap(
2372        cubemap_file: impl AsRef<Path>,
2373        srgb_data: bool,
2374        load_priority: i32,
2375    ) -> Result<SHCubemap, StereoKitError> {
2376        let path = cubemap_file.as_ref();
2377        let path_buf = path.to_path_buf();
2378        let c_str = CString::new(path.to_str().ok_or(StereoKitError::TexCString(path.to_str().unwrap().to_owned()))?)?;
2379        let tex =
2380            Tex(
2381                NonNull::new(unsafe { tex_create_cubemap_file(c_str.as_ptr(), srgb_data as Bool32T, load_priority) })
2382                    .ok_or(StereoKitError::TexFile(path_buf.clone(), "tex_create_cubemap_file failed".to_string()))?,
2383            );
2384
2385        Ok(Tex::get_cubemap_lighting(&tex))
2386    }
2387
2388    /// Creates a cubemap texture from 6 different image files! If you have a single equirectangular image, use
2389    /// Tex.FromEquirectangular instead. Asset Id will be the first filename.
2390    /// order of the file names is +X -X +Y -Y +Z -Z
2391    /// <https://stereokit.net/Pages/StereoKit/Tex/FromCubemapFile.html>
2392    /// * `files_utf8` - 6 image filenames, in order of/ +X, -X, +Y, -Y, +Z, -Z.
2393    /// * `srgb_data` - Is this image color data in sRGB format, or is it normal/metal/rough/data that's not for direct
2394    ///   display? sRGB colors get converted to linear color space on the graphics card, so getting this right can have a
2395    ///   big impact on visuals.
2396    /// * `load_priority` - The priority sort order for this asset in the async loading system. Lower values mean loading
2397    ///   sooner.
2398    ///
2399    /// see also [`tex_create_cubemap_files`]
2400    /// ### Examples
2401    /// ```
2402    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2403    /// use stereokit_rust::{system::AssetState, tex::SHCubemap};
2404    ///
2405    /// let cubemap_files = [
2406    ///     "hdri/giza/right.png",
2407    ///     "hdri/giza/left.png",
2408    ///     "hdri/giza/top.png",
2409    ///     "hdri/giza/bottom.png",
2410    ///     "hdri/giza/front.png",
2411    ///     "hdri/giza/back.png",
2412    /// ];
2413    /// let sh_cubemap = SHCubemap::from_cubemap_files(&cubemap_files, true, 9999)
2414    ///                                 .expect("Cubemap should be created");
2415    /// sh_cubemap.render_as_sky();
2416    ///
2417    /// let tex = sh_cubemap.tex;
2418    ///
2419    /// test_steps!( // !!!! Get a proper main loop !!!!
2420    ///     if tex.get_asset_state() != AssetState::Loaded {iter -= 1}
2421    /// );
2422    /// assert_eq!(tex.get_asset_state(), AssetState::Loaded);
2423    /// ```
2424    pub fn from_cubemap_files<P: AsRef<Path>>(
2425        files_utf8: &[P; 6],
2426        srgb_data: bool,
2427        load_priority: i32,
2428    ) -> Result<SHCubemap, StereoKitError> {
2429        let mut c_files = Vec::new();
2430        for path in files_utf8 {
2431            let path = path.as_ref();
2432            let path_buf = path.to_path_buf();
2433            let c_str =
2434                CString::new(path.to_str().ok_or(StereoKitError::TexCString(path_buf.to_str().unwrap().to_owned()))?)?;
2435            c_files.push(c_str);
2436        }
2437        let mut c_files_ptr = Vec::new();
2438        for str in c_files.iter() {
2439            c_files_ptr.push(str.as_ptr());
2440        }
2441        let in_arr_cube_face_file_xxyyzz = c_files_ptr.as_mut_slice().as_mut_ptr();
2442        let tex = Tex(NonNull::new(unsafe {
2443            tex_create_cubemap_files(in_arr_cube_face_file_xxyyzz, srgb_data as Bool32T, load_priority)
2444        })
2445        .ok_or(StereoKitError::TexFiles(
2446            PathBuf::from(r"one_of_6_files"),
2447            "tex_create_cubemap_files failed".to_string(),
2448        ))?);
2449
2450        //Ok(Tex::get_cubemap_lighting(&tex))
2451        Ok(SHCubemap { sh: SphericalHarmonics::default(), tex })
2452    }
2453
2454    /// Generates a cubemap texture from a gradient and a direction! These are entirely suitable for skyboxes, which
2455    /// you can set via Renderer.SkyTex.
2456    /// <https://stereokit.net/Pages/StereoKit/Tex/GenCubemap.html>
2457    /// * `gradient` - A color gradient the generator will sample from! This looks at the 0-1 range of the gradient.
2458    /// * `gradient_dir` - This vector points to where the ‘top’ of the color gradient will go. Conversely, the ‘bottom’
2459    ///   of the gradient will be opposite, and it’ll blend along that axis.
2460    /// * `resolution` - The square size in pixels of each cubemap face! This generally doesn’t need to be large, unless
2461    ///   you have a really complicated gradient. 16 is a good default value.
2462    ///
2463    /// see also [`tex_gen_cubemap`]
2464    /// ### Examples
2465    /// ```
2466    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2467    /// use stereokit_rust::{maths::Vec3, tex::SHCubemap, system::AssetState,
2468    ///                      util::{named_colors, Gradient, GradientKey, Color128}};
2469    ///
2470    /// let mut keys = [
2471    ///     GradientKey::new(Color128::BLACK_TRANSPARENT, 0.0),
2472    ///     GradientKey::new(named_colors::RED, 0.1),
2473    ///     GradientKey::new(named_colors::CYAN, 0.4),
2474    ///     GradientKey::new(named_colors::YELLOW, 0.5),
2475    ///     GradientKey::new(Color128::BLACK, 0.7)];
2476    ///
2477    /// let sh_cubemap = SHCubemap::gen_cubemap_gradient(Gradient::new(Some(&keys)),
2478    ///                                                  Vec3::UP, 128);
2479    /// sh_cubemap.render_as_sky();
2480    ///
2481    /// let tex = sh_cubemap.tex;
2482    /// assert_eq!(tex.get_asset_state(), AssetState::Loaded);
2483    /// assert_ne!(sh_cubemap.sh.coefficients[0], Vec3::ZERO);
2484    /// assert_ne!(sh_cubemap.sh.coefficients[8], Vec3::ZERO);
2485    /// test_steps!( // !!!! Get a proper main loop !!!!
2486    /// );
2487    /// ```
2488    pub fn gen_cubemap_gradient(
2489        gradient: impl AsRef<Gradient>,
2490        gradient_dir: impl Into<Vec3>,
2491        resolution: i32,
2492    ) -> SHCubemap {
2493        let mut sh = SphericalHarmonics::default();
2494        let tex = Tex(NonNull::new(unsafe {
2495            tex_gen_cubemap(gradient.as_ref().0.as_ptr(), gradient_dir.into(), resolution, &mut sh)
2496        })
2497        .unwrap());
2498        //unsafe { sk.tex_addref(&cubemap.1) }
2499        SHCubemap { sh, tex }
2500    }
2501
2502    /// Create the associated cubemap texture with the light spot.
2503    /// warning ! The SphericalHarmonics is moved to the result struct.
2504    /// <https://stereokit.net/Pages/StereoKit/Tex/GenCubemap.html>
2505    /// * `lighting` - Lighting information stored in a SphericalHarmonics.
2506    /// * `resolution` - The square size in pixels of each cubemap face! This generally doesn’t need to be large, as
2507    ///   SphericalHarmonics typically contain pretty low frequency information.
2508    /// * `light_spot_size_pct` - The size of the glowing spot added in the primary light direction. You can kinda think
2509    ///   of the unit as a percentage of the cubemap face’s size, but it’s technically a Chebyshev distance from the
2510    ///   light’s point on a 2m cube.
2511    /// * `light_spot_intensity` - The glowing spot’s color is the primary light direction’s color, but multiplied by
2512    ///   this value. Since this method generates a 128bpp texture, this is not clamped between 0-1, so feel free to go
2513    ///   nuts here! Remember that reflections will often cut down some reflection intensity.
2514    ///
2515    ///
2516    /// see also [`tex_gen_cubemap_sh`]
2517    /// ### Examples
2518    /// ```
2519    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2520    /// use stereokit_rust::{maths::Vec3, tex::SHCubemap, system::AssetState,
2521    ///                      util::{named_colors, SHLight, SphericalHarmonics}};
2522    ///
2523    /// let lights: [SHLight; 1] = [SHLight::new(Vec3::ONE, named_colors::WHITE); 1];
2524    /// let sh = SphericalHarmonics::from_lights(&lights);
2525    /// let sh_cubemap = SHCubemap::gen_cubemap_sh(sh, 128, 0.5, 1.0);
2526    /// sh_cubemap.render_as_sky();
2527    ///
2528    /// let tex = sh_cubemap.tex;
2529    /// assert_eq!(tex.get_asset_state(), AssetState::Loaded);
2530    /// assert_eq!(sh_cubemap.sh.get_dominent_light_direction(), -Vec3::ONE.get_normalized());
2531    /// assert_ne!(sh_cubemap.sh.coefficients[0], Vec3::ZERO);
2532    /// assert_ne!(sh_cubemap.sh.coefficients[1], Vec3::ZERO);
2533    /// assert_eq!(sh_cubemap.sh.coefficients[8], Vec3::ZERO);
2534    /// test_steps!( // !!!! Get a proper main loop !!!!
2535    /// );
2536    /// ```
2537    pub fn gen_cubemap_sh(
2538        lighting: SphericalHarmonics,
2539        resolution: i32,
2540        light_spot_size_pct: f32,
2541        light_spot_intensity: f32,
2542    ) -> SHCubemap {
2543        let tex = Tex(NonNull::new(unsafe {
2544            tex_gen_cubemap_sh(&lighting, resolution, light_spot_size_pct, light_spot_intensity)
2545        })
2546        .unwrap());
2547        SHCubemap { sh: lighting, tex }
2548    }
2549
2550    /// Get the associated lighting extracted from the cubemap.
2551    /// <https://stereokit.net/Pages/StereoKit/Tex/CubemapLighting.html>
2552    ///
2553    /// see also [`tex_gen_cubemap_sh`]
2554    /// ### Examples
2555    /// ```
2556    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2557    /// use stereokit_rust::{maths::Vec3, tex::SHCubemap, system::AssetState,
2558    ///                      util::{named_colors, SHLight, SphericalHarmonics}};
2559    ///
2560    /// let lights: [SHLight; 1] = [SHLight::new(Vec3::ONE, named_colors::WHITE); 1];
2561    /// let sh = SphericalHarmonics::from_lights(&lights);
2562    /// let sh_cubemap = SHCubemap::gen_cubemap_sh(sh, 128, 0.5, 1.0);
2563    /// let tex = sh_cubemap.tex;
2564    ///
2565    /// let sh_cubemap2 = SHCubemap::get_cubemap_lighting(tex);
2566    /// let tex2 = sh_cubemap2.tex;
2567    /// assert_eq!(tex2.get_asset_state(), AssetState::Loaded);
2568    /// assert_eq!(sh_cubemap2.sh.get_dominent_light_direction(), -Vec3::ONE.get_normalized());
2569    /// assert_ne!(sh_cubemap2.sh.coefficients[0], Vec3::ZERO);
2570    /// assert_ne!(sh_cubemap2.sh.coefficients[1], Vec3::ZERO);
2571    /// assert_eq!(sh_cubemap2.sh.coefficients[8], Vec3::ZERO);
2572    /// ```
2573    pub fn get_cubemap_lighting(cubemap_texture: impl AsRef<Tex>) -> SHCubemap {
2574        SHCubemap {
2575            sh: unsafe { tex_get_cubemap_lighting(cubemap_texture.as_ref().0.as_ptr()) },
2576            tex: Tex(NonNull::new(unsafe { tex_find(tex_get_id(cubemap_texture.as_ref().0.as_ptr())) }).unwrap()),
2577        }
2578    }
2579
2580    /// Get the cubemap texture and SH light of the the current skylight
2581    /// <https://stereokit.net/Pages/StereoKit/Renderer/SkyLight.html>
2582    /// <https://stereokit.net/Pages/StereoKit/Renderer/SkyTex.html>
2583    ///
2584    /// see also [`crate::system::Renderer`]
2585    /// ### Examples
2586    /// ```
2587    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2588    /// use stereokit_rust::tex::SHCubemap;
2589    ///
2590    /// let sh_cubemap = SHCubemap::get_rendered_sky();
2591    ///
2592    /// let tex = sh_cubemap.tex;
2593    /// assert_eq!(tex.get_id(), "default/cubemap");
2594    /// ```
2595    pub fn get_rendered_sky() -> SHCubemap {
2596        SHCubemap {
2597            sh: unsafe { render_get_skylight() },
2598            tex: Tex(NonNull::new(unsafe { render_get_skytex() }).unwrap()),
2599        }
2600    }
2601
2602    /// set the spherical harmonics as skylight and the the cubemap texture as skytex
2603    /// <https://stereokit.net/Pages/StereoKit/Renderer/SkyLight.html>
2604    /// <https://stereokit.net/Pages/StereoKit/Renderer/SkyTex.html>
2605    ///
2606    /// see also see also [`crate::system::Renderer`]
2607    /// ### Examples
2608    /// ```
2609    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2610    /// use stereokit_rust::{maths::Vec3, tex::SHCubemap, system::{AssetState, Renderer}};
2611    ///
2612    /// let mut sh_cubemap = SHCubemap::from_cubemap("hdri/sky_dawn.hdr", true, 9999)
2613    ///                                .expect("Cubemap should be created");
2614    /// assert_eq!(Renderer::get_enable_sky(), true);
2615    ///
2616    /// sh_cubemap.render_as_sky();
2617    ///
2618    /// Renderer::enable_sky(false);
2619    /// assert_eq!(Renderer::get_enable_sky(), false);
2620    /// ```
2621    pub fn render_as_sky(&self) {
2622        unsafe {
2623            render_set_skylight(&self.sh);
2624            render_set_skytex(self.tex.0.as_ptr());
2625        }
2626    }
2627
2628    /// Get the cubemap tuple
2629    ///
2630    /// see also [`Tex`] [`crate::util::SphericalHarmonics`]
2631    /// ### Examples
2632    /// ```
2633    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2634    /// use stereokit_rust::{tex::SHCubemap, maths::Vec3};
2635    ///
2636    /// let sh_cubemap = SHCubemap::get_rendered_sky();
2637    ///
2638    /// let (sh, tex) = sh_cubemap.get();
2639    /// assert_eq!(tex.get_id(), "default/cubemap");
2640    /// assert_eq!(sh.get_dominent_light_direction(), Vec3 { x: -0.20119436, y: -0.92318374, z: -0.32749438 });
2641    /// ```
2642    pub fn get(&self) -> (SphericalHarmonics, Tex) {
2643        (self.sh, Tex(NonNull::new(unsafe { tex_find(tex_get_id(self.tex.0.as_ptr())) }).unwrap()))
2644    }
2645}