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