stereokit_rust/
system.rs

1use crate::{
2    StereoKitError,
3    anchor::{_AnchorT, Anchor},
4    font::{_FontT, Font, FontT},
5    material::{_MaterialT, Material, MaterialBuffer, MaterialBufferT, MaterialT},
6    maths::{Bool32T, Matrix, Pose, Quat, Ray, Rect, Vec2, Vec3, ray_from_mouse},
7    mesh::{_MeshT, Mesh, MeshT},
8    model::{_ModelT, Model, ModelT},
9    render_list::{_RenderListT, RenderList},
10    shader::{_ShaderT, Shader, ShaderT},
11    sk::{MainThreadToken, OriginMode},
12    sound::{_SoundT, Sound, SoundT},
13    sprite::{_SpriteT, Sprite},
14    tex::{_TexT, Tex, TexFormat, TexT},
15    util::{Color32, Color128, SphericalHarmonics},
16};
17use std::{
18    ffi::{CStr, CString, c_char, c_ushort, c_void},
19    fmt,
20    mem::{size_of, transmute_copy},
21    path::Path,
22    ptr::{NonNull, null, null_mut},
23};
24
25// Re-export interactor types for convenient access
26pub use crate::interactor::{
27    DefaultInteractors, Interaction, Interactor, InteractorActivation, InteractorEvent, InteractorType,
28};
29
30/// All StereoKit assets implement this interface! This is mostly to help group and hold Asset objects, and is
31/// particularly useful when working with Assets at a high level with the Assets class.
32/// <https://stereokit.net/Pages/StereoKit/IAsset.html>
33pub trait IAsset {
34    // sets the unique identifier of this asset resource! This can be helpful for debugging, managing your assets, or
35    // finding them later on!
36    // <https://stereokit.net/Pages/StereoKit/IAsset/Id.html>
37    //fn id(&mut self, id: impl AsRef<str>);
38
39    /// gets the unique identifier of this asset resource! This can be helpful for debugging, managing your assets, or
40    /// finding them later on!
41    /// <https://stereokit.net/Pages/StereoKit/IAsset/Id.html>
42    fn get_id(&self) -> &str;
43}
44
45/// StereoKit uses an asynchronous loading system to prevent assets from blocking execution! This means that asset
46/// loading systems will return an asset to you right away, even though it is still being processed in the background.
47/// <https://stereokit.net/Pages/StereoKit/AssetState.html>
48///
49/// see also: [`Tex::get_asset_state`]
50#[derive(Debug, Copy, Clone, PartialEq, Eq)]
51#[repr(C)]
52pub enum AssetState {
53    /// This asset encountered an issue when parsing the source data. Either the format is unrecognized by StereoKit,
54    /// or the data may be corrupt. Check the logs for additional details.
55    Unsupported = -3,
56    /// The asset data was not found! This is most likely an issue with a bad file path, or file permissions. Check
57    /// the logs for additional details.
58    NotFound = -2,
59    /// An unknown error occurred when trying to load the asset! Check the logs for additional details.
60    Error = -1,
61    /// This asset is in its default state. It has not been told to load anything, nor does it have any data!
62    None = 0,
63    /// This asset is currently queued for loading, but hasn’t received any data yet. Attempting to access metadata or
64    /// asset data will result in blocking the app’s execution until that data is loaded!
65    Loading = 1,
66    /// This asset is still loading, but some of the higher level data is already available for inspection without
67    /// blocking the app. Attempting to access the core asset data will result in blocking the app’s execution until
68    /// that data is loaded!
69    LoadedMeta = 2,
70    /// This asset is completely loaded without issues, and is ready for use!
71    Loaded = 3,
72}
73
74/// A flag for what ‘type’ an Asset may store.
75///
76/// None -> No type, this may come from some kind of invalid Asset id.
77/// <https://stereokit.net/Pages/StereoKit/AssetType.html>
78///
79/// see also [`Assets`] [`Asset`]
80#[derive(Debug, Copy, Clone, PartialEq, Eq)]
81#[repr(u32)]
82pub enum AssetType {
83    None = 0,
84    Mesh = 1,
85    Tex = 2,
86    Shader = 3,
87    Material = 4,
88    Model = 5,
89    Font = 6,
90    Sprite = 7,
91    Sound = 8,
92    Solid = 9,
93    Anchor = 10,
94    RenderList = 11,
95}
96
97/// If you want to manage loading assets, this is the class for you!
98///  <https://stereokit.net/Pages/StereoKit/Assets.html>
99///
100/// ### Examples
101/// ```
102/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
103/// use stereokit_rust::{maths::Matrix, system::{Assets, AssetType, Asset, Pivot},
104///                      sprite::Sprite};
105///
106/// let my_sprite = Sprite::from_file("textures/open_gltf.jpeg", None, None)
107///                   .expect("open_gltf.jpeg should be able to create sprite");
108///
109/// for asset in Assets::all().filter(|s| !s.to_string().contains(" default/")) {
110///     if let Asset::Sprite(sprite) = asset {
111///         if !sprite.get_id().starts_with("sk/ui/") {
112///             assert_eq!(sprite, my_sprite);
113///         }
114///     }
115/// }
116///
117/// for asset in Assets::all_of_type(AssetType::Sprite) {
118///     if let Asset::Sprite(sprite) = asset {
119///         if !sprite.get_id().starts_with("sk/ui/") {
120///             assert_eq!(sprite, my_sprite);
121///         }
122///     } else {
123///         panic!("asset should be a sprite");
124///     }
125/// }
126///
127/// filename_scr = "screenshots/assets.jpeg"; fov_scr= 55.0;
128/// test_screenshot!( // !!!! Get a proper main loop !!!!
129///     my_sprite.draw(token, Matrix::Y_180, Pivot::Center, None);
130/// );
131/// ```
132/// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/assets.jpeg" alt="screenshot" width="200">
133pub struct Assets;
134
135pub type AssetT = *mut c_void;
136
137unsafe extern "C" {
138    pub fn assets_releaseref_threadsafe(asset: *mut c_void);
139    pub fn assets_current_task() -> i32;
140    pub fn assets_total_tasks() -> i32;
141    pub fn assets_current_task_priority() -> i32;
142    pub fn assets_block_for_priority(priority: i32);
143    pub fn assets_count() -> i32;
144    pub fn assets_get_index(index: i32) -> AssetT;
145    pub fn assets_get_type(index: i32) -> AssetType;
146    pub fn asset_get_type(asset: AssetT) -> AssetType;
147    pub fn asset_set_id(asset: AssetT, id: *const c_char);
148    pub fn asset_get_id(asset: AssetT) -> *const c_char;
149    pub fn asset_addref(asset: AssetT);
150    pub fn asset_release(asset: AssetT);
151}
152
153/// Non-canonical structure to store an asset and avoid reducer `Box<dyn Asset>`
154///
155/// see also [`AssetType`] [`Assets`]
156#[derive(Debug)]
157pub enum Asset {
158    None,
159    Mesh(Mesh),
160    Tex(Tex),
161    Shader(Shader),
162    Material(Material),
163    Model(Model),
164    Font(Font),
165    Sprite(Sprite),
166    Sound(Sound),
167    Solid(*mut c_void),
168    Anchor(Anchor),
169    RenderList(RenderList),
170}
171
172impl fmt::Display for Asset {
173    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174        match self {
175            Asset::None => write!(f, "None"),
176            Asset::Mesh(v) => write!(f, "Mesh : {}", v.get_id()),
177            Asset::Tex(v) => write!(f, "Tex : {}", v.get_id()),
178            Asset::Shader(v) => write!(f, "Shader : {}", v.get_id()),
179            Asset::Material(v) => write!(f, "Material : {}", v.get_id()),
180            Asset::Model(v) => write!(f, "Model : {}", v.get_id()),
181            Asset::Font(v) => write!(f, "Font : {}", v.get_id()),
182            Asset::Sprite(v) => write!(f, "Sprite : {}", v.get_id()),
183            Asset::Sound(v) => write!(f, "Sound : {}", v.get_id()),
184            Asset::Solid(_) => write!(f, "Solid : ... deprecated ..."),
185            Asset::Anchor(v) => write!(f, "Anchor : {}", v.get_id()),
186            Asset::RenderList(v) => write!(f, "RenderList : {}", v.get_id()),
187        }
188    }
189}
190
191/// Iterator on [`Assets`] producing some [`Asset`]
192///
193/// see also [`Assets::all`] [`Assets::all_of_type`]
194#[derive(Debug, Copy, Clone)]
195pub struct AssetIter {
196    index: i32,
197    pub asset_type: AssetType,
198}
199
200impl Iterator for AssetIter {
201    type Item = Asset;
202
203    fn next(&mut self) -> Option<Self::Item> {
204        self.index += 1;
205        let count = unsafe { assets_count() };
206        if self.asset_type == AssetType::None {
207            if self.index < count {
208                match unsafe { assets_get_type(self.index) } {
209                    AssetType::None => {
210                        Log::err(format!("Asset at index {:?}/{:?} is AssetType::None", self.index, count));
211                        None
212                    }
213                    asset_type => {
214                        let asset_id = unsafe { assets_get_index(self.index) };
215                        Some(self.to_asset(asset_type, asset_id))
216                    }
217                }
218            } else {
219                None
220            }
221        } else {
222            while self.index < count {
223                if unsafe { assets_get_type(self.index) } == self.asset_type {
224                    let asset_id = unsafe { assets_get_index(self.index) };
225                    return Some(self.to_asset(self.asset_type, asset_id));
226                } else {
227                    self.index += 1;
228                }
229            }
230            None
231        }
232    }
233}
234
235impl AssetIter {
236    /// Get the asset
237    fn to_asset(self, asset_type: AssetType, c_id: *mut c_void) -> Asset {
238        match asset_type {
239            AssetType::None => Asset::None,
240            AssetType::Mesh => Asset::Mesh(Mesh(NonNull::new(c_id as *mut _MeshT).unwrap())),
241            AssetType::Tex => Asset::Tex(Tex(NonNull::new(c_id as *mut _TexT).unwrap())),
242            AssetType::Shader => Asset::Shader(Shader(NonNull::new(c_id as *mut _ShaderT).unwrap())),
243            AssetType::Material => Asset::Material(Material(NonNull::new(c_id as *mut _MaterialT).unwrap())),
244            AssetType::Model => Asset::Model(Model(NonNull::new(c_id as *mut _ModelT).unwrap())),
245            AssetType::Font => Asset::Font(Font(NonNull::new(c_id as *mut _FontT).unwrap())),
246            AssetType::Sprite => Asset::Sprite(Sprite(NonNull::new(c_id as *mut _SpriteT).unwrap())),
247            AssetType::Sound => Asset::Sound(Sound(NonNull::new(c_id as *mut _SoundT).unwrap())),
248            AssetType::Solid => todo!("Solids are deprecated!"),
249            AssetType::Anchor => Asset::Anchor(Anchor(NonNull::new(c_id as *mut _AnchorT).unwrap())),
250            AssetType::RenderList => Asset::RenderList(RenderList(NonNull::new(c_id as *mut _RenderListT).unwrap())),
251        }
252    }
253
254    /// Get an iterator upon all assets loaded if asset_type is None or only assets of the given AssetType
255    /// <https://stereokit.net/Pages/StereoKit/Assets.html>
256    pub fn iterate(asset_type: Option<AssetType>) -> AssetIter {
257        let asset_type = asset_type.unwrap_or(AssetType::None);
258        AssetIter { index: -1, asset_type }
259    }
260}
261
262impl Assets {
263    /// A list of supported model format extensions. This pairs pretty well with Platform::file_picker when attempting to
264    /// load a Model!
265    /// <https://stereokit.net/Pages/StereoKit/Assets/ModelFormats.html>
266    pub const MODEL_FORMATS: [&'static str; 5] = [".gltf", ".glb", ".obj", ".stl", ".ply"];
267
268    /// A list of supported texture format extensions. This pairs pretty well with Platform::file_picker when attempting
269    /// to load a Tex!
270    /// <https://stereokit.net/Pages/StereoKit/Assets/TextureFormats.html>
271    pub const TEXTURE_FORMATS: [&'static str; 11] =
272        [".jpg", ".jpeg", ".png", ".hdr", ".tga", ".bmp", ".psd", ".pic", ".qoi", ".gif", ".ktx2"];
273
274    /// supported sound format by asset Sound <https://stereokit.net/Pages/StereoKit/Sound.html>
275    pub const SOUND_FORMATS: [&'static str; 2] = [".wav", ".mp3"];
276
277    /// This is an iterator upon all assets loaded by StereoKit at the current moment.
278    /// <https://stereokit.net/Pages/StereoKit/Assets/All.html>
279    ///
280    /// see also [`AssetIter`] [`Asset`]
281    /// ### Examples
282    /// ```
283    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
284    /// use stereokit_rust::{maths::Matrix,  system::{Assets, AssetType, Asset},
285    ///                      sprite::Sprite};
286    ///
287    /// let my_sprite = Sprite::from_file("textures/open_gltf.jpeg", None, None)
288    ///                   .expect("open_gltf.jpeg should be able to create sprite");
289    ///
290    /// let all = Assets::all();
291    ///
292    /// let mut sprite_count = 0    ; let mut texture_count = 0;
293    /// let mut model_count = 0     ; let mut sound_count = 0;
294    /// let mut material_count = 0  ; let mut shader_count = 0;
295    /// let mut font_count = 0      ; let mut other_count = 0;
296    /// let mut mesh_count = 0      ; let mut render_list_count = 0;
297    /// for asset in all {
298    ///     match asset {
299    ///         Asset::Sprite(sprite) => sprite_count += 1,
300    ///         Asset::Model(model) => model_count +=1,
301    ///         Asset::Sound(sound) => sound_count +=1,
302    ///         Asset::Tex(texture) => texture_count +=1,
303    ///         Asset::Material(material) => material_count +=1,
304    ///         Asset::Font(font) => font_count +=1,
305    ///         Asset::Mesh(mesh) => mesh_count +=1,
306    ///         Asset::Shader(shader) => shader_count +=1,
307    ///         Asset::RenderList(render_list) => render_list_count +=1,
308    ///     _  => other_count +=1,  
309    ///
310    ///     }
311    /// }
312    /// assert_eq!(sprite_count,    13 + 1 );
313    /// assert_eq!(texture_count,   23 + 1 );
314    /// assert_eq!(model_count,     2);
315    /// assert_eq!(sound_count,     5);
316    /// assert_eq!(material_count,  37 + 1 );
317    /// assert_eq!(shader_count,    15);
318    /// assert_eq!(font_count,      1);
319    /// assert_eq!(mesh_count,  26);
320    /// assert_eq!(render_list_count, 1);
321    /// assert_eq!(other_count, 0);
322    /// ```
323    pub fn all() -> AssetIter {
324        AssetIter::iterate(None)
325    }
326
327    /// This is an iterator upon all assets matching the specified type.
328    /// <https://stereokit.net/Pages/StereoKit/Assets/Type.html>
329    /// * `asset_type` - Any [`IAsset`] type
330    ///
331    /// see also [`AssetIter`] [`Asset`] [`IAsset`]
332    /// ### Examples
333    /// ```
334    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
335    /// use stereokit_rust::{system::{Assets, AssetType, Asset},
336    ///                      sprite::Sprite};
337    ///
338    /// let my_sprite = Sprite::from_file("textures/open_gltf.jpeg", None, None)
339    ///                   .expect("open_gltf.jpeg should be able to create sprite");
340    ///
341    /// let all = Assets::all_of_type(AssetType::Sprite);
342    ///
343    /// let mut sprite_count = 0;
344    /// for asset in all {
345    ///     match asset {
346    ///         Asset::Sprite(sprite) => sprite_count += 1,
347    ///         _ => panic!("asset should be a sprite"),
348    ///     }
349    /// }
350    /// assert_eq!(sprite_count, 13 + 1);
351    /// ```
352    pub fn all_of_type(asset_type: AssetType) -> AssetIter {
353        AssetIter::iterate(Some(asset_type))
354    }
355
356    /// This is the index of the current asset loading task. Note that to load one asset, multiple tasks are generated.
357    /// <https://stereokit.net/Pages/StereoKit/Assets/CurrentTask.html>
358    ///
359    /// see also [`assets_current_task`] [`Assets::total_tasks`]
360    /// ### Examples
361    /// ```
362    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
363    /// use stereokit_rust::{system::Assets, sprite::Sprite};
364    /// let my_sprite = Sprite::from_file("textures/open_gltf.jpeg", None, None)
365    ///                   .expect("open_gltf.jpeg should be able to create sprite");
366    ///
367    /// let current_task = Assets::current_task();
368    /// // TODO: most of the time true but ... assert_eq!(Assets::total_tasks(), 1);
369    /// number_of_steps = 200;
370    /// assert_eq!(current_task, 0);
371    /// ```
372    pub fn current_task() -> i32 {
373        unsafe { assets_current_task() }
374    }
375
376    /// StereoKit processes tasks in order of priority. This returns the priority of the current task, and can be used
377    /// to wait until all tasks within a certain priority range have been completed.
378    /// <https://stereokit.net/Pages/StereoKit/Assets/CurrentTaskPriority.html>
379    ///
380    /// see also [`assets_current_task_priority`]
381    /// ### Examples
382    /// ```
383    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
384    /// use stereokit_rust::{system::Assets, sprite::Sprite};
385    ///
386    /// let my_sprite = Sprite::from_file("textures/open_gltf.jpeg", None, None)
387    ///                   .expect("open_gltf.jpeg should be able to create sprite");
388    ///
389    /// let current_task_priority  = Assets::current_task_priority();
390    /// assert_eq!(current_task_priority, 10);
391    /// ```
392    pub fn current_task_priority() -> i32 {
393        unsafe { assets_current_task_priority() }
394    }
395
396    /// This is the total number of tasks that have been added to the loading system, including all completed and
397    /// pending tasks. Note that to load one asset, multiple tasks are generated.
398    /// <https://stereokit.net/Pages/StereoKit/Assets/TotalTasks.html>
399    ///
400    /// see also [`assets_total_tasks`]
401    /// ### Examples
402    /// ```
403    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
404    /// use stereokit_rust::{system::Assets, sprite::Sprite};
405    ///
406    /// let my_sprite1 = Sprite::from_file("textures/open_gltf.jpeg", None, None)
407    ///                   .expect("open_gltf.jpeg should be able to create sprite");
408    ///
409    /// let my_sprite2 = Sprite::from_file("textures/log_viewer.jpeg", None, None)
410    ///                   .expect("log_viewer.jpeg should be able to create sprite");
411    ///
412    /// test_steps!( // !!!! Get a proper main loop !!!!
413    ///     let total_tasks  = Assets::total_tasks();
414    ///     assert_eq!(total_tasks, 2);
415    /// );
416    /// ```
417    pub fn total_tasks() -> i32 {
418        unsafe { assets_total_tasks() }
419    }
420
421    /// This will block the execution of the application until all asset tasks below the priority value have completed
422    /// loading. To block until all assets are loaded, pass in i32::MAX for the priority.
423    /// <https://stereokit.net/Pages/StereoKit/Assets/BlockForPriority.html>
424    ///
425    /// see also [`assets_block_for_priority`]
426    /// ### Examples
427    /// ```
428    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
429    /// use stereokit_rust::{maths::{Vec3, Matrix},  system::{Assets, AssetState}, tex::Tex,
430    ///                      material::Material, mesh::Mesh, model::Model, util::named_colors};
431    ///
432    /// // The model is loaded asynchronously, so we need to wait for it to be loaded before we can screenshot it.
433    /// let model = Model::from_file("cuve.glb", None)
434    ///                 .expect("mobiles.gltf should be a valid model");
435    /// let transform = Matrix::t_r_s([0.15, -0.75, -1.0], [0.0, 110.0, 0.0], [0.4, 0.4, 0.4]);
436    ///
437    /// Assets::block_for_priority(i32::MAX);
438    ///
439    /// filename_scr = "screenshots/assets_block_for_priority.jpeg";
440    /// test_screenshot!( // !!!! Get a proper main loop !!!!
441    ///     model.draw(token, transform, Some(named_colors::MISTY_ROSE.into()), None);
442    /// );
443    /// ```
444    /// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/assets_block_for_priority.jpeg" alt="screenshot" width="200">
445    pub fn block_for_priority(priority: i32) {
446        unsafe { assets_block_for_priority(priority) }
447    }
448}
449
450/// This describes what technology is being used to power StereoKit’s XR backend.
451/// <https://stereokit.net/Pages/StereoKit/BackendXRType.html>
452///
453/// see also [`Backend::xr_type`]
454#[derive(Debug, Copy, Clone, PartialEq, Eq)]
455#[repr(u32)]
456pub enum BackendXRType {
457    /// StereoKit is not using an XR backend of any sort. That means the application is flatscreen and has the simulator
458    /// disabled.
459    None = 0,
460    /// StereoKit is using the flatscreen XR simulator. Inputs are emulated, and some advanced XR functionality may not
461    /// be available.
462    Simulator = 1,
463    /// StereoKit is currently powered by OpenXR! This means we’re running on a real XR device. Not all OpenXR runtimes
464    /// provide the same functionality, but we will have access to more fun stuff :)
465    OpenXR = 2,
466    /// StereoKit is running in a browser, and is using WebXR!
467    WebXR = 3,
468}
469
470/// This describes the platform that StereoKit is running on.
471/// <https://stereokit.net/Pages/StereoKit/BackendPlatform.html>
472///
473/// see also [`Backend::platform`]
474#[derive(Debug, Copy, Clone, PartialEq, Eq)]
475#[repr(u32)]
476pub enum BackendPlatform {
477    /// This is running as a Windows app using the Win32 APIs.
478    Win32 = 0,
479    /// This is running as a Windows app using the UWP APIs.
480    Uwp = 1,
481    /// This is running as a Linux app.
482    Linux = 2,
483    /// This is running as an Android app.
484    Android = 3,
485    /// This is running in a browser.
486    Web = 4,
487}
488
489/// This describes the graphics API thatStereoKit is using for rendering.
490/// <https://stereokit.net/Pages/StereoKit/BackendGraphics.html>
491///
492/// see also [`Backend::graphics`]
493#[derive(Debug, Copy, Clone, PartialEq, Eq)]
494#[repr(u32)]
495pub enum BackendGraphics {
496    /// An invalid default value.
497    None = 0,
498    /// DirectX’s Direct3D11 is used for rendering! This is used by default on Windows.
499    D3D11 = 1,
500    /// OpenGL is used for rendering, using GLX (OpenGL Extension to the X Window System) for loading. This is used by
501    /// default on Linux.
502    OpenGLGLX = 2,
503    /// OpenGL is used for rendering, using WGL (Windows Extensions to OpenGL) for loading. Native developers can
504    /// configure SK to use this on Windows.
505    OpenGLWGL = 3,
506    /// OpenGL ES is used for rendering, using EGL (EGL Native Platform Graphics Interface) for loading. This is used by
507    /// default on Android, and native developers can configure SK to use this on Linux.
508    OpenGLESEGL = 4,
509    /// WebGL is used for rendering. This is used by default on Web.
510    WebGL = 5,
511}
512
513/// XrInstance type
514pub type OpenXRHandleT = u64;
515
516/// This class exposes some of StereoKit’s backend functionality. This allows for tighter integration with certain
517/// platforms, but also means your code becomes less portable. Everything in this class should be guarded by
518/// availability checks.
519///  
520/// <https://stereokit.net/Pages/StereoKit/Backend.html>
521/// ### Examples
522/// ```
523/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
524/// use stereokit_rust::system::{Backend, BackendGraphics, BackendPlatform, BackendXRType, BackendOpenXR};
525///
526/// let graphics = Backend::graphics();
527/// let platform = Backend::platform();
528/// let xr_type = Backend::xr_type();
529///
530/// if cfg!(target_os = "windows") {
531///     assert_eq!(graphics, BackendGraphics::D3D11);
532///     assert_eq!(platform, BackendPlatform::Win32);
533/// } else {
534///     assert_eq!(graphics, BackendGraphics::OpenGLESEGL);
535///     assert_eq!(platform, BackendPlatform::Linux);
536/// }
537/// assert_eq!(BackendOpenXR::eyes_sample_time(), 0);
538///
539/// xr_mode_stop_here!();
540/// // These are the expected results for offscreen tests on a PC:
541/// assert_eq!(xr_type, BackendXRType::None);
542///
543/// ```
544pub struct Backend;
545
546pub type VoidFunction = unsafe extern "system" fn();
547
548unsafe extern "C" {
549    pub fn backend_xr_get_type() -> BackendXRType;
550    pub fn backend_openxr_get_instance() -> OpenXRHandleT;
551    pub fn backend_openxr_get_session() -> OpenXRHandleT;
552    pub fn backend_openxr_get_system_id() -> OpenXRHandleT;
553    pub fn backend_openxr_get_space() -> OpenXRHandleT;
554    pub fn backend_openxr_get_time() -> i64;
555    pub fn backend_openxr_get_eyes_sample_time() -> i64;
556    pub fn backend_openxr_get_function(function_name: *const c_char) -> Option<VoidFunction>;
557    pub fn backend_openxr_ext_enabled(extension_name: *const c_char) -> Bool32T;
558    pub fn backend_openxr_ext_request(extension_name: *const c_char);
559    pub fn backend_openxr_ext_exclude(extension_name: *const c_char);
560    pub fn backend_openxr_use_minimum_exts(use_minimum_exts: Bool32T);
561    pub fn backend_openxr_composition_layer(XrCompositionLayerBaseHeader: *mut c_void, data_size: i32, sort_order: i32);
562    pub fn backend_openxr_end_frame_chain(XrBaseHeader: *mut c_void, data_size: i32);
563    pub fn backend_openxr_set_hand_joint_scale(joint_scale_factor: f32);
564    pub fn backend_openxr_add_callback_pre_session_create(
565        xr_pre_session_create_callback: ::std::option::Option<unsafe extern "C" fn(context: *mut c_void)>,
566        context: *mut c_void,
567    );
568    pub fn backend_openxr_add_callback_poll_event(
569        xr_poll_event_callback: ::std::option::Option<
570            unsafe extern "C" fn(context: *mut c_void, xr_event_data_buffer: *mut c_void),
571        >,
572        context: *mut c_void,
573    );
574    pub fn backend_openxr_remove_callback_poll_event(
575        xr_poll_event_callback: ::std::option::Option<
576            unsafe extern "C" fn(context: *mut c_void, xr_event_data_buffer: *mut c_void),
577        >,
578    );
579    pub fn backend_platform_get() -> BackendPlatform;
580    pub fn backend_android_get_java_vm() -> *mut c_void;
581    pub fn backend_android_get_activity() -> *mut c_void;
582    pub fn backend_android_get_jni_env() -> *mut c_void;
583    pub fn backend_graphics_get() -> BackendGraphics;
584    pub fn backend_d3d11_get_d3d_device() -> *mut c_void;
585    pub fn backend_d3d11_get_d3d_context() -> *mut c_void;
586    pub fn backend_d3d11_get_deferred_d3d_context() -> *mut c_void;
587    pub fn backend_d3d11_get_deferred_mtx() -> *mut c_void;
588    pub fn backend_d3d11_get_main_thread_id() -> u32;
589    pub fn backend_opengl_wgl_get_hdc() -> *mut c_void;
590    pub fn backend_opengl_wgl_get_hglrc() -> *mut c_void;
591    pub fn backend_opengl_glx_get_context() -> *mut c_void;
592    pub fn backend_opengl_glx_get_display() -> *mut c_void;
593    pub fn backend_opengl_glx_get_drawable() -> *mut c_void;
594    pub fn backend_opengl_egl_get_context() -> *mut c_void;
595    pub fn backend_opengl_egl_get_config() -> *mut c_void;
596    pub fn backend_opengl_egl_get_display() -> *mut c_void;
597}
598
599impl Backend {
600    /// This describes the graphics API thatStereoKit is using for rendering. StereoKit uses D3D11 for Windows platforms,
601    /// and a flavor of OpenGL for Linux, Android, and Web.
602    /// <https://stereokit.net/Pages/StereoKit/Backend/Graphics.html>
603    ///
604    /// see also [`backend_graphics_get`]
605    /// ### Examples
606    /// ```
607    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
608    /// use stereokit_rust::system::{Backend, BackendGraphics};
609    ///
610    /// let graphics = Backend::graphics();
611    /// if cfg!(target_os = "windows") {
612    ///     assert_eq!(graphics, BackendGraphics::D3D11);
613    /// } else {
614    ///     assert_eq!(graphics, BackendGraphics::OpenGLESEGL);
615    /// }
616    /// ```
617    pub fn graphics() -> BackendGraphics {
618        unsafe { backend_graphics_get() }
619    }
620
621    /// What kind of platform is StereoKit running on? This can be important to tell you what APIs or functionality is
622    /// available to the app.
623    /// <https://stereokit.net/Pages/StereoKit/Backend/Platform.html>
624    ///
625    /// see also [`backend_platform_get`]
626    /// ### Examples
627    /// ```
628    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
629    /// use stereokit_rust::system::{Backend, BackendPlatform};
630    ///
631    /// let platform = Backend::platform();
632    /// if cfg!(target_os = "windows") {
633    ///     assert_eq!(platform, BackendPlatform::Win32);
634    /// } else {
635    ///     assert_eq!(platform, BackendPlatform::Linux);
636    /// }
637    /// ```
638    pub fn platform() -> BackendPlatform {
639        unsafe { backend_platform_get() }
640    }
641
642    /// What technology is being used to drive StereoKit’s XR functionality? OpenXR is the most likely candidate here,
643    /// but if you’re running the flatscreen Simulator, or running in the web with WebXR, then this will reflect that.
644    /// <https://stereokit.net/Pages/StereoKit/Backend/XRType.html>
645    ///
646    /// see also [`backend_xr_get_type`]
647    /// ### Examples
648    /// ```
649    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
650    /// use stereokit_rust::system::{Backend, BackendXRType};
651    ///
652    /// let xr_type = Backend::xr_type();
653    ///
654    /// xr_mode_stop_here!();
655    /// // These are the expected results for offscreen tests on a PC:
656    /// assert_eq!(xr_type, BackendXRType::None);
657    /// ```
658    pub fn xr_type() -> BackendXRType {
659        unsafe { backend_xr_get_type() }
660    }
661}
662
663/// This class is NOT of general interest, unless you are trying to add support for some unusual OpenXR extension!
664/// StereoKit should do all the OpenXR work that most people will need. If you find yourself here anyhow for something
665/// you feel StereoKit should support already, please add a feature request on GitHub!
666///
667/// This class contains handles and methods for working directly with OpenXR. This may allow you to activate or work
668/// with OpenXR extensions that StereoKit hasn’t implemented or exposed yet. Check that Backend.XRType is OpenXR before
669/// using any of this.
670///
671/// These properties may best be used with some external OpenXR binding library, but you may get some limited mileage
672/// with the API as provided here.
673/// <https://stereokit.net/Pages/StereoKit/Backend.OpenXR.html>
674///
675/// see implementations in [`crate::tools::xr_fb_passthrough`] [`crate::tools::os_api`]
676/// ### Examples
677/// ```
678/// use stereokit_rust::system::{Backend, BackendOpenXR, BackendXRType};
679///
680/// // This must be set before initializing StereoKit.
681/// BackendOpenXR::use_minimum_exts(false);
682/// BackendOpenXR::exclude_ext("XR_EXT_hand_tracking");
683/// BackendOpenXR::request_ext("XR_EXT_hand_tracking");
684///
685/// stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
686///
687/// let xr_type = Backend::xr_type();
688/// let eyes_sample_time = BackendOpenXR::eyes_sample_time();
689/// let instance         = BackendOpenXR::instance();
690/// let session          = BackendOpenXR::session();
691/// let space            = BackendOpenXR::space();
692/// let system_id        = BackendOpenXR::system_id();
693/// let time             = BackendOpenXR::time();
694/// let ext_enabled      = BackendOpenXR::ext_enabled("XR_EXT_hand_tracking");
695/// let get_function_ptr = BackendOpenXR::get_function_ptr("xrGetHandTrackerEXT");
696/// let get_function     = BackendOpenXR::get_function::<unsafe extern "C" fn()>("xrGetHandTrackerEXT");
697/// BackendOpenXR::set_hand_joint_scale(1.0);
698/// BackendOpenXR::use_minimum_exts(true);
699///
700/// xr_mode_stop_here!();
701/// // These are the expected results for offscreen tests on a PC:
702/// assert_eq!( xr_type, BackendXRType::None);
703///  assert_ne!( xr_type, BackendXRType::OpenXR);
704/// assert_eq!(eyes_sample_time, 0);
705/// assert_eq!(instance, 0);
706/// assert_eq!(session, 0);
707/// assert_eq!(space, 0);
708/// assert_eq!(system_id, 0);
709/// assert_eq!(time, 0);
710/// assert_eq!(ext_enabled, false);
711/// assert_eq!(get_function_ptr, None);
712/// assert_eq!(get_function, None);
713/// ```
714pub struct BackendOpenXR;
715
716impl BackendOpenXR {
717    /// Type: XrTime. This is the OpenXR time of the eye tracker sample associated with the current value of.
718    /// <https://stereokit.net/Pages/StereoKit/Backend.OpenXR/EyesSampleTime.html>
719    ///
720    /// see also [`backend_openxr_get_eyes_sample_time`]
721    pub fn eyes_sample_time() -> i64 {
722        unsafe { backend_openxr_get_eyes_sample_time() }
723    }
724
725    /// Type: XrInstance. StereoKit’s instance handle, valid after Sk.initialize.
726    /// <https://stereokit.net/Pages/StereoKit/Backend.OpenXR/Instance.html>
727    ///
728    /// see also [`backend_openxr_get_instance`]
729    ///
730    /// ### Examples
731    /// ```
732    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
733    /// use stereokit_rust::system::BackendOpenXR;
734    ///
735    /// let instance_handle = BackendOpenXR::instance();
736    ///
737    /// // In XR mode, this would be a valid XrInstance handle for OpenXR operations
738    /// // In offscreen mode, returns 0
739    ///
740    /// offscreen_mode_stop_here!();
741    /// assert_ne!(instance_handle, 0);
742    /// ```
743    pub fn instance() -> OpenXRHandleT {
744        unsafe { backend_openxr_get_instance() }
745    }
746
747    /// Type: XrSession. StereoKit’s current session handle, this will be valid after SK.Initialize, but the session may
748    /// not be started quite so early.
749    /// <https://stereokit.net/Pages/StereoKit/Backend.OpenXR/Session.html>
750    ///
751    /// see also [`backend_openxr_get_session`]
752    ///
753    /// ### Examples
754    /// ```
755    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
756    /// use stereokit_rust::system::BackendOpenXR;
757    ///
758    /// let session_handle = BackendOpenXR::session();
759    ///
760    /// // In XR mode, this would be a valid XrSession handle for OpenXR session operations
761    /// // In offscreen mode, returns 0
762    ///
763    /// offscreen_mode_stop_here!();
764    /// assert_ne!(session_handle, 0);
765    /// ```
766    pub fn session() -> OpenXRHandleT {
767        unsafe { backend_openxr_get_session() }
768    }
769
770    /// Type: XrSpace. StereoKit’s primary coordinate space, valid after SK.Initialize, this will most likely be created
771    /// from XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT or XR_REFERENCE_SPACE_TYPE_LOCAL.
772    /// <https://stereokit.net/Pages/StereoKit/Backend.OpenXR/Space.html>
773    ///
774    /// see also [`backend_openxr_get_space`]
775    ///
776    /// ### Examples
777    /// ```
778    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
779    /// use stereokit_rust::system::BackendOpenXR;
780    ///
781    /// let space_handle = BackendOpenXR::space();
782    ///
783    /// // In XR mode, this would be a valid XrSpace handle for coordinate transformations
784    /// // In offscreen mode, returns 0
785    ///
786    /// offscreen_mode_stop_here!();
787    /// assert_ne!(space_handle, 0);
788    /// ```
789    pub fn space() -> OpenXRHandleT {
790        unsafe { backend_openxr_get_space() }
791    }
792
793    /// Type: XrSystemId. This is the id of the device StereoKit is currently using! This is the result of calling
794    /// xrGetSystem with XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY.
795    /// <https://stereokit.net/Pages/StereoKit/Backend.OpenXR/SystemId.html>
796    ///
797    /// see also [`backend_openxr_get_system_id`]
798    ///
799    /// ### Examples
800    /// ```
801    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
802    /// use stereokit_rust::system::BackendOpenXR;
803    ///
804    /// let system_id = BackendOpenXR::system_id();
805    ///
806    /// // In XR mode, this would be a valid XrSystemId for the current XR device
807    /// // In offscreen mode, returns 0
808    ///
809    /// offscreen_mode_stop_here!();
810    /// assert_ne!(system_id, 0);
811    /// ```
812    pub fn system_id() -> OpenXRHandleT {
813        unsafe { backend_openxr_get_system_id() }
814    }
815
816    /// Type: XrTime. This is the OpenXR time for the current frame, and is available after Sk.initialize.
817    /// <https://stereokit.net/Pages/StereoKit/Backend.OpenXR/Time.html>
818    ///
819    /// see also [`backend_openxr_get_time`]
820    ///
821    /// ### Examples
822    /// ```
823    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
824    /// use stereokit_rust::system::BackendOpenXR;
825    ///
826    /// let current_time = BackendOpenXR::time();
827    ///
828    /// // In offscreen mode, returns 0
829    ///
830    /// offscreen_mode_stop_here!();
831    /// assert_ne!(current_time, 0);
832    /// ```
833    pub fn time() -> i64 {
834        unsafe { backend_openxr_get_time() }
835    }
836
837    /// Tells StereoKit to request only the extensions that are absolutely critical to StereoKit. You can still request
838    /// extensions via OpenXR.RequestExt, and this can be used to opt-in to extensions that StereoKit would normally
839    /// request automatically.
840    /// <https://stereokit.net/Pages/StereoKit/Backend.OpenXR/UseMinimumExts.html>
841    ///
842    /// see also [`backend_openxr_use_minimum_exts`]
843    pub fn use_minimum_exts(value: bool) {
844        unsafe { backend_openxr_use_minimum_exts(value as Bool32T) }
845    }
846
847    /// This allows you to add XrCompositionLayers to the list that StereoKit submits to xrEndFrame. You must call this
848    /// every frame you wish the layer to be included.
849    /// <https://stereokit.net/Pages/StereoKit/Backend.OpenXR/AddCompositionLayer.html>
850    /// * `xr_composition_layer_x` - A serializable XrCompositionLayer struct that follows the
851    ///   XrCompositionLayerBaseHeader data pattern.
852    /// * `sort_order` - An sort order value for sorting with other composition layers in the list. The primary
853    ///   projection layer that StereoKit renders to is at 0, -1 would be before it, and +1 would be after.
854    ///
855    /// see also [`backend_openxr_composition_layer`]
856    ///
857    /// ### Examples
858    /// ```
859    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
860    /// use stereokit_rust::system::BackendOpenXR;
861    ///
862    /// // Only works in XR mode but offscreen accept it.
863    /// use openxr_sys as oxr;
864    ///
865    /// // Create projection views for left eye only
866    /// let mut projection_views = [
867    ///     oxr::CompositionLayerProjectionView {
868    ///         ty: oxr::StructureType::COMPOSITION_LAYER_PROJECTION_VIEW,
869    ///         next: std::ptr::null(),
870    ///         sub_image: oxr::SwapchainSubImage {
871    ///             swapchain: oxr::Swapchain::from_raw(0), // Should be valid swapchain
872    ///             image_rect: oxr::Rect2Di {
873    ///                 offset: oxr::Offset2Di { x: 0, y: 0 },
874    ///                 extent: oxr::Extent2Di { width: 1024, height: 1024 },
875    ///             },
876    ///             image_array_index: 0,
877    ///         },
878    ///         pose: oxr::Posef {
879    ///             orientation: oxr::Quaternionf { x: 0.0, y: 0.0, z: 0.0, w: 1.0 },
880    ///             position: oxr::Vector3f { x: -0.032, y: 0.0, z: 0.0 }, // Left eye offset
881    ///         },
882    ///         fov: oxr::Fovf {
883    ///             angle_left: -0.7853981, // -45 degrees
884    ///             angle_right: 0.7853981,  // 45 degrees
885    ///             angle_up: 0.7853981,     // 45 degrees
886    ///             angle_down: -0.7853981,  // -45 degrees
887    ///         },
888    ///     }
889    /// ];
890    ///
891    /// let mut composition_layer = oxr::CompositionLayerProjection {
892    ///     ty: oxr::StructureType::COMPOSITION_LAYER_PROJECTION,
893    ///     next: std::ptr::null(),
894    ///     layer_flags: oxr::CompositionLayerFlags::BLEND_TEXTURE_SOURCE_ALPHA,
895    ///     space: oxr::Space::from_raw(BackendOpenXR::space()),
896    ///     view_count: 1,
897    ///     views: projection_views.as_ptr(),
898    /// };
899    ///
900    /// test_steps!( // !!!! Get a proper main loop !!!!
901    ///     BackendOpenXR::add_composition_layer(&mut composition_layer, 0);
902    /// );
903    /// ```
904    pub fn add_composition_layer<T>(xr_composition_layer_x: &mut T, sort_order: i32) {
905        let size = size_of::<T>();
906        let ptr = xr_composition_layer_x as *mut _ as *mut c_void;
907        unsafe { backend_openxr_composition_layer(ptr, size as i32, sort_order) }
908    }
909
910    /// This adds an item to the chain of objects submitted to StereoKit’s xrEndFrame call!
911    /// <https://stereokit.net/Pages/StereoKit/Backend.OpenXR/AddEndFrameChain.html>
912    /// * `xr_base_header` - An OpenXR object that will be chained into the xrEndFrame call.
913    ///
914    /// see also [`backend_openxr_end_frame_chain`]
915    ///
916    /// ### Examples
917    /// ```
918    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
919    /// use stereokit_rust::system::BackendOpenXR;
920    ///
921    /// // Only works in XR mode but offscreen accept it.
922    /// use openxr_sys as oxr;
923    /// let mut frame_end_info = oxr::FrameEndInfo {
924    ///     ty: oxr::StructureType::FRAME_END_INFO,
925    ///     next: std::ptr::null(),
926    ///     display_time: oxr::Time::from_nanos(BackendOpenXR::time()),
927    ///     environment_blend_mode:  oxr::EnvironmentBlendMode::OPAQUE,
928    ///     layer_count: 0,
929    ///     layers: std::ptr::null_mut(), // Should be filled with valid layers
930    ///     
931    /// };
932    ///
933    /// test_steps!( // !!!! Get a proper main loop !!!!
934    ///     BackendOpenXR::add_end_frame_chain(&mut frame_end_info);
935    /// );
936    /// ```
937    pub fn add_end_frame_chain<T>(xr_base_header: &mut T) {
938        let size = size_of::<T>();
939        let ptr = xr_base_header as *mut _ as *mut c_void;
940        unsafe { backend_openxr_end_frame_chain(ptr, size as i32) }
941    }
942
943    /// This ensures that StereoKit does not load a particular extension! StereoKit will behave as if the extension is
944    /// not available on the device. It will also be excluded even if you explicitly requested it with RequestExt
945    /// earlier, or afterwards. This MUST be called before SK.Initialize.
946    /// <https://stereokit.net/Pages/StereoKit/Backend.OpenXR/ExcludeExt.html>
947    /// * `extension_name` - The extension name as listed in the OpenXR spec. For example: “XR_EXT_hand_tracking”.
948    ///
949    /// see also [`backend_openxr_ext_exclude`]
950    ///
951    /// ### Examples
952    /// ```
953    /// use stereokit_rust::system::BackendOpenXR;
954    ///
955    /// // This must be called before SK.Initialize
956    /// BackendOpenXR::exclude_ext("XR_EXT_hand_tracking");
957    /// BackendOpenXR::exclude_ext("XR_FB_passthrough");
958    ///
959    /// stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
960    ///
961    /// offscreen_mode_stop_here!();
962    /// // Later, we can check if the extensions were not loaded:
963    /// assert_eq!(BackendOpenXR::ext_enabled("XR_EXT_hand_tracking"), false);
964    /// assert_eq!(BackendOpenXR::ext_enabled("XR_FB_passthrough"), false);
965    /// ```
966    pub fn exclude_ext(extension_name: impl AsRef<str>) {
967        let c_str = CString::new(extension_name.as_ref()).unwrap();
968        unsafe { backend_openxr_ext_exclude(c_str.as_ptr()) }
969    }
970
971    /// Requests that OpenXR load a particular extension. This MUST be called before SK.Initialize. Note that it’s
972    /// entirely possible that your extension will not load on certain runtimes, so be sure to check ExtEnabled to see
973    /// if it’s available to use.
974    /// <https://stereokit.net/Pages/StereoKit/Backend.OpenXR/RequestExt.html>
975    /// * `extension_name` - The extension name as listed in the OpenXR spec. For example: “XR_EXT_hand_tracking”.
976    ///
977    /// see also [`backend_openxr_ext_request`]
978    ///
979    /// ### Examples
980    /// ```
981    /// use stereokit_rust::system::BackendOpenXR;
982    ///
983    /// // This must be called before SK.Initialize
984    /// BackendOpenXR::request_ext("XR_EXT_hand_tracking");
985    /// BackendOpenXR::request_ext("XR_the_ext_that_does_not_exist");
986    ///
987    /// stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
988    ///
989    /// offscreen_mode_stop_here!();
990    /// // Later, check if extensions were loaded as we can't be sure they are ok for this runtime:
991    /// assert_eq!(BackendOpenXR::ext_enabled("XR_EXT_hand_tracking"), true);
992    /// assert_eq!(BackendOpenXR::ext_enabled("XR_the_ext_that_does_not_exist"), false);
993    /// ```
994    pub fn request_ext(extension_name: impl AsRef<str>) {
995        let c_str = CString::new(extension_name.as_ref()).unwrap();
996        unsafe { backend_openxr_ext_request(c_str.as_ptr()) }
997    }
998
999    /// This tells if an OpenXR extension has been requested and successfully loaded by the runtime. This MUST only be
1000    /// called after SK.Initialize.
1001    /// <https://stereokit.net/Pages/StereoKit/Backend.OpenXR/ExtEnabled.html>
1002    /// * `extension_name` - The extension name as listed in the OpenXR spec. For example: “XR_EXT_hand_tracking”.
1003    ///
1004    /// see also [`backend_openxr_ext_enabled`]
1005    ///
1006    /// ### Examples
1007    /// ```
1008    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1009    /// use stereokit_rust::system::BackendOpenXR;
1010    ///
1011    /// // Check if an extension is enabled (only works in XR mode)
1012    /// let hand_tracking_enabled = BackendOpenXR::ext_enabled("XR_EXT_hand_tracking");
1013    /// let imaginary_enabled = BackendOpenXR::ext_enabled("XR_the_ext_that_does_not_exist");
1014    ///
1015    /// offscreen_mode_stop_here!();
1016    /// // In offscreen mode, extensions are never enabled
1017    /// assert_eq!(hand_tracking_enabled, true);
1018    /// assert_eq!(imaginary_enabled, false);
1019    /// ```
1020    pub fn ext_enabled(extension_name: impl AsRef<str>) -> bool {
1021        if Backend::xr_type() == BackendXRType::OpenXR {
1022            let c_str = CString::new(extension_name.as_ref()).unwrap();
1023            unsafe { backend_openxr_ext_enabled(c_str.as_ptr()) != 0 }
1024        } else {
1025            false
1026        }
1027    }
1028
1029    /// This is basically xrGetInstanceProcAddr from OpenXR, you can use this to get and call functions from an
1030    /// extension you’ve loaded.
1031    /// ### Important Note
1032    /// It is more relevant to use the openxrs crate which contains the function signatures
1033    ///
1034    /// <https://stereokit.net/Pages/StereoKit/Backend.OpenXR/GetFunctionPtr.html>
1035    /// * `function_name` - The name of the function to get the pointer for.
1036    ///
1037    /// see also [`backend_openxr_get_function`]
1038    ///
1039    /// ### Examples
1040    /// ```
1041    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1042    /// use stereokit_rust::system::BackendOpenXR;
1043    ///
1044    /// // Get a function pointer from an OpenXR extension (only works in XR mode)
1045    /// let hand_tracker_fn = BackendOpenXR::get_function_ptr("xrCreateHandTrackerEXT");
1046    /// let passthrough_fn = BackendOpenXR::get_function_ptr("xrInexistantFunction");
1047    ///
1048    /// offscreen_mode_stop_here!();
1049    /// // In offscreen mode, function pointers are None
1050    /// assert_eq!(hand_tracker_fn.is_some(), true);
1051    /// assert_eq!(passthrough_fn, None);
1052    /// ```
1053    pub fn get_function_ptr(function_name: impl AsRef<str>) -> Option<VoidFunction> {
1054        let c_str = CString::new(function_name.as_ref()).unwrap();
1055        unsafe { backend_openxr_get_function(c_str.as_ptr()) }
1056    }
1057
1058    /// This is basically xrGetInstanceProcAddr from OpenXR, you can use this to get and call functions from an
1059    /// extension you’ve loaded.
1060    /// ### Important Note
1061    /// It is more relevant to use the openxrs crate which contains the function signatures
1062    ///
1063    /// <https://stereokit.net/Pages/StereoKit/Backend.OpenXR/GetFunctionPtr.html>
1064    /// * `function_name` - The name of the function to get the pointer for.
1065    ///
1066    /// see also [`backend_openxr_get_function`]
1067    ///
1068    /// ### Examples
1069    /// ```
1070    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1071    /// use stereokit_rust::system::BackendOpenXR;
1072    ///
1073    /// // Get a typed function pointer from an OpenXR extension (only works in XR mode)
1074    /// let hand_tracker_fn: Option<unsafe extern "C" fn()> = BackendOpenXR::get_function("xrCreateHandTrackerEXT");
1075    ///
1076    /// offscreen_mode_stop_here!();
1077    /// // In offscreen mode, function pointers are None
1078    /// assert_eq!(hand_tracker_fn.is_some(), true);
1079    /// ```
1080    pub fn get_function<T>(function_name: impl AsRef<str>) -> Option<T> {
1081        let c_str = CString::new(function_name.as_ref()).unwrap();
1082        let function = unsafe { backend_openxr_get_function(c_str.as_ptr()) };
1083        unsafe { transmute_copy(&function) }
1084    }
1085
1086    /// This sets a scaling value for joints provided by the articulated hand extension. Some systems just don’t seem to
1087    /// get their joint sizes right!
1088    /// <https://stereokit.net/Pages/StereoKit/Backend.OpenXR/SetHandJointScale.html>
1089    /// * `joint_scale_factor` - 1 being the default value, 2 being twice as large as normal, and 0.5 being half as big
1090    ///   as normal.
1091    ///
1092    /// see also [`backend_openxr_set_hand_joint_scale`]
1093    ///
1094    /// ### Example
1095    /// ```
1096    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1097    /// use stereokit_rust::system::{Backend, BackendOpenXR, BackendXRType};
1098    ///
1099    /// // Adjust hand joint scaling (only effective in XR mode with hand tracking)
1100    /// BackendOpenXR::set_hand_joint_scale(1.2); // Make joints 20% larger
1101    ///
1102    /// // Or make them smaller
1103    /// BackendOpenXR::set_hand_joint_scale(0.8); // Make joints 20% smaller
1104    ///
1105    /// // Reset to default
1106    /// BackendOpenXR::set_hand_joint_scale(1.0);
1107    /// ```
1108    pub fn set_hand_joint_scale(joint_scale_factor: f32) {
1109        unsafe { backend_openxr_set_hand_joint_scale(joint_scale_factor) }
1110    }
1111}
1112
1113/// This class contains variables that may be useful for interop with the Android operating system, or other Android
1114/// libraries.
1115///
1116/// see also `SkInfo::get_android_app`
1117/// <https://stereokit.net/Pages/StereoKit/Backend.Android.html>
1118///
1119/// ### Examples
1120/// ```
1121/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1122/// use stereokit_rust::system::BackendAndroid;
1123///
1124/// let activity = BackendAndroid::activity();
1125/// let java_vm = BackendAndroid::java_vm();
1126/// let jni_environment = BackendAndroid::jni_environment();
1127///
1128/// // These are results for a non Android environment:
1129/// assert_eq!(activity, std::ptr::null_mut());
1130/// assert_eq!(java_vm, std::ptr::null_mut());
1131/// assert_eq!(jni_environment, std::ptr::null_mut());
1132/// ```
1133pub struct BackendAndroid;
1134
1135impl BackendAndroid {
1136    /// This is the jobject activity that StereoKit uses on Android. This is only valid after Sk.initialize, on Android
1137    /// systems.
1138    /// <https://stereokit.net/Pages/StereoKit/Backend.Android/Activity.html>
1139    ///
1140    /// see also [`backend_android_get_activity`]
1141    pub fn activity() -> *mut c_void {
1142        unsafe { backend_android_get_activity() }
1143    }
1144
1145    /// This is the JavaVM* object that StereoKit uses on Android. This is only valid after Sk.initialize, on Android
1146    /// systems.
1147    /// <https://stereokit.net/Pages/StereoKit/Backend.Android/JavaVM.html>
1148    ///
1149    /// see also [`backend_android_get_java_vm`]
1150    pub fn java_vm() -> *mut c_void {
1151        unsafe { backend_android_get_java_vm() }
1152    }
1153
1154    /// This is the JNIEnv* object that StereoKit uses on Android. This is only valid after Sk.initialize, on Android
1155    /// systems.
1156    /// <https://stereokit.net/Pages/StereoKit/Backend.Android/JNIEnvironment.html>
1157    ///
1158    /// see also [`backend_android_get_jni_env`]
1159    pub fn jni_environment() -> *mut c_void {
1160        unsafe { backend_android_get_jni_env() }
1161    }
1162}
1163
1164/// When using Direct3D11 for rendering, this contains a number of variables that may be useful for doing advanced
1165/// rendering tasks. This is the default rendering backend on Windows.
1166/// <https://stereokit.net/Pages/StereoKit/Backend.D3D11.html>
1167///
1168/// ### Examples
1169/// ```
1170/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1171/// use stereokit_rust::system::BackendD3D11;
1172/// let d3d_context = BackendD3D11::d3d_context();
1173/// let d3d_device = BackendD3D11::d3d_device();
1174///
1175/// if cfg!(target_os = "windows") {
1176///     // These are results for a D3D11 environment:
1177///     assert_eq!(d3d_context, std::ptr::null_mut());
1178///     assert_ne!(d3d_device, std::ptr::null_mut());
1179/// } else {
1180///     // These are results for a non D3D11 environment:
1181///     assert_eq!(d3d_context, std::ptr::null_mut());
1182///     assert_eq!(d3d_device, std::ptr::null_mut());
1183/// }
1184/// ```
1185pub struct BackendD3D11;
1186
1187impl BackendD3D11 {
1188    /// This is the main ID3D11DeviceContext* StereoKit uses for rendering.
1189    /// <https://stereokit.net/Pages/StereoKit/Backend.D3D11/D3DContext.html>
1190    ///
1191    /// see also [`backend_d3d11_get_d3d_context`]
1192    pub fn d3d_context() -> *mut c_void {
1193        unsafe { backend_d3d11_get_d3d_context() }
1194    }
1195
1196    /// This is the main ID3D11Device* StereoKit uses for rendering.
1197    /// <https://stereokit.net/Pages/StereoKit/Backend.D3D11/D3DDevice.html>
1198    ///
1199    /// see also [`backend_d3d11_get_d3d_device`]
1200    pub fn d3d_device() -> *mut c_void {
1201        unsafe { backend_d3d11_get_d3d_device() }
1202    }
1203}
1204
1205/// When using OpenGL with the WGL loader for rendering, this contains a number of variables that may be useful for
1206/// doing advanced rendering tasks. This is Windows only, and requires gloabally defining SKG_FORCE_OPENGL when building
1207/// the core StereoKitC library.
1208/// <https://stereokit.net/Pages/StereoKit/Backend.OpenGL_WGL.html>
1209///
1210/// ### Examples
1211/// ```
1212/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1213/// use stereokit_rust::system::BackendOpenGLWGL;
1214/// let hdc = BackendOpenGLWGL::hdc();
1215/// let hglrc = BackendOpenGLWGL::hglrc();
1216///
1217/// // These are results for a non OpenGLWGL environment:
1218/// assert_eq!(hdc, std::ptr::null_mut());
1219/// assert_eq!(hglrc, std::ptr::null_mut());
1220/// ```
1221pub struct BackendOpenGLWGL;
1222
1223impl BackendOpenGLWGL {
1224    /// This is the Handle to Device Context HDC StereoKit uses with wglMakeCurrent.
1225    /// <https://stereokit.net/Pages/StereoKit/Backend.OpenGL_WGL/HDC.html>
1226    ///
1227    /// see also [`backend_opengl_wgl_get_hdc`]
1228    pub fn hdc() -> *mut c_void {
1229        unsafe { backend_opengl_wgl_get_hdc() }
1230    }
1231
1232    /// This is the Handle to an OpenGL Rendering Context HGLRC StereoKit uses with wglMakeCurrent.
1233    /// <https://stereokit.net/Pages/StereoKit/Backend.OpenGL_WGL/HGLRC.html>
1234    ///
1235    /// see also [`backend_opengl_wgl_get_hglrc`]
1236    pub fn hglrc() -> *mut c_void {
1237        unsafe { backend_opengl_wgl_get_hglrc() }
1238    }
1239}
1240
1241/// When using OpenGL ES with the EGL loader for rendering, this contains a number of variables that may be useful for
1242/// doing advanced rendering tasks. This is the default rendering backend for Android, and Linux builds can be
1243/// configured to use this with the SK_LINUX_EGL cmake option when building the core StereoKitC library.
1244/// <https://stereokit.net/Pages/StereoKit/Backend.OpenGLES_EGL.html>
1245///
1246/// ### Examples
1247/// ```
1248/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1249/// use stereokit_rust::system::BackendOpenGLESEGL;
1250///
1251/// if cfg!(target_os = "linux") {
1252///     // These are results for a OpenGLESEGL environment:
1253///
1254///     let context = BackendOpenGLESEGL::context();
1255///     assert_ne!(context, std::ptr::null_mut());
1256///
1257///     let display = BackendOpenGLESEGL::display();
1258///     assert_ne!(display, std::ptr::null_mut());
1259/// }
1260/// ```
1261pub struct BackendOpenGLESEGL;
1262
1263impl BackendOpenGLESEGL {
1264    /// This is the EGLContext StereoKit receives from eglCreateContext.
1265    /// <https://stereokit.net/Pages/StereoKit/Backend.OpenGLES_EGL/Context.html>
1266    ///
1267    /// see also [`backend_opengl_egl_get_context`]
1268    pub fn context() -> *mut c_void {
1269        unsafe { backend_opengl_egl_get_context() }
1270    }
1271
1272    /// This is the EGLDisplay StereoKit receives from eglGetDisplay
1273    /// <https://stereokit.net/Pages/StereoKit/Backend.OpenGLES_EGL/Display.html>
1274    ///
1275    /// see also [`backend_opengl_egl_get_display`]
1276    pub fn display() -> *mut c_void {
1277        unsafe { backend_opengl_egl_get_display() }
1278    }
1279}
1280
1281/// When used with a hierarchy modifying function that will push/pop items onto a
1282/// stack, this can be used to change the behavior of how parent hierarchy items
1283/// will affect the item being added to the top of the stack.
1284/// <https://stereokit.net/Pages/StereoKit/HierarchyParent.html>
1285///
1286/// see also [`Hierarchy`]
1287#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1288#[repr(u32)]
1289pub enum HierarchyParent {
1290    /// Inheriting is generally the default behavior of a hierarchy stack, the
1291    /// current item will inherit the properties of the parent stack item in some
1292    /// form or another.
1293    Inherit = 0,
1294    /// Ignoring the parent hierarchy stack item will let you skip inheriting
1295    /// anything from the parent item. The new item remains exactly as provided.
1296    Ignore = 1,
1297}
1298
1299/// This class represents a stack of transform matrices that build up a transform hierarchy! This can be used like an
1300/// object-less parent-child system, where you push a parent’s transform onto the stack, render child objects relative
1301/// to that parent transform and then pop it off the stack.
1302///
1303/// Performance note: if any matrices are on the hierarchy stack, any render will cause a matrix multiplication to
1304/// occur! So if you have a collection of objects with their transforms baked and cached into matrices for performance
1305/// reasons, you’ll want to ensure there are no matrices in the hierarchy stack, or that the hierarchy is disabled!
1306/// It’ll save you a matrix multiplication in that case :)
1307/// <https://stereokit.net/Pages/StereoKit/Hierarchy.html>
1308///
1309/// ### Examples
1310/// ```
1311/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1312/// use stereokit_rust::{maths::Matrix, system::{Hierarchy, HierarchyParent}, mesh::Mesh,
1313///                      material::Material, util::named_colors};
1314///
1315/// let sphere = Mesh::generate_sphere(0.2, None);
1316/// let material = Material::pbr();
1317/// let transform = Matrix::t([0.4, 0.4, 0.4]);
1318///
1319/// filename_scr = "screenshots/hierarchy.jpeg";
1320/// test_screenshot!( // !!!! Get a proper main loop !!!!
1321///     sphere.draw(token, &material, transform, None, None);
1322///
1323///     assert!(Hierarchy::is_enabled(&token));
1324///
1325///     Hierarchy::push(token, Matrix::t([0.0, -0.5, -0.5]), None);
1326///     sphere.draw(token, &material, transform, Some(named_colors::RED.into()), None);
1327///     assert_eq!(Hierarchy::to_local_point(&token, [0.4, 0.4, 0.4]), [0.4, 0.9, 0.9].into());
1328///     assert_eq!(Hierarchy::to_world_point(&token, [0.4, 0.9, 0.9]), [0.4, 0.4, 0.4].into());
1329///     Hierarchy::pop(token);
1330///
1331///     Hierarchy::push(token, Matrix::t([-0.5, -0.5, 0.25]), Some(HierarchyParent::Ignore));
1332///     sphere.draw(token, &material, transform, Some(named_colors::GREEN.into()), None);
1333///     assert_eq!(Hierarchy::to_local_point(&token, [0.4, 0.4, 0.4]), [0.9, 0.9, 0.15].into());
1334///     assert_eq!(Hierarchy::to_world_point(&token, [0.9, 0.9, 0.15]), [0.4, 0.4, 0.4].into());
1335///
1336///     Hierarchy::enabled(token, false);
1337///     sphere.draw(token, &material, Matrix::IDENTITY, Some(named_colors::BLUE.into()), None);
1338///     assert_eq!(Hierarchy::to_local_point(&token, [0.4, 0.4, 0.4]), [0.4, 0.4, 0.4].into());
1339///     Hierarchy::enabled(token, true);
1340///     Hierarchy::pop(&token);
1341/// );
1342/// ```
1343/// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/hierarchy.jpeg" alt="screenshot" width="200">
1344pub struct Hierarchy;
1345
1346unsafe extern "C" {
1347    pub fn hierarchy_push(transform: *const Matrix, parent_behavior: HierarchyParent);
1348    pub fn hierarchy_push_pose(pose: *const Pose, parent_behavior: HierarchyParent);
1349    pub fn hierarchy_pop();
1350    pub fn hierarchy_set_enabled(enabled: Bool32T);
1351    pub fn hierarchy_is_enabled() -> Bool32T;
1352    pub fn hierarchy_to_world() -> *const Matrix;
1353    pub fn hierarchy_to_local() -> *const Matrix;
1354    pub fn hierarchy_to_local_point(world_pt: *const Vec3) -> Vec3;
1355    pub fn hierarchy_to_local_direction(world_dir: *const Vec3) -> Vec3;
1356    pub fn hierarchy_to_local_rotation(world_orientation: *const Quat) -> Quat;
1357    pub fn hierarchy_to_local_pose(world_pose: *const Pose) -> Pose;
1358    pub fn hierarchy_to_local_ray(world_ray: Ray) -> Ray;
1359    pub fn hierarchy_to_world_point(local_pt: *const Vec3) -> Vec3;
1360    pub fn hierarchy_to_world_direction(local_dir: *const Vec3) -> Vec3;
1361    pub fn hierarchy_to_world_rotation(local_orientation: *const Quat) -> Quat;
1362    pub fn hierarchy_to_world_pose(local_pose: *const Pose) -> Pose;
1363    pub fn hierarchy_to_world_ray(local_ray: Ray) -> Ray;
1364}
1365
1366impl Hierarchy {
1367    /// This is enabled by default. Disabling this will cause any draw call to ignore any Matrices that are on the
1368    /// Hierarchy stack.
1369    /// <https://stereokit.net/Pages/StereoKit/Hierarchy/Enabled.html>
1370    ///
1371    /// see also [`hierarchy_set_enabled`] [`Hierarchy::is_enabled`]
1372    pub fn enabled(_token: &MainThreadToken, enable: bool) {
1373        unsafe { hierarchy_set_enabled(enable as Bool32T) }
1374    }
1375
1376    /// This is enabled by default. Disabling this will cause any draw call to ignore any Matrices that are on the
1377    /// Hierarchy stack.
1378    /// <https://stereokit.net/Pages/StereoKit/Hierarchy/Enabled.html>
1379    ///
1380    /// see also [hierarchy_is_enabled] [`Hierarchy::enabled`]
1381    pub fn is_enabled(_token: &MainThreadToken) -> bool {
1382        unsafe { hierarchy_is_enabled() != 0 }
1383    }
1384
1385    /// Removes the top Matrix from the stack!
1386    /// <https://stereokit.net/Pages/StereoKit/Hierarchy/Pop.html>
1387    ///
1388    /// see also [`hierarchy_pop`] [`Hierarchy::push`]
1389    pub fn pop(_token: &MainThreadToken) {
1390        unsafe { hierarchy_pop() }
1391    }
1392
1393    /// Pushes a transform Matrix (eventually a Pose) onto the stack, and combines it with the Matrix below it. Any draw
1394    /// operation’s Matrix will now be combined with this Matrix to make it relative to the current hierarchy. Use
1395    /// Hierarchy.pop to remove it from the Hierarchy stack! All Push calls must have an accompanying Pop call.
1396    /// <https://stereokit.net/Pages/StereoKit/Hierarchy/Push.html>
1397    /// * `parent_behavior` - This determines how this matrix combines with the parent matrix below it. Normal behavior
1398    ///   is to "inherit" the parent matrix, but there are cases where you may wish to entirely ignore the parent
1399    ///   transform. For example, if you're in UI space, and wish to do some world space rendering. If None, has default
1400    ///   value "Inherit"
1401    ///
1402    /// see also [`hierarchy_push`] [`Hierarchy::pop`]
1403    /// ### Examples
1404    /// ```
1405    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1406    /// use stereokit_rust::{maths::Matrix, system::{Hierarchy, HierarchyParent}};
1407    ///
1408    /// test_steps! { // !!!! Get a proper main loop !!!!
1409    ///     Hierarchy::push(token, Matrix::t([0.0, -0.5, -0.5]), None);
1410    ///     assert_eq!(Hierarchy::to_local_point(token, [0.4, 0.4, 0.4]), [0.4, 0.9, 0.9].into());
1411    ///     assert_eq!(Hierarchy::to_world_point(token, [0.4, 0.9, 0.9]), [0.4, 0.4, 0.4].into());
1412    ///     Hierarchy::pop(token);
1413    /// }
1414    /// ```
1415    pub fn push<M: Into<Matrix>>(_token: &MainThreadToken, transform: M, parent_behavior: Option<HierarchyParent>) {
1416        let parent_behavior = parent_behavior.unwrap_or(HierarchyParent::Inherit);
1417        unsafe { hierarchy_push(&transform.into(), parent_behavior) }
1418    }
1419
1420    /// Converts a world space point into the local space of the current Hierarchy stack!
1421    /// <https://stereokit.net/Pages/StereoKit/Hierarchy/ToLocal.html>
1422    /// * `world_point` - A point in world space.
1423    ///
1424    /// Returns the provided point now in local hierarchy space
1425    /// see also [`hierarchy_to_local_point`] [`Hierarchy::to_world_point`]
1426    /// ### Examples
1427    /// ```
1428    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1429    /// use stereokit_rust::{maths::Pose, system::{Hierarchy, HierarchyParent}};
1430    ///
1431    /// test_steps! { // !!!! Get a proper main loop !!!!
1432    ///     Hierarchy::push(token, Pose::new([0.0, -0.5, -0.5], None), None);
1433    ///     assert_eq!(Hierarchy::to_local_point(token, [0.4, 0.4, 0.4]), [0.4, 0.9, 0.9].into());
1434    ///     assert_eq!(Hierarchy::to_world_point(token, [0.4, 0.9, 0.9]), [0.4, 0.4, 0.4].into());
1435    ///     Hierarchy::pop(token);
1436    /// }
1437    /// ```
1438    pub fn to_local_point<V: Into<Vec3>>(_token: &MainThreadToken, world_point: V) -> Vec3 {
1439        unsafe { hierarchy_to_local_point(&world_point.into()) }
1440    }
1441
1442    /// Converts a world space rotation into the local space of the current Hierarchy stack!
1443    /// <https://stereokit.net/Pages/StereoKit/Hierarchy/ToLocal.html>
1444    /// * `world_orientation` - A rotation in world space
1445    ///
1446    /// Returns the provided rotation now in local hierarchy space
1447    /// see also [`hierarchy_to_local_rotation`] [`Hierarchy::to_world_rotation`]
1448    /// ### Examples
1449    /// ```
1450    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1451    /// use stereokit_rust::{maths::{Matrix, Quat, Vec3}, system::{Hierarchy, HierarchyParent}};
1452    ///
1453    /// test_steps! { // !!!! Get a proper main loop !!!!
1454    ///     Hierarchy::push(token, Matrix::r([0.0, 0.0, 180.0]), None);
1455    ///     let local: Vec3 = Hierarchy::to_local_rotation(token, [90.0, 180.0, 0.0])
1456    ///                           .to_angles_degrees().into();
1457    ///     assert_eq!(local, [-90.0, 0.0, 0.0].into());
1458    ///
1459    ///     let world: Vec3 = Hierarchy::to_world_rotation(token, [90.0, 180.0, 0.0])
1460    ///                           .to_angles_degrees().into();
1461    ///     assert_eq!(world, [-90.0, 0.0, 0.0].into());
1462    ///     Hierarchy::pop(token);
1463    /// }
1464    /// ```
1465    pub fn to_local_rotation<Q: Into<Quat>>(_token: &MainThreadToken, world_orientation: Q) -> Quat {
1466        unsafe { hierarchy_to_local_rotation(&world_orientation.into()) }
1467    }
1468
1469    /// Converts a world pose relative to the current hierarchy stack into local space!
1470    /// <https://stereokit.net/Pages/StereoKit/Hierarchy/ToLocal.html>
1471    /// * `world_pose` - A pose in world space.
1472    ///
1473    /// Returns the provided pose now in local hierarchy space!
1474    /// see also [`hierarchy_to_local_pose`] [Hierarchy::to_local_pose]
1475    /// ### Examples
1476    /// ```
1477    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1478    /// use stereokit_rust::{maths::{Matrix, Quat, Pose}, system::{Hierarchy, HierarchyParent}};
1479    ///
1480    /// test_steps! { // !!!! Get a proper main loop !!!!
1481    ///     Hierarchy::push(token, Matrix::t([0.0, -0.5, -0.5]), None);
1482    ///     let pose = Pose::new([10.0, 20.0, 30.0], None);
1483    ///     assert_eq!(Hierarchy::to_local_pose(token, pose), Pose::new([10.0, 20.5, 30.5], None));
1484    ///     assert_eq!(Hierarchy::to_world_pose(token, Pose::new([10.0, 20.5, 30.5], None)), pose);
1485    ///     Hierarchy::pop(token);
1486    /// }
1487    /// ```
1488    pub fn to_local_pose<P: Into<Pose>>(_token: &MainThreadToken, world_pose: P) -> Pose {
1489        unsafe { hierarchy_to_local_pose(&world_pose.into()) }
1490    }
1491
1492    /// Converts a world ray relative to the current hierarchy stack into local space!
1493    /// <https://stereokit.net/Pages/StereoKit/Hierarchy/ToLocal.html>
1494    /// * `world_ray` - A ray in world space
1495    ///
1496    /// Returns the provided ray now in local hierarchy space
1497    /// see also [`hierarchy_to_local_ray`] [`Hierarchy::to_world_ray`]
1498    /// ### Examples
1499    /// ```
1500    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1501    /// use stereokit_rust::{maths::{Vec3, Matrix, Quat, Ray}, system::{Lines, Hierarchy},
1502    ///     util::{named_colors}, mesh::Mesh, material::{Material, Cull}};
1503    ///
1504    /// // Create Meshes
1505    /// let cube = Mesh::generate_cube(Vec3::ONE * 0.8, None);
1506    /// let sphere = Mesh::generate_sphere(1.0, Some(4));
1507    ///
1508    /// let material = Material::pbr().copy();
1509    /// let transform = Matrix::r(Quat::from_angles(40.0, 50.0, 20.0));
1510    /// let inv = transform.get_inverse();
1511    ///
1512    /// let ray = Ray::new([1.0, 2.0, 2.5 ], [-1.0, -2.0, -2.25]);
1513    ///
1514    /// filename_scr = "screenshots/hierarchy_ray.jpeg";
1515    /// test_screenshot!( // !!!! Get a proper main loop !!!!
1516    ///     let world_space_ray = Hierarchy::to_world_ray(token, ray);
1517    ///     assert_eq!(world_space_ray, ray);
1518    ///     Lines::add_ray(token, world_space_ray, 2.2, named_colors::WHITE, None, 0.02);
1519    ///
1520    ///     Hierarchy::push(token, transform, None);
1521    ///     let local_transform = Matrix::t([-0.1, 0.1, 0.1]);
1522    ///     cube.draw(token, &material, local_transform, Some(named_colors::MAGENTA.into()), None);
1523    ///
1524    ///     let local_space_ray = Hierarchy::to_local_ray(token, world_space_ray);
1525    ///     let mesh_space_ray = local_transform.get_inverse().transform_ray(local_space_ray);
1526    ///     let (contact_cube, ind_cube) = cube.intersect( mesh_space_ray, Some(Cull::Back))
1527    ///                                        .expect("Ray should touch cube");
1528    ///     assert_eq!(ind_cube, 15);
1529    ///
1530    ///     let local_contact_cube = local_transform.transform_point(contact_cube);
1531    ///     let transform_contact = Matrix::t_s(local_contact_cube, Vec3::ONE * 0.1);
1532    ///     sphere.draw(token, &material, transform_contact, Some(named_colors::YELLOW.into()), None );
1533    ///     Hierarchy::pop(token);
1534    /// );
1535    /// ```
1536    /// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/hierarchy_ray.jpeg" alt="screenshot" width="200">
1537    pub fn to_local_ray<R: Into<Ray>>(_token: &MainThreadToken, world_ray: R) -> Ray {
1538        unsafe { hierarchy_to_local_ray(world_ray.into()) }
1539    }
1540
1541    /// Converts a world space direction into the local space of the current Hierarchy stack! This excludes the
1542    /// translation component normally applied to vectors, so it’s still a valid direction.
1543    /// <https://stereokit.net/Pages/StereoKit/Hierarchy/ToLocalDirection.html>
1544    /// * `world_direction` - A direction in world space
1545    ///
1546    /// Returns the provided direction now in local hierarchy space
1547    /// see also [`hierarchy_to_local_direction`] [`Hierarchy::to_world_direction`]
1548    /// ### Examples
1549    /// ```
1550    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1551    /// use stereokit_rust::{maths::{Matrix, Vec3}, system::{Hierarchy, HierarchyParent}};
1552    ///
1553    /// test_steps! { // !!!! Get a proper main loop !!!!
1554    ///     Hierarchy::push(token, Matrix::r([0.0, 0.0, 180.0]), None);
1555    ///     assert_eq!(Hierarchy::to_local_direction(token, [1.0, 0.0, 0.0]), [-1.0, 0.0, 0.0].into());
1556    ///     assert_eq!(Hierarchy::to_world_direction(token, [-1.0, 0.0, 0.0]), [1.0, 0.0, 0.0].into());
1557    ///     Hierarchy::pop(token);
1558    /// }
1559    /// ```
1560    /// see also [`hierarchy_to_local_direction`] [`hierarchy_to_world_direction`]
1561    pub fn to_local_direction<V: Into<Vec3>>(_token: &MainThreadToken, world_direction: V) -> Vec3 {
1562        unsafe { hierarchy_to_local_direction(&world_direction.into()) }
1563    }
1564
1565    /// Converts a local point relative to the current hierarchy stack into world space!
1566    /// <https://stereokit.net/Pages/StereoKit/Hierarchy/ToWorld.html>
1567    /// * `local_point` - A point in local space
1568    ///
1569    /// Returns the provided point now in world space
1570    ///
1571    /// see also [`hierarchy_to_world_point`]
1572    /// see example in [`Hierarchy::to_local_point`]
1573    pub fn to_world_point<V: Into<Vec3>>(_token: &MainThreadToken, local_point: V) -> Vec3 {
1574        unsafe { hierarchy_to_world_point(&local_point.into()) }
1575    }
1576
1577    /// Converts a local rotation relative to the current hierarchy stack into world space!
1578    /// <https://stereokit.net/Pages/StereoKit/Hierarchy/ToWorld.html>
1579    /// * `local_orientaion` - A rotation in local space
1580    ///
1581    /// Returns the provided rotation now in world space
1582    ///
1583    /// see also [`hierarchy_to_world_rotation`]
1584    /// see example in [`Hierarchy::to_local_rotation`]
1585    pub fn to_world_rotation<Q: Into<Quat>>(_token: &MainThreadToken, local_orientation: Q) -> Quat {
1586        unsafe { hierarchy_to_world_rotation(&local_orientation.into()) }
1587    }
1588
1589    /// Converts a local pose relative to the current hierarchy stack into world space!
1590    /// <https://stereokit.net/Pages/StereoKit/Hierarchy/ToWorld.html>
1591    /// * `local_pose` - A pose in local space
1592    ///
1593    /// Returns the provided pose now in world space
1594    ///
1595    /// see also [`hierarchy_to_world_pose`]
1596    /// see example in [`Hierarchy::to_local_pose`]
1597    pub fn to_world_pose<P: Into<Pose>>(_token: &MainThreadToken, local_pose: P) -> Pose {
1598        unsafe { hierarchy_to_world_pose(&local_pose.into()) }
1599    }
1600
1601    /// Converts a local ray relative to the current hierarchy stack into world space!
1602    /// <https://stereokit.net/Pages/StereoKit/Hierarchy/ToWorld.html>
1603    /// * `local_ray` - A ray in local space
1604    ///
1605    /// Returns the provided ray now in world space
1606    ///
1607    /// see also [`hierarchy_to_world_ray`]
1608    /// see example in [`Hierarchy::to_local_ray`]
1609    pub fn to_world_ray<P: Into<Ray>>(_token: &MainThreadToken, local_ray: P) -> Ray {
1610        unsafe { hierarchy_to_world_ray(local_ray.into()) }
1611    }
1612
1613    /// Converts a local direction relative to the current hierarchy stack into world space! This excludes the
1614    /// translation component normally applied to vectors, so it’s still a valid direction.
1615    /// <https://stereokit.net/Pages/StereoKit/Hierarchy/ToWorldDirection.html>
1616    /// * `local_direction` - A direction in local space
1617    ///
1618    /// Returns the provided direction now in world space
1619    ///
1620    /// see also [`hierarchy_to_world_direction`]
1621    /// see example in [`Hierarchy::to_local_direction`]
1622    pub fn to_world_direction<V: Into<Vec3>>(_token: &MainThreadToken, local_direction: V) -> Vec3 {
1623        unsafe { hierarchy_to_world_direction(&local_direction.into()) }
1624    }
1625}
1626
1627bitflags::bitflags! {
1628/// What type of device is the source of the pointer? This is a bit-flag that can contain some input source family
1629/// information.
1630/// <https://stereokit.net/Pages/StereoKit/InputSource.html>
1631///
1632/// see also [`Pointer`] [`Input`]
1633    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
1634    #[repr(C)]
1635    pub struct InputSource: u32 {
1636        /// Matches with all input sources!
1637        const Any = 2147483647;
1638        /// Zero, this is not a valid input source, and should never be used!
1639        const None = 0;
1640        /// Matches with any hand input source.
1641        const Hand = 1;
1642        /// Matches with left hand input sources.
1643        const HandLeft = 2;
1644        /// Matches with right hand input sources.
1645        const HandRight = 4;
1646        /// Matches with Gaze category input sources.
1647        #[deprecated(since = "0.4.0", note = "Use Input::get_eyes() instead")]
1648        const Gaze = 16;
1649        /// Matches with the head gaze input source.
1650        #[deprecated(since = "0.4.0", note = "Use Input::get_eyes() instead")]
1651        const GazeHead = 32;
1652        /// Matches with the eye gaze input source.
1653        #[deprecated(since = "0.4.0", note = "Use Input::get_eyes() instead")]
1654        const GazeEyes = 64;
1655        /// Matches with mouse cursor simulated gaze as an input source.
1656        #[deprecated(since = "0.4.0", note = "Use Input::get_eyes() instead")]
1657        const GazeCurzor = 128;
1658        /// Matches with any input source that has an activation button!
1659        #[deprecated(since = "0.4.0", note = "Not working any more")]
1660        const CanPress = 256;
1661    }
1662}
1663
1664/// An enum for indicating which hand to use!
1665/// <https://stereokit.net/Pages/StereoKit/Handed.html>
1666///
1667/// see also [Hand] [Controller]
1668#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1669#[repr(u32)]
1670pub enum Handed {
1671    /// Left hand.
1672    Left = 0,
1673    /// Right hand.
1674    Right = 1,
1675    /// The number of hands one generally has, this is much nicer than doing a for loop with ‘2’ as the condition! It’s
1676    /// much clearer when you can loop Hand.Max times instead.
1677    Max = 2,
1678}
1679
1680bitflags::bitflags! {
1681    /// A bit-flag for the current state of a button input.
1682    /// <https://stereokit.net/Pages/StereoKit/BtnState.html>
1683    ///
1684    /// see also [`Input`] [`Ui`]
1685    /// ### Examples
1686    /// ```
1687    /// use stereokit_rust::system::BtnState;
1688    ///
1689    /// let state = BtnState::Active | BtnState::JustActive;
1690    /// assert!(state.contains(BtnState::Active));
1691    /// assert!(state.contains(BtnState::JustActive));
1692    /// assert!(!state.contains(BtnState::JustInactive));
1693    /// assert!(!state.contains(BtnState::Changed));
1694    /// ```
1695    #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, PartialOrd)]
1696    #[repr(C)]
1697    pub struct BtnState: u32 {
1698        /// Is the button currently up, unpressed?
1699        const Inactive = 0;
1700        /// Is the button currently down, pressed?
1701        const Active = 1 << 0;
1702        /// Has the button just been released? Only true for a single frame.
1703        const JustInactive = 1 << 1;
1704        /// Has the button just been pressed? Only true for a single frame.
1705        const JustActive = 1 << 2;
1706        /// Has the button just changed state this frame?
1707        const Changed = Self::JustInactive.bits() | Self::JustActive.bits();
1708        /// Matches with all states!
1709        const Any = 0x7FFFFFFF;
1710    }
1711}
1712
1713/// A collection of extension methods for the BtnState enum that makes bit-field checks a little easier.
1714/// <https://stereokit.net/Pages/StereoKit/BtnStateExtensions.html>
1715impl BtnState {
1716    /// Creates a Button State using the current and previous frame's state! These two states allow us to add the
1717    /// "JustActive" and "JustInactive" bitflags when changes happen.
1718    /// <https://stereokit.net/Pages/StereoKit/BtnState/Make.html>
1719    /// * `was_active` - Was it active previously?
1720    /// * `is_active` - And is it active currently?
1721    ///
1722    /// Returns a bitflag with "Just" events added in!
1723    /// ### Examples
1724    /// ```
1725    /// use stereokit_rust::system::BtnState;
1726    ///
1727    /// // Button was not pressed, now it is pressed
1728    /// let state = BtnState::make(false, true);
1729    /// assert!(state.contains(BtnState::Active));
1730    /// assert!(state.contains(BtnState::JustActive));
1731    /// assert!(!state.contains(BtnState::JustInactive));
1732    ///
1733    /// // Button was pressed, now it is not pressed
1734    /// let state = BtnState::make(true, false);
1735    /// assert!(!state.contains(BtnState::Active));
1736    /// assert!(state.contains(BtnState::JustInactive));
1737    /// assert!(!state.contains(BtnState::JustActive));
1738    ///
1739    /// // Button was pressed, still pressed
1740    /// let state = BtnState::make(true, true);
1741    /// assert!(state.contains(BtnState::Active));
1742    /// assert!(!state.contains(BtnState::JustActive));
1743    /// assert!(!state.contains(BtnState::JustInactive));
1744    /// ```
1745    pub fn make(was_active: bool, is_active: bool) -> BtnState {
1746        let mut result = if is_active { BtnState::Active } else { BtnState::Inactive };
1747
1748        if was_active && !is_active {
1749            result |= BtnState::JustInactive;
1750        }
1751        if is_active && !was_active {
1752            result |= BtnState::JustActive;
1753        }
1754
1755        result
1756    }
1757
1758    /// Is the button pressed?
1759    /// <https://stereokit.net/Pages/StereoKit/BtnStateExtensions/IsActive.html>
1760    pub fn is_active(&self) -> bool {
1761        (*self & BtnState::Active) > BtnState::Inactive
1762    }
1763
1764    /// Has the button just been pressed this frame?
1765    /// <https://stereokit.net/Pages/StereoKit/BtnStateExtensions/IsJustActive.html>
1766    pub fn is_just_active(&self) -> bool {
1767        (*self & BtnState::JustActive) > BtnState::Inactive
1768    }
1769
1770    /// Has the button just been released this frame?
1771    /// <https://stereokit.net/Pages/StereoKit/BtnStateExtensions/IsJustInactive.html>
1772    pub fn is_just_inactive(&self) -> bool {
1773        (*self & BtnState::JustInactive) > BtnState::Inactive
1774    }
1775
1776    /// Was the button either presses or released this frame?
1777    /// <https://stereokit.net/Pages/StereoKit/BtnStateExtensions/IsChanged.html>
1778    pub fn is_changed(&self) -> bool {
1779        (*self & BtnState::Changed) > BtnState::Inactive
1780    }
1781}
1782
1783/// This is the tracking state of a sensory input in the world, like a controller’s position sensor, or a QR code
1784/// identified by a tracking system.
1785/// <https://stereokit.net/Pages/StereoKit/TrackState.html>
1786///
1787/// see also [`Controller`]
1788/// ### Examples
1789/// ```
1790/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1791/// use stereokit_rust::system::{TrackState, Input, Handed};
1792///
1793/// let controller = Input::controller(Handed::Right);
1794///
1795/// assert_eq!(controller.tracked_pos, TrackState::Lost);
1796/// assert_ne!(controller.tracked_pos, TrackState::Inferred);
1797/// assert_ne!(controller.tracked_pos, TrackState::Known);
1798///
1799/// assert_eq!(controller.tracked_rot, TrackState::Lost);
1800/// assert_ne!(controller.tracked_rot, TrackState::Inferred);
1801/// assert_ne!(controller.tracked_rot, TrackState::Known);
1802/// ```
1803#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1804#[repr(u32)]
1805pub enum TrackState {
1806    /// The system has no current knowledge about the state of this input. It may be out of visibility, or possibly just
1807    /// disconnected.
1808    Lost = 0,
1809    /// The system doesn’t know for sure where this is, but it has an educated guess that may be inferred from previous
1810    /// data at a lower quality. For example, a controller may still have accelerometer data after going out of view,
1811    /// which can still be accurate for a short time after losing optical tracking.
1812    Inferred = 1,
1813    /// The system actively knows where this input is. Within the constraints of the relevant hardware’s capabilities,
1814    /// this is as accurate as it gets!
1815    Known = 2,
1816}
1817
1818/// Pointer is an abstraction of a number of different input sources, and a way to surface input events!
1819/// <https://stereokit.net/Pages/StereoKit/Pointer.html>
1820///
1821/// see also [`Input`]
1822/// ### Examples
1823/// ```
1824/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1825/// use stereokit_rust::{system::{Input, InputSource, Pointer, BtnState, Handed, TrackState},
1826///                      maths::{Vec3, Quat, Pose, Ray}};
1827///
1828/// // By default we only have the 2 hands.
1829/// assert_eq!(Input::pointer_count(None), 0);
1830/// let pointer = Input::pointer(0, None);
1831///
1832/// assert_eq!(pointer.source, InputSource::None);
1833/// assert_eq!(pointer.state, BtnState::Inactive);
1834/// assert_eq!(pointer.tracked, BtnState::Inactive);
1835/// assert_eq!(pointer.orientation, Quat::ZERO);
1836/// assert_eq!(pointer.ray, Ray::ZERO);
1837/// assert_eq!(pointer.get_pose(), Pose::ZERO);
1838///
1839/// let hand_pointer = Input::pointer(1, Some(InputSource::Hand));
1840/// assert_eq!(hand_pointer.source, InputSource::None);
1841/// assert_eq!(pointer.state, BtnState::Inactive);
1842/// assert_eq!(pointer.tracked, BtnState::Inactive);
1843/// assert_eq!(pointer.orientation, Quat::ZERO);
1844/// assert_eq!(pointer.ray, Ray::ZERO);
1845/// assert_eq!(pointer.get_pose(), Pose::ZERO);
1846/// ```
1847#[derive(Debug, Copy, Clone)]
1848#[repr(C)]
1849pub struct Pointer {
1850    /// What input source did this pointer come from? This is a bit-flag that contains input family and capability
1851    /// information.
1852    pub source: InputSource,
1853    /// Is the pointer source being tracked right now?
1854    pub tracked: BtnState,
1855    /// What is the state of the input source’s ‘button’, if it has one?
1856    pub state: BtnState,
1857    /// A ray in the direction of the pointer.
1858    pub ray: Ray,
1859    /// Orientation of the pointer! Since a Ray has no concept of ‘up’, this can be used to retrieve more orientation
1860    /// information.
1861    pub orientation: Quat,
1862}
1863
1864impl Pointer {
1865    /// Convenience function that turns ray.position and orientation into a Pose.
1866    /// <https://stereokit.net/Pages/StereoKit/Pointer/Pose.html>
1867    pub fn get_pose(&self) -> Pose {
1868        Pose::new(self.ray.position, Some(self.orientation))
1869    }
1870}
1871
1872/// Contains information to represents a joint on the hand.
1873/// <https://stereokit.net/Pages/StereoKit/HandJoint.html>
1874///
1875/// see also  [`Input::hand`] [`Hand::get`] [`FingerId`] [`JointId`]
1876/// ### Examples
1877/// ```
1878/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1879/// use stereokit_rust::{system::{Input, Handed, FingerId, JointId},
1880///                      maths::{Vec3, Quat, Pose, Ray}};
1881///
1882/// let hand = Input::hand(Handed::Left);
1883/// let index_root = hand.get(FingerId::Index, JointId::Root);
1884/// assert_eq!(index_root.position, Vec3 { x: -0.011, y: -0.038, z: 0.004 });
1885///
1886/// let hand = Input::hand(Handed::Right);
1887/// let index_root = hand.get(FingerId::Index, JointId::Root);
1888/// assert_eq!(index_root.position, Vec3 { x:  0.011, y: -0.038, z: 0.004 });
1889///
1890/// let index_tip = hand.get(FingerId::Index, JointId::Tip);
1891/// assert_eq!(index_tip.position, Vec3 { x: 0.029, y: 0.097, z: -0.041 });
1892/// assert_eq!(index_tip.orientation, Quat { x: -0.193, y: -0.004, z: 0.046, w: -0.98 });
1893/// assert_eq!(index_tip.radius, 0.007);
1894/// ```
1895#[derive(Debug, Copy, Clone, PartialEq)]
1896#[repr(C)]
1897pub struct HandJoint {
1898    /// The center of the joint’s world space location.
1899    pub position: Vec3,
1900    /// The joint’s world space orientation, where Forward points to the next joint down the finger, and Up will point
1901    /// towards the back of the hand. On the left hand, Right will point towards the thumb, and on the right hand, Right
1902    /// will point away from the thumb.
1903    pub orientation: Quat,
1904    /// The distance, in meters, to the surface of the hand from this joint.
1905    pub radius: f32,
1906}
1907
1908/// Index values for each finger! From 0-4, from thumb to little finger.
1909/// <https://stereokit.net/Pages/StereoKit/FingerId.html>
1910///
1911/// see also  [`Input::hand`] [`Hand::get`] [`JointId`]
1912#[derive(Debug, Copy, Clone)]
1913#[repr(u32)]
1914pub enum FingerId {
1915    /// Thumb
1916    Thumb = 0,
1917    /// The primary index/pointer finger! Finger 1.
1918    Index = 1,
1919    /// next to the index finger.
1920    Middle = 2,
1921    /// ! What does one do with this finger? I guess… wear rings on it?
1922    Ring = 3,
1923    /// The smallest little finger! AKA, The Pinky.
1924    Little = 4,
1925}
1926
1927/// Here’s where hands get crazy! Technical terms, and watch out for the thumbs!
1928/// <https://stereokit.net/Pages/StereoKit/JointId.html>
1929///
1930/// see also  [`Input::hand`] [`Hand::get`] [`FingerId`]
1931#[derive(Debug, Copy, Clone)]
1932#[repr(u32)]
1933pub enum JointId {
1934    /// This is at the base of the hand, right above the wrist. For the thumb, Root and KnuckleMajor have the same
1935    /// value.
1936    Root = 0,
1937    /// Joint 1. These are the knuckles at the top of the palm! For the thumb, Root and KnuckleMajor have the same
1938    /// value.
1939    KnuckleMajor = 1,
1940    ///  These are the knuckles in the middle of the finger! First joints on the fingers themselves.
1941    KnuckleMid = 2,
1942    /// The joints right below the fingertip!
1943    KnuckleMinor = 3,
1944    /// The end/tip of each finger!
1945    Tip = 4,
1946}
1947
1948/// This enum provides information about StereoKit’s hand tracking data source. It allows you to distinguish between
1949/// true hand data such as that provided by a Leap Motion Controller, and simulated data that StereoKit provides when
1950/// true hand data is not present.
1951/// <https://stereokit.net/Pages/StereoKit/HandSource.html>
1952///
1953/// see also [`Input::hand_source`]
1954#[derive(Debug, Copy, Clone, PartialEq)]
1955#[repr(u32)]
1956pub enum HandSource {
1957    /// There is currently no source of hand data! This means there are no tracked controllers, or active hand tracking
1958    /// systems. This may happen if the user has hand tracking disabled, and no active controllers.
1959    None = 0,
1960    /// The current hand data is a simulation of hand data rather than true hand data. It is backed by either a
1961    /// controller, or a mouse, and may have a more limited range of motion.
1962    Simulated = 1,
1963    /// This is true hand data which exhibits the full range of motion of a normal hand. It is backed by something like
1964    /// a Leap Motion Controller, or some other optical (or maybe glove?) hand tracking system.
1965    Articulated = 2,
1966    /// This hand data is provided by your use of SK’s override functionality. What properties it exhibits depends on
1967    /// what override data you’re sending to StereoKit!
1968    Overridden = 3,
1969}
1970
1971/// Id of a simulated hand pose, for use with Input.HandSimPoseRemove
1972/// <https://stereokit.net/Pages/StereoKit/HandSimId.html>
1973///
1974/// see also [`Input::hand_sim_pose_add`] [`Input::hand_sim_pose_remove`]
1975pub type HandSimId = i32;
1976
1977#[derive(Debug, Copy, Clone)]
1978#[repr(C)]
1979/// Information about a hand!
1980/// <https://stereokit.net/Pages/StereoKit/Hand.html>
1981///
1982/// see also [`Input::hand`]
1983/// ### Examples
1984/// ```
1985/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
1986/// use stereokit_rust::{system::{Hierarchy, Input, Handed, FingerId, JointId}, util::named_colors,
1987///                      maths::{Vec3, Quat, Pose, Matrix}, mesh::Mesh, material::Material};
1988///
1989/// let hand = Input::hand(Handed::Left);
1990/// let thumb_tip = hand.get(FingerId::Thumb, JointId::Tip);
1991///
1992/// let sphere = Mesh::generate_sphere(1.0, Some(12));
1993/// let mut material_sphere = Material::pbr().copy();
1994/// let main_transform = Matrix::t_r([0.0, -0.05, 0.88], [0.0, 210.0, 0.0]);
1995///
1996/// filename_scr = "screenshots/hand.jpeg";
1997/// test_screenshot!( // !!!! Get a proper main loop !!!!
1998///     for finger in 0..5 {
1999///         for joint in 0..5 {
2000///             let joint_pose = hand.get_u(finger, joint);
2001///             let transform = Matrix::t_s(joint_pose.position, Vec3::ONE * joint_pose.radius);
2002///             Hierarchy::push(token, main_transform, None);
2003///                 sphere.draw(token, &material_sphere, transform, Some(named_colors::BLACK.into()), None);
2004///             Hierarchy::pop(token);
2005///         }
2006///     }
2007/// );
2008/// ```
2009/// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/hand.jpeg" alt="screenshot" width="200">
2010///
2011/// ```
2012/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2013/// use stereokit_rust::{system::{Input, Handed, FingerId, JointId, BtnState, Hand, HandJoint},
2014///                      maths::{Vec3, Quat, Pose}};
2015///
2016/// let hand = Input::hand(Handed::Left);
2017/// let thumb_tip = hand.get(FingerId::Thumb, JointId::Tip);
2018/// assert_eq!(thumb_tip.position, Vec3 { x: -0.072, y: 0.028, z: -0.055 });
2019///
2020/// let hand = Input::hand(Handed::Right);
2021///
2022/// let thumb_tip  = hand.get(FingerId::Thumb, JointId::Tip);
2023/// let thumb_tip2 = hand.get_u(0,4);
2024/// let thumb_tip3 = hand.fingers[FingerId::Thumb as usize][JointId::Tip as usize];
2025/// assert_eq!(thumb_tip.position, Vec3 { x: 0.072, y: 0.028, z: -0.055 });
2026/// assert_eq!(thumb_tip, thumb_tip2);
2027/// assert_eq!(thumb_tip, thumb_tip3);
2028///
2029/// assert_eq!(hand.wrist,      Pose::ZERO);
2030/// assert_eq!(hand.palm,       Pose::IDENTITY);
2031/// assert_eq!(hand.aim,        Pose::ZERO);
2032/// assert_eq!(hand.pinch_pt,   Vec3::ZERO);
2033/// assert_eq!(hand.handed,     Handed::Right);
2034/// assert_eq!(hand.tracked,    BtnState::Inactive);
2035/// assert_eq!(hand.pinch,      BtnState::Inactive);
2036/// assert_eq!(hand.grip,       BtnState::Inactive);
2037/// assert_eq!(hand.aim_ready,  BtnState::Inactive);
2038///
2039/// assert_eq!(hand.is_gripped(), false);
2040/// assert_eq!(hand.is_just_gripped(), false);
2041/// assert_eq!(hand.is_just_ungripped(), false);
2042/// assert_eq!(hand.is_pinched(), false);
2043/// assert_eq!(hand.is_just_pinched(), false);
2044/// assert_eq!(hand.is_just_unpinched(), false);
2045/// assert_eq!(hand.is_tracked(), false);
2046/// assert_eq!(hand.is_just_tracked(), false);
2047/// assert_eq!(hand.is_just_untracked(), false);
2048/// ```
2049pub struct Hand {
2050    /// This is a 2D array with 25 HandJoints. You can get the right joint by finger*5 + joint
2051    pub fingers: [[HandJoint; 5usize]; 5usize],
2052    /// Pose of the wrist. TODO: Not populated right now.
2053    pub wrist: Pose,
2054    /// The position and orientation of the palm! Position is specifically defined as the middle of the middle finger’s
2055    /// root (metacarpal) bone. For orientation, Forward is the direction the flat of the palm is facing, “Iron Man”
2056    /// style. X+ is to the outside of the right hand, and to the inside of the left hand.
2057    pub palm: Pose,
2058    /// A pose an orientation representing where the hand is pointing to. This may be provided by the OpenXR runtime, or
2059    /// be a fallback provided by StereoKit. Typically this starts and the index finger's primary knuckle, and points in
2060    /// the same direction as a line drawn from the shoulder to the knuckle.
2061    pub aim: Pose,
2062    /// This is an approximation of where the center of a ‘pinch’ gesture occurs, and is used internally by StereoKit
2063    /// for some tasks, such as UI. For simulated hands, this position will give you the most stable pinch location
2064    /// possible. For real hands, it’ll be pretty close to the stablest point you’ll get. This is especially important
2065    /// for when the user begins and ends their pinch action, as you’ll often see a lot of extra movement in the fingers
2066    /// then.
2067    pub pinch_pt: Vec3,
2068    /// Is this a right hand, or a left hand?
2069    pub handed: Handed,
2070    /// Is the hand being tracked by the sensors right now?
2071    pub tracked: BtnState,
2072    /// Is the hand making a pinch gesture right now? Finger and thumb together.
2073    pub pinch: BtnState,
2074    /// Is the hand making a grip gesture right now? Fingers next to the palm.
2075    pub grip: BtnState,
2076    /// This is a filter state for when the hand is ready to interact with something at a distance. This often factors
2077    /// into account palm direction, as well as distance from the body, and the current pinch and tracked state.
2078    pub aim_ready: BtnState,
2079    /// This is the size of the hand, calculated by measuring the length of the middle finger! This is calculated by
2080    /// adding the distances between each joint, then adding the joint radius of the root and tip. This value is
2081    /// recalculated at relatively frequent intervals, and can vary by as much as a centimeter.
2082    pub size: f32,
2083    /// What percentage of activation is the pinch gesture right now? Where 0 is a hand in an outstretched resting
2084    /// position, and 1 is fingers touching, within a device error tolerant threshold.
2085    pub pinch_activation: f32,
2086    /// What percentage of activation is the grip gesture right now? Where 0 is a hand in an outstretched resting
2087    /// position, and 1 is ring finger touching the base of the palm, within a device error tolerant threshold.
2088    pub grip_activation: f32,
2089}
2090
2091impl Hand {
2092    /// Returns the joint information of the indicated hand joint! This also includes fingertips as a ‘joint’. This is
2093    /// the same as the [] operator. Note that for thumbs, there are only 4 ‘joints’ in reality, so StereoKit has
2094    /// JointId.Root and JointId.KnuckleMajor as the same pose, so JointId.Tip is still the tip of the thumb!
2095    /// <https://stereokit.net/Pages/StereoKit/Hand/Get.html>
2096    pub fn get(&self, finger: FingerId, joint: JointId) -> HandJoint {
2097        self.fingers[finger as usize][joint as usize]
2098    }
2099
2100    /// Returns the joint information of the indicated hand joint! This also includes fingertips as a ‘joint’. This is
2101    /// the same as the [] operator. Note that for thumbs, there are only 4 ‘joints’ in reality, so StereoKit has
2102    /// JointId.Root and JointId.KnuckleMajor as the same pose, so JointId.Tip is still the tip of the thumb!
2103    /// <https://stereokit.net/Pages/StereoKit/Hand/Get.html>
2104    pub fn get_u(&self, finger: usize, joint: usize) -> HandJoint {
2105        self.fingers[finger][joint]
2106    }
2107
2108    /// Are the fingers currently gripped?
2109    /// <https://stereokit.net/Pages/StereoKit/Hand/IsGripped.html>
2110    pub fn is_gripped(&self) -> bool {
2111        (self.grip & BtnState::Active) > BtnState::Inactive
2112    }
2113
2114    /// Have the fingers just been gripped this frame?
2115    /// <https://stereokit.net/Pages/StereoKit/Hand/IsJustGripped.html>
2116    pub fn is_just_gripped(&self) -> bool {
2117        (self.grip & BtnState::JustActive) > BtnState::Inactive
2118    }
2119
2120    /// Have the fingers just stopped being gripped this frame?
2121    /// <https://stereokit.net/Pages/StereoKit/Hand/IsJustUngripped.html>
2122    pub fn is_just_ungripped(&self) -> bool {
2123        (self.grip & BtnState::JustInactive) > BtnState::Inactive
2124    }
2125
2126    /// Are the fingers currently pinched?
2127    /// <https://stereokit.net/Pages/StereoKit/Hand/IsPinched.html>
2128    pub fn is_pinched(&self) -> bool {
2129        (self.pinch & BtnState::Active) > BtnState::Inactive
2130    }
2131
2132    /// Have the fingers just been pinched this frame?
2133    /// <https://stereokit.net/Pages/StereoKit/Hand/IsJustPinched.html>
2134    pub fn is_just_pinched(&self) -> bool {
2135        (self.pinch & BtnState::JustActive) > BtnState::Inactive
2136    }
2137
2138    /// Have the fingers just stopped being pinched this frame?
2139    /// <https://stereokit.net/Pages/StereoKit/Hand/IsJustUnpinched.html>
2140    pub fn is_just_unpinched(&self) -> bool {
2141        (self.pinch & BtnState::JustInactive) > BtnState::Inactive
2142    }
2143
2144    /// Is the hand being tracked by the sensors right now?
2145    /// <https://stereokit.net/Pages/StereoKit/Hand/IsTracked.html>
2146    pub fn is_tracked(&self) -> bool {
2147        (self.tracked & BtnState::Active) > BtnState::Inactive
2148    }
2149
2150    /// Has the hand just started being tracked this frame?
2151    /// <https://stereokit.net/Pages/StereoKit/Hand/IsJustTracked.html>
2152    pub fn is_just_tracked(&self) -> bool {
2153        (self.tracked & BtnState::JustActive) > BtnState::Inactive
2154    }
2155
2156    /// Has the hand just stopped being tracked this frame?
2157    /// <https://stereokit.net/Pages/StereoKit/Hand/IsJustUntracked.html>
2158    pub fn is_just_untracked(&self) -> bool {
2159        (self.tracked & BtnState::JustInactive) > BtnState::Inactive
2160    }
2161
2162    /// Set the Material used to render the hand! The default material uses an offset of 10 to ensure it gets drawn
2163    /// overtop of other elements.
2164    /// <https://stereokit.net/Pages/StereoKit/Hand/Material.html>
2165    ///
2166    /// see also [`input_hand_material`]
2167    /// ### Examples
2168    /// ```
2169    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2170    /// use stereokit_rust::{system::{Input, Handed, Hand}, material::Material, util::Color128};
2171    ///
2172    /// let mut hand = Input::hand(Handed::Right);
2173    ///
2174    /// let mut material = Material::hand().copy();
2175    /// material.color_tint(Color128::new(0.8, 0.5, 0.1, 1.0));
2176    /// hand.material(&material);
2177    ///
2178    /// assert_ne!(material, Material::hand())
2179    /// ```
2180    pub fn material(&mut self, material: impl AsRef<Material>) -> &mut Self {
2181        unsafe { input_hand_material(self.handed, material.as_ref().0.as_ptr()) }
2182        self
2183    }
2184
2185    /// Sets whether or not StereoKit should render this hand for you. Turn this to false if you’re going to render your
2186    /// own, or don’t need the hand itself to be visible.
2187    /// <https://stereokit.net/Pages/StereoKit/Hand/Visible.html>
2188    ///
2189    /// see also [`input_hand_visible`]
2190    pub fn visible(&mut self, visible: bool) -> &mut Self {
2191        unsafe { input_hand_visible(self.handed, visible as Bool32T) }
2192        self
2193    }
2194}
2195
2196/// Represents an input from an XR headset’s controller!
2197/// <https://stereokit.net/Pages/StereoKit/ControllerKey.html>
2198///
2199/// see also [`Input::hand_sim_pose_add`]
2200#[derive(Debug, Copy, Clone)]
2201#[repr(u32)]
2202pub enum ControllerKey {
2203    /// Doesn’t represent a key, generally means this item has not been set to any particular value!
2204    None_ = 0,
2205    /// The trigger button on the controller, where the user’s index finger typically sits.
2206    Trigger = 1,
2207    /// The grip button on the controller, usually where the fingers that are not the index finger sit.
2208    Grip = 2,
2209    /// This is the lower of the two primary thumb buttons, sometimes labelled X, and sometimes A.
2210    X1 = 3,
2211    /// This is the upper of the two primary thumb buttons, sometimes labelled Y, and sometimes B.
2212    X2 = 4,
2213    /// This is when the thumbstick on the controller is actually pressed. This has nothing to do with the horizontal
2214    /// or vertical movement of the stick.
2215    Stick = 5,
2216    /// This is the menu, or settings button of the controller.
2217    Menu = 6,
2218}
2219
2220/// This represents a physical controller input device! Tracking information, buttons, analog sticks and triggers!
2221/// There’s also a Menu button that’s tracked separately at Input.ContollerMenu.
2222/// <https://stereokit.net/Pages/StereoKit/Controller.html>
2223///
2224/// see also [`Input::controller`]
2225/// ### Examples
2226/// ```
2227/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2228/// use stereokit_rust::{system::{Hierarchy, Input, Handed},
2229///                      maths::{Matrix}, model::Model, material::Material};
2230///
2231/// let model_left = Input::get_controller_model(Handed::Left);
2232/// let model_right = Input::get_controller_model(Handed::Right);
2233/// let transform_left = Matrix::t_r([-0.05, 0.0, 0.93], [90.0, 00.0, 0.0]);
2234/// let transform_right = Matrix::t_r([0.05, 0.0, 0.93], [90.0, 00.0, 0.0]);
2235///
2236/// filename_scr = "screenshots/controller.jpeg";
2237/// test_screenshot!( // !!!! Get a proper main loop !!!!
2238///     model_left.draw(token, transform_left, None, None);
2239///     model_right.draw(token, transform_right, None, None);
2240/// );
2241/// ```
2242/// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/controller.jpeg" alt="screenshot" width="200">
2243///
2244/// ```
2245/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2246/// use stereokit_rust::{system::{Input, Handed, BtnState, TrackState},
2247///                      maths::{Vec2, Vec3, Quat, Pose}};
2248///
2249/// let controller = Input::controller(Handed::Left);
2250///
2251/// let controller = Input::controller(Handed::Right);
2252///
2253/// assert_eq!(controller.pose,       Pose::ZERO);
2254/// assert_eq!(controller.palm,       Pose::ZERO);
2255/// assert_eq!(controller.aim,        Pose::ZERO);
2256/// assert_eq!(controller.tracked,    BtnState::Inactive);
2257/// assert_eq!(controller.tracked_pos, TrackState::Lost);
2258/// assert_eq!(controller.tracked_rot, TrackState::Lost);
2259/// assert_eq!(controller.x1,         BtnState::Inactive);
2260/// assert_eq!(controller.x2,         BtnState::Inactive);
2261/// assert_eq!(controller.trigger,    0.0);
2262/// assert_eq!(controller.grip,       0.0);
2263/// assert_eq!(controller.stick,      Vec2::ZERO);
2264///
2265/// assert_eq!(controller.is_just_tracked(), false);
2266/// assert_eq!(controller.is_just_untracked(), false);
2267/// assert_eq!(controller.is_stick_clicked(), false);
2268/// assert_eq!(controller.is_stick_just_clicked(), false);
2269/// assert_eq!(controller.is_tracked(), false);
2270/// assert_eq!(controller.is_x1_just_pressed(), false);
2271/// assert_eq!(controller.is_x1_just_unpressed(), false);
2272/// assert_eq!(controller.is_x1_pressed(), false);
2273/// assert_eq!(controller.is_x2_just_pressed(), false);
2274/// assert_eq!(controller.is_x2_just_unpressed(), false);
2275/// assert_eq!(controller.is_x2_pressed(), false);
2276/// ```
2277#[derive(Debug, Copy, Clone)]
2278#[repr(C)]
2279pub struct Controller {
2280    /// The grip pose of the controller. This approximately represents the center of the hand’s position. Check
2281    /// trackedPos and trackedRot for the current state of the pose data.
2282    pub pose: Pose,
2283    pub palm: Pose,
2284    /// The aim pose of a controller is where the controller ‘points’ from and to. This is great for pointer rays and
2285    /// far interactions.
2286    pub aim: Pose,
2287    /// This tells the current tracking state of this controller overall. If either position or rotation are trackable,
2288    /// then this will report tracked. Typically, positional tracking will be lost first, when the controller goes out
2289    /// of view, and rotational tracking will often remain as long as the controller is still connected. This is a good
2290    /// way to check if the controller is connected to the system at all.
2291    pub tracked: BtnState,
2292    /// This tells the current tracking state of the controller’s position information. This is often the first part of
2293    /// tracking data to go, so it can often be good to account for this on occasions.
2294    pub tracked_pos: TrackState,
2295    /// This tells the current tracking state of the controller’s rotational information.
2296    pub tracked_rot: TrackState,
2297    /// This represents the click state of the controller’s analog stick or directional controller.
2298    pub stick_click: BtnState,
2299    /// The current state of the controller’s X1 button. Depending on the specific hardware, this is the first general
2300    /// purpose button on the controller. For example, on an Oculus Quest Touch controller this would represent ‘X’ on
2301    /// the left controller, and ‘A’ on the right controller.
2302    pub x1: BtnState,
2303    ///The current state of the controller’s X2 button. Depending on the specific hardware, this is the second general
2304    /// purpose button on the controller. For example, on an Oculus Quest Touch controller this would represent ‘Y’ on
2305    /// the left controller, and ‘B’ on the right controller.
2306    pub x2: BtnState,
2307    /// The trigger button at the user’s index finger. These buttons typically have a wide range of activation, so this
2308    /// is provided as a value from 0.0 -> 1.0, where 0 is no interaction, and 1 is full interaction. If a controller
2309    /// has binary activation, this will jump straight from 0 to 1.
2310    pub trigger: f32,
2311    /// The grip button typically sits under the user’s middle finger. These buttons occasionally have a wide range of
2312    /// activation, so this is provided as a value from 0.0 -> 1.0, where 0 is no interaction, and 1 is full
2313    /// interaction. If a controller has binary activation, this will jump straight from 0 to 1.
2314    pub grip: f32,
2315    /// This is the current 2-axis position of the analog stick or equivalent directional controller. This generally
2316    /// ranges from -1 to +1 on each axis. This is a raw input, so dead-zones and similar issues are not accounted for
2317    /// here, unless modified by the OpenXR platform itself.
2318    pub stick: Vec2,
2319}
2320
2321impl Controller {
2322    /// Is the controller’s X1 button currently pressed? Depending on the specific hardware, this is the first
2323    /// general purpose button on the controller. For example, on an Oculus Quest Touch controller this would
2324    /// represent ‘X’ on the left controller, and ‘A’ on the right controller.
2325    /// <https://stereokit.net/Pages/StereoKit/Controller/IsX1Pressed.html>
2326    pub fn is_x1_pressed(&self) -> bool {
2327        (self.x1 & BtnState::Active) > BtnState::Inactive
2328    }
2329
2330    /// Has the controller’s X1 button just been pressed this frame? Depending on the specific hardware, this is the
2331    /// first general purpose button on the controller. For example, on an Oculus Quest Touch controller this would
2332    /// represent ‘X’ on the left controller, and ‘A’ on the right controller.
2333    /// <https://stereokit.net/Pages/StereoKit/Controller/IsX1JustPressed.html>
2334    pub fn is_x1_just_pressed(&self) -> bool {
2335        (self.x1 & BtnState::JustActive) > BtnState::Inactive
2336    }
2337
2338    /// Has the controller’s X1 button just been released this frame? Depending on the specific hardware, this is
2339    /// the first general purpose button on the controller. For example, on an Oculus Quest Touch controller this
2340    /// would represent ‘X’ on the left controller, and ‘A’ on the right controller.
2341    /// <https://stereokit.net/Pages/StereoKit/Controller/IsX1JustUnPressed.html>
2342    pub fn is_x1_just_unpressed(&self) -> bool {
2343        (self.x1 & BtnState::JustInactive) > BtnState::Inactive
2344    }
2345
2346    /// Is the controller’s X2 button currently pressed? Depending on the specific hardware, this is the second
2347    /// general purpose button on the controller. For example, on an Oculus Quest Touch controller this would
2348    /// represent ‘Y’ on the left controller, and ‘B’ on the right controller.
2349    /// <https://stereokit.net/Pages/StereoKit/Controller/IsX2Pressed.html>
2350    pub fn is_x2_pressed(&self) -> bool {
2351        (self.x2 & BtnState::Active) > BtnState::Inactive
2352    }
2353
2354    /// Has the controller’s X2 button just been pressed this frame? Depending on the specific hardware, this is the
2355    /// second general purpose button on the controller. For example, on an Oculus Quest Touch controller this would
2356    /// represent ‘Y’ on the left controller, and ‘B’ on the right controller.
2357    /// <https://stereokit.net/Pages/StereoKit/Controller/IsX2JustPressed.html>
2358    pub fn is_x2_just_pressed(&self) -> bool {
2359        (self.x2 & BtnState::JustActive) > BtnState::Inactive
2360    }
2361
2362    /// Has the controller’s X2 button just been released this frame? Depending on the specific hardware, this is
2363    /// the second general purpose button on the controller. For example, on an Oculus Quest Touch controller this
2364    /// would represent ‘Y’ on the left controller, and ‘B’ on the right controller.
2365    /// <https://stereokit.net/Pages/StereoKit/Controller/IsX2JustUnPressed.html>
2366    pub fn is_x2_just_unpressed(&self) -> bool {
2367        (self.x2 & BtnState::JustInactive) > BtnState::Inactive
2368    }
2369
2370    /// Is the analog stick/directional controller button currently being actively pressed?
2371    /// <https://stereokit.net/Pages/StereoKit/Controller/IsStickClicked.html>
2372    pub fn is_stick_clicked(&self) -> bool {
2373        (self.stick_click & BtnState::Active) > BtnState::Inactive
2374    }
2375
2376    /// Is the analog stick/directional controller button currently being actively pressed?
2377    /// <https://stereokit.net/Pages/StereoKit/Controller/IsStickJustClicked.html>
2378    pub fn is_stick_just_clicked(&self) -> bool {
2379        (self.stick_click & BtnState::JustActive) > BtnState::Inactive
2380    }
2381
2382    /// Has the analog stick/directional controller button just been released this frame?
2383    /// <https://stereokit.net/Pages/StereoKit/Controller/IsStickJustUnclicked.html>
2384    pub fn is_stick_just_unclicked(&self) -> bool {
2385        (self.stick_click & BtnState::JustInactive) > BtnState::Inactive
2386    }
2387
2388    /// Is the controller being tracked by the sensors right now?
2389    /// <https://stereokit.net/Pages/StereoKit/Controller/IsTracked.html>
2390    pub fn is_tracked(&self) -> bool {
2391        (self.tracked & BtnState::Active) > BtnState::Inactive
2392    }
2393
2394    /// Has the controller just started being tracked this frame?
2395    /// <https://stereokit.net/Pages/StereoKit/Controller/IsJustTracked.html>
2396    pub fn is_just_tracked(&self) -> bool {
2397        (self.tracked & BtnState::JustActive) > BtnState::Inactive
2398    }
2399
2400    /// Has the analog stick/directional controller button just been released this frame?
2401    /// <https://stereokit.net/Pages/StereoKit/Controller/IsJustUntracked.html>
2402    pub fn is_just_untracked(&self) -> bool {
2403        (self.tracked & BtnState::JustInactive) > BtnState::Inactive
2404    }
2405}
2406
2407/// This stores information about the mouse! What’s its state, where’s it pointed, do we even have one?
2408/// <https://stereokit.net/Pages/StereoKit/Mouse.html>
2409///
2410/// see also [`Input::get_mouse`]
2411/// ### Examples
2412/// ```
2413/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2414/// use stereokit_rust::{system::Input, maths::{Vec2, Vec3}};
2415///
2416/// let mouse = Input::get_mouse();
2417///
2418/// assert_eq!(mouse.is_available(),false);
2419/// assert_eq!(mouse.pos,           Vec2::ZERO);
2420/// assert_eq!(mouse.pos_change,    Vec2::ZERO);
2421/// assert_eq!(mouse.scroll,        0.0);
2422/// assert_eq!(mouse.scroll_change, 0.0);
2423///
2424/// assert_eq!(mouse.get_ray().position, Vec3::ZERO);
2425/// // Warning: No ray if the mouse isn't available!
2426/// // assert_eq!(mouse.get_ray().direction, Vec3::new(f32::NAN, f32::NAN, f32::NAN));
2427/// ```
2428#[derive(Debug, Copy, Clone)]
2429#[repr(C)]
2430pub struct Mouse {
2431    /// Is the mouse available to use? Most MR systems likely won’t have a mouse!
2432    pub available: Bool32T,
2433    /// Position of the mouse relative to the window it’s in! This is the number of pixels from the top left corner of
2434    /// the screen.
2435    pub pos: Vec2,
2436    /// How much has the mouse’s position changed in the current frame? Measured in pixels.
2437    pub pos_change: Vec2,
2438    /// What’s the current scroll value for the mouse’s scroll wheel? TODO: Units
2439    pub scroll: f32,
2440    /// How much has the scroll wheel value changed during this frame? TODO: Units
2441    pub scroll_change: f32,
2442}
2443
2444impl Mouse {
2445    /// Ray representing the position and orientation that the current Input::get_mouse() is pointing in.
2446    /// <https://stereokit.net/Pages/StereoKit/Mouse/Ray.html>
2447    ///
2448    /// see also [`ray_from_mouse`]
2449    pub fn get_ray(&self) -> Ray {
2450        let mut out_ray = Ray::default();
2451        unsafe { ray_from_mouse(self.pos, &mut out_ray) };
2452        out_ray
2453    }
2454
2455    /// Is the mouse available ?
2456    /// <https://stereokit.net/Pages/StereoKit/Mouse/Available.html>
2457    pub fn is_available(&self) -> bool {
2458        self.available != 0
2459    }
2460}
2461
2462/// A collection of system key codes, representing keyboard characters and mouse buttons. Based on VK codes.
2463/// <https://stereokit.net/Pages/StereoKit/Key.html>
2464///
2465/// see also [`Input::key`] [`Input::key_inject_press`] [`Input::key_inject_release`] [`Input::hand_sim_pose_add`]
2466#[derive(Debug, Copy, Clone, PartialEq, Eq)]
2467#[repr(u32)]
2468pub enum Key {
2469    None = 0,
2470    MouseLeft = 1,
2471    MouseRight = 2,
2472    MouseCenter = 4,
2473    MouseForward = 5,
2474    MouseBack = 6,
2475    Backspace = 8,
2476    Tab = 9,
2477    Return = 13,
2478    Shift = 16,
2479    Ctrl = 17,
2480    Alt = 18,
2481    CapsLock = 20,
2482    Esc = 27,
2483    Space = 32,
2484    End = 35,
2485    Home = 36,
2486    Left = 37,
2487    Right = 39,
2488    Up = 38,
2489    Down = 40,
2490    PageUp = 33,
2491    PageDown = 34,
2492    PrintScreen = 42,
2493    KeyInsert = 45,
2494    Del = 46,
2495    Key0 = 48,
2496    Key1 = 49,
2497    Key2 = 50,
2498    Key3 = 51,
2499    Key4 = 52,
2500    Key5 = 53,
2501    Key6 = 54,
2502    Key7 = 55,
2503    Key8 = 56,
2504    Key9 = 57,
2505    A = 65,
2506    B = 66,
2507    C = 67,
2508    D = 68,
2509    E = 69,
2510    F = 70,
2511    G = 71,
2512    H = 72,
2513    I = 73,
2514    J = 74,
2515    K = 75,
2516    L = 76,
2517    M = 77,
2518    N = 78,
2519    O = 79,
2520    P = 80,
2521    Q = 81,
2522    R = 82,
2523    S = 83,
2524    T = 84,
2525    U = 85,
2526    V = 86,
2527    W = 87,
2528    X = 88,
2529    Y = 89,
2530    Z = 90,
2531    Numpad0 = 96,
2532    Numpad1 = 97,
2533    Numpad2 = 98,
2534    Numpad3 = 99,
2535    Numpad4 = 100,
2536    Numpad5 = 101,
2537    Numpad6 = 102,
2538    Numpad7 = 103,
2539    Numpad8 = 104,
2540    Numpad9 = 105,
2541    F1 = 112,
2542    F2 = 113,
2543    F3 = 114,
2544    F4 = 115,
2545    F5 = 116,
2546    F6 = 117,
2547    F7 = 118,
2548    F8 = 119,
2549    F9 = 120,
2550    F10 = 121,
2551    F11 = 122,
2552    F12 = 123,
2553    Comma = 188,
2554    Period = 190,
2555    SlashFwd = 191,
2556    SlashBack = 220,
2557    Semicolon = 186,
2558    Apostrophe = 222,
2559    BracketOpen = 219,
2560    BracketClose = 221,
2561    Minus = 189,
2562    Equals = 187,
2563    Backtick = 192,
2564    LCmd = 91,
2565    RCmd = 92,
2566    Multiply = 106,
2567    Add = 107,
2568    Subtract = 109,
2569    Decimal = 110,
2570    Divide = 111,
2571}
2572
2573/// Input from the system come from this class! Hands, eyes, heads, mice and pointers!
2574/// <https://stereokit.net/Pages/StereoKit/Input.html>
2575///
2576/// ### Examples
2577/// ```
2578/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2579/// use stereokit_rust::{system::{Input, InputSource, Handed},
2580///                      maths::{Vec2, Vec3, Quat, Pose}};
2581///
2582/// let controller = Input::controller(Handed::Left);
2583/// assert_eq!(controller.is_tracked(), false);
2584///
2585/// let hand = Input::hand(Handed::Right);
2586/// assert_eq!(hand.is_tracked(), false);
2587///
2588/// let head = Input::get_head();
2589/// assert_eq!(head , Pose::IDENTITY);
2590///
2591/// let mouse = Input::get_mouse();
2592/// assert_eq!(mouse.is_available(), false);
2593///
2594/// assert_eq!(Input::pointer_count(None), 0);
2595/// let pointer = Input::pointer(0, Some(InputSource::Hand));
2596/// assert_eq!(pointer.source, InputSource::None);
2597/// ```
2598pub struct Input;
2599
2600unsafe extern "C" {
2601    pub fn input_pointer_count(filter: InputSource) -> i32;
2602    pub fn input_pointer(index: i32, filter: InputSource) -> Pointer;
2603    pub fn input_hand(hand: Handed) -> *const Hand;
2604    pub fn input_hand_override(hand: Handed, in_arr_hand_joints: *const HandJoint);
2605    pub fn input_hand_source(hand: Handed) -> HandSource;
2606    pub fn input_controller(hand: Handed) -> *const Controller;
2607    pub fn input_controller_menu() -> BtnState;
2608    pub fn input_controller_model_set(hand: Handed, model: ModelT);
2609    pub fn input_controller_model_get(hand: Handed) -> ModelT;
2610    pub fn input_head() -> Pose;
2611    pub fn input_eyes() -> Pose;
2612    pub fn input_eyes_tracked() -> BtnState;
2613    pub fn input_mouse() -> *const Mouse;
2614    pub fn input_key(key: Key) -> BtnState;
2615    pub fn input_key_inject_press(key: Key);
2616    pub fn input_key_inject_release(key: Key);
2617    pub fn input_text_consume() -> u32;
2618    pub fn input_text_reset();
2619    pub fn input_text_inject_char(character: u32);
2620    pub fn input_hand_visible(hand: Handed, visible: Bool32T);
2621    // Deprecated: pub fn input_hand_solid(hand: Handed, solid: Bool32T);
2622    pub fn input_hand_material(hand: Handed, material: MaterialT);
2623    pub fn input_get_finger_glow() -> Bool32T;
2624    pub fn input_set_finger_glow(visible: Bool32T);
2625    pub fn input_hand_sim_pose_add(
2626        in_arr_palm_relative_hand_joints_25: *const Pose,
2627        button1: ControllerKey,
2628        and_button2: ControllerKey,
2629        or_hotkey1: Key,
2630        and_hotkey2: Key,
2631    ) -> HandSimId;
2632    pub fn input_hand_sim_pose_remove(id: HandSimId);
2633    pub fn input_hand_sim_pose_clear();
2634
2635    #[deprecated(since = "0.4.0", note = "Not working anymore")]
2636    pub fn input_subscribe(
2637        source: InputSource,
2638        input_event: BtnState,
2639        input_event_callback: Option<
2640            unsafe extern "C" fn(source: InputSource, input_event: BtnState, in_pointer: *const Pointer),
2641        >,
2642    );
2643
2644    #[deprecated(since = "0.4.0", note = "Not working anymore")]
2645    pub fn input_unsubscribe(
2646        source: InputSource,
2647        input_event: BtnState,
2648        input_event_callback: Option<
2649            unsafe extern "C" fn(source: InputSource, input_event: BtnState, in_pointer: *const Pointer),
2650        >,
2651    );
2652
2653    #[deprecated(since = "0.4.0", note = "Not working anymore")]
2654    pub fn input_fire_event(source: InputSource, input_event: BtnState, pointer: *const Pointer);
2655}
2656
2657impl Input {
2658    /// When StereoKit is rendering the input source, this allows you to override the controller Model SK uses. The
2659    /// Model SK uses by default may be provided from the OpenXR runtime depending on extension support, but if not, SK
2660    /// does have a default Model.
2661    /// Setting this to None will restore SK's default.
2662    /// <https://stereokit.net/Pages/StereoKit/Input/ControllerModelSet.html>
2663    /// * `handed` - The hand to assign the Model to.
2664    /// * `model` - The Model to use to represent the controller.
2665    ///   None is valid, and will restore SK's default model.
2666    ///
2667    ///  see also [`input_controller_model_set`]  [`Input::get_controller_model`]  
2668    /// ### Examples
2669    /// ```
2670    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2671    /// use stereokit_rust::{system::{Input, Handed}, model::Model};
2672    ///
2673    /// assert_eq!(Input::get_controller_model(Handed::Left).get_id(), "default/model_controller_l");
2674    ///
2675    /// let model_left = Model::from_file("center.glb", None)
2676    ///                     .expect("mobiles.gltf should be a valid model");
2677    ///
2678    /// Input::set_controller_model(Handed::Left, Some(&model_left));
2679    /// assert_eq!(Input::get_controller_model(Handed::Left).get_id(), "center.glb");
2680    ///
2681    /// Input::set_controller_model(Handed::Left, None);
2682    /// assert_eq!(Input::get_controller_model(Handed::Left).get_id(), "default/model_controller_l");
2683    /// ```
2684    pub fn set_controller_model(handed: Handed, model: Option<&Model>) {
2685        match model {
2686            Some(model) => unsafe { input_controller_model_set(handed, model.0.as_ptr()) },
2687            None => unsafe { input_controller_model_set(handed, null_mut()) },
2688        }
2689    }
2690
2691    /// Gets raw controller input data from the system. Note that not all buttons provided here are guaranteed to be
2692    /// present on the user’s physical controller. Controllers are also not guaranteed to be available on the system,
2693    /// and are never simulated.
2694    /// <https://stereokit.net/Pages/StereoKit/Input/Controller.html>
2695    /// * `handed` - The handedness of the controller to get the state of.
2696    ///
2697    /// Returns a reference to a class that contains state information  about the indicated controller.
2698    /// see also [`input_controller`]    
2699    /// ### Examples
2700    /// ```
2701    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2702    /// use stereokit_rust::system::{Input, Handed, TrackState};
2703    ///
2704    /// let controller = Input::controller(Handed::Right);
2705    ///
2706    /// assert_eq!(controller.tracked_pos, TrackState::Lost);
2707    /// assert_eq!(controller.tracked_rot, TrackState::Lost);
2708    /// ```
2709    pub fn controller(handed: Handed) -> Controller {
2710        unsafe { *input_controller(handed) }
2711    }
2712
2713    /// This function allows you to artifically insert an input event, simulating any device source and event type you
2714    /// want.
2715    /// <https://stereokit.net/Pages/StereoKit/Input/FireEvent.html>
2716    /// * `event_source` - The event source to simulate, this is a bit flag.
2717    /// * `event_types` - The event type to simulate, this is a bit flag.
2718    /// * `pointer` - The pointer data to pass along with this simulated input event.
2719    ///
2720    /// see also [`input_fire_event`]    
2721    /// ### Examples
2722    /// ```
2723    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2724    /// use stereokit_rust::{system::{Input, InputSource, Pointer, BtnState, Handed, TrackState},
2725    ///                      maths::{Vec3, Quat, Pose, Ray}};
2726    ///
2727    /// let pointer = Input::pointer(0, None);
2728    /// assert_eq!(pointer.source, InputSource::None);
2729    ///
2730    /// test_steps!( // !!!! Get a proper main loop !!!!
2731    ///     assert_eq!(pointer.state, BtnState::Inactive);
2732    ///     assert_eq!(pointer.tracked, BtnState::Inactive);
2733    ///     if iter == 0 {    
2734    ///         Input::fire_event(InputSource::CanPress, BtnState::Active, &pointer);
2735    ///     } else if iter == 1 {
2736    ///         Input::fire_event(InputSource::Hand | InputSource::HandLeft, BtnState::JustInactive, &pointer);
2737    ///     }
2738    /// );
2739    /// ```
2740    #[deprecated(since = "0.4.0", note = "Not working anymore")]
2741    #[allow(deprecated)]
2742    pub fn fire_event(event_source: InputSource, event_types: BtnState, pointer: &Pointer) {
2743        unsafe { input_fire_event(event_source, event_types, pointer) };
2744    }
2745
2746    /// Retrieves all the information about the user’s hand! StereoKit will always provide hand information, however
2747    /// sometimes that information is simulated, like in the case of a mouse, or controllers.
2748    ///
2749    /// Note that this is a pointer to the hand information, and it’s a good chunk of data, so it’s a good idea to grab
2750    /// it once and keep it around for the frame, or at least function, rather than asking for it again and again each
2751    /// time you want to touch something.
2752    /// <https://stereokit.net/Pages/StereoKit/Input/Hand.html>
2753    /// * `handed` - Do you want the left or the right hand? 0 is left, and 1 is right.
2754    ///
2755    /// Returns a copy of the entire set of hand data!
2756    /// see also [`input_hand`]    
2757    /// ### Examples
2758    /// ```
2759    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2760    /// use stereokit_rust::system::{Input, Handed, Hand, HandJoint, FingerId, JointId};
2761    /// use stereokit_rust::maths::{Vec3, Quat, Pose};
2762    ///
2763    /// let hand = Input::hand(Handed::Left);
2764    /// let thumb_tip = hand.get(FingerId::Thumb, JointId::Tip);
2765    /// assert_eq!(thumb_tip.position, Vec3 { x: -0.072, y: 0.028, z: -0.055 });
2766    ///
2767    /// let hand = Input::hand(Handed::Right);
2768    /// let thumb_tip = hand.get(FingerId::Thumb, JointId::Tip);
2769    /// assert_eq!(thumb_tip.position, Vec3 { x: 0.072, y: 0.028, z: -0.055 });
2770    /// ```
2771    pub fn hand(handed: Handed) -> Hand {
2772        unsafe { *input_hand(handed) }
2773    }
2774
2775    /// Clear out the override status from Input::hand_override, and restore the user’s control over it again.
2776    /// <https://stereokit.net/Pages/StereoKit/Input/HandClearOverride.html>
2777    /// * `hand` - Which hand are we clearing the override on?
2778    ///
2779    /// see also [`input_hand_override`]    
2780    /// ### Examples
2781    /// ```
2782    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2783    /// use stereokit_rust::{system::{Input, Handed, HandJoint, FingerId, JointId},
2784    ///                      maths::{Vec3, Quat}};
2785    ///
2786    /// let mut hand_joints = [HandJoint { position: Vec3::ZERO, orientation: Quat::IDENTITY, radius: 0.0 }; 25];
2787    ///
2788    /// Input::hand_override(Handed::Left, &hand_joints);
2789    ///
2790    ///
2791    /// test_steps!( // !!!! Get a proper main loop !!!!
2792    ///     if iter == 0 {
2793    ///         let hand = Input::hand(Handed::Left);
2794    ///         let thumb_tip = hand.get(FingerId::Thumb, JointId::Tip);
2795    ///         assert_eq!(thumb_tip.position, Vec3::ZERO);
2796    ///     } else if iter == 1 {
2797    ///         Input::hand_clear_override(Handed::Left);
2798    ///     }
2799    /// );
2800    /// ```
2801    pub fn hand_clear_override(hand: Handed) {
2802        unsafe { input_hand_override(hand, null()) };
2803    }
2804
2805    /// This allows you to completely override the hand’s pose information! It is still treated like the user’s hand,
2806    /// so this is great for simulating input for testing purposes. It will remain overridden until you call
2807    /// Input::hand_clear_override.
2808    /// <https://stereokit.net/Pages/StereoKit/Input/HandOverride.html>
2809    /// * `hand` - Which hand should be overridden?
2810    /// * `joints` - A 2D array of 25 joints that should be used as StereoKit's hand information. See `Hand.fingers`
2811    ///   for more information.
2812    ///
2813    /// see also [`input_hand_override`]
2814    /// see example in [`Input::hand_clear_override`]
2815    pub fn hand_override(hand: Handed, joints: &[HandJoint]) {
2816        unsafe { input_hand_override(hand, joints.as_ptr()) };
2817    }
2818
2819    /// Set the Material used to render the hand! The default material uses an offset of 10 to ensure it gets drawn
2820    /// overtop of other elements.
2821    /// <https://stereokit.net/Pages/StereoKit/Input/HandMaterial.html>
2822    /// * `hand` - The hand to assign the Material to. If Handed::Max, this will set the value for both hands.
2823    /// * `material` - The new material. If None, will reset to the default value
2824    ///
2825    /// see also [`input_hand_material`] [`Material::hand`]
2826    /// ### Examples
2827    /// ```
2828    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2829    /// use stereokit_rust::{system::{Input, Handed}, util::named_colors,
2830    ///                      material::Material};
2831    ///
2832    /// let mut hand_material = Material::hand().copy();
2833    /// hand_material.color_tint(named_colors::YELLOW).id("My_hand_material");
2834    /// Input::hand_material(Handed::Left, Some(hand_material));
2835    ///
2836    /// test_steps! ( // !!!! Get a proper main loop !!!!
2837    ///     if iter == 0 {
2838    ///         // Of course, Material::hand() is not modified.
2839    ///         assert_eq!(Material::hand().get_id(), "default/material_hand");
2840    ///     } else if iter == 1 {
2841    ///         // The reason why Material::hand() should not be modified:
2842    ///         Input::hand_material(Handed::Left, None);
2843    ///     }
2844    /// );
2845    /// ```
2846    pub fn hand_material(hand: Handed, material: Option<Material>) {
2847        match material {
2848            Some(material) => unsafe { input_hand_material(hand, material.0.as_ptr()) },
2849            None => unsafe { input_hand_material(hand, null_mut()) },
2850        }
2851    }
2852
2853    /// StereoKit will use controller inputs to simulate an articulated hand. This function allows you to add new
2854    /// simulated poses to different controller or keyboard buttons!
2855    /// <https://stereokit.net/Pages/StereoKit/Input/HandSimPoseAdd.html>
2856    /// * `hand_joints_palm_relative_25` - 25 joint poses, thumb to pinky, and root to tip with two duplicate poses for
2857    ///   the thumb root joint. These should be right handed, and relative to the palm joint.
2858    /// * `button1` - Controller button to activate this pose, can/ be None if this is a keyboard only pose.
2859    /// * `and_button2` - Second controller button required to activate this pose. First must also be pressed. Can be
2860    ///   None if it's only a single button pose.
2861    /// * `or_hotkey1` - Keyboard key to activate this pose, can be None if this is a controller only pose.
2862    /// * `and_hotkey2` - Second keyboard key required to activatethis pose. First must also be pressed. Can be None if
2863    ///   it's only a single key pose.
2864    ///
2865    /// Returns the id of the hand sim pose, so it can be removed later.
2866    /// see also [`input_hand_sim_pose_add`]    
2867    /// ### Examples
2868    /// ```
2869    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2870    /// use stereokit_rust::{system::{Input, Handed, HandJoint, FingerId, JointId, ControllerKey, Key},
2871    ///                      maths::{Vec3, Quat, Pose}};
2872    ///
2873    /// let hand_joints = [Pose::IDENTITY;25];
2874    ///
2875    /// let id = Input::hand_sim_pose_add(&hand_joints, ControllerKey::Trigger, ControllerKey::None_, Key::None, Key::None);
2876    /// assert_eq!(id, 5);
2877    ///
2878    /// let hand = Input::hand(Handed::Left);
2879    ///
2880    /// Input::hand_sim_pose_remove(id);
2881    ///
2882    /// let id = Input::hand_sim_pose_add(&hand_joints, ControllerKey::Grip, ControllerKey::None_, Key::None, Key::None);
2883    /// assert_eq!(id, 6);
2884    ///
2885    /// Input::hand_sim_pose_clear();
2886    ///
2887    /// let id = Input::hand_sim_pose_add(&hand_joints, ControllerKey::X1, ControllerKey::None_, Key::None, Key::None);
2888    /// assert_eq!(id, 7);
2889    /// ```
2890    pub fn hand_sim_pose_add(
2891        hand_joints_palm_relative_25: &[Pose],
2892        button1: ControllerKey,
2893        and_button2: ControllerKey,
2894        or_hotkey1: Key,
2895        and_hotkey2: Key,
2896    ) -> HandSimId {
2897        unsafe {
2898            input_hand_sim_pose_add(
2899                hand_joints_palm_relative_25.as_ptr(),
2900                button1,
2901                and_button2,
2902                or_hotkey1,
2903                and_hotkey2,
2904            )
2905        }
2906    }
2907
2908    /// This clears all registered hand simulation poses, including the ones that StereoKit registers by default!
2909    /// <https://stereokit.net/Pages/StereoKit/Input/HandSimPoseClear.html>
2910    ///
2911    /// see also [`input_hand_sim_pose_clear`]   
2912    /// see example in [`Input::hand_sim_pose_add`]
2913    pub fn hand_sim_pose_clear() {
2914        unsafe { input_hand_sim_pose_clear() };
2915    }
2916
2917    /// Lets you remove an existing hand pose.
2918    /// <https://stereokit.net/Pages/StereoKit/Input/HandSimPoseRemove.html>
2919    /// * `id` - Any valid or invalid hand sim pose id.
2920    ///
2921    /// see also [`input_hand_sim_pose_remove`]    
2922    /// see example in [`Input::hand_sim_pose_add`]
2923    pub fn hand_sim_pose_remove(id: HandSimId) {
2924        unsafe { input_hand_sim_pose_remove(id) };
2925    }
2926
2927    /// This gets the current source of the hand joints! This allows you to distinguish between fully articulated
2928    /// joints, and simulated hand joints that may not have the same range of mobility. Note that this may change during
2929    /// a session, the user may put down their controllers, automatically switching to hands, or visa versa.
2930    /// <https://stereokit.net/Pages/StereoKit/Input/HandSource.html>
2931    /// * `hand` - Do  you want the left or right hand?
2932    ///
2933    /// Returns information about hand tracking data source.
2934    /// see also [`input_hand_source`]    
2935    /// ### Examples
2936    /// ```
2937    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2938    /// use stereokit_rust::system::{Input, Handed, HandSource};
2939    ///
2940    /// let hand_source = Input::hand_source(Handed::Left);
2941    /// let hand_source = Input::hand_source(Handed::Right);
2942    ///
2943    /// xr_mode_stop_here!();
2944    /// // These are the expected results for offscreen tests on a PC:
2945    /// assert_eq!(hand_source, HandSource::None);
2946    /// ```
2947    pub fn hand_source(hand: Handed) -> HandSource {
2948        unsafe { input_hand_source(hand) }
2949    }
2950
2951    /// Sets whether or not StereoKit should render the hand for you. Turn this to false if you’re going to render your
2952    /// own, or don’t need the hand itself to be visible.
2953    /// <https://stereokit.net/Pages/StereoKit/Input/HandVisible.html>
2954    /// * `hand` - If Handed.Max, this will set the value for  both hands.
2955    /// * `visible` - True, StereoKit renders this. False, it doesn't.
2956    ///
2957    /// see also [`input_hand_visible`]    
2958    /// ### Examples
2959    /// ```
2960    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2961    /// use stereokit_rust::system::{Input, Handed, HandSource};
2962    ///
2963    /// Input::hand_visible(Handed::Right, false);
2964    /// Input::hand_visible(Handed::Max, false);
2965    /// Input::hand_visible(Handed::Left, true);
2966    /// ```
2967    pub fn hand_visible(hand: Handed, visible: bool) {
2968        unsafe { input_hand_visible(hand, visible as Bool32T) };
2969    }
2970
2971    /// This controls the visibility of StereoKit's finger glow effect on the UI. When true, SK will fill out global
2972    /// shader variable `sk_fingertip[2]` with the location of the pointer finger's tips. When false, or the hand is
2973    /// untracked, the location will be set to an unlikely faraway position.
2974    /// <https://stereokit.net/Pages/StereoKit/Input/FingerGlow.html>
2975    /// * `visible` - True, StereoKit renders this. False, it doesn't.
2976    ///
2977    /// see also [`input_set_finger_glow`]    
2978    /// ### Examples
2979    /// ```
2980    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
2981    /// use stereokit_rust::system::{Input, Handed, HandSource};
2982    ///
2983    /// assert_eq!(Input::get_finger_glow(), true);
2984    ///
2985    /// Input::finger_glow(false);
2986    ///
2987    /// assert_eq!(Input::get_finger_glow(), false);
2988    ///
2989    /// Input::finger_glow(true);
2990    /// assert_eq!(Input::get_finger_glow(), true);
2991    /// ```
2992    pub fn finger_glow(visible: bool) {
2993        unsafe { input_set_finger_glow(visible as Bool32T) };
2994    }
2995
2996    /// Keyboard key state! On desktop this is super handy, but even standalone MR devices can have bluetooth keyboards,
2997    /// or even just holographic system keyboards!
2998    /// <https://stereokit.net/Pages/StereoKit/Input/Key.html>
2999    /// * `key` - The key to get the state of. Any key!
3000    ///
3001    /// Returns a BtnState with a number of different bits of info about whether or not the key was pressed or released
3002    /// this frame.
3003    /// see also [`input_key`]    
3004    /// ### Examples
3005    /// ```
3006    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
3007    /// use stereokit_rust::system::{Input, Key, BtnState};
3008    ///
3009    /// let key_state = Input::key(Key::A);
3010    ///
3011    /// assert_eq!(key_state, BtnState::Inactive);
3012    /// assert_eq!(key_state.is_active(), false);
3013    /// assert_eq!(key_state.is_just_active(), false);
3014    /// assert_eq!(key_state.is_just_inactive(), false);
3015    /// assert_eq!(key_state.is_changed(), false);
3016    /// ```
3017    pub fn key(key: Key) -> BtnState {
3018        unsafe { input_key(key) }
3019    }
3020
3021    /// This will inject a key press event into StereoKit’s input event queue. It will be processed at the start of the
3022    /// next frame, and will be indistinguishable from a physical key press. Remember to release your key as well!
3023    ///
3024    /// This will not submit text to StereoKit’s text queue, and will not show up in places like UI.Input. For that, you
3025    /// must submit a TextInjectChar call.
3026    /// <https://stereokit.net/Pages/StereoKit/Input/KeyInjectPress.html>
3027    /// * `key` - The key to press.
3028    ///
3029    /// see also [`input_key_inject_press`]    
3030    /// ### Examples
3031    /// ```
3032    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
3033    /// use stereokit_rust::{system::{Input, Key, BtnState}};
3034    ///
3035    ///
3036    /// test_steps!( // !!!! Get a proper main loop !!!!
3037    ///     if iter == 0 {    
3038    ///         assert_eq!(Input::key(Key::A).is_just_active(), false);
3039    ///         Input::key_inject_press(Key::A);
3040    ///     } else if iter == 1 {
3041    ///         assert_eq!(Input::key(Key::A).is_just_active(), true);
3042    ///         Input::key_inject_release(Key::A);
3043    ///     } else if iter == 2 {
3044    ///         Input::key_inject_release(Key::A);
3045    ///         assert_eq!(Input::key(Key::A).is_just_inactive(), true);
3046    ///         Input::key_inject_press(Key::A);
3047    ///     } else if iter == 3 {
3048    ///         assert_eq!(Input::key(Key::A).is_active(), true);
3049    ///     }
3050    /// );
3051    /// assert_eq!(Input::key(Key::A).is_active(), true);
3052    /// ```
3053    pub fn key_inject_press(key: Key) {
3054        unsafe { input_key_inject_press(key) };
3055    }
3056
3057    /// This will inject a key release event into StereoKit’s input event queue. It will be processed at the start of
3058    /// the next frame, and will be indistinguishable from a physical key release. This should be preceded by a key
3059    /// press!
3060    ///
3061    /// This will not submit text to StereoKit’s text queue, and will not show up in places like UI.Input. For that, you
3062    /// must submit a TextInjectChar call.
3063    /// <https://stereokit.net/Pages/StereoKit/Input/KeyInjectRelease.html>
3064    /// * `key` - The key to release.
3065    ///
3066    /// see also [`input_key_inject_release`]    
3067    /// see example [`Input::key_inject_press`]
3068    pub fn key_inject_release(key: Key) {
3069        unsafe { input_key_inject_release(key) };
3070    }
3071
3072    /// This gets the pointer by filter based index.
3073    /// <https://stereokit.net/Pages/StereoKit/Input/Pointer.html>
3074    /// * `index` - Index of the Pointer.
3075    /// * `filter` - Filter used to search for the Pointer. If None has default value of ANY.
3076    ///
3077    /// Returns the Pointer data.
3078    /// see also [`input_pointer`]    
3079    /// ### Examples
3080    /// ```
3081    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
3082    /// use stereokit_rust::{system::{Input, InputSource, Pointer, BtnState, Handed, TrackState},
3083    ///                      maths::{Vec3, Quat, Pose, Ray}};
3084    ///
3085    /// // By default we only have the 2 hands.
3086    /// assert_eq!(Input::pointer_count(None), 0);
3087    /// let pointer = Input::pointer(0, None);
3088    ///
3089    /// assert_eq!(pointer.source, InputSource::None);
3090    /// assert_eq!(pointer.state, BtnState::Inactive);
3091    /// assert_eq!(pointer.tracked, BtnState::Inactive);
3092    /// assert_eq!(pointer.orientation, Quat::ZERO);
3093    /// assert_eq!(pointer.ray, Ray::ZERO);
3094    /// assert_eq!(pointer.get_pose(), Pose::ZERO);
3095    /// ```
3096    pub fn pointer(index: i32, filter: Option<InputSource>) -> Pointer {
3097        let filter = filter.unwrap_or(InputSource::Any);
3098        unsafe { input_pointer(index, filter) }
3099    }
3100
3101    /// The number of Pointer inputs that StereoKit is tracking that match the given filter.
3102    /// <https://stereokit.net/Pages/StereoKit/Input/PointerCount.html>
3103    /// * `filter` - You can filter input sources using this bit flat. If None has default value of ANY
3104    ///
3105    /// Returns the number of Pointers StereoKit knows about that matches the given filter.
3106    /// see also [`input_pointer_count`]  
3107    /// see example in [`Input::pointer`]  
3108    pub fn pointer_count(filter: Option<InputSource>) -> i32 {
3109        let filter = filter.unwrap_or(InputSource::Any);
3110        unsafe { input_pointer_count(filter) }
3111    }
3112
3113    /// Returns the next text character from the list of characters that have been entered this frame! Will return `\0`
3114    /// if there are no more characters left in the list. These are from the system’s text entry system, and so can be
3115    /// unicode, will repeat if their ‘key’ is held down, and could arrive from something like a copy/paste operation.
3116    ///
3117    /// If you wish to reset this function to begin at the start of the read list on the next call, you can call
3118    /// Input::text_reset.
3119    /// <https://stereokit.net/Pages/StereoKit/Input/TextConsume.html>
3120    ///
3121    /// Returns the next character in this frame's list, or '\0' if none remain, or None if the value doesn't
3122    /// match char.
3123    /// see also [`input_text_consume`] [`char::from_u32`]
3124    /// ### Examples
3125    /// ```
3126    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
3127    /// use stereokit_rust::system::Input;
3128    ///
3129    /// // Simulate some text input
3130    /// Input::text_inject_char('H');
3131    /// Input::text_inject_char('i');
3132    ///
3133    /// test_steps!( // !!!! Get a proper main loop !!!!
3134    ///     if iter == 0 {
3135    ///         assert_eq!(Input::text_consume(), Some('H'));
3136    ///         assert_eq!(Input::text_consume(), Some('i'));
3137    ///         Input::text_inject_char('!');
3138    ///         assert_eq!(Input::text_consume(), Some('\0'));
3139    ///     } else if iter == 1 {
3140    ///         assert_eq!(Input::text_consume(), Some('!'));
3141    ///     } else {
3142    ///         assert_eq!(Input::text_consume(), Some('\0'));
3143    ///     }
3144    /// );
3145    /// ```
3146    pub fn text_consume() -> Option<char> {
3147        char::from_u32(unsafe { input_text_consume() })
3148    }
3149
3150    /// Resets the Input::text_consume read list back to the start. For example, UI.Input will not call text_reset, so
3151    /// it effectively will consume those characters, hiding them from any TextConsume calls following it. If you wanted
3152    /// to check the current frame’s text, but still allow UI.Input to work later on in the frame, you would read
3153    /// everything with TextConsume, and then TextReset afterwards to reset the read list for the following UI.Input.
3154    /// <https://stereokit.net/Pages/StereoKit/Input/TextReset.html>
3155    ///
3156    /// see also [`input_text_reset`]    
3157    /// ### Examples
3158    /// ```
3159    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
3160    /// use stereokit_rust::system::Input;
3161    ///
3162    /// // Simulate some text input
3163    /// Input::text_inject_char('H');
3164    /// Input::text_inject_char('i');
3165    ///
3166    /// test_steps!( // !!!! Get a proper main loop !!!!
3167    ///     if iter == 0 {
3168    ///         assert_eq!(Input::text_consume(), Some('H'));
3169    ///         assert_eq!(Input::text_consume(), Some('i'));
3170    ///         Input::text_inject_char('!');
3171    ///         assert_eq!(Input::text_consume(), Some('\0'));
3172    ///         Input::text_reset();
3173    ///         assert_eq!(Input::text_consume(), Some('H'));
3174    ///         assert_eq!(Input::text_consume(), Some('i'));
3175    ///         assert_eq!(Input::text_consume(), Some('\0'));
3176    ///     } else if iter == 1 {
3177    ///         assert_eq!(Input::text_consume(), Some('!'));
3178    ///     } else {
3179    ///         assert_eq!(Input::text_consume(), Some('\0'));
3180    ///     }
3181    /// );
3182    /// ```
3183    pub fn text_reset() {
3184        unsafe { input_text_reset() };
3185    }
3186
3187    /// This will inject a UTF32 Unicode text character into StereoKit’s text input queue. It will be available at the
3188    /// start of the next frame, and will be indistinguishable from normal text entry.
3189    ///
3190    /// This will not submit key press/release events to StereoKit’s input queue, use key_inject_press/_release
3191    /// for that.
3192    /// <https://stereokit.net/Pages/StereoKit/Input/TextInjectChar.html>
3193    /// * `character` - An unsigned integer representing a single UTF32 character.
3194    ///
3195    /// see also [`input_text_inject_char`]    
3196    /// ### Examples
3197    /// ```
3198    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
3199    /// use stereokit_rust::system::Input;
3200    ///
3201    /// // Simulate some text input
3202    /// Input::text_inject_char('H');
3203    /// Input::text_inject_char('i');
3204    /// Input::text_inject_char('!');
3205    /// Input::text_inject_char('😬');
3206    ///
3207    /// test_steps!( // !!!! Get a proper main loop !!!!
3208    ///     if iter == 0 {
3209    ///         assert_eq!(Input::text_consume(), Some('H'));
3210    ///         assert_eq!(Input::text_consume(), Some('i'));
3211    ///         assert_eq!(Input::text_consume(), Some('!'));
3212    ///         assert_eq!(Input::text_consume(), Some('😬'));
3213    ///     } else {
3214    ///         assert_eq!(Input::text_consume(), Some('\0'));
3215    ///     }
3216    /// );
3217    /// ```
3218    pub fn text_inject_char(character: char) {
3219        unsafe { input_text_inject_char(character as u32) };
3220    }
3221
3222    /// This will convert an str into a number of UTF32 Unicode text characters, and inject them into StereoKit’s
3223    /// text input queue. It will be available at the start of the next frame, and will be indistinguishable from normal
3224    /// text entry.
3225    ///
3226    /// This will not submit key press/release events to StereoKit’s input queue, use key_inject_press/_release
3227    /// for that.
3228    /// <https://stereokit.net/Pages/StereoKit/Input/TextInjectChar.html>
3229    /// * `chars` - A collection of characters to submit as text input.
3230    ///
3231    /// see also [`input_text_inject_char`]    
3232    /// ### Examples
3233    /// ```
3234    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
3235    /// use stereokit_rust::system::Input;
3236    ///
3237    /// // Simulate some text input
3238    /// Input::text_inject_chars("Hi!❤");
3239    ///
3240    /// test_steps!( // !!!! Get a proper main loop !!!!
3241    ///     if iter == 0 {
3242    ///         assert_eq!(Input::text_consume(), Some('H'));
3243    ///         assert_eq!(Input::text_consume(), Some('i'));
3244    ///         assert_eq!(Input::text_consume(), Some('!'));
3245    ///         assert_eq!(Input::text_consume(), Some('❤'));
3246    ///     } else {
3247    ///         assert_eq!(Input::text_consume(), Some('\0'));
3248    ///     }
3249    /// );
3250    /// ```
3251    pub fn text_inject_chars(str: impl AsRef<str>) {
3252        for character in str.as_ref().chars() {
3253            unsafe { input_text_inject_char(character as u32) }
3254        }
3255    }
3256
3257    /// You can subscribe to input events from Pointer sources here. StereoKit will call your callback and pass along a
3258    /// Pointer that matches the position of that pointer at the moment the event occurred. This can be more accurate
3259    /// than polling for input data, since polling happens specifically at frame start.
3260    /// <https://stereokit.net/Pages/StereoKit/Input/Subscribe.html>
3261    /// * `event_source` - What input sources do we want to listen for. This is a bit flag.
3262    /// * `event_types` - What events do we want to listen for. This is a bit flag.
3263    /// * `on_event` - The callback to call when the event occurs!
3264    ///
3265    /// see also [`input_subscribe`]    
3266    /// ### Examples
3267    /// ```
3268    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
3269    /// use stereokit_rust::system::{Input, InputSource, Pointer, BtnState, Handed};
3270    ///
3271    /// let pointer_left  = Input::pointer(0, None);
3272    ///
3273    /// unsafe extern "C" fn input_cb (source: InputSource, input_event: BtnState, in_pointer: *const Pointer) {
3274    ///     let in_pointer = unsafe { *in_pointer };
3275    ///     assert_eq!(source, InputSource::CanPress);
3276    ///     assert_eq!(in_pointer.source, InputSource::None);
3277    ///     assert_eq!(input_event, BtnState::JustActive);
3278    /// }
3279    ///
3280    /// number_of_steps = 8;
3281    /// test_steps!( // !!!! Get a proper main loop !!!!
3282    ///     if iter == 0 {    
3283    ///         Input::subscribe (InputSource::CanPress, BtnState::JustActive, Some(input_cb));
3284    ///     } if iter == 1 {
3285    ///         Input::fire_event(InputSource::CanPress, BtnState::JustActive, &pointer_left);
3286    ///     } else if iter == 8 {
3287    ///         Input::unsubscribe(InputSource::Hand | InputSource::HandLeft, BtnState::JustInactive, Some(input_cb));
3288    ///     }
3289    /// );
3290    /// ```
3291    #[deprecated(since = "0.4.0", note = "Not working anymore")]
3292    #[allow(deprecated)]
3293    pub fn subscribe(
3294        event_source: InputSource,
3295        event_types: BtnState,
3296        on_event: Option<unsafe extern "C" fn(source: InputSource, input_event: BtnState, in_pointer: *const Pointer)>,
3297    ) {
3298        unsafe { input_subscribe(event_source, event_types, on_event) }
3299    }
3300
3301    /// Unsubscribes a listener from input events.
3302    /// <https://stereokit.net/Pages/StereoKit/Input/Unsubscribe.html>
3303    /// * `event_source` - The sources this listener was originally registered for.
3304    /// * `event_types` - The events this listener was originally registered for.
3305    /// * `on_event` - The callback this lisener originally used.
3306    ///
3307    /// see also [`input_unsubscribe`]    
3308    /// see example in [`Input::subscribe`]
3309    #[deprecated(since = "0.4.0", note = "Not working anymore")]
3310    #[allow(deprecated)]
3311    pub fn unsubscribe(
3312        event_source: InputSource,
3313        event_types: BtnState,
3314        on_event: Option<unsafe extern "C" fn(source: InputSource, input_event: BtnState, in_pointer: *const Pointer)>,
3315    ) {
3316        unsafe { input_unsubscribe(event_source, event_types, on_event) }
3317    }
3318
3319    /// This retreives the Model currently in use by StereoKit to represent the controller input source. By default,
3320    /// this will be a Model provided by OpenXR, or SK's fallback Model. This will never be null while SK is
3321    /// initialized.
3322    /// <https://stereokit.net/Pages/StereoKit/Input.html>
3323    /// * `handed` - The hand of the controller Model to retreive.
3324    ///
3325    /// Returns the current controller Model. By default, his will be a Model provided by OpenXR, or SK's fallback
3326    /// Model. This will never be null while SK is initialized.
3327    /// see also [`input_controller_model_get`]
3328    /// see example in [`Input::set_controller_model`]
3329    pub fn get_controller_model(handed: Handed) -> Model {
3330        match NonNull::new(unsafe { input_controller_model_get(handed) }) {
3331            Some(model) => Model(model),
3332            None => Model::new(),
3333        }
3334    }
3335
3336    /// This is the state of the controller’s menu button, this is not attached to any particular hand, so it’s
3337    /// independent of a left or right controller.
3338    /// <https://stereokit.net/Pages/StereoKit/Input/ControllerMenuButton.html>
3339    ///
3340    /// see also [`input_controller_menu`]    
3341    /// ### Examples
3342    /// ```
3343    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
3344    /// use stereokit_rust::system::{Input, BtnState};
3345    ///
3346    /// assert_eq!(Input::get_controller_menu_button(), BtnState::Inactive);
3347    /// assert_eq!(Input::get_controller_menu_button().is_just_active(), false);
3348    ///
3349    /// let button_state = Input::get_controller_menu_button();
3350    /// assert_eq!(button_state.is_active(), false);
3351    /// assert_eq!(button_state.is_just_active(), false);
3352    /// assert_eq!(button_state.is_just_inactive(), false);
3353    /// assert_eq!(button_state.is_changed(), false);
3354    /// ```
3355    pub fn get_controller_menu_button() -> BtnState {
3356        unsafe { input_controller_menu() }
3357    }
3358
3359    /// If the device has eye tracking hardware and the app has permission to use it, then this is the most recently
3360    /// tracked eye pose. Check Input.EyesTracked to see if the pose is up-to date, or if it’s a leftover!
3361    ///
3362    /// You can also check Sk::System::eye_tracking_present to see if the hardware is capable of providing eye tracking.
3363    ///
3364    /// On Flatscreen when the MR sim is still enabled, then eyes are emulated using the cursor position when the user
3365    /// holds down Alt.
3366    /// <https://stereokit.net/Pages/StereoKit/Input/Eyes.html>
3367    ///
3368    /// see also [`input_eyes`] [`Input::get_eyes_tracked`]
3369    /// ### Examples
3370    /// ```
3371    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
3372    /// use stereokit_rust::{system::{Input, BtnState}, maths::Pose};
3373    ///
3374    /// let eyes_pose = Input::get_eyes();
3375    ///
3376    /// assert_eq!(eyes_pose, Pose::IDENTITY);
3377    /// assert_eq!(Input::get_eyes_tracked(), BtnState::Inactive)
3378    /// ```
3379    pub fn get_eyes() -> Pose {
3380        unsafe { input_eyes() }
3381    }
3382
3383    /// If eye hardware is available and app has permission, then this is the tracking state of the eyes. Eyes may move
3384    /// out of bounds, hardware may fail to detect eyes, or who knows what else!
3385    ///
3386    /// On Flatscreen when MR sim is still enabled, this will report whether the user is simulating eye input with the
3387    /// Alt key.
3388    ///
3389    /// Permissions:
3390    /// * You may need to add an entry to your AndroidManifest.xml (or Cargo.toml), refer to your device’s
3391    ///   documentation for specifics.
3392    ///
3393    ///  <https://stereokit.net/Pages/StereoKit/Input/EyesTracked.html>
3394    ///
3395    /// see also [`input_eyes_tracked`]
3396    /// ### Examples
3397    /// ```
3398    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
3399    /// use stereokit_rust::{system::{Input, BtnState}, maths::Pose};
3400    ///
3401    /// let eyes_tracked = Input::get_eyes_tracked();
3402    ///
3403    /// assert_eq!(eyes_tracked.is_active(), false);
3404    /// assert_eq!(eyes_tracked, BtnState::Inactive);
3405    ///
3406    /// assert_eq!(Input::get_eyes(),Pose::IDENTITY)
3407    /// ```
3408    pub fn get_eyes_tracked() -> BtnState {
3409        unsafe { input_eyes_tracked() }
3410    }
3411
3412    /// The position and orientation of the user’s head! This is the center point between the user’s eyes, NOT the
3413    /// center of the user’s head. Forward points the same way the user’s face is facing.
3414    /// <https://stereokit.net/Pages/StereoKit/Input/Head.html>
3415    ///
3416    /// see also [`input_head`]
3417    /// ### Examples
3418    /// ```
3419    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
3420    /// use stereokit_rust::{system::Input, maths::Pose};
3421    ///
3422    /// let head_pose = Input::get_head();
3423    ///
3424    /// assert_eq!(head_pose, Pose::IDENTITY);
3425    /// ```
3426    pub fn get_head() -> Pose {
3427        unsafe { input_head() }
3428    }
3429
3430    /// Information about this system’s mouse, or lack thereof!
3431    /// <https://stereokit.net/Pages/StereoKit/Input/Mouse.html>
3432    ///
3433    /// see also [`input_mouse`]    
3434    /// ### Examples
3435    /// ```
3436    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
3437    /// use stereokit_rust::{system::Input, maths::{Vec2, Vec3}};
3438    ///
3439    /// let mouse = Input::get_mouse();
3440    ///
3441    /// assert_eq!(mouse.is_available(),false);
3442    /// assert_eq!(mouse.pos,           Vec2::ZERO);
3443    /// assert_eq!(mouse.pos_change,    Vec2::ZERO);
3444    /// assert_eq!(mouse.scroll,        0.0);
3445    /// assert_eq!(mouse.scroll_change, 0.0);
3446    ///
3447    /// assert_eq!(mouse.get_ray().position, Vec3::ZERO);
3448    /// // Warning: No ray if the mouse isn't available!
3449    /// // assert_eq!(mouse.get_ray().direction, Vec3::new(f32::NAN, f32::NAN, f32::NAN));
3450    /// ```
3451    pub fn get_mouse() -> Mouse {
3452        unsafe { *input_mouse() }
3453    }
3454
3455    /// This controls the visibility of StereoKit's finger glow effect on the UI. When true, SK will fill out global
3456    /// shader variable `sk_fingertip[2]` with the location of the pointer finger's tips. When false, or the hand is
3457    /// untracked, the location will be set to an unlikely faraway position.
3458    /// <https://stereokit.net/Pages/StereoKit/Input/FingerGlow.html>
3459    ///
3460    /// Returns true if StereoKit renders this. False, it doesn't.
3461    /// see also [`input_set_finger_glow`]
3462    /// see example in [`Input::finger_glow`]
3463    pub fn get_finger_glow() -> bool {
3464        unsafe { input_get_finger_glow() != 0 }
3465    }
3466}
3467
3468/// Used to represent lines for the line drawing functions! This is just a snapshot of information about each individual
3469/// point on a line.
3470/// <https://stereokit.net/Pages/StereoKit/LinePoint.html>
3471/// ### Examples
3472/// ```
3473/// use stereokit_rust::{system::LinePoint, util::named_colors};
3474///
3475/// let line_point = LinePoint::new( [0.1, 0.2, 0.3], 0.01, named_colors::CYAN);
3476///
3477/// assert_eq!(line_point, LinePoint {pt: [0.1, 0.2, 0.3].into(), thickness: 0.01, color: named_colors::CYAN});
3478/// ```
3479#[derive(Debug, Copy, Clone, PartialEq)]
3480#[repr(C)]
3481pub struct LinePoint {
3482    pub pt: Vec3,
3483    pub thickness: f32,
3484    pub color: Color32,
3485}
3486
3487impl LinePoint {
3488    /// Create a new LinePoint.
3489    pub fn new(pt: impl Into<Vec3>, thickness: f32, color: Color32) -> Self {
3490        Self { pt: pt.into(), thickness, color }
3491    }
3492}
3493
3494/// A line drawing class! This is an easy way to visualize lines or relationships between objects. The current
3495/// implementation uses a quad strip that always faces the user, via vertex shader manipulation.
3496/// <https://stereokit.net/Pages/StereoKit/Lines.html>
3497///
3498/// ### Examples
3499/// ```
3500/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
3501/// use stereokit_rust::{maths::{Vec3, Pose, Ray}, system::{Lines, LinePoint},
3502///                      util::{named_colors}};
3503///
3504/// let ray = Ray::new([-0.3, -0.8, 0.2], [1.0, 0.0, 0.0]);
3505///
3506/// let axis_pose = Pose::new([0.0, -0.35, 0.0], None);
3507///
3508/// filename_scr = "screenshots/lines.jpeg";
3509/// test_screenshot!( // !!!! Get a proper main loop !!!!
3510///     Lines::add(token, [0.7, 0.7, 0.2], [ 0.7,-0.7, 0.2], named_colors::LIME, None, 0.06);
3511///     Lines::add(token, [0.7, 0.7, 0.2], [-0.7, 0.7, 0.2], named_colors::RED, None, 0.03);
3512///
3513///     Lines::add_list(token, &[
3514///        LinePoint {pt: [-0.7,-0.7, 0.2].into(), thickness: 0.08, color: named_colors::FUCHSIA},
3515///        LinePoint::new([-0.5,-0.1, 0.2], 0.08, named_colors::BLACK),
3516///        LinePoint::new([-0.7, 0.7, 0.2], 0.01, named_colors::YELLOW),
3517///     ]);
3518///
3519///     Lines::add_ray(token, ray, 0.6, named_colors::RED, None, 0.08 );
3520///
3521///     Lines::add_axis(token, axis_pose, Some(0.7), Some(0.04));
3522/// );
3523/// ```
3524/// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/lines.jpeg" alt="screenshot" width="200">
3525pub struct Lines;
3526
3527unsafe extern "C" {
3528    pub fn line_add(start: Vec3, end: Vec3, color_start: Color32, color_end: Color32, thickness: f32);
3529    pub fn line_addv(start: LinePoint, end: LinePoint);
3530    pub fn line_add_axis(pose: Pose, size: f32);
3531    pub fn line_add_list(points: *const Vec3, count: i32, color: Color32, thickness: f32);
3532    pub fn line_add_listv(in_arr_points: *const LinePoint, count: i32);
3533}
3534
3535impl Lines {
3536    /// Adds a line to the environment for the current frame.
3537    /// <https://stereokit.net/Pages/StereoKit/Lines/Add.html>
3538    /// * `start` - The start of the line.
3539    /// * `end` - The end of the line.
3540    /// * `color_start` - Color for the start of the line, this is embedded in the vertex color of the line.
3541    /// * `color_end` - Color for the end of the line, this is embedded in the vertex color of the line. If None,
3542    ///   uses color_start.
3543    /// * `thickness` - The thickness of the line.
3544    ///
3545    /// see also [line_add]
3546    /// ### Examples
3547    /// ```
3548    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
3549    /// use stereokit_rust::{maths::{Vec3, Pose, Ray}, system::{Lines, LinePoint},
3550    ///                      util::{named_colors}};
3551    ///
3552    /// test_steps!( // !!!! Get a proper main loop !!!!
3553    ///     Lines::add(token, [0.7, 0.7, 0.2], [ 0.7,-0.7, 0.2], named_colors::LIME, None, 0.06);
3554    ///
3555    ///     Lines::add(token, [0.7, 0.7, 0.2], [-0.7, 0.7, 0.2], named_colors::RED, None, 0.03);
3556    /// );
3557    /// ```
3558    pub fn add<V: Into<Vec3>>(
3559        _token: &MainThreadToken,
3560        start: V,
3561        end: V,
3562        color_start: Color32,
3563        color_end: Option<Color32>,
3564        thickness: f32,
3565    ) {
3566        let color_end = color_end.unwrap_or(color_start);
3567        unsafe { line_add(start.into(), end.into(), color_start, color_end, thickness) }
3568    }
3569
3570    /// Adds a line based on a ray to the environment for the current frame.
3571    /// <https://stereokit.net/Pages/StereoKit/Lines/Add.html>
3572    /// * `ray` - The ray we want to visualize!
3573    /// * `length` - How long should the ray be? Actual length will be ray.direction.Magnitude * length.
3574    /// * `color_start` - Color for the start of the line, this is embedded in the vertex color of the line.
3575    /// * `color_end` - Color for the end of the line, this is embedded in the vertex color of the line. If None,
3576    ///   uses color_start.
3577    /// * `thickness` - The thickness of the line.
3578    ///
3579    /// see also [line_add]
3580    /// ### Examples
3581    /// ```
3582    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
3583    /// use stereokit_rust::{maths::{Vec3, Ray}, system::{Lines, LinePoint},
3584    ///                      util::{named_colors}};
3585    ///
3586    /// // axis at the origins:
3587    /// let ray1 = Ray::new(Vec3::ZERO, Vec3::X);
3588    /// let ray2 = Ray::new(Vec3::ZERO, Vec3::Y);
3589    /// let ray3 = Ray::new(Vec3::ZERO, Vec3::Z);
3590    ///
3591    ///
3592    /// test_steps!( // !!!! Get a proper main loop !!!!
3593    ///     Lines::add_ray(token, ray1, 1.0, named_colors::WHITE, Some(named_colors::RED), 0.03 );
3594    ///     Lines::add_ray(token, ray2, 1.0, named_colors::WHITE, Some(named_colors::GREEN), 0.03 );
3595    ///     Lines::add_ray(token, ray2, 1.0, named_colors::WHITE, Some(named_colors::BLUE), 0.03 );
3596    /// );
3597    /// ```
3598    pub fn add_ray<R: Into<Ray>>(
3599        _token: &MainThreadToken,
3600        ray: R,
3601        length: f32,
3602        color_start: Color32,
3603        color_end: Option<Color32>,
3604        thickness: f32,
3605    ) {
3606        let color_end = color_end.unwrap_or(color_start);
3607        let ray: Ray = ray.into();
3608        unsafe { line_add(ray.position, ray.get_at(length), color_start, color_end, thickness) }
3609    }
3610
3611    /// Adds a line from a list of line points to the environment. This does not close the path, so if you want it
3612    /// closed, you’ll have to add an extra point or two at the end yourself!
3613    /// <https://stereokit.net/Pages/StereoKit/Lines/Add.html>
3614    /// * `points` - An array of LinePoint.
3615    ///
3616    /// see also [line_add]
3617    /// ### Examples
3618    /// ```
3619    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
3620    /// use stereokit_rust::{maths::{Vec3, Pose, Ray}, system::{Lines, LinePoint},
3621    ///                      util::{named_colors}};
3622    /// test_steps!( // !!!! Get a proper main loop !!!!
3623    ///
3624    ///     Lines::add_list(token, &[
3625    ///        LinePoint {pt: [-0.7,-0.7, 0.2].into(), thickness: 0.08, color: named_colors::FUCHSIA},
3626    ///        LinePoint::new([-0.5,-0.1, 0.2], 0.08, named_colors::BLACK),
3627    ///        LinePoint::new([-0.7, 0.7, 0.2], 0.01, named_colors::YELLOW),
3628    ///     ]);
3629    ///
3630    /// );
3631    /// ```
3632    pub fn add_list(_token: &MainThreadToken, points: &[LinePoint]) {
3633        unsafe { line_add_listv(points.as_ptr(), points.len() as i32) }
3634    }
3635
3636    /// Displays an RGB/XYZ axis widget at the pose! Each line is extended along the positive direction of each axis, so
3637    /// the red line is +X, green is +Y, and blue is +Z. A white line is drawn along -Z to indicate the Forward vector
3638    /// of the pose (-Z is forward in StereoKit).
3639    /// <https://stereokit.net/Pages/StereoKit/Lines/AddAxis.html>
3640    /// * `at_pose` - What position and orientation do we want this axis widget at?
3641    /// * `size` - How long should the widget lines be, in meters? If None, has value of 1 cm
3642    /// * `thickness` - How thick should the lines be, in meters? If None, will use a faster renderer with a thickness of
3643    ///   one tenth of the size.
3644    ///
3645    /// see also [line_add]
3646    /// ### Examples
3647    /// ```
3648    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
3649    /// use stereokit_rust::{maths::{Vec3, Pose, Ray}, system::{Lines, LinePoint},
3650    ///                      util::{named_colors}};
3651    ///
3652    /// // Axis at the origins:
3653    /// let axis_pose = Pose::IDENTITY;
3654    ///
3655    /// test_steps!( // !!!! Get a proper main loop !!!!
3656    ///
3657    ///     Lines::add_axis(token, axis_pose, Some(0.7), Some(0.02));
3658    ///
3659    /// );
3660    /// ```
3661    pub fn add_axis<P: Into<Pose>>(token: &MainThreadToken, at_pose: P, size: Option<f32>, thickness: Option<f32>) {
3662        let at_pose: Pose = at_pose.into();
3663        let size = size.unwrap_or(0.01);
3664        match thickness {
3665            Some(thickness) => {
3666                Self::add(
3667                    token,
3668                    at_pose.position,
3669                    at_pose.orientation.mul_vec3(at_pose.position + Vec3::X) * size,
3670                    Color32::new(255, 0, 0, 255),
3671                    None,
3672                    thickness,
3673                );
3674                Self::add(
3675                    token,
3676                    at_pose.position,
3677                    at_pose.orientation.mul_vec3(at_pose.position + Vec3::Y) * size,
3678                    Color32::new(0, 255, 0, 255),
3679                    None,
3680                    thickness,
3681                );
3682                Self::add(
3683                    token,
3684                    at_pose.position,
3685                    at_pose.orientation.mul_vec3(at_pose.position + Vec3::Z) * size,
3686                    Color32::new(0, 0, 255, 255),
3687                    None,
3688                    thickness,
3689                );
3690                Self::add(
3691                    token,
3692                    at_pose.position,
3693                    at_pose.orientation.mul_vec3(at_pose.position + Vec3::FORWARD) * size * 0.5,
3694                    Color32::new(255, 255, 255, 255),
3695                    None,
3696                    thickness,
3697                )
3698            }
3699            None => unsafe { line_add_axis(at_pose, size) },
3700        }
3701    }
3702}
3703
3704/// The log tool will write to the console with annotations for console colors, which helps with readability, but isn’t
3705/// always supported. These are the options available for configuring those colors.
3706/// <https://stereokit.net/Pages/StereoKit/LogColors.html>
3707///
3708/// see also [`Log`]
3709#[derive(Debug, Copy, Clone, PartialEq, Eq)]
3710#[repr(u32)]
3711pub enum LogColors {
3712    /// Use console coloring annotations.
3713    Ansi = 0,
3714    ///Scrape out any color annotations, so logs are all completely plain text.
3715    None = 1,
3716}
3717
3718/// Severity of a log item.
3719/// <https://stereokit.net/Pages/StereoKit/LogLevel.html>
3720#[derive(Debug, Copy, Clone, PartialEq, Eq)]
3721#[repr(u32)]
3722pub enum LogLevel {
3723    /// A default log level that indicates it has not yet been set
3724    None = 0,
3725    /// This is for diagnostic information, where you need to know details about what -exactly- is going on in the
3726    /// system. This info doesn’t surface by default.
3727    Diagnostic = 1,
3728    /// This is non-critical information, just to let you know what’s going on.
3729    Inform = 2,
3730    /// Something bad has happened, but it’s still within the realm of what’s expected.
3731    Warning = 3,
3732    /// Danger Will Robinson! Something really bad just happened and needs fixing!
3733    Error = 4,
3734}
3735
3736/// Non canonical structure used for subscribed callback
3737#[derive(Debug, Clone)]
3738pub struct LogItem {
3739    pub level: LogLevel,
3740    pub text: String,
3741    pub count: i32,
3742}
3743
3744/// A class for logging errors, warnings and information!
3745/// Different levels of information can be filtered out, and supports
3746/// coloration via &lt;`~colorCode`&gt; and &lt;`~clr`&gt; tags.
3747///
3748/// Text colors can be set with a tag, and reset back to default with
3749/// &lt;`~clr`&gt;. Color codes are as follows:
3750///
3751/// | Dark | Bright | Description |
3752/// |------|--------|-------------|
3753/// | DARK | BRIGHT | DESCRIPTION |
3754/// | blk  | BLK    | Black       |
3755/// | red  | RED    | Red         |
3756/// | grn  | GRN    | Green       |
3757/// | ylw  | YLW    | Yellow      |
3758/// | blu  | BLU    | Blue        |
3759/// | mag  | MAG    | Magenta     |
3760/// | cyn  | cyn    | Cyan        |
3761/// | grn  | GRN    | Green       |
3762/// | wht  | WHT    | White       |
3763///
3764/// <https://stereokit.net/Pages/StereoKit/Log.html>
3765///
3766/// ### Examples
3767/// ```
3768/// use stereokit_rust::system::{Log, LogColors, LogLevel};
3769///
3770/// Log::colors(LogColors::Ansi);
3771/// Log::filter(LogLevel::Diagnostic);
3772///
3773/// Log::info("model <~GRN>node count<~clr> : <~RED>6589<~clr> !!!");
3774///
3775/// let value = 42;
3776/// Log::diag(format!("My value is {}", value));
3777///
3778/// Log::warn("This is not very good!");
3779///
3780/// Log::err("This is very bad!!!");
3781///
3782/// Log::write(LogLevel::Diagnostic, format!("Again, my value is {}", 2));
3783/// ```
3784pub struct Log;
3785
3786unsafe extern "C" {
3787    pub fn log_diag(text: *const c_char);
3788    //pub fn log_diagf(text: *const c_char, ...);
3789    pub fn log_info(text: *const c_char);
3790    //pub fn log_infof(text: *const c_char, ...);
3791    pub fn log_warn(text: *const c_char);
3792    //pub fn log_warnf(text: *const c_char, ...);
3793    pub fn log_err(text: *const c_char);
3794    //pub fn log_errf(text: *const c_char, ...);
3795    //pub fn log_writef(level: LogLevel, text: *const c_char, ...);
3796    pub fn log_write(level: LogLevel, text: *const c_char);
3797    pub fn log_set_filter(level: LogLevel);
3798    pub fn log_set_colors(colors: LogColors);
3799    pub fn log_subscribe(
3800        log_callback: Option<unsafe extern "C" fn(context: *mut c_void, level: LogLevel, text: *const c_char)>,
3801        context: *mut c_void,
3802    );
3803    pub fn log_unsubscribe(
3804        log_callback: Option<unsafe extern "C" fn(context: *mut c_void, level: LogLevel, text: *const c_char)>,
3805        context: *mut c_void,
3806    );
3807}
3808
3809/// Log subscribe trampoline
3810///
3811/// see also [`Log::subscribe`]
3812unsafe extern "C" fn log_trampoline<'a, F: FnMut(LogLevel, &str) + 'a>(
3813    context: *mut c_void,
3814    log_level: LogLevel,
3815    text: *const c_char,
3816) {
3817    let closure = unsafe { &mut *(context as *mut &mut F) };
3818    let c_str = unsafe { CStr::from_ptr(text).to_str().unwrap().trim_end() };
3819    closure(log_level, c_str)
3820}
3821
3822impl Log {
3823    /// What's the lowest level of severity logs to display on the console? Default is LogLevel::Info. This property
3824    /// can safely be set before SK initialization.
3825    /// <https://stereokit.net/Pages/StereoKit/Log.html>
3826    ///
3827    /// see also [`log_set_filter`]
3828    /// ### Examples
3829    /// ```
3830    /// use stereokit_rust::system::{Log, LogLevel};
3831    ///
3832    /// // Set the log filter to only show errors and above.
3833    /// Log::filter(LogLevel::Error);
3834    ///
3835    /// // Set the log filter to only show warnings and above (errors)
3836    /// Log::filter(LogLevel::Warning);
3837    ///
3838    /// // Set the log filter to only show infos and above (wanings and errors)
3839    /// Log::filter(LogLevel::Inform);
3840    ///
3841    /// // Set the log filter to show every logs
3842    /// Log::filter(LogLevel::Diagnostic);
3843    /// ```
3844    pub fn filter(filter: LogLevel) {
3845        unsafe { log_set_filter(filter) }
3846    }
3847
3848    /// Set the colors
3849    /// <https://stereokit.net/Pages/StereoKit/Log.html>
3850    ///
3851    /// see also [`log_set_colors`]
3852    /// ### Examples
3853    /// ```
3854    /// use stereokit_rust::system::{Log, LogColors};
3855    ///
3856    /// // Set the log colors to use ANSI color codes.
3857    /// Log::colors(LogColors::Ansi);
3858    ///
3859    /// // Set the log colors to use no color codes.
3860    /// Log::colors(LogColors::None);
3861    /// ```
3862    pub fn colors(colors: LogColors) {
3863        unsafe { log_set_colors(colors) }
3864    }
3865
3866    /// Writes a formatted line to the log using a LogLevel.Error severity level!
3867    /// <https://stereokit.net/Pages/StereoKit/Log.html>
3868    ///
3869    /// see also [`log_err`]
3870    /// ### Examples
3871    /// ```
3872    /// use stereokit_rust::system::Log;
3873    ///
3874    /// Log::err("This is very bad!!!");
3875    ///
3876    /// let value = 42;
3877    /// Log::err(format!("My problematic value is {}", value));
3878    /// ```
3879    pub fn err<S: AsRef<str>>(text: S) {
3880        let c_str = CString::new(text.as_ref()).unwrap();
3881        unsafe { log_err(c_str.as_ptr()) }
3882    }
3883
3884    /// Writes a formatted line to the log using a LogLevel.Inform severity level!
3885    /// <https://stereokit.net/Pages/StereoKit/Log.html>
3886    ///
3887    /// see also [`log_info`]
3888    /// ### Examples
3889    /// ```
3890    /// use stereokit_rust::system::Log;
3891    ///
3892    /// Log::info("This is good!");
3893    ///
3894    /// let value = 42;
3895    /// Log::info(format!("My value is {}", value));
3896    /// ```
3897    pub fn info<S: AsRef<str>>(text: S) {
3898        let c_str = CString::new(text.as_ref()).unwrap();
3899        unsafe { log_info(c_str.as_ptr()) }
3900    }
3901
3902    /// Writes a formatted line to the log using a LogLevel.Warning severity level!
3903    /// <https://stereokit.net/Pages/StereoKit/Log.html>
3904    ///
3905    /// see also [`log_warn`]
3906    /// ### Examples
3907    /// ```
3908    /// use stereokit_rust::system::Log;
3909    ///
3910    /// Log::warn("This is not very good!");
3911    ///
3912    /// let value = 42;
3913    /// Log::warn(format!("My not so good value is {}", value));
3914    /// ```
3915    pub fn warn<S: AsRef<str>>(text: S) {
3916        let c_str = CString::new(text.as_ref()).unwrap();
3917        unsafe { log_warn(c_str.as_ptr()) }
3918    }
3919
3920    /// Writes a formatted line to the log using a LogLevel.Diagnostic severity level!
3921    /// <https://stereokit.net/Pages/StereoKit/Log.html>
3922    ///
3923    /// see also [`log_diag`]
3924    /// ### Examples
3925    /// ```
3926    /// use stereokit_rust::system::Log;
3927    ///
3928    /// Log::diag("This is something to check!");
3929    ///
3930    /// let value = 42;
3931    /// Log::diag(format!("My value to check is {}", value));
3932    /// ```
3933    pub fn diag<S: AsRef<str>>(text: S) {
3934        let c_str = CString::new(text.as_ref()).unwrap();
3935        unsafe { log_diag(c_str.as_ptr()) }
3936    }
3937
3938    /// Writes a formatted line to the log with the specified severity level!
3939    /// <https://stereokit.net/Pages/StereoKit/Log.html>
3940    ///
3941    /// see also [`log_write`]
3942    /// ### Examples
3943    /// ```
3944    /// use stereokit_rust::system::{Log, LogLevel};
3945    ///
3946    /// Log::write(LogLevel::Diagnostic, "This is something to check!!!");
3947    ///
3948    /// let value = 42;
3949    /// Log::write(LogLevel::Error, format!("My problematic value is {}", value));
3950    /// ```
3951    pub fn write<S: AsRef<str>>(level: LogLevel, text: S) {
3952        let c_str = CString::new(text.as_ref()).unwrap();
3953        unsafe { log_write(level, c_str.as_ptr()) }
3954    }
3955
3956    /// Allows you to listen in on log events! Any callback subscribed here will be called when something is logged.
3957    /// This does honor the Log.Filter, so filtered logs will not be received here. This method can safely be called
3958    /// before SK initialization.
3959    /// <https://stereokit.net/Pages/StereoKit/Log/Subscribe.html>
3960    ///
3961    /// see also [`log_subscribe`] [`Log::unsubscribe`]   
3962    /// ### Examples
3963    /// ```
3964    /// use stereokit_rust::system::{Log, LogLevel, LogItem};
3965    /// use std::sync::{Arc, Mutex};
3966    ///
3967    /// /// Somewhere to copy the log
3968    /// static LOG_LOG: Mutex<Vec<LogItem>> = Mutex::new(vec![]);
3969    ///
3970    /// let fn_mut = |level: LogLevel, log_text: &str| {
3971    ///     let mut items = LOG_LOG.lock().unwrap();
3972    ///     items.push(LogItem { level, text: log_text.to_owned(), count: 1 });
3973    /// };
3974    /// Log::subscribe( fn_mut );
3975    ///
3976    /// Log::info("This is an info message");
3977    /// Log::warn("This is a warning message");
3978    /// Log::err("This is an error message");
3979    ///
3980    /// let messages = LOG_LOG.lock().unwrap();
3981    /// assert_eq!(messages.len(), 3);
3982    /// assert_eq!(messages[0].level, LogLevel::Inform);
3983    /// assert_eq!(messages[1].text, "This is a warning message");
3984    ///
3985    /// Log::unsubscribe( fn_mut );
3986    /// ```
3987    pub fn subscribe<'a, F: FnMut(LogLevel, &str) + 'a>(mut on_log: F) {
3988        let mut closure = &mut on_log;
3989        unsafe { log_subscribe(Some(log_trampoline::<F>), &mut closure as *mut _ as *mut c_void) }
3990    }
3991
3992    /// If you subscribed to the log callback, you can unsubscribe that callback here! This method can safely be
3993    /// called before initialization.
3994    /// <https://stereokit.net/Pages/StereoKit/Log/Unsubscribe.html>
3995    ///
3996    /// see also [`log_unsubscribe`]
3997    /// see example in [`Log::subscribe`]   
3998    pub fn unsubscribe<'a, F: FnMut(LogLevel, &str) + 'a>(mut on_log: F) {
3999        let mut closure = &mut on_log;
4000        unsafe { log_unsubscribe(Some(log_trampoline::<F>), &mut closure as *mut _ as *mut c_void) }
4001    }
4002}
4003
4004/// This class provides access to the hardware’s microphone, and stores it in a Sound stream. Start and Stop recording,
4005/// and check the Sound property for the results! Remember to ensure your application has microphone permissions enabled!
4006/// <https://stereokit.net/Pages/StereoKit/Microphone.html>
4007///
4008/// see also: [`Sound`]
4009/// /// ### Examples
4010/// ```
4011/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
4012/// use stereokit_rust::{maths::{Vec3, Matrix}, mesh::Mesh, material::Material,
4013///                      sound::Sound, system::Microphone, util::named_colors};
4014///
4015/// let sphere = Mesh::generate_cube(Vec3::ONE * 0.5, None);
4016/// let material = Material::pbr().tex_file_copy("textures/micro.jpeg", true, None)
4017///                    .expect("sound.jpeg should be there");
4018/// let mut position = Vec3::new( 0.0, 0.0, 0.5);
4019/// let transform = Matrix::t(position);
4020///
4021/// let micros = Microphone::get_devices();
4022///
4023/// if micros.len() > 0 {
4024///     let first_in_list = micros[0].clone();
4025///     if Microphone::start(Some(first_in_list)) {
4026///         assert!(Microphone::is_recording());
4027///     } else {
4028///         assert!(!Microphone::is_recording());
4029///     }
4030/// }
4031///
4032/// filename_scr = "screenshots/microphone.jpeg";
4033/// test_screenshot!( // !!!! Get a proper main loop !!!!
4034///     sphere.draw(token, &material, transform, Some(named_colors::LIGHT_BLUE.into()), None  );
4035///     if iter == 1990 && Microphone::is_recording() {
4036///         let micro_sound = Microphone::sound().expect("Microphone should be recording");
4037///         let mut read_samples: Vec<f32> = vec![0.0; 48000];
4038///         let recorded_data = micro_sound.read_samples(read_samples.as_mut_slice(), None);
4039///         Microphone::stop();
4040///         //assert_ne!(recorded_data, 0);
4041///     }
4042/// );
4043/// ```
4044/// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/microphone.jpeg" alt="screenshot" width="200">
4045#[repr(C)]
4046#[derive(Debug, PartialEq)]
4047pub struct Microphone {
4048    sound: Sound,
4049}
4050
4051unsafe extern "C" {
4052    pub fn mic_get_stream() -> SoundT;
4053    pub fn mic_is_recording() -> Bool32T;
4054    pub fn mic_device_count() -> i32;
4055    pub fn mic_device_name(index: i32) -> *const c_char;
4056    pub fn mic_start(device_name: *const c_char) -> Bool32T;
4057    pub fn mic_stop();
4058}
4059
4060impl Microphone {
4061    /// This is the sound stream of the Microphone when it is recording. This Asset is created the first time it is
4062    /// accessed via this property, or during Start, and will persist. It is re-used for the Microphone stream if you
4063    /// start/stop/switch devices.
4064    /// <https://stereokit.net/Pages/StereoKit/Microphone/Sound.html>
4065    ///
4066    /// see also [mic_get_stream]
4067    pub fn sound() -> Result<Sound, StereoKitError> {
4068        Ok(Sound(
4069            NonNull::new(unsafe { mic_get_stream() })
4070                .ok_or(StereoKitError::SoundCreate("microphone stream".to_string()))?,
4071        ))
4072    }
4073
4074    /// Is the microphone currently recording?
4075    /// <https://stereokit.net/Pages/StereoKit/Microphone/IsRecording.html>
4076    ///
4077    /// see also [`mic_is_recording`]
4078    pub fn is_recording() -> bool {
4079        unsafe { mic_is_recording() != 0 }
4080    }
4081
4082    /// Constructs a list of valid Microphone devices attached to the system. These names can be passed into Start to
4083    /// select a specific device to record from. It’s recommended to cache this list if you’re using it frequently, as
4084    /// this list is constructed each time you call it.
4085    ///
4086    /// It’s good to note that a user might occasionally plug or unplug microphone devices from their system, so this
4087    /// list may occasionally change.
4088    /// <https://stereokit.net/Pages/StereoKit/Microphone/GetDevices.html>
4089    ///
4090    /// see also [`mic_device_count`] [`mic_device_name`]
4091    pub fn get_devices() -> Vec<String> {
4092        let mut devices = Vec::new();
4093        for iter in 0..unsafe { mic_device_count() } {
4094            let device_name = unsafe { CStr::from_ptr(mic_device_name(iter)) }.to_str().unwrap().to_string();
4095            devices.push(device_name);
4096        }
4097        devices
4098    }
4099
4100    /// This begins recording audio from the Microphone! Audio is stored in Microphone.Sound as a stream of audio. If
4101    /// the Microphone is already recording with a different device, it will stop the previous recording and start again
4102    /// with the new device.
4103    ///
4104    /// If null is provided as the device, then they system’s default input device will be used. Some systems may not
4105    /// provide access to devices other than the system’s default.
4106    /// <https://stereokit.net/Pages/StereoKit/Microphone/Start.html>
4107    /// * `device_name` - The name of the microphone device to use, as seen in the GetDevices list. None will use the
4108    ///   system’s default device preference.
4109    ///
4110    /// see also [`mic_start`] [`Microphone::get_devices`] [`Microphone::stop`]
4111    pub fn start(device_name: Option<String>) -> bool {
4112        if let Some(device_name) = device_name
4113            && !device_name.is_empty()
4114        {
4115            let cstr = CString::new(device_name).unwrap();
4116            return unsafe { mic_start(cstr.as_ptr() as *const c_char) != 0 };
4117        }
4118        // Here we call for a null_mut device_name
4119        unsafe { mic_start(null_mut() as *const c_char) != 0 }
4120    }
4121
4122    /// Stops recording audio from the microphone.
4123    /// <https://stereokit.net/Pages/StereoKit/Microphone/Stop.html>
4124    ///
4125    /// see also [mic_stop]
4126    pub fn stop() {
4127        unsafe { mic_stop() }
4128    }
4129}
4130
4131/// When rendering to a rendertarget, this tells if and what of the rendertarget gets cleared before rendering. For
4132/// example, if you are assembling a sheet of images, you may want to clear everything on the first image draw, but not
4133/// clear on subsequent draws.
4134/// <https://stereokit.net/Pages/StereoKit/RenderClear.html>
4135///
4136/// see also [`Renderer`]
4137#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4138#[repr(u32)]
4139pub enum RenderClear {
4140    /// Don’t clear anything, leave it as it is.
4141    None = 0,
4142    /// Clear the rendertarget’s color data.
4143    Color = 1,
4144    /// Clear the rendertarget’s depth data, if present.
4145    Depth = 2,
4146    /// Clear both color and depth data.
4147    All = 3,
4148}
4149
4150bitflags::bitflags! {
4151    /// When rendering content, you can filter what you’re rendering by the RenderLayer that they’re on. This allows
4152    /// you to draw items that are visible in one render, but not another. For example, you may wish to draw a player’s
4153    /// avatar in a ‘mirror’ rendertarget, but not in the primary display. See Renderer.LayerFilter for configuring
4154    /// what the primary display renders.
4155    /// <https://stereokit.net/Pages/StereoKit/RenderLayer.html>
4156    ///
4157    /// see also [`Renderer`] [`Mesh::draw`] [`Model::draw`] [`Model::draw_mat`] [`RenderList`]
4158    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
4159    #[repr(C)]
4160    pub struct RenderLayer: u32 {
4161        /// The default render layer. All Draw use this layer unless otherwise specified.
4162        const Layer0 = 1 << 0;
4163        /// Render layer 1.
4164        const Layer1 = 1 << 1;
4165        /// Render layer 2.
4166        const Layer2 = 1 << 2;
4167        /// Render layer 3.
4168        const Layer3 = 1 << 3;
4169        /// Render layer 4.
4170        const Layer4 = 1 << 4;
4171        /// Render layer 5.
4172        const Layer5 = 1 << 5;
4173        /// Render layer 6.
4174        const Layer6 = 1 << 6;
4175        /// Render layer 7.
4176        const Layer7 = 1 << 7;
4177        /// Render layer 8.
4178        const Layer8 = 1 << 8;
4179        /// Render layer 9.
4180        const Layer9 = 1 << 9;
4181        /// The default VFX layer, StereoKit draws some non-standard mesh content using this flag, such as lines.
4182        const VFX = 10;
4183        /// For items that should only be drawn from the first person perspective. By default, this is enabled for
4184        /// renders that are from a 1st person viewpoint.
4185        const FirstPerson    = 1 << 11;
4186        /// For items that should only be drawn from the third person perspective. By default, this is enabled for
4187        /// renders that are from a 3rd person viewpoint.
4188        const ThirdPerson    = 1 << 12;
4189        /// This is a flag that specifies all possible layers. If you want to render all layers, then this is the layer
4190        ///  filter you would use. This is the default for render filtering.
4191        const All = 0xFFFF;
4192        /// This is a combination of all layers that are not the VFX layer.
4193        const AllRegular = Self::Layer0.bits() | Self::Layer1.bits() | Self::Layer2.bits() | Self::Layer3.bits() | Self::Layer4.bits() | Self::Layer5.bits() | Self::Layer6.bits() | Self::Layer7.bits() | Self::Layer8.bits() | Self::Layer9.bits();
4194        /// All layers except for the third person layer.
4195        const AllFirstPerson = Self::All.bits() & !Self::ThirdPerson.bits();
4196        ///All layers except for the first person layer.
4197        const AllThirdPerson = Self::All.bits() & !Self::FirstPerson.bits();
4198    }
4199}
4200
4201impl Default for RenderLayer {
4202    /// Layer_all is the default.
4203    fn default() -> Self {
4204        RenderLayer::All
4205    }
4206}
4207
4208/// The projection mode used by StereoKit for the main camera! You can use this with Renderer.Projection. These options
4209/// are only available in flatscreen mode, as MR headsets provide very specific projection matrices.
4210/// <https://stereokit.net/Pages/StereoKit/Projection.html>
4211///
4212/// see also [`Renderer`]
4213#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4214#[repr(u32)]
4215pub enum Projection {
4216    /// This is the default projection mode, and the one you’re most likely to be familiar with! This is where parallel
4217    /// lines will converge as they go into the distance.
4218    Perspective = 0,
4219    /// Orthographic projection mode is often used for tools, 2D rendering, thumbnails of 3D objects, or other similar
4220    /// cases. In this mode, parallel lines remain parallel regardless of how far they travel.
4221    Orthographic = 1,
4222}
4223
4224/// Do you need to draw something? Well, you’re probably in the right place! This static class includes a variety of
4225/// different drawing methods, from rendering Models and Meshes, to setting rendering options and drawing to offscreen
4226/// surfaces! Even better, it’s entirely a static class, so you can call it from anywhere :)
4227/// <https://stereokit.net/Pages/StereoKit/Renderer.html>
4228///
4229/// ### Examples
4230/// ```
4231/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
4232/// use stereokit_rust::{system::{Renderer, RenderLayer}, maths::{Vec3, Matrix, Pose},
4233///                      render_list::RenderList,
4234///                      mesh::Mesh, model::Model, material::Material, util::named_colors};
4235///
4236/// let sun = Mesh::generate_sphere(5.0, None);
4237/// let material = Material::pbr();
4238/// let transform_sun = Matrix::t([-6.0, -4.0, -10.0]);
4239///
4240/// let plane = Model::from_file("plane.glb", None).expect("plane.glb should be there");
4241/// let transform_plane = Matrix::t_r_s([0.0, 0.2, -0.7], [0.0, 120.0, 0.0], [0.15, 0.15, 0.15]);
4242///
4243/// // We want to replace the gray background with a dark blue sky:
4244/// let mut primary = RenderList::primary();
4245/// assert_eq!(primary.get_count(), 0);
4246/// Renderer::clear_color(named_colors::BLUE);
4247///
4248/// filename_scr = "screenshots/renderer.jpeg";
4249/// test_steps!( // !!!! Get a proper main loop !!!!
4250///     
4251///     primary.clear();
4252///
4253///     Renderer::add_mesh(token, &sun, &material, transform_sun,
4254///         Some(named_colors::RED.into()), None);
4255///
4256///     Renderer::add_model(token, &plane, transform_plane,
4257///         Some(named_colors::PINK.into()), Some(RenderLayer::FirstPerson));
4258///
4259///     Renderer::layer_filter(RenderLayer::All);
4260///  
4261///     if iter == number_of_steps {
4262///         // This is the way test_screenshot!() works:
4263///         Renderer::screenshot(token, filename_scr, 90, Pose::look_at(from_scr, at_scr),
4264///             width_scr, height_scr, Some(fov_scr) );
4265///     }
4266/// );
4267/// ```
4268/// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/renderer.jpeg" alt="screenshot" width="200">
4269pub struct Renderer;
4270
4271unsafe extern "C" {
4272    pub fn render_set_clip(near_plane: f32, far_plane: f32);
4273    pub fn render_get_clip(out_near_plane: *mut f32, out_far_plane: *mut f32);
4274    pub fn render_set_fov(vertical_field_of_view_degrees: f32);
4275    pub fn render_get_fov() -> f32;
4276    pub fn render_set_ortho_clip(near_plane: f32, far_plane: f32);
4277    pub fn render_set_ortho_size(viewport_height_meters: f32);
4278    pub fn render_get_ortho_size() -> f32;
4279    pub fn render_set_projection(proj: Projection);
4280    pub fn render_get_projection() -> Projection;
4281    pub fn render_get_cam_root() -> Matrix;
4282    pub fn render_set_cam_root(cam_root: *const Matrix);
4283    pub fn render_set_skytex(sky_texture: TexT);
4284    pub fn render_get_skytex() -> TexT;
4285    pub fn render_set_skymaterial(sky_material: MaterialT);
4286    pub fn render_get_skymaterial() -> MaterialT;
4287    pub fn render_set_skylight(light_info: *const SphericalHarmonics);
4288    pub fn render_get_skylight() -> SphericalHarmonics;
4289    pub fn render_set_filter(layer_filter: RenderLayer);
4290    pub fn render_get_filter() -> RenderLayer;
4291    pub fn render_set_scaling(display_tex_scale: f32);
4292    pub fn render_get_scaling() -> f32;
4293    pub fn render_set_viewport_scaling(viewport_rect_scale: f32);
4294    pub fn render_get_viewport_scaling() -> f32;
4295    pub fn render_set_multisample(display_tex_multisample: i32);
4296    pub fn render_get_multisample() -> i32;
4297    pub fn render_override_capture_filter(use_override_filter: Bool32T, layer_filter: RenderLayer);
4298    pub fn render_get_capture_filter() -> RenderLayer;
4299    pub fn render_has_capture_filter() -> Bool32T;
4300    pub fn render_set_clear_color(color_gamma: Color128);
4301    pub fn render_get_clear_color() -> Color128;
4302    pub fn render_enable_skytex(show_sky: Bool32T);
4303    pub fn render_enabled_skytex() -> Bool32T;
4304
4305    pub fn render_global_texture(register_slot: i32, texture: TexT);
4306    pub fn render_global_buffer(register_slot: i32, buffer: MaterialBufferT);
4307    pub fn render_add_mesh(
4308        mesh: MeshT,
4309        material: MaterialT,
4310        transform: *const Matrix,
4311        color_linear: Color128,
4312        layer: RenderLayer,
4313    );
4314    pub fn render_add_model(model: ModelT, transform: *const Matrix, color_linear: Color128, layer: RenderLayer);
4315    pub fn render_add_model_mat(
4316        model: ModelT,
4317        material_override: MaterialT,
4318        transform: *const Matrix,
4319        color_linear: Color128,
4320        layer: RenderLayer,
4321    );
4322    pub fn render_blit(to_rendertarget: TexT, material: MaterialT);
4323
4324    pub fn render_screenshot(
4325        file_utf8: *const c_char,
4326        file_quality_100: i32,
4327        viewpoint: Pose,
4328        width: i32,
4329        height: i32,
4330        field_of_view_degrees: f32,
4331    );
4332    pub fn render_screenshot_capture(
4333        render_on_screenshot_callback: ::std::option::Option<
4334            unsafe extern "C" fn(color_buffer: *mut Color32, width: i32, height: i32, context: *mut c_void),
4335        >,
4336        viewpoint: Pose,
4337        width: i32,
4338        height: i32,
4339        field_of_view_degrees: f32,
4340        tex_format: TexFormat,
4341        context: *mut c_void,
4342    );
4343    pub fn render_screenshot_viewpoint(
4344        render_on_screenshot_callback: ::std::option::Option<
4345            unsafe extern "C" fn(color_buffer: *mut Color32, width: i32, height: i32, context: *mut c_void),
4346        >,
4347        camera: Matrix,
4348        projection: Matrix,
4349        width: i32,
4350        height: i32,
4351        layer_filter: RenderLayer,
4352        clear: RenderClear,
4353        viewport: Rect,
4354        tex_format: TexFormat,
4355        context: *mut c_void,
4356    );
4357    pub fn render_to(
4358        to_rendertarget: TexT,
4359        to_target_index: i32,
4360        override_material: MaterialT,
4361        camera: *const Matrix,
4362        projection: *const Matrix,
4363        layer_filter: RenderLayer,
4364        clear: RenderClear,
4365        viewport: Rect,
4366    );
4367
4368    pub fn render_MaterialTo(
4369        to_rendertarget: TexT,
4370        override_material: MaterialT,
4371        camera: *const Matrix,
4372        projection: *const Matrix,
4373        layer_filter: RenderLayer,
4374        clear: RenderClear,
4375        viewport: Rect,
4376    );
4377    pub fn render_get_device(device: *mut *mut c_void, context: *mut *mut c_void);
4378
4379}
4380
4381/// screenshot_capture trampoline
4382///
4383/// see also [`Renderer::screenshot_capture`]
4384unsafe extern "C" fn sc_capture_trampoline<F: FnMut(&[Color32], usize, usize)>(
4385    color_buffer: *mut Color32,
4386    width: i32,
4387    height: i32,
4388    context: *mut c_void,
4389) {
4390    let closure = unsafe { &mut *(context as *mut &mut F) };
4391    closure(
4392        unsafe { std::slice::from_raw_parts(color_buffer, (width * height) as usize) },
4393        width as usize,
4394        height as usize,
4395    )
4396}
4397
4398impl Renderer {
4399    /// Sets the root transform of the camera! This will be the identity matrix by default. The user’s head
4400    /// location will then be relative to this point. This is great to use if you’re trying to do teleportation,
4401    /// redirected walking, or just shifting the floor around.
4402    /// <https://stereokit.net/Pages/StereoKit/Renderer/CameraRoot.html>
4403    ///
4404    /// see also [`render_set_cam_root`]
4405    /// ### Examples
4406    /// ```
4407    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
4408    /// use stereokit_rust::{maths::{Matrix, Vec3}, system::Renderer};
4409    ///
4410    /// let camera_root = Renderer::get_camera_root();
4411    /// assert_eq!(camera_root, Matrix::IDENTITY);
4412    ///
4413    /// let transform = Matrix::t([0.0, 0.0, -1.0]);
4414    ///
4415    /// test_steps!( // !!!! Get a proper main loop !!!!
4416    ///     Renderer::camera_root(transform);
4417    ///     let camera_root = Renderer::get_camera_root();
4418    ///     assert_eq!(camera_root, transform);
4419    /// );
4420    /// ```
4421    pub fn camera_root(transform: impl Into<Matrix>) {
4422        unsafe { render_set_cam_root(&transform.into()) }
4423    }
4424
4425    /// This is the gamma space color the renderer will clear the screen to when beginning to draw a new frame.
4426    /// [`Color128::BLACK_TRANSPARENT`] is the default and is mandatory for some Passthrough solutions.
4427    /// <https://stereokit.net/Pages/StereoKit/Renderer/ClearColor.html>
4428    ///
4429    /// see also [`render_set_clear_color`]
4430    /// ### Examples
4431    /// ```
4432    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
4433    /// use stereokit_rust::{system::Renderer,
4434    ///                      render_list::RenderList, util::{named_colors, Color128}};
4435    ///
4436    /// // We want to replace the gray background with a dark blue sky:
4437    /// let mut primary = RenderList::primary();
4438    /// assert_eq!(primary.get_count(), 0);
4439    ///
4440    ///
4441    /// assert_eq!(Renderer::get_clear_color(), Color128::BLACK_TRANSPARENT);
4442    /// Renderer::clear_color(named_colors::BLUE);
4443    ///
4444    /// filename_scr = "screenshots/renderer.jpeg";
4445    /// test_steps!( // !!!! Get a proper main loop !!!!
4446    ///     
4447    ///     primary.clear();
4448    ///
4449    ///     assert_eq!(Renderer::get_clear_color(), named_colors::BLUE.into());
4450    ///
4451    /// );
4452    /// ```
4453    pub fn clear_color(color_gamma: impl Into<Color128>) {
4454        unsafe { render_set_clear_color(color_gamma.into()) }
4455    }
4456
4457    /// Enables or disables rendering of the skybox texture! It’s enabled by default on Opaque displays, and completely
4458    /// unavailable for transparent displays.
4459    /// <https://stereokit.net/Pages/StereoKit/Renderer/EnableSky.html>
4460    ///
4461    /// see also [`render_enable_skytex`] [`Renderer::clear_color`] [`crate::tex::SHCubemap`]
4462    /// ### Examples
4463    /// ```
4464    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
4465    /// use stereokit_rust::system::Renderer;
4466    ///
4467    /// assert_eq!(Renderer::get_enable_sky(), true);
4468    ///
4469    /// Renderer::enable_sky(false);
4470    /// assert_eq!(Renderer::get_enable_sky(), false);
4471    ///
4472    /// Renderer::enable_sky(true);
4473    /// assert_eq!(Renderer::get_enable_sky(), true);
4474    /// ```
4475    pub fn enable_sky(enable: bool) {
4476        unsafe { render_enable_skytex(enable as Bool32T) }
4477    }
4478
4479    /// By default, StereoKit renders all first-person layers. This is a bit flag that allows you to change which layers
4480    /// StereoKit renders for the primary viewpoint. To change what layers a visual is on, use a Draw method that
4481    /// includes a RenderLayer as a parameter.
4482    /// <https://stereokit.net/Pages/StereoKit/Renderer/LayerFilter.html>
4483    ///
4484    /// see also [`render_set_filter`]
4485    /// ### Examples
4486    /// ```
4487    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
4488    /// use stereokit_rust::system::{Renderer, RenderLayer};
4489    ///
4490    /// assert_eq!(Renderer::get_layer_filter(), RenderLayer::AllFirstPerson);
4491    ///
4492    /// Renderer::layer_filter(RenderLayer::All);
4493    /// assert_eq!(Renderer::get_layer_filter(), RenderLayer::All);
4494    ///
4495    /// Renderer::layer_filter(RenderLayer::AllFirstPerson);
4496    /// assert_eq!(Renderer::get_layer_filter(), RenderLayer::AllFirstPerson);
4497    /// ```
4498    pub fn layer_filter(filter: RenderLayer) {
4499        unsafe { render_set_filter(filter) }
4500    }
4501
4502    /// Allows you to set the multisample (MSAA) level of the render surface. Valid values are 1, 2, 4, 8, 16, though
4503    /// some OpenXR runtimes may clamp this to lower values. Note that while this can greatly smooth out edges, it also
4504    /// greatly increases RAM usage and fill rate, so use it sparingly. Only works in XR mode. If known in advance, set
4505    /// this via [`crate::sk::SkSettings`] in initialization. This is a very costly change to make.
4506    /// <https://stereokit.net/Pages/StereoKit/Renderer/Multisample.html>
4507    ///
4508    /// see also [`render_set_multisample`]
4509    /// ### Examples
4510    /// ```
4511    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
4512    /// use stereokit_rust::system::Renderer;
4513    ///
4514    /// assert_eq!(Renderer::get_multisample(), 1);
4515    ///
4516    /// Renderer::multisample(4);
4517    /// assert_eq!(Renderer::get_multisample(), 4);
4518    ///
4519    /// Renderer::multisample(1);
4520    /// assert_eq!(Renderer::get_multisample(), 1);
4521    /// ```
4522    pub fn multisample(level: i32) {
4523        unsafe { render_set_multisample(level) }
4524    }
4525
4526    /// For flatscreen applications only! This allows you to change the camera projection between perspective and
4527    /// orthographic projection. This may be of interest for some category of UI work, but is generally a niche piece of
4528    /// functionality.
4529    /// Swapping between perspective and orthographic will also switch the clipping planes and field of view to the
4530    /// values associated with that mode. See set_clip/set_fov for perspective, and set_ortho_clip/set_ortho_size for
4531    /// orthographic.
4532    /// <https://stereokit.net/Pages/StereoKit/Renderer/Projection.html>
4533    ///
4534    /// see also [`render_set_projection`]
4535    /// ### Examples
4536    /// ```
4537    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
4538    /// use stereokit_rust::system::{Renderer, Projection};
4539    ///
4540    /// assert_eq!(Renderer::get_projection(), Projection::Perspective);
4541    ///
4542    /// Renderer::projection(Projection::Orthographic);
4543    /// assert_eq!(Renderer::get_projection(), Projection::Orthographic);
4544    ///
4545    /// Renderer::projection(Projection::Perspective);
4546    /// assert_eq!(Renderer::get_projection(), Projection::Perspective);
4547    /// ```
4548    pub fn projection(projection: Projection) {
4549        unsafe { render_set_projection(projection) }
4550    }
4551
4552    /// OpenXR has a recommended default for the main render surface, this value allows you to set SK’s surface to a
4553    /// multiple of the recommended size. Note that the final resolution may also be clamped or quantized. Only works in
4554    /// XR mode. If known in advance, set this via [`crate::sk::SkSettings`] in initialization. This is a very costly change to make.
4555    /// Consider if Viewport_scaling will work for you instead, and prefer that.
4556    /// <https://stereokit.net/Pages/StereoKit/Renderer/Scaling.html>
4557    ///
4558    /// see also [`render_set_scaling`]
4559    /// ### Examples
4560    /// ```
4561    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
4562    /// use stereokit_rust::system::Renderer;
4563    ///
4564    /// assert_eq!(Renderer::get_scaling(), 1.0);
4565    ///
4566    /// Renderer::scaling(0.5);
4567    /// assert_eq!(Renderer::get_scaling(), 0.5);
4568    ///
4569    /// Renderer::scaling(1.0);
4570    /// assert_eq!(Renderer::get_scaling(), 1.0);
4571    /// ```
4572    pub fn scaling(scaling: f32) {
4573        unsafe { render_set_scaling(scaling) }
4574    }
4575
4576    /// This allows you to trivially scale down the area of the swapchain that StereoKit renders to! This can be used
4577    /// to boost performance in situations where full resolution is not needed, or to reduce GPU time. This value is
4578    /// locked to the 0-1 range
4579    /// <https://stereokit.net/Pages/StereoKit/Renderer/ViewportScaling.html>
4580    ///
4581    /// see also [`render_set_viewport_scaling`]
4582    /// ### Examples
4583    /// ```
4584    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
4585    /// use stereokit_rust::system::Renderer;
4586    ///
4587    /// assert_eq!(Renderer::get_viewport_scaling(), 1.0);
4588    ///
4589    /// Renderer::viewport_scaling(0.5);
4590    /// assert_eq!(Renderer::get_viewport_scaling(), 0.5);
4591    ///
4592    /// Renderer::viewport_scaling(1.0);
4593    /// assert_eq!(Renderer::get_viewport_scaling(), 1.0);
4594    /// ```
4595    pub fn viewport_scaling(scaling: f32) {
4596        unsafe { render_set_viewport_scaling(scaling) }
4597    }
4598
4599    /// Sets the lighting information for the scene! You can build one through [`SphericalHarmonics::from_lights`], or grab
4600    /// one from [`crate::tex::SHCubemap`]
4601    /// <https://stereokit.net/Pages/StereoKit/Renderer/SkyLight.html>
4602    ///
4603    /// see also [`render_set_skylight`] [`crate::tex::SHCubemap`] [`crate::util::SHLight`]
4604    /// ### Examples
4605    /// ```
4606    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
4607    /// use stereokit_rust::{system::Renderer, maths::Vec3,
4608    ///                      util::{named_colors, SphericalHarmonics, SHLight}};
4609    ///
4610    /// let light1 = SHLight::new([0.0, 1.0, 0.0], named_colors::WHITE);
4611    /// let light2 = SHLight::new([0.0, 0.0, 1.0], named_colors::WHITE);
4612    ///
4613    /// let mut sh = SphericalHarmonics::from_lights(&[light1, light2]);
4614    ///
4615    /// Renderer::sky_light(sh);
4616    /// let sky_light = Renderer::get_sky_light();
4617    ///
4618    /// assert_eq!(sky_light, sh);
4619    /// assert_eq!(sh.get_dominent_light_direction(),
4620    ///            Vec3 { x: -0.0, y: -1.0, z: -1.0 }.get_normalized())
4621    /// ```
4622    pub fn sky_light(light_info: SphericalHarmonics) {
4623        unsafe { render_set_skylight(&light_info) }
4624    }
4625
4626    /// Set a cubemap skybox texture for rendering a background! This is only visible on Opaque displays, since
4627    /// transparent displays have the real world behind them already! StereoKit has a a default procedurally generated
4628    /// skybox. You can load one with [`crate::tex::SHCubemap`]. If you’re trying to affect the lighting,
4629    /// see [`Renderer::sky_light`].
4630    /// <https://stereokit.net/Pages/StereoKit/Renderer/SkyTex.html>
4631    ///
4632    /// see also [`render_set_skytex`] [`crate::tex::SHCubemap`]
4633    /// ### Examples
4634    /// ```
4635    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
4636    /// use stereokit_rust::{system::{Renderer, Assets}, tex::{Tex, TexType}};
4637    ///
4638    /// let sky_tex = Tex::from_file("hdri/sky_dawn.jpeg", true, None)
4639    ///                        .expect("sky_tex should be created");
4640    ///
4641    /// Assets::block_for_priority(i32::MAX);
4642    ///
4643    /// Renderer::sky_tex(&sky_tex);
4644    /// let sky_tex_get = Renderer::get_sky_tex();
4645    ///
4646    /// assert_eq!(sky_tex_get, sky_tex);
4647    /// ```
4648    pub fn sky_tex(tex: impl AsRef<Tex>) {
4649        unsafe { render_set_skytex(tex.as_ref().0.as_ptr()) }
4650    }
4651
4652    /// This is the Material that StereoKit is currently using to draw the skybox! It needs a special shader that's
4653    /// tuned for a full-screen quad. If you just want to change the skybox image, try setting [`Renderer::sky_tex`]
4654    /// instead.
4655    ///  
4656    /// This value will never be null! If you try setting this to null, it will assign SK's built-in default sky
4657    /// material. If you want to turn off the skybox, see [`Renderer::enable_sky`] instead.
4658    ///  
4659    /// Recommended Material settings would be:
4660    /// - DepthWrite: false
4661    /// - DepthTest: LessOrEq
4662    /// - QueueOffset: 100
4663    ///
4664    /// <https://stereokit.net/Pages/StereoKit/Renderer/SkyMaterial.html>
4665    ///
4666    /// see also [`render_set_skymaterial`] [`crate::tex::SHCubemap`]
4667    /// ### Examples
4668    /// ```
4669    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
4670    /// use stereokit_rust::{system::Renderer, material::Material, util::named_colors};
4671    ///
4672    /// let material = Material::pbr().copy();
4673    /// Renderer::sky_material(&material);
4674    ///
4675    /// let same_material = Renderer::get_sky_material();
4676    /// assert_eq!(same_material, material);
4677    /// ```
4678    pub fn sky_material(material: impl AsRef<Material>) {
4679        unsafe { render_set_skymaterial(material.as_ref().0.as_ptr()) }
4680    }
4681
4682    /// Adds a mesh to the render queue for this frame! If the Hierarchy has a transform on it, that transform is
4683    /// combined with the Matrix provided here.
4684    /// <https://stereokit.net/Pages/StereoKit/Renderer/Add.html>
4685    /// * `mesh` - A valid Mesh you wish to draw.
4686    /// * `material` - A Material to apply to the Mesh.
4687    /// * `transform` - A Matrix that will transform the mesh from Model Space into the current Hierarchy Space.
4688    /// * `color` - A per-instance linear space color value to pass into the shader! Normally this gets used like a
4689    ///   material tint. If you’re adventurous and don’t need per-instance colors, this is a great spot to pack in
4690    ///   extra per-instance data for the shader! If None has default value of WHITE
4691    /// * `layer` - All visuals are rendered using a layer bit-flag. By default, all layers are rendered, but this can be
4692    ///   useful for filtering out objects for different rendering purposes! For example: rendering a mesh over the
4693    ///   user’s head from a 3rd person perspective, but filtering it out from the 1st person perspective.If None has
4694    ///   default value of RenderLayer::Layer0
4695    ///
4696    /// see also [`render_add_mesh`] [`Mesh::draw`]
4697    /// ### Examples
4698    /// ```
4699    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
4700    /// use stereokit_rust::{system::{Renderer, RenderLayer}, maths::{Vec3, Matrix},
4701    ///                      mesh::Mesh, material::Material, util::named_colors};
4702    ///
4703    /// let sphere = Mesh::generate_sphere(0.5, None);
4704    /// let material = Material::pbr();
4705    /// let transform1 = Matrix::t([-0.5, 0.0, 0.0]);
4706    /// let transform2 = Matrix::t([ 0.5, 0.0, -1.0]);
4707    ///
4708    /// test_steps!( // !!!! Get a proper main loop !!!!
4709    ///
4710    ///     Renderer::add_mesh(token, &sphere, &material, transform1,
4711    ///         Some(named_colors::RED.into()), Some(RenderLayer::Layer0));
4712    ///
4713    ///     Renderer::add_mesh(token, &sphere, &material, transform2, None, None);
4714    /// );
4715    /// ```
4716    pub fn add_mesh(
4717        _token: &MainThreadToken,
4718        mesh: impl AsRef<Mesh>,
4719        material: impl AsRef<Material>,
4720        transform: impl Into<Matrix>,
4721        color: Option<Color128>,
4722        layer: Option<RenderLayer>,
4723    ) {
4724        let color = color.unwrap_or(Color128::WHITE);
4725        let layer = layer.unwrap_or(RenderLayer::Layer0);
4726        unsafe {
4727            render_add_mesh(mesh.as_ref().0.as_ptr(), material.as_ref().0.as_ptr(), &transform.into(), color, layer)
4728        }
4729    }
4730
4731    /// Adds a Model to the render queue for this frame! If the Hierarchy has a transform on it, that transform is
4732    /// combined with the Matrix provided here.
4733    /// <https://stereokit.net/Pages/StereoKit/Renderer/Add.html>
4734    /// * `model` -  A valid Model you wish to draw.
4735    /// * `transform` - A Matrix that will transform the Model from Model Space into the current Hierarchy Space.
4736    /// * `color` - A per-instance linear space color value to pass into the shader! Normally this gets used like a
4737    ///   material tint. If you’re adventurous and don’t need per-instance colors, this is a great spot to pack in
4738    ///   extra per-instance data for the shader! If None has default value of WHITE
4739    /// * `layer` - All visuals are rendered using a layer bit-flag. By default, all layers are rendered, but this can
4740    ///   be useful for filtering out objects for different rendering purposes! For example: rendering a mesh over the
4741    ///   user’s head from a 3rd person perspective, but filtering it out from the 1st person perspective. If None has
4742    ///   default value of RenderLayer::Layer0
4743    ///
4744    /// see also [`render_add_model`] [`Model::draw`] [`Model::draw_with_material`]
4745    /// ### Examples
4746    /// ```
4747    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
4748    /// use stereokit_rust::{system::{Renderer, RenderLayer}, maths::{Vec3, Matrix},
4749    ///                      model::Model, util::named_colors};
4750    ///
4751    /// let model = Model::from_file("plane.glb", None).expect("plane.glb should be there");
4752    /// let transform1 = Matrix::t([-2.5, 0.0, -5.0]);
4753    /// let transform2 = Matrix::t([ 2.5, 0.0, -5.0]);
4754    ///
4755    /// test_steps!( // !!!! Get a proper main loop !!!!
4756    ///
4757    ///     Renderer::add_model(token, &model, transform1,
4758    ///         Some(named_colors::RED.into()), Some(RenderLayer::Layer0));
4759    ///
4760    ///     Renderer::add_model(token, &model, transform2, None, None);
4761    /// );
4762    /// ```
4763    pub fn add_model(
4764        _token: &MainThreadToken,
4765        model: impl AsRef<Model>,
4766        transform: impl Into<Matrix>,
4767        color: Option<Color128>,
4768        layer: Option<RenderLayer>,
4769    ) {
4770        let color = color.unwrap_or(Color128::WHITE);
4771        let layer = layer.unwrap_or(RenderLayer::Layer0);
4772        unsafe { render_add_model(model.as_ref().0.as_ptr(), &transform.into(), color, layer) }
4773    }
4774
4775    /// Renders a Material onto a rendertarget texture! StereoKit uses a 4 vert quad stretched over the surface of the
4776    /// texture, and renders the material onto it to the texture.
4777    /// <https://stereokit.net/Pages/StereoKit/Renderer/Blit.html>
4778    /// * `to_render_target` - A texture that’s been set up as a render target!
4779    /// * `material` - This material is rendered onto the texture! Set it up like you would if you were applying it to
4780    ///   a plane, or quad mesh.
4781    ///
4782    /// see also [`render_blit`]
4783    /// ### Examples
4784    /// ```
4785    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
4786    /// use stereokit_rust::{system::Renderer, material::Material, tex::Tex};
4787    ///
4788    /// let material = Material::pbr();
4789    /// let tex = Tex::render_target(200,200, None, None, None)
4790    ///                    .expect("RenderTarget should be created");
4791    ///
4792    /// test_steps!( // !!!! Get a proper main loop !!!!
4793    ///     Renderer::blit(&tex, &material);
4794    /// );
4795    /// ```
4796    pub fn blit(to_render_target: impl AsRef<Tex>, material: impl AsRef<Material>) {
4797        unsafe { render_blit(to_render_target.as_ref().0.as_ptr(), material.as_ref().0.as_ptr()) }
4798    }
4799
4800    /// The capture_filter is a layer mask for Mixed Reality Capture, or 2nd person observer rendering. On HoloLens and
4801    /// WMR, this is the video rendering feature. This allows you to hide, or reveal certain draw calls when rendering
4802    /// video output.
4803    ///
4804    /// By default, the capture_filter will always be the same as [`Renderer::layer_filter`], overriding this will mean this
4805    /// filter no longer updates with layer_filter.
4806    /// <https://stereokit.net/Pages/StereoKit/Renderer/OverrideCaptureFilter.html>
4807    /// * `use_override_filter` - Enables (true) or disables (false) the overridden filter value provided here.
4808    /// * `override_filter` - The filter for capture rendering to use. This is ignored if useOverrideFilter is false.
4809    ///
4810    /// see also [`render_override_capture_filter`]
4811    /// ### Examples
4812    /// ```
4813    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
4814    /// use stereokit_rust::{system::{Renderer, RenderLayer},
4815    ///                      maths::Matrix, mesh::Mesh, material::Material};
4816    ///
4817    /// let sphere = Mesh::generate_sphere(0.2, None);
4818    /// let material = Material::pbr();
4819    ///
4820    /// assert_eq!(Renderer::has_capture_filter(), false);
4821    /// assert_eq!(Renderer::get_capture_filter(), RenderLayer::AllFirstPerson);
4822    ///
4823    /// Renderer::override_capture_filter(true, RenderLayer::Layer1);
4824    ///
4825    /// assert_eq!(Renderer::has_capture_filter(), true);
4826    /// assert_eq!(Renderer::get_capture_filter(), RenderLayer::Layer1);
4827    ///
4828    ///
4829    /// test_steps!( // !!!! Get a proper main loop !!!!
4830    ///     sphere.draw(token, &material, Matrix::IDENTITY, None, Some(RenderLayer::Layer1));
4831    /// );
4832    ///
4833    /// Renderer::override_capture_filter(false, RenderLayer::Layer0);
4834    /// assert_eq!(Renderer::has_capture_filter(), false);
4835    /// ```
4836    pub fn override_capture_filter(use_override_filter: bool, override_filter: RenderLayer) {
4837        unsafe { render_override_capture_filter(use_override_filter as Bool32T, override_filter) }
4838    }
4839
4840    /// This renders the current scene to the indicated rendertarget texture, from the specified viewpoint. This call
4841    /// enqueues a render that occurs immediately before the screen itself is rendered.
4842    /// <https://stereokit.net/Pages/StereoKit/Renderer/RenderTo.html>
4843    /// * `to_render_target` - The texture to which the scene will be rendered to. This must be a Rendertarget type
4844    ///   texture.
4845    /// * `to_target_index` - (Optional) Index of the render target's array slice we want to draw to. If None, defaults
4846    ///   to 0. This is only relevant for array/render target textures with multiple slices.
4847    /// * `override_material` - (Optional) A material that will override all materials used during this render pass.
4848    ///   This can be useful for depth pre-pass, shadow map rendering, or special effects. If None, materials attached
4849    ///   to individual draw items are used (normal behavior).
4850    /// * `camera` - A TRS matrix representing the location and orientation of the camera. This matrix gets inverted
4851    ///   later on, so no need to do it yourself.
4852    /// * `projection` - The projection matrix describes how the geometry is flattened onto the draw surface. Normally,
4853    ///   you’d use Matrix::perspective, and occasionally Matrix::orthographic might be helpful as well.
4854    /// * `layer_filter` - This is a bit flag that allows you to change which layers StereoKit renders for this particular
4855    ///   render viewpoint. To change what layers a visual is on, use a Draw method that includes a RenderLayer as a
4856    ///   parameter. If None has default value of RenderLayer::ALL
4857    /// * `clear` - Describes if and how the rendertarget should be cleared before rendering. Note that clearing the
4858    ///   target is unaffected by the viewport, so this will clean the entire surface! If None has default value of
4859    ///   RenderClear::All
4860    /// * `vieport` - Allows you to specify a region of the rendertarget to draw to! This is in normalized coordinates,
4861    ///   0-1. If the width of this value is zero, then this will render to the entire texture. If None has default value
4862    ///   of (0, 0, 0, 0)
4863    ///
4864    /// see also [`render_to`]
4865    /// ### Examples
4866    /// ```
4867    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
4868    /// use stereokit_rust::{system::{Renderer, RenderLayer}, maths::{Vec3, Quat, Matrix},
4869    ///                      render_list::RenderList, tex::{Tex, TexType, TexFormat},
4870    ///                      mesh::Mesh, model::Model, material::Material, util::named_colors};
4871    ///
4872    /// let sun = Mesh::generate_sphere(5.0, None);
4873    /// let material = Material::pbr();
4874    /// let transform_sun = Matrix::t([-6.0, -1.0, -10.0]);
4875    ///
4876    /// let plane = Mesh::generate_plane_up([1.0,1.0], None, true);
4877    /// let mut material = Material::unlit().copy();
4878    /// let tex = Tex::render_target(200,200, None, None, None)
4879    ///                    .expect("RenderTarget should be created");
4880    /// material.diffuse_tex(&tex);
4881    /// let transform_plane = Matrix::t([0.0, -0.55, 0.0]);
4882    ///
4883    /// let camera = Matrix::t_r(Vec3::Z * 2.0, Quat::look_at(Vec3::Z, Vec3::ZERO, None));
4884    /// let projection = Matrix::perspective(90.0, 1.0, 0.1, 20.0);
4885    ///
4886    /// test_steps!( // !!!! Get a proper main loop !!!!
4887    ///     
4888    ///     Renderer::add_mesh(token, &sun, &material, transform_sun,
4889    ///         Some(named_colors::RED.into()), None);
4890    ///
4891    ///     Renderer::add_mesh(token, &plane, &material, transform_plane,
4892    ///         None, None);
4893    ///
4894    ///     Renderer::render_to(token, &tex, None, None, camera, projection, None, None, None);
4895    /// );
4896    /// ```
4897    #[allow(clippy::too_many_arguments)]
4898    pub fn render_to<M: Into<Matrix>>(
4899        _token: &MainThreadToken,
4900        to_render_target: impl AsRef<Tex>,
4901        to_target_index: Option<i32>,
4902        override_material: Option<&Material>,
4903        camera: M,
4904        projection: M,
4905        layer_filter: Option<RenderLayer>,
4906        clear: Option<RenderClear>,
4907        viewport: Option<Rect>,
4908    ) {
4909        let to_target_index = to_target_index.unwrap_or(0);
4910        let override_material_ptr = override_material.map(|m| m.0.as_ptr()).unwrap_or(std::ptr::null_mut());
4911        let layer_filter = layer_filter.unwrap_or(RenderLayer::All);
4912        let clear = clear.unwrap_or(RenderClear::All);
4913        let viewport = viewport.unwrap_or_default();
4914
4915        unsafe {
4916            render_to(
4917                to_render_target.as_ref().0.as_ptr(),
4918                to_target_index,
4919                override_material_ptr,
4920                &camera.into(),
4921                &projection.into(),
4922                layer_filter,
4923                clear,
4924                viewport,
4925            )
4926        }
4927    }
4928
4929    /// This attaches a texture resource globally across all shaders. StereoKit uses this to attach the sky cubemap for
4930    /// use in reflections across all materials (register 11). It can be used for things like shadowmaps, wind data, etc.
4931    ///  Prefer a higher registers (11+) to prevent conflicting with normal Material textures.
4932    /// <https://stereokit.net/Pages/StereoKit/Renderer/SetGlobalTexture.html>
4933    /// * `texture_register` - The texture resource register the texture will bind to. SK uses register 11 already, so
4934    ///   values above that should be fine.
4935    /// * `tex` - The texture to assign globally. Setting None here will clear any texture that is currently bound.
4936    ///
4937    /// see also [`render_global_texture`]
4938    /// ### Examples
4939    /// ```
4940    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
4941    /// use stereokit_rust::{system::{Renderer, RenderLayer}, tex::{Tex, TexFormat},
4942    ///                      maths::Matrix, util::named_colors};
4943    ///
4944    /// let tex = Tex::from_file("hdri/sky_dawn.jpeg", true, None)
4945    ///                    .expect("tex should be created");
4946    ///
4947    /// test_steps!( // !!!! Get a proper main loop !!!!
4948    ///     if iter < 2 {
4949    ///         Renderer::set_global_texture(token, 12, Some(&tex));
4950    ///     } else {
4951    ///         Renderer::set_global_texture(token, 12, None);
4952    ///     }
4953    /// );
4954    /// ```
4955    pub fn set_global_texture(_token: &MainThreadToken, texture_register: i32, tex: Option<&Tex>) {
4956        if let Some(tex) = tex {
4957            unsafe { render_global_texture(texture_register, tex.0.as_ptr()) }
4958        } else {
4959            unsafe { render_global_texture(texture_register, null_mut()) }
4960        }
4961    }
4962
4963    /// This attaches a buffer resource globally across all shaders. StereoKit uses this to attach the stereokit
4964    /// rendering constants. It can be used for things like shadowmaps, wind data, etc.
4965    /// <https://stereokit.net/Pages/StereoKit/Renderer/SetGlobalBuffer.html>
4966    /// * `buffer_register` - Valid values are 3-16. This is the register id that this data will be bound to. In HLSL,
4967    ///   you'll see the slot id for '3' indicated like this `: register(b3)`
4968    /// * `buffer` - The data buffer you would like to bind
4969    ///
4970    /// see also [`render_global_buffer`] []
4971    /// ### Examples
4972    /// ```
4973    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
4974    /// use stereokit_rust::{system::Renderer, material::MaterialBuffer};
4975    ///
4976    /// #[repr(C)]
4977    /// #[derive(Default, Copy, Clone)]
4978    /// struct Globals { time: f32, padding: [f32;3] }
4979    ///
4980    /// let mut globals = Globals { time: 1.0, ..Default::default() };
4981    /// let buffer = MaterialBuffer::<Globals>::new();
4982    /// buffer.set(&mut globals as *mut _);
4983    ///
4984    /// test_steps!( // !!!! Get a proper main loop !!!!
4985    ///     // Bind the buffer to slot 3 so shaders can read it.
4986    ///     Renderer::set_global_buffer( 3, &buffer);
4987    /// );
4988    /// ```
4989    pub fn set_global_buffer<T>(buffer_register: i32, buffer: &MaterialBuffer<T>) {
4990        unsafe {
4991            render_global_buffer(buffer_register, buffer.as_ref().as_ptr());
4992        }
4993    }
4994
4995    /// Unbinds any global MaterialBuffer previously bound to this register slot (3-16). Equivalent to passing None
4996    /// to [`Renderer::set_global_buffer`]. Provided as a convenience method.
4997    /// <https://stereokit.net/Pages/StereoKit/Renderer/SetGlobalBuffer.html>
4998    /// * `buffer_register` - Valid values are 3-16. This is the register id the data was bound to.
4999    ///
5000    /// see also [`render_global_buffer`] [`Renderer::set_global_buffer`]
5001    /// ### Examples
5002    /// ```
5003    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
5004    /// use stereokit_rust::{system::Renderer, material::MaterialBuffer};
5005    ///
5006    /// #[repr(C)]
5007    /// #[derive(Default, Copy, Clone)]
5008    /// struct Globals { value: f32, padding: [f32;3] }
5009    /// let buffer = MaterialBuffer::<Globals>::new();
5010    /// test_steps!(
5011    ///     Renderer::set_global_buffer(4, &buffer);
5012    ///     // Later we decide to unbind it completely
5013    ///     if iter == number_of_steps -1 {
5014    ///         Renderer::unset_global_buffer(4);
5015    ///     }
5016    /// );
5017    /// ```
5018    pub fn unset_global_buffer(buffer_register: i32) {
5019        unsafe { render_global_buffer(buffer_register, std::ptr::null_mut()) }
5020    }
5021
5022    /// Schedules a screenshot for the end of the frame! The view will be rendered from the given pose, with a
5023    /// resolution the same size as the screen’s surface. It’ll be saved as a JPEG or PNG file depending on the filename
5024    /// extension provided.
5025    /// <https://stereokit.net/Pages/StereoKit/Renderer/Screenshot.html>
5026    /// * `filename` - Filename to write the screenshot to! This will be a PNG if the extension ends with (case
5027    ///   insensitive) “.png”, and will be a 90 quality JPEG if it ends with anything else.
5028    /// * `file_quality` - For JPEG files, this is the compression quality of the file from 0-100, 100 being highest
5029    ///   quality, 0 being smallest size. SK uses a default of 90 here.
5030    /// * `viewpoint` - is Pose::look_at(from_point, looking_at_point)
5031    /// * `width` - Size of the screenshot horizontally, in pixels.
5032    /// * `height`- Size of the screenshot vertically, in pixels
5033    /// * `field_of_view` - The angle of the viewport, in degrees. If None will use default value of 90°
5034    ///
5035    /// see also [`render_screenshot`]
5036    /// see example in [`Renderer`]
5037    pub fn screenshot(
5038        _token: &MainThreadToken,
5039        filename: impl AsRef<Path>,
5040        file_quality: i32,
5041        viewpoint: Pose,
5042        width: i32,
5043        height: i32,
5044        field_of_view: Option<f32>,
5045    ) {
5046        let path = filename.as_ref();
5047        let c_str = CString::new(path.to_str().unwrap_or("!!!path.to_str error!!!").to_owned()).unwrap();
5048        let field_of_view = field_of_view.unwrap_or(90.0);
5049        unsafe { render_screenshot(c_str.as_ptr(), file_quality, viewpoint, width, height, field_of_view) }
5050    }
5051
5052    /// Schedules a screenshot for the end of the frame! The view will be rendered from the given position at the given
5053    /// point, with a resolution the same size as the screen’s surface. This overload allows for retrieval of the color
5054    /// data directly from the render thread! You can use the color data directly by saving/processing it inside your
5055    /// callback, or you can keep the data alive for as long as it is referenced.
5056    /// <https://stereokit.net/Pages/StereoKit/Renderer/Screenshot.html>
5057    /// * `on_screenshot` : closure |&[Color32], width:usize, height:usize|
5058    /// * `viewpoint` - is Pose::look_at(from_point, looking_at_point)
5059    /// * `width` - Size of the screenshot horizontally, in pixels.
5060    /// * `height`- Size of the screenshot vertically, in pixels
5061    /// * `field_of_view` - The angle of the viewport, in degrees. If None will use default value of 90°
5062    /// * `tex_format` - The pixel format of the color data. If None will use default value of TexFormat::RGBA32
5063    ///
5064    /// see also [`render_screenshot_capture`]
5065    /// ### Examples
5066    /// ```
5067    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
5068    /// use stereokit_rust::{system::{Renderer, RenderLayer}, maths::{Vec3, Quat, Pose, Matrix},
5069    ///                      render_list::RenderList, tex::{Tex, TexType, TexFormat},
5070    ///                      mesh::Mesh, model::Model, material::Material, util::named_colors};
5071    ///
5072    /// let sun = Mesh::generate_sphere(7.0, None);
5073    /// let material_sun = Material::pbr();
5074    /// let transform_sun = Matrix::t([-6.0, 3.0, -10.0]);
5075    ///
5076    /// let plane = Mesh::generate_plane_up([1.0,1.0], None, true);
5077    /// let mut material = Material::unlit().copy();
5078    /// let mut tex = Tex::render_target(200,200, None, None, None)
5079    ///                    .expect("RenderTarget should be created");
5080    /// tex.id("CAPTURE_TEXTURE_ID");
5081    /// material.diffuse_tex(&tex);
5082    /// let transform_plane = Matrix::t([0.0, -0.55, 0.0]);
5083    ///
5084    /// let camera_pose = Pose::new([0.0, 0.0, 1.0], None);
5085    ///
5086    /// number_of_steps = 20;
5087    /// filename_scr = "screenshots/screenshot_capture.jpeg";
5088    /// test_screenshot!( // !!!! Get a proper main loop !!!!
5089    ///     
5090    ///     Renderer::add_mesh(token, &sun, &material_sun, transform_sun,
5091    ///         Some(named_colors::RED.into()), None);
5092    ///
5093    ///     Renderer::add_mesh(token, &plane, &material, transform_plane,
5094    ///         None, None);
5095    ///
5096    ///     Renderer::screenshot_capture( token,
5097    ///         move |dots, width, height| {
5098    ///             let tex = Tex::find("CAPTURE_TEXTURE_ID").ok();
5099    ///             match tex {
5100    ///                 Some(mut tex) => tex.set_colors32(width, height, dots),
5101    ///                 None => panic!("CAPTURE_TEXTURE_ID not found!"),
5102    ///             };
5103    ///         },
5104    ///         camera_pose, 200, 200, None, None
5105    ///     );
5106    /// );
5107    /// ```
5108    /// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/screenshot_capture.jpeg" alt="screenshot" width="200">
5109    pub fn screenshot_capture<F: FnMut(&[Color32], usize, usize)>(
5110        _token: &MainThreadToken,
5111        mut on_screenshot: F,
5112        viewpoint: Pose,
5113        width: i32,
5114        height: i32,
5115        field_of_view: Option<f32>,
5116        tex_format: Option<TexFormat>,
5117    ) {
5118        let field_of_view = field_of_view.unwrap_or(90.0);
5119        let tex_format = tex_format.unwrap_or(TexFormat::RGBA32);
5120        let mut closure = &mut on_screenshot;
5121        unsafe {
5122            render_screenshot_capture(
5123                Some(sc_capture_trampoline::<F>),
5124                viewpoint,
5125                width,
5126                height,
5127                field_of_view,
5128                tex_format,
5129                &mut closure as *mut _ as *mut c_void,
5130            )
5131        }
5132    }
5133
5134    /// Schedules a screenshot for the end of the frame! The view will be rendered from the given position at the given
5135    /// point, with a resolution the same size as the screen’s surface. This overload allows for retrieval of the color
5136    /// data directly from the render thread! You can use the color data directly by saving/processing it inside your
5137    /// callback, or you can keep the data alive for as long as it is referenced.
5138    ///  <https://stereokit.net/Pages/StereoKit/Renderer/Screenshot.html>
5139    /// * `on_screenshot` : closure |&[Color32], width:usize, height:usize|
5140    /// * `camera` - A TRS matrix representing the location and orientation of the camera. This matrix gets inverted
5141    ///   later on, so no need to do it yourself.
5142    /// * `projection` - The projection matrix describes how the geometry is flattened onto the draw surface. Normally,
5143    ///   you’d use [`Matrix::perspective`], and occasionally [`Matrix::orthographic`] might be helpful as well.
5144    /// * `width` - Size of the screenshot horizontally, in pixels.
5145    /// * `height`- Size of the screenshot vertically, in pixels
5146    /// * `render_layer` - This is a bit flag that allows you to change which layers StereoKit renders for this
5147    ///   particular render viewpoint. To change what layers a visual is on, use a Draw method that includes a
5148    ///   RenderLayer as a parameter. If None will use default value of All
5149    /// * `clear` - Describes if and how the rendertarget should be cleared before rendering. Note that clearing the
5150    ///   target is unaffected by the viewport, so this will clean the entire surface! If None wille use default value
5151    ///   of All
5152    /// * `viewport` - Allows you to specify a region of the rendertarget to draw to! This is in normalized coordinates,
5153    ///   0-1. If the width of this value is zero, then this will render to the entire texture. If None has default value
5154    ///   of (0, 0, 0, 0)
5155    /// * `tex_format` - The pixel format of the color data. If None will use default value of TexFormat::RGBA32
5156    ///
5157    /// see also [`render_screenshot_viewpoint`]
5158    /// ### Examples
5159    /// ```
5160    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
5161    /// use stereokit_rust::{system::{Renderer, RenderLayer}, maths::{Vec3, Quat, Pose, Matrix},
5162    ///                      render_list::RenderList, tex::{Tex, TexType, TexFormat},
5163    ///                      mesh::Mesh, model::Model, material::Material, util::named_colors};
5164    ///
5165    /// let sun = Mesh::generate_sphere(7.0, None);
5166    /// let material_sun = Material::pbr();
5167    /// let transform_sun = Matrix::t([6.0, 3.0, -10.0]);
5168    ///
5169    /// let plane = Mesh::generate_plane_up([1.0,1.0], None, true);
5170    /// let mut material = Material::unlit().copy();
5171    /// let mut tex = Tex::gen_color(named_colors::VIOLET, 200, 200, TexType::Rendertarget, TexFormat::RGBA32);
5172    ///
5173    /// tex.id("CAPTURE_TEXTURE_ID");
5174    /// material.diffuse_tex(&tex);
5175    /// let transform_plane = Matrix::t([0.0, -0.55, 0.0]);
5176    ///
5177    /// let camera = Matrix::t_r(Vec3::Z * 2.0, Quat::look_at(Vec3::Z, Vec3::ZERO, None));
5178    /// let projection = Matrix::perspective(90.0, 1.0, 0.1, 20.0);
5179    ///
5180    /// number_of_steps = 200;
5181    /// filename_scr = "screenshots/screenshot_viewpoint.jpeg";
5182    /// test_screenshot!( // !!!! Get a proper main loop !!!!
5183    ///     
5184    ///     Renderer::add_mesh(token, &sun, &material_sun, transform_sun,
5185    ///         Some(named_colors::RED.into()), None);
5186    ///
5187    ///     Renderer::add_mesh(token, &plane, &material, transform_plane,
5188    ///         None, None);
5189    ///
5190    ///     Renderer::screenshot_viewpoint( token,
5191    ///         move |dots, width, height| {
5192    ///             let tex = Tex::find("CAPTURE_TEXTURE_ID").ok();
5193    ///             match tex {
5194    ///                 Some(mut tex) => tex.set_colors32(width, height, dots),
5195    ///                 None => panic!("CAPTURE_TEXTURE_ID not found!"),
5196    ///             };
5197    ///         },
5198    ///         camera, projection, 200, 200, None, None, None, None
5199    ///     );
5200    /// );
5201    /// ```
5202    /// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/screenshot_viewpoint.jpeg" alt="screenshot" width="200">
5203    #[allow(clippy::too_many_arguments)]
5204    pub fn screenshot_viewpoint<M: Into<Matrix>, F: FnMut(&[Color32], usize, usize)>(
5205        _token: &MainThreadToken,
5206        mut on_screenshot: F,
5207        camera: M,
5208        projection: M,
5209        width: i32,
5210        height: i32,
5211        render_layer: Option<RenderLayer>,
5212        clear: Option<RenderClear>,
5213        viewport: Option<Rect>,
5214        tex_format: Option<TexFormat>,
5215    ) {
5216        let tex_format = tex_format.unwrap_or(TexFormat::RGBA32);
5217        let render_layer = render_layer.unwrap_or(RenderLayer::all());
5218        let clear = clear.unwrap_or(RenderClear::All);
5219        let viewport = viewport.unwrap_or_default();
5220        let mut closure = &mut on_screenshot;
5221        unsafe {
5222            render_screenshot_viewpoint(
5223                Some(sc_capture_trampoline::<F>),
5224                camera.into(),
5225                projection.into(),
5226                width,
5227                height,
5228                render_layer,
5229                clear,
5230                viewport,
5231                tex_format,
5232                &mut closure as *mut _ as *mut c_void,
5233            )
5234        }
5235    }
5236
5237    /// Set the near and far clipping planes of the camera! These are important to z-buffer quality, especially when
5238    /// using low bit depth z-buffers as recommended for devices like the HoloLens. The smaller the range between the
5239    /// near and far planes, the better your z-buffer will look! If you see flickering on objects that are overlapping,
5240    /// try making the range smaller.
5241    ///
5242    /// These values only affect perspective mode projection, which is the default projection mode.
5243    /// <https://stereokit.net/Pages/StereoKit/Renderer/SetClip.html>
5244    /// * `near_plane` - The GPU discards pixels that are too close to the camera, this is that distance! It must be
5245    ///   larger than zero, due to the projection math, which also means that numbers too close to zero will produce
5246    ///   z-fighting artifacts. This has an enforced minimum of 0.001, but you should probably stay closer to 0.1.
5247    /// * `far_plane` - At what distance from the camera does the GPU discard pixel? This is not true distance, but
5248    ///   rather Z-axis distance from zero in View Space coordinates!
5249    ///
5250    /// see also [`render_set_clip`] [`Renderer::get_clip`]
5251    /// ### Examples
5252    /// ```
5253    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
5254    /// use stereokit_rust::system::Renderer;
5255    ///
5256    /// let (near, far) = Renderer::get_clip();
5257    /// assert_eq!(near, 0.02);
5258    /// assert_eq!(far, 50.0);
5259    ///
5260    /// Renderer::set_clip(0.01, 10.0);
5261    /// let (near, far) = Renderer::get_clip();
5262    /// assert_eq!(near, 0.01);
5263    /// assert_eq!(far, 10.0);
5264    /// ```
5265    pub fn set_clip(near_plane: f32, far_plane: f32) {
5266        unsafe { render_set_clip(near_plane, far_plane) }
5267    }
5268
5269    /// Only works for 2D windowed modes! This updates the camera's projection matrix with a new vertical field of view.
5270    ///
5271    /// This value only affects perspective mode projection, which is the default projection mode.
5272    /// <https://stereokit.net/Pages/StereoKit/Renderer/SetFOV.html>
5273    /// * `vertical_field_of_view` - Vertical field of view in degrees.`
5274    ///
5275    /// see also [`render_set_fov`] [`Renderer::get_fov`]
5276    /// ### Examples
5277    /// ```
5278    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
5279    /// use stereokit_rust::system::Renderer;
5280    /// let fov = Renderer::get_fov();
5281    /// assert_eq!(fov, 90.0);
5282    ///
5283    /// Renderer::set_fov(120.0);
5284    /// let fov = Renderer::get_fov();
5285    /// assert_eq!(fov, 120.0);
5286    /// ```
5287    pub fn set_fov(vertical_field_of_view: f32) {
5288        unsafe { render_set_fov(vertical_field_of_view) }
5289    }
5290
5291    /// Set the near and far clipping planes of the camera! These are important to z-buffer quality, especially when
5292    /// using low bit depth z-buffers as recommended for devices like the HoloLens. The smaller the range between the
5293    /// near and far planes, the better your z-buffer will look! If you see flickering on objects that are overlapping,
5294    /// try making the range smaller.
5295    ///
5296    /// These values only affect orthographic mode projection, which is only available in 2D window modes.
5297    /// <https://stereokit.net/Pages/StereoKit/Renderer/SetOrthoClip.html>
5298    /// * `near_plane` - The GPU discards pixels that are too close to the camera, this is that distance! It must be
5299    ///   larger than zero, due to the projection math, which also means that numbers too close to zero will produce
5300    ///   z-fighting artifacts. This has an enforced minimum of 0.001, but you should probably stay closer to 0.1.
5301    /// * `far_plane` - At what distance from the camera does the GPU discard pixel? This is not true distance, but
5302    ///   rather Z-axis distance from zero in View Space coordinates!
5303    ///
5304    /// see also [`render_set_ortho_clip`]
5305    /// ### Examples
5306    /// ```
5307    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
5308    /// use stereokit_rust::system::Renderer;
5309    ///
5310    /// Renderer::set_ortho_clip(0.01, 5.0);
5311    /// ```
5312    pub fn set_ortho_clip(near_plane: f32, far_plane: f32) {
5313        unsafe { render_set_ortho_clip(near_plane, far_plane) }
5314    }
5315
5316    /// This sets the size of the orthographic projection’s viewport. You can use this feature to zoom in and out of the
5317    /// scene.
5318    ///
5319    /// This value only affects orthographic mode projection, which is only available in 2D window modes.
5320    /// <https://stereokit.net/Pages/StereoKit/Renderer/SetOrthoSize.html>
5321    /// * `viewport_height_meters` - The vertical size of the projection’s viewport, in meters.
5322    ///
5323    /// see also [`render_set_ortho_size`] [`Renderer::get_ortho_size`]
5324    /// ### Examples
5325    /// ```
5326    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
5327    /// use stereokit_rust::system::Renderer;
5328    ///
5329    /// let ortho_size = Renderer::get_ortho_size();
5330    /// assert_eq!(ortho_size, 1.0);
5331    ///
5332    /// Renderer::set_ortho_size(12.0);
5333    /// let ortho_size = Renderer::get_ortho_size();
5334    /// assert_eq!(ortho_size, 12.0);
5335    /// ```
5336    pub fn set_ortho_size(view_port_height_meters: f32) {
5337        unsafe { render_set_ortho_size(view_port_height_meters) }
5338    }
5339
5340    /// Gets the root transform of the camera! This will be the identity matrix by default. The user’s head
5341    /// location will then be relative to this point. This is great to use if you’re trying to do teleportation,
5342    /// redirected walking, or just shifting the floor around.
5343    /// <https://stereokit.net/Pages/StereoKit/Renderer/CameraRoot.html>
5344    ///
5345    /// see also [`render_get_cam_root`]
5346    /// see example in [`Renderer::camera_root`]
5347    pub fn get_camera_root() -> Matrix {
5348        unsafe { render_get_cam_root() }
5349    }
5350
5351    /// This retrieves the current near and far clipping planes for the perspective matrix of the primary draw surface.
5352    ///
5353    /// <https://stereokit.net/Pages/StereoKit/Renderer/GetClip.html>
5354    ///
5355    /// Returns a tuple (`near_plane`, `far_plane`)
5356    /// * `near_plane` - The GPU discards pixels that are too close to the camera, this is that distance! It will be larger
5357    ///   than zero, due to the projection math, which also means that numbers too close to zero will produce z-fighting artifacts. This
5358    ///   has an enforced minimum of 0.001, but will probably be closer to 0.1.
5359    /// * `far_plane` - At what distance from the camera does the GPU discard pixel? This is not true distance, but rather Z-axis
5360    ///   distance from zero in View Space coordinates!
5361    ///
5362    /// see also [`render_get_clip`]
5363    /// see example in [`Renderer::set_clip`]
5364    pub fn get_clip() -> (f32, f32) {
5365        let mut near_plane = 0.0;
5366        let mut far_plane = 0.0;
5367        unsafe { render_get_clip(&mut near_plane, &mut far_plane) }
5368        (near_plane, far_plane)
5369    }
5370
5371    /// Only works for 2D windowed modes! This retrieves the vertical field of view of the camera's projection matrix when in
5372    /// perspective projection mode.
5373    ///
5374    /// <https://stereokit.net/Pages/StereoKit/Renderer/GetFOV.html>
5375    ///
5376    /// see also [`render_get_fov`]
5377    /// see example in [`Renderer::set_fov`]
5378    pub fn get_fov() -> f32 {
5379        unsafe { render_get_fov() }
5380    }
5381
5382    /// This retrieves the size the primary render surface's view when using orthographic projection mode.
5383    ///
5384    /// <https://stereokit.net/Pages/StereoKit/Renderer/GetOrthoSize.html>
5385    ///
5386    /// see also [`render_get_ortho_size`] []
5387    /// see example in [`Renderer::set_ortho_size`]
5388    pub fn get_ortho_size() -> f32 {
5389        unsafe { render_get_ortho_size() }
5390    }
5391
5392    /// This is the current render layer mask for Mixed Reality Capture, or 2nd person observer rendering. By default,
5393    /// this is directly linked to Renderer::layer_filter, but this behavior can be overridden via
5394    /// Renderer::override_capture_filter.
5395    /// <https://stereokit.net/Pages/StereoKit/Renderer/CaptureFilter.html>
5396    ///
5397    /// see also [`render_get_capture_filter`]
5398    /// see example in [`Renderer::override_capture_filter`]
5399    pub fn get_capture_filter() -> RenderLayer {
5400        unsafe { render_get_capture_filter() }
5401    }
5402
5403    /// This is the gamma space color the renderer will clear the screen to when beginning to draw a new frame.
5404    /// <https://stereokit.net/Pages/StereoKit/Renderer/ClearColor.html>
5405    ///
5406    /// see also [`render_get_clear_color`]
5407    /// see example in [`Renderer::clear_color`]
5408    pub fn get_clear_color() -> Color128 {
5409        unsafe { render_get_clear_color() }
5410    }
5411
5412    /// Enables or disables rendering of the skybox texture! It’s enabled by default on Opaque displays, and completely
5413    /// unavailable for transparent displays.
5414    /// <https://stereokit.net/Pages/StereoKit/Renderer/EnableSky.html>
5415    ///
5416    /// see also [`render_enabled_skytex`]
5417    /// see example in [`Renderer::enable_sky`]
5418    pub fn get_enable_sky() -> bool {
5419        unsafe { render_enabled_skytex() != 0 }
5420    }
5421
5422    /// This tells if capture_filter has been overridden to a specific value via Renderer::override_capture_filter.
5423    /// <https://stereokit.net/Pages/StereoKit/Renderer/HasCaptureFilter.html>
5424    ///
5425    /// see also [`render_has_capture_filter`]
5426    /// see example in [`Renderer::override_capture_filter`]
5427    pub fn has_capture_filter() -> bool {
5428        unsafe { render_has_capture_filter() != 0 }
5429    }
5430
5431    /// By default, StereoKit renders all first-person layers. This is a bit flag that allows you to change which layers
5432    /// StereoKit renders for the primary viewpoint. To change what layers a visual is on, use a Draw method that
5433    /// includes a RenderLayer as a parameter.
5434    /// <https://stereokit.net/Pages/StereoKit/Renderer/LayerFilter.html>
5435    ///
5436    /// see also [`render_get_filter`]
5437    /// see example in [`Renderer::layer_filter`]
5438    pub fn get_layer_filter() -> RenderLayer {
5439        unsafe { render_get_filter() }
5440    }
5441
5442    /// Get the multisample (MSAA) level of the render surface. Valid values are 1, 2, 4, 8, 16, though
5443    /// some OpenXR runtimes may clamp this to lower values. Note that while this can greatly smooth out edges, it also
5444    /// greatly increases RAM usage and fill rate, so use it sparingly. Only works in XR mode. If known in advance, set
5445    /// this via [`crate::sk::SkSettings`] in initialization. This is a very costly change to make.
5446    /// <https://stereokit.net/Pages/StereoKit/Renderer/Multisample.html>
5447    ///
5448    /// see also [`render_get_multisample`]
5449    /// see example in [`Renderer::multisample`]
5450    pub fn get_multisample() -> i32 {
5451        unsafe { render_get_multisample() }
5452    }
5453
5454    /// For flatscreen applications only! This allows you to get the camera projection between perspective and
5455    /// orthographic projection. This may be of interest for some category of UI work, but is generally a niche piece of
5456    /// functionality.
5457    /// Swapping between perspective and orthographic will also switch the clipping planes and field of view to the
5458    /// values associated with that mode. See set_clip/set_fov for perspective, and set_ortho_clip/set_ortho_size for
5459    /// orthographic.
5460    /// <https://stereokit.net/Pages/StereoKit/Renderer/Projection.html>
5461    ///
5462    /// see also [`render_get_projection`]
5463    /// see example in [`Renderer::projection`]
5464    pub fn get_projection() -> Projection {
5465        unsafe { render_get_projection() }
5466    }
5467
5468    /// OpenXR has a recommended default for the main render surface, this value allows you to set SK’s surface to a
5469    /// multiple of the recommended size. Note that the final resolution may also be clamped or quantized. Only works in
5470    /// XR mode. If known in advance, set this via SKSettings in initialization. This is a very costly change to make.
5471    /// Consider if viewport_caling will work for you
5472    /// instead, and prefer that.
5473    /// <https://stereokit.net/Pages/StereoKit/Renderer/Scaling.html>
5474    ///
5475    /// see also [`render_get_scaling`]
5476    /// see example in [`Renderer::scaling`]
5477    pub fn get_scaling() -> f32 {
5478        unsafe { render_get_scaling() }
5479    }
5480
5481    /// This allows you to trivially scale down the area of the swapchain that StereoKit renders to! This can be used to
5482    /// boost performance in situations where full resolution is not needed, or to reduce GPU time. This value is
5483    /// locked to the 0-1 range
5484    /// <https://stereokit.net/Pages/StereoKit/Renderer/ViewportScaling.html>
5485    ///
5486    /// see also [`render_get_viewport_scaling`]
5487    /// see example in [`Renderer::viewport_scaling`]
5488    pub fn get_viewport_scaling() -> f32 {
5489        unsafe { render_get_viewport_scaling() }
5490    }
5491
5492    /// Gets the lighting information for the scene! You can build one through SphericalHarmonics::from_lights, or grab
5493    /// one from [`crate::tex::SHCubemap`].
5494    /// <https://stereokit.net/Pages/StereoKit/Renderer/SkyLight.html>
5495    ///
5496    /// see also [`render_get_skylight`]
5497    /// see example in [`Renderer::sky_light`]
5498    pub fn get_sky_light() -> SphericalHarmonics {
5499        unsafe { render_get_skylight() }
5500    }
5501
5502    /// Get the cubemap skybox texture for rendering a background! This is only visible on Opaque displays, since
5503    /// transparent displays have the real world behind them already! StereoKit has a a default procedurally generated
5504    /// skybox. You can load one with [`crate::tex::SHCubemap`]. If you’re trying to affect the lighting,
5505    /// see Renderer::sky_light.
5506    /// <https://stereokit.net/Pages/StereoKit/Renderer/SkyTex.html>
5507    ///
5508    /// see also [`render_get_skytex`]
5509    /// see example in [`Renderer::sky_tex`]
5510    pub fn get_sky_tex() -> Tex {
5511        Tex(NonNull::new(unsafe { render_get_skytex() }).unwrap())
5512    }
5513
5514    /// This is the Material that StereoKit is currently using to draw the skybox! It needs a special shader that's
5515    /// tuned for a full-screen quad. If you just want to change the skybox image, try setting [`Renderer::sky_tex`]
5516    /// instead.
5517    ///  
5518    /// This value will never be null! If you try setting this to null, it will assign SK's built-in default sky
5519    /// material. If you want to turn off the skybox, see [`Renderer::enable_sky`] instead.
5520    ///  
5521    /// Recommended Material settings would be:
5522    /// - DepthWrite: false
5523    /// - DepthTest: LessOrEq
5524    /// - QueueOffset: 100
5525    ///
5526    /// <https://stereokit.net/Pages/StereoKit/Renderer/SkyMaterial.html>
5527    ///
5528    /// see also [`render_get_skymaterial`]
5529    /// see example in [`Renderer::sky_material`]
5530    pub fn get_sky_material() -> Material {
5531        Material(NonNull::new(unsafe { render_get_skymaterial() }).unwrap())
5532    }
5533}
5534
5535/// A text style is a font plus size/color/material parameters, and are used to keep text looking more consistent
5536/// through the application by encouraging devs to re-use styles throughout the project. See Text.MakeStyle for making a
5537/// TextStyle object.
5538/// <https://stereokit.net/Pages/StereoKit/TextStyle.html>
5539///
5540/// ### Examples
5541/// ```
5542/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
5543/// use stereokit_rust::{system::{TextStyle, Pivot, Align, Text, Lines, Hierarchy},
5544///                      font::Font, material::Material, mesh::Mesh, maths::{Vec3, Matrix},
5545///                      util::named_colors::{WHITE, GOLD, GREEN, BLUE, RED, BLACK}};
5546///
5547/// let font = Font::default();
5548/// let style = TextStyle::from_font(font, 0.88, WHITE);
5549/// let text = "ÂjlD;";
5550/// let size = Text::size_layout(text, Some(style), None);
5551///
5552/// let base_line_at   = -style.get_cap_height();
5553/// let ascender_at    = base_line_at + style.get_ascender();
5554/// let cap_height_at  = base_line_at + style.get_cap_height();
5555/// let descender_at   = base_line_at - style.get_descender();
5556/// let line_height_at = ascender_at - style.get_line_height_pct() * style. get_total_height();
5557///
5558/// let sizex = size.x;
5559///
5560/// let recenter = Matrix::t(Vec3::Y * 0.6);
5561///
5562/// filename_scr = "screenshots/text_style.jpeg"; fov_scr=110.0;
5563/// test_screenshot!( // !!!! Get a proper main loop !!!!
5564///    Hierarchy::push(token, recenter, None);
5565///    Text::add_at(token, text, Matrix::Y_180, Some(style), Some(GOLD.into()),
5566///             Some(Pivot::TopCenter), Some(Align::TopLeft), None, None, None);
5567///    
5568///    Lines::add(token, [sizex, ascender_at, 0.0],    [-sizex, ascender_at, 0.0],    GREEN, None, 0.03  );
5569///    Lines::add(token, [sizex, base_line_at, 0.0],   [-sizex, base_line_at, 0.0],   WHITE, None, 0.03  );
5570///    Lines::add(token, [sizex, cap_height_at, 0.0],  [-sizex, cap_height_at, 0.0],  BLACK, None, 0.03  );
5571///    Lines::add(token, [sizex, descender_at, 0.0],   [-sizex, descender_at, 0.0],   BLUE, None, 0.03  );
5572///    Lines::add(token, [sizex, line_height_at, 0.0], [-sizex, line_height_at, 0.0], RED, None, 0.03  );
5573///    Hierarchy::pop(token);
5574/// );
5575/// ```
5576/// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/text_style.jpeg" alt="screenshot" width="200">
5577#[derive(Debug, Copy, Clone, PartialEq, Eq)]
5578#[repr(C)]
5579pub struct TextStyle {
5580    _id: u32,
5581}
5582
5583unsafe extern "C" {
5584    pub fn text_make_style(font: FontT, layout_height: f32, color_gamma: Color128) -> TextStyle;
5585    pub fn text_make_style_shader(font: FontT, layout_height: f32, shader: ShaderT, color_gamma: Color128)
5586    -> TextStyle;
5587    pub fn text_make_style_mat(
5588        font: FontT,
5589        layout_height: f32,
5590        material: MaterialT,
5591        color_gamma: Color128,
5592    ) -> TextStyle;
5593    pub fn text_style_get_line_height_pct(style: TextStyle) -> f32;
5594    pub fn text_style_set_line_height_pct(style: TextStyle, height_percent: f32);
5595    pub fn text_style_get_layout_height(style: TextStyle) -> f32;
5596    pub fn text_style_set_layout_height(style: TextStyle, height_meters: f32);
5597    pub fn text_style_get_total_height(style: TextStyle) -> f32;
5598    pub fn text_style_set_total_height(style: TextStyle, height_meters: f32);
5599    pub fn text_style_get_material(style: TextStyle) -> MaterialT;
5600    pub fn text_style_get_ascender(style: TextStyle) -> f32;
5601    pub fn text_style_get_descender(style: TextStyle) -> f32;
5602    pub fn text_style_get_cap_height(style: TextStyle) -> f32;
5603    pub fn text_style_get_baseline(style: TextStyle) -> f32;
5604}
5605
5606impl Default for TextStyle {
5607    /// This is the default text style used by StereoKit.
5608    /// <https://stereokit.net/Pages/StereoKit/TextStyle/Default.html>
5609    fn default() -> Self {
5610        Self { _id: 0 }
5611    }
5612}
5613
5614impl TextStyle {
5615    /// Create a text style for use with other text functions! A text style is a font plus size/color/material
5616    /// parameters, and are used to keep text looking more consistent through the application by encouraging devs to
5617    /// re-use styles throughout the project.
5618    ///
5619    /// This fn will create an unique Material for this style based on Default.ShaderFont.
5620    /// <https://stereokit.net/Pages/StereoKit/TextStyle/FromFont.html>
5621    /// * `font` - Font asset you want attached to this style.
5622    /// * `layout_height_meters` - Height of a text glyph in meters. StereoKit currently bases this on CapHeight.
5623    /// * `color_gamma` - The gamma space color of the text style. This will be embedded in the vertex color of the
5624    ///   text mesh.
5625    ///
5626    /// see also [`text_make_style`]
5627    /// ### Examples
5628    /// ```
5629    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
5630    /// use stereokit_rust::{system::TextStyle, font::Font, util::named_colors};
5631    ///
5632    /// let font = Font::default();
5633    ///
5634    /// let text_style = TextStyle::from_font(&font, 0.02, named_colors::WHITE);
5635    ///
5636    /// assert_eq!(text_style.get_material().get_id(), "sk/text_style/2/material");
5637    /// assert_eq!(text_style.get_layout_height(), 0.02);
5638    /// ```
5639    pub fn from_font(font: impl AsRef<Font>, layout_height_meters: f32, color_gamma: impl Into<Color128>) -> Self {
5640        unsafe { text_make_style(font.as_ref().0.as_ptr(), layout_height_meters, color_gamma.into()) }
5641    }
5642
5643    /// Create a text style for use with other text functions! A text style is a font plus size/color/material
5644    /// parameters, and are used to keep text looking more consistent through the application by encouraging devs to
5645    /// re-use styles throughout the project.
5646    ///
5647    /// This function will create an unique Material for this style based on the provided Shader.
5648    /// <https://stereokit.net/Pages/StereoKit/TextStyle/FromFont.html>
5649    /// * `font` - Font asset you want attached to this style.
5650    /// * `layout_height_meters` - Height of a text glyph in meters. StereoKit currently bases this on CapHeight.
5651    /// * `shader` - This style will create and use a unique/ Material based on the Shader that you provide here.
5652    /// * `color_gamma` - The gamma space color of the text style. This will be embedded in the vertex color of the
5653    ///   text mesh.
5654    ///
5655    /// see also [`text_make_style_shader`]
5656    /// ### Examples
5657    /// ```
5658    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
5659    /// use stereokit_rust::{system::TextStyle, font::Font, util::named_colors, shader::Shader};
5660    ///
5661    /// let font = Font::default();
5662    /// let shader = Shader::from_file("shaders/brick_pbr.hlsl.sks")
5663    ///                          .expect("Brick_pbr should be a valid shader");
5664    ///
5665    /// let text_style = TextStyle::from_font_and_shader(&font, 0.02, shader, named_colors::WHITE);
5666    ///
5667    /// assert_eq!(text_style.get_material().get_id(), "sk/text_style/2/material");
5668    /// assert_eq!(text_style.get_layout_height(), 0.02);
5669    /// ```
5670    pub fn from_font_and_shader(
5671        font: impl AsRef<Font>,
5672        layout_height_meters: f32,
5673        shader: impl AsRef<Shader>,
5674        color_gamma: impl Into<Color128>,
5675    ) -> Self {
5676        unsafe {
5677            text_make_style_shader(
5678                font.as_ref().0.as_ptr(),
5679                layout_height_meters,
5680                shader.as_ref().0.as_ptr(),
5681                color_gamma.into(),
5682            )
5683        }
5684    }
5685
5686    /// Create a text style for use with other text functions! A text style is a font plus size/color/material
5687    /// parameters, and are used to keep text looking more consistent through the application by encouraging devs to
5688    /// re-use styles throughout the project.
5689    ///
5690    /// This overload allows you to set the specific Material that is used. This can be helpful if you’re keeping styles
5691    /// similar enough to re-use the material and save on draw calls. If you don’t know what that means, then prefer
5692    /// using the overload that takes a Shader, or takes neither a Shader nor a Material!
5693    /// <https://stereokit.net/Pages/StereoKit/TextStyle/FromFont.html>
5694    /// * `font` - Font asset you want attached to this style.
5695    /// * `layout_height_meters` - Height of a text glyph in meters. StereoKit currently bases this on CapHeight.
5696    /// * `material` - Which material should be used to render the text with? Note that this does NOT duplicate the
5697    ///   material, so the text with? Note that this does NOT duplicate the material, so some parameters of this
5698    ///   Material instance will get overwritten, like the texture used for the glyph atlas. You should either use a new
5699    ///   Material, or a Material that was already used with this same font.
5700    /// * `color_gamma` - The gamma space color of the text style. This will be embedded in the vertex color of the
5701    ///   text mesh.
5702    ///
5703    /// see also [`text_make_style_mat`]
5704    /// ### Examples
5705    /// ```
5706    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
5707    /// use stereokit_rust::{system::TextStyle, font::Font, util::named_colors, material::Material};
5708    ///
5709    /// let font = Font::default();
5710    /// let material = Material::pbr().copy();
5711    ///
5712    /// let text_style = TextStyle::from_font_and_material(&font, 0.02, &material, named_colors::WHITE);
5713    ///
5714    /// assert_eq!(text_style.get_material(), material);
5715    /// assert_eq!(text_style.get_layout_height(), 0.02);
5716    /// ```
5717    pub fn from_font_and_material(
5718        font: impl AsRef<Font>,
5719        layout_height_meters: f32,
5720        material: impl AsRef<Material>,
5721        color_gamma: impl Into<Color128>,
5722    ) -> Self {
5723        unsafe {
5724            text_make_style_mat(
5725                font.as_ref().0.as_ptr(),
5726                layout_height_meters,
5727                material.as_ref().0.as_ptr(),
5728                color_gamma.into(),
5729            )
5730        }
5731    }
5732
5733    /// Height of a text glyph in meters. StereoKit currently bases this on the letter ‘T’.
5734    /// <https://stereokit.net/Pages/StereoKit/TextStyle/CharHeight.html>
5735    ///
5736    /// see also [`text_style_set_layout_height`]
5737    #[deprecated(since = "0.40.0", note = "please use TextStyle::layout_height")]
5738    pub fn char_height(&mut self, char_height: f32) {
5739        unsafe { text_style_set_layout_height(*self, char_height) }
5740    }
5741
5742    /// (meters) Layout height is the height of the font's CapHeight, which is used for calculating the vertical height
5743    /// of the text when doing text layouts. This does _not_ include the height of the descender , nor
5744    /// does it represent the maximum possible height a glyph may extend upwards (use Text::size_render).
5745    /// <https://stereokit.net/Pages/StereoKit/TextStyle/LayoutHeight.html>
5746    ///
5747    /// see also [`text_style_set_layout_height`]
5748    /// ### Examples
5749    /// ```
5750    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
5751    /// use stereokit_rust::{font::Font, util::named_colors, system::TextStyle};
5752    ///
5753    /// let font = Font::default();
5754    /// let mut text_style = TextStyle::from_font(font, 0.02, named_colors::WHITE);
5755    /// assert_eq!(text_style.get_layout_height(), 0.02);
5756    ///
5757    /// text_style.layout_height(0.03);
5758    ///
5759    /// assert!((text_style.get_layout_height() - 0.03) < 0.0001);
5760    /// ```
5761    pub fn layout_height(&mut self, height_meters: f32) {
5762        unsafe { text_style_set_layout_height(*self, height_meters) }
5763    }
5764
5765    /// (meters) Height from the layout descender to the layout ascender. This is most equivalent to the 'font-size' in
5766    /// CSS or other text layout tools. Since ascender and descenders can vary a lot, using layout_height in many cases
5767    /// can lead to more consistency in the long run.
5768    /// <https://stereokit.net/Pages/StereoKit/TextStyle/TotalHeight.html>
5769    ///
5770    /// see also [`text_style_set_total_height`]
5771    /// ### Examples
5772    /// ```
5773    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
5774    /// use stereokit_rust::{font::Font, util::named_colors, system::TextStyle};
5775    ///
5776    /// let font = Font::default();
5777    /// let mut text_style = TextStyle::from_font(font, 0.02, named_colors::WHITE);
5778    ///
5779    /// text_style.total_height(0.03);
5780    ///
5781    /// assert_eq!(text_style.get_total_height(), 0.03);
5782    /// ```
5783    pub fn total_height(&mut self, height_meters: f32) {
5784        unsafe { text_style_set_total_height(*self, height_meters) }
5785    }
5786
5787    /// This is the space a full line of text takes, from baseline to baseline, as a 0-1 percentage of the font's
5788    /// character height. This is similar to CSS line-height, a value of 1.0 means the line takes _only_
5789    /// <https://stereokit.net/Pages/StereoKit/TextStyle/LineHeightPct.html>
5790    ///
5791    /// see also [`text_style_set_line_height_pct`]
5792    /// ### Examples
5793    /// ```
5794    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
5795    /// use stereokit_rust::{font::Font, util::named_colors, system::TextStyle};
5796    ///
5797    /// let font = Font::default();
5798    /// let mut text_style = TextStyle::from_font(font, 0.02, named_colors::WHITE);
5799    /// assert_eq!(text_style.get_layout_height(), 0.02);
5800    ///
5801    /// text_style.line_height_pct(30.0);
5802    ///
5803    /// assert_eq!(text_style.get_line_height_pct(), 30.0);
5804    /// ```
5805    pub fn line_height_pct(&mut self, height_percent: f32) {
5806        unsafe { text_style_set_line_height_pct(*self, height_percent) }
5807    }
5808
5809    /// This provides a reference to the Material used by this style, so you can override certain features! Note that if
5810    /// you’re creating TextStyles with manually provided Materials, this Material may not be unique to this style.
5811    /// <https://stereokit.net/Pages/StereoKit/TextStyle/Material.html>
5812    ///
5813    /// see also [`text_style_get_material`]
5814    /// see example in [`TextStyle::from_font_and material`]
5815    pub fn get_material(&self) -> Material {
5816        Material(NonNull::new(unsafe { text_style_get_material(*self) }).unwrap())
5817    }
5818
5819    /// Returns the maximum height of a text character using this style, in meters.
5820    /// <https://stereokit.net/Pages/StereoKit/TextStyle/CharHeight.html>
5821    ///
5822    /// see also [`text_style_get_layout_height`]
5823    #[deprecated(since = "0.40.0", note = "please use get_layout_height")]
5824    pub fn get_char_height(&self) -> f32 {
5825        unsafe { text_style_get_layout_height(*self) }
5826    }
5827
5828    /// (meters) Layout height is the height of the font's ascender, which is used for calculating the vertical height
5829    /// of the text when doing text layouts. This does _not_ include the height of the descender (use total_height), nor
5830    /// does it represent the maximum possible height a glyph may extend upwards (use Text::size_render).
5831    /// <https://stereokit.net/Pages/StereoKit/TextStyle/LayoutHeight.html>
5832    ///
5833    /// see also [`text_style_get_layout_height`]
5834    /// see example in [`TextStyle::layout_height`]
5835    pub fn get_layout_height(&self) -> f32 {
5836        unsafe { text_style_get_layout_height(*self) }
5837    }
5838
5839    /// (meters) Height from the layout descender to the layout ascender. This is most equivalent to the 'font-size' in
5840    /// CSS or other text layout tools. Since ascender and descenders can vary a lot, using layout_height in many cases
5841    /// can lead to more consistency in the long run.
5842    /// <https://stereokit.net/Pages/StereoKit/TextStyle/TotalHeight.html>
5843    ///
5844    /// see also [`text_style_get_total_height`]
5845    /// see example in [`TextStyle::total_height`]
5846    pub fn get_total_height(&self) -> f32 {
5847        unsafe { text_style_get_total_height(*self) }
5848    }
5849
5850    /// This is the space a full line of text takes, from baseline to baseline, as a 0-1 percentage of the font's
5851    /// character height. This is similar to CSS line-height, a value of 1.0 means the line takes _only_
5852    /// <https://stereokit.net/Pages/StereoKit/TextStyle/LineHeightPct.html>
5853    ///
5854    /// see also [`text_style_get_line_height_pct`]
5855    /// see example in [`TextStyle::line_height_pct`]
5856    pub fn get_line_height_pct(&self) -> f32 {
5857        unsafe { text_style_get_line_height_pct(*self) }
5858    }
5859    /// (meters) The height of a standard captial letter, such as 'H' or 'T'
5860    /// <https://stereokit.net/Pages/StereoKit/TextStyle/CapHeight.html>
5861    ///
5862    /// see also [`text_style_get_cap_height`]
5863    /// ### Examples
5864    /// ```
5865    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
5866    /// use stereokit_rust::{font::Font, util::named_colors, system::TextStyle};
5867    ///
5868    /// let font = Font::default();
5869    /// let mut text_style = TextStyle::from_font(font, 0.02, named_colors::WHITE);
5870    /// assert_eq!(text_style.get_layout_height(), 0.02);
5871    ///
5872    /// assert_eq!(text_style.get_cap_height(), 0.02);
5873    /// ```
5874    pub fn get_cap_height(&self) -> f32 {
5875        unsafe { text_style_get_cap_height(*self) }
5876    }
5877
5878    /// (meters) The layout ascender of the font, this is the height of the "tallest" glyphs as far as layout is
5879    /// concerned. Characters such as 'l' typically rise above the CapHeight, and this value usually matches this height.
5880    /// Some glyphs such as those with hats or umlauts will almost always be taller than this height
5881    /// (see Text::size_render), but this is not used when laying out characters.
5882    /// <https://stereokit.net/Pages/StereoKit/TextStyle/Ascender.html>
5883    ///
5884    /// see also [`text_style_get_ascender`]
5885    /// ### Examples
5886    /// ```
5887    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
5888    /// use stereokit_rust::{font::Font, util::named_colors, system::TextStyle};
5889    ///
5890    /// let font = Font::default();
5891    /// let mut text_style = TextStyle::from_font(font, 0.02, named_colors::WHITE);
5892    /// assert_eq!(text_style.get_layout_height(), 0.02);
5893    ///
5894    /// //TODO: linux   assert_eq!(text_style.get_ascender(), 0.03);
5895    /// //TODO: windows assert_eq!(text_style.get_ascender(),  0.021176472);
5896    /// ```
5897    pub fn get_ascender(&self) -> f32 {
5898        unsafe { text_style_get_ascender(*self) }
5899    }
5900
5901    /// (meters) The layout descender of the font, this is the positive height below the baseline
5902    /// <https://stereokit.net/Pages/StereoKit/TextStyle/Descender.html>
5903    ///
5904    /// see also [`text_style_get_descender`]
5905    /// ### Examples
5906    /// ```
5907    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
5908    /// use stereokit_rust::{font::Font, util::named_colors, system::TextStyle};
5909    ///
5910    /// let font = Font::default();
5911    /// let mut text_style = TextStyle::from_font(font, 0.02, named_colors::WHITE);
5912    /// assert_eq!(text_style.get_layout_height(), 0.02);
5913    ///
5914    /// assert_ne!(text_style.get_descender(), 0.0);
5915    /// ```
5916    pub fn get_descender(&self) -> f32 {
5917        unsafe { text_style_get_descender(*self) }
5918    }
5919}
5920
5921bitflags::bitflags! {
5922    /// A bit-flag enum for describing alignment or positioning. Items can be combined using the '|' operator, like so:
5923    /// `let alignment = Align::YTop | Align::XLeft;`.
5924    /// Avoid combining multiple items of the same axis. There are also a complete list of valid bit flag combinations!
5925    /// These are the values without an axis listed in their names, 'TopLeft', 'BottomCenter',
5926    /// etc.
5927    /// <https://stereokit.net/Pages/StereoKit/Align.html>
5928    ///
5929    /// see also [`Text`] [`crate::ui::Ui`]
5930    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
5931    #[repr(C)]
5932    pub struct Align: u32 {
5933        /// On the x axis, this item should start on the left.
5934        const XLeft = 1 << 0;
5935        /// On the y axis, this item should start at the top.
5936        const YTop = 1 << 1;
5937        /// On the x axis, the item should be centered.
5938        const XCenter = 1 << 2;
5939        /// On the y axis, the item should be centered.
5940        const YCenter = 1 << 3;
5941        /// On the x axis, this item should start on the right.
5942        const XRight = 1 << 4;
5943        /// On the y axis, this item should start on the bottom.
5944        const YBottom = 1 << 5;
5945        /// Center on both X and Y axes. This is a combination of XCenter and YCenter.
5946        const Center = Self::XCenter.bits() | Self::YCenter.bits();
5947        /// Start on the left of the X axis, center on the Y axis. This is a combination of XLeft and YCenter.
5948        const CenterLeft = Self::XLeft.bits() | Self::YCenter.bits();
5949        /// Start on the right of the X axis, center on the Y axis. This is a combination of XRight and YCenter.
5950        const CenterRight = Self::XRight.bits() | Self::YCenter.bits();
5951        /// Center on the X axis, and top on the Y axis. This is a combination of XCenter and YTop.
5952        const TopCenter = Self::XCenter.bits() | Self::YTop.bits();
5953        /// Start on the left of the X axis, and top on the Y axis. This is a combination of XLeft and YTop.
5954        const TopLeft = Self::XLeft.bits() | Self::YTop.bits();
5955        /// Start on the right of the X axis, and top on the Y axis. This is a combination of XRight and YTop.
5956        const TopRight = Self::XRight.bits() | Self::YTop.bits();
5957        /// Center on the X axis, and bottom on the Y axis. This is a combination of XCenter and YBottom.
5958        const BottomCenter = Self::XCenter.bits() | Self::YBottom.bits();
5959        /// Start on the left of the X axis, and bottom on the Y axis. This is a combination of XLeft and YBottom.
5960        const BottomLeft = Self::XLeft.bits() | Self::YBottom.bits();
5961        /// Start on the right of the X axis, and bottom on the Y axis.This is a combination of XRight and YBottom.
5962        const BottomRight = Self::XRight.bits() | Self::YBottom.bits();
5963    }
5964}
5965
5966bitflags::bitflags! {
5967    /// A bit-flag enum for describing alignment or positioning. Items can be combined using the '|' operator, like so:
5968    /// `let alignment = Pivot::YTop | Pivot::XLeft;`.
5969    /// Avoid combining multiple items of the same axis. There are also a complete list of valid bit flag combinations!
5970    /// These are the values without an axis listed in their names, 'TopLeft', 'BottomCenter',
5971    /// etc.
5972    /// <https://stereokit.net/Pages/StereoKit/Pivot.html>
5973    ///
5974    /// see also [`Text`] [`Sprite`]
5975    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
5976    #[repr(C)]
5977    pub struct Pivot: u32 {
5978        /// On the x axis, this item should start on the left.
5979        const XLeft = 1 << 0;
5980        /// On the y axis, this item should start at the top.
5981        const YTop = 1 << 1;
5982        /// On the x axis, the item should be centered.
5983        const XCenter = 1 << 2;
5984        /// On the y axis, the item should be centered.
5985        const YCenter = 1 << 3;
5986        /// On the x axis, this item should start on the right.
5987        const XRight = 1 << 4;
5988        /// On the y axis, this item should start on the bottom.
5989        const YBottom = 1 << 5;
5990        /// Center on both X and Y axes. This is a combination of XCenter and YCenter.
5991        const Center = Self::XCenter.bits() | Self::YCenter.bits();
5992        /// Start on the left of the X axis, center on the Y axis. This is a combination of XLeft and YCenter.
5993        const CenterLeft = Self::XLeft.bits() | Self::YCenter.bits();
5994        /// Start on the right of the X axis, center on the Y axis. This is a combination of XRight and YCenter.
5995        const CenterRight = Self::XRight.bits() | Self::YCenter.bits();
5996        /// Center on the X axis, and top on the Y axis. This is a combination of XCenter and YTop.
5997        const TopCenter = Self::XCenter.bits() | Self::YTop.bits();
5998        /// Start on the left of the X axis, and top on the Y axis. This is a combination of XLeft and YTop.
5999        const TopLeft = Self::XLeft.bits() | Self::YTop.bits();
6000        /// Start on the right of the X axis, and top on the Y axis. This is a combination of XRight and YTop.
6001        const TopRight = Self::XRight.bits() | Self::YTop.bits();
6002        /// Center on the X axis, and bottom on the Y axis. This is a combination of XCenter and YBottom.
6003        const BottomCenter = Self::XCenter.bits() | Self::YBottom.bits();
6004        /// Start on the left of the X axis, and bottom on the Y axis. This is a combination of XLeft and YBottom.
6005        const BottomLeft = Self::XLeft.bits() | Self::YBottom.bits();
6006        /// Start on the right of the X axis, and bottom on the Y axis.This is a combination of XRight and YBottom.
6007        const BottomRight = Self::XRight.bits() | Self::YBottom.bits();
6008    }
6009}
6010
6011bitflags::bitflags! {
6012    /// This enum describes how text layout behaves within the space it is given.
6013    /// <https://stereokit.net/Pages/StereoKit/TextFit.html>
6014    ///
6015    /// see also [`Text`] [`crate::ui::Ui`]
6016    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
6017    #[repr(C)]
6018    pub struct TextFit: u32 {
6019        /// No particularly special behavior.
6020        const None = 0;
6021        /// The text will wrap around to the next line down when it reaches the end of the space on the X axis.
6022        const Wrap = 1;
6023        /// When the text reaches the end, it is simply truncated and no longer visible.
6024        const Clip = 2;
6025        /// If the text is too large to fit in the space provided, it will be scaled down to fit inside. This will not scale up.
6026        const Squeeze = 4;
6027        /// If the text is larger, or smaller than the space provided, it will scale down or up to fill the space.
6028        const Exact = 8;
6029        /// The text will ignore the containing space, and just keep on going.
6030        const Overflow = 16;
6031    }
6032}
6033
6034/// Soft keyboard layouts are often specific to the type of text that they’re editing! This enum is a collection of
6035/// common text contexts that SK can pass along to the OS’s soft keyboard for a more optimal layout.
6036/// <https://stereokit.net/Pages/StereoKit/TextContext.html>
6037///
6038/// see also [`crate::ui::Ui::input`] [`crate::ui::Ui::input_at`] [`crate::util::Platform::keyboard_show`]
6039#[derive(Debug, Copy, Clone, PartialEq, Eq)]
6040#[repr(u32)]
6041pub enum TextContext {
6042    /// General text editing, this is the most common type of text, and would result in a ‘standard’ keyboard layout.
6043    Text = 0,
6044    /// Numbers and numerical values.
6045    Number = 1,
6046    /// This text specifically represents some kind of URL/URI address.
6047    Uri = 2,
6048    /// This is a password, and should not be visible when typed!
6049    Password = 3,
6050}
6051
6052/// A collection of functions for rendering and working with text. These are a lower level access to text rendering than
6053/// the UI text functions, and are completely unaware of the UI code.
6054/// <https://stereokit.net/Pages/StereoKit/Text.html>
6055///
6056/// ### Examples
6057/// ```
6058/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
6059/// use stereokit_rust::{system::{ Pivot, Align, TextFit, Text, Lines, Hierarchy },
6060///                      font::Font, material::Material, mesh::Mesh, maths::{Vec3, Matrix},
6061///                      util::named_colors::{WHITE, GOLD, GREEN, RED}};
6062///
6063/// let font = Font::default();
6064/// let style = Text::make_style(font, 0.28, WHITE);
6065/// let transform1 = Matrix::t([0.7, 0.7, 0.0]) * Matrix::Y_180;
6066/// let transform2 = Matrix::t([0.3, 0.1, 0.0]) * Matrix::Y_180;
6067/// let transform3 = Matrix::t([-0.1,-0.5, 0.0]) * Matrix::Y_180;
6068///
6069/// filename_scr = "screenshots/text.jpeg"; fov_scr=110.0;
6070/// test_screenshot!( // !!!! Get a proper main loop !!!!
6071///    Text::add_at(token, "Many", transform1, Some(style), Some(GOLD.into()),
6072///             Some(Pivot::TopCenter), Some(Align::TopLeft), None, None, None);
6073///    
6074///    let size = Text::add_in(token, "Texts!", transform2, [0.6, 0.6], TextFit::Squeeze,
6075///             Some(style), Some(GREEN.into()), Some(Pivot::Center), Some(Align::TopLeft),
6076///             None, Some(-0.3), Some(-0.3));
6077///    assert_ne!(size , 0.0);
6078///
6079///    Text::add_at(token, "----/****", transform3, Some(style), None,
6080///             None, None, None, None, None);
6081/// );
6082/// ```
6083/// <img src="https://raw.githubusercontent.com/mvvvv/StereoKit-rust/refs/heads/master/screenshots/text.jpeg" alt="screenshot" width="200">
6084pub struct Text;
6085
6086unsafe extern "C" {
6087    pub fn text_add_at(
6088        text_utf8: *const c_char,
6089        transform: *const Matrix,
6090        style: TextStyle,
6091        position: Pivot,
6092        align: Align,
6093        off_x: f32,
6094        off_y: f32,
6095        off_z: f32,
6096        vertex_tint_linear: Color128,
6097    );
6098    pub fn text_add_at_16(
6099        text_utf16: *const c_ushort,
6100        transform: *const Matrix,
6101        style: TextStyle,
6102        position: Pivot,
6103        align: Align,
6104        off_x: f32,
6105        off_y: f32,
6106        off_z: f32,
6107        vertex_tint_linear: Color128,
6108    );
6109    pub fn text_add_in(
6110        text_utf8: *const c_char,
6111        transform: *const Matrix,
6112        size: Vec2,
6113        fit: TextFit,
6114        style: TextStyle,
6115        position: Pivot,
6116        align: Align,
6117        off_x: f32,
6118        off_y: f32,
6119        off_z: f32,
6120        vertex_tint_linear: Color128,
6121    ) -> f32;
6122    pub fn text_add_in_16(
6123        text_utf16: *const c_ushort,
6124        transform: *const Matrix,
6125        size: Vec2,
6126        fit: TextFit,
6127        style: TextStyle,
6128        position: Pivot,
6129        align: Align,
6130        off_x: f32,
6131        off_y: f32,
6132        off_z: f32,
6133        vertex_tint_linear: Color128,
6134    ) -> f32;
6135    pub fn text_size_layout(text_utf8: *const c_char, style: TextStyle) -> Vec2;
6136    pub fn text_size_layout_constrained(text_utf8: *const c_char, style: TextStyle, max_width: f32) -> Vec2;
6137    pub fn text_size_layout_16(text_utf16: *const c_ushort, style: TextStyle) -> Vec2;
6138    pub fn text_size_layout_constrained_16(text_utf16: *const c_ushort, style: TextStyle, max_width: f32) -> Vec2;
6139    pub fn text_size_render(layout_size: Vec2, style: TextStyle, y_offset: *mut f32) -> Vec2;
6140    pub fn text_char_at(
6141        text_utf8: *const c_char,
6142        style: TextStyle,
6143        char_index: i32,
6144        opt_size: *mut Vec2,
6145        fit: TextFit,
6146        position: Pivot,
6147        align: Align,
6148    ) -> Vec2;
6149    pub fn text_char_at_16(
6150        text_utf16: *const c_ushort,
6151        style: TextStyle,
6152        char_index: i32,
6153        opt_size: *mut Vec2,
6154        fit: TextFit,
6155        position: Pivot,
6156        align: Align,
6157    ) -> Vec2;
6158}
6159
6160impl Text {
6161    /// Create a text style for use with other text functions! A text style is a font plus size/color/material
6162    /// parameters, and are used to keep text looking more consistent through the application by encouraging devs to
6163    /// re-use styles throughout the project.
6164    ///
6165    /// This fn will create an unique Material for this style based on Default.ShaderFont.
6166    /// <https://stereokit.net/Pages/StereoKit/Text/MakeStyle.html>
6167    /// * `font` - Font asset you want attached to this style.
6168    /// * `layout_height_meters`- Height of a text glyph in meters. StereoKit currently bases this on CapHeight.
6169    /// * `color_gamma` - The gamma space color of the text style. This will be embedded in the vertex color of the
6170    ///   text mesh.
6171    ///
6172    /// Returns a text style id for use with text rendering functions.
6173    ///
6174    /// see also [`text_make_style`] same as [`TextStyle::from_font`]
6175    /// ### Examples
6176    /// ```
6177    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
6178    /// use stereokit_rust::{system::Text, font::Font, util::named_colors};
6179    ///
6180    /// let font = Font::default();
6181    ///
6182    /// let text_style = Text::make_style(&font, 0.02, named_colors::WHITE);
6183    ///
6184    /// assert_eq!(text_style.get_material().get_id(), "sk/text_style/2/material");
6185    /// assert_eq!(text_style.get_layout_height(), 0.02);
6186    /// ```
6187    pub fn make_style(
6188        font: impl AsRef<Font>,
6189        layout_height_meters: f32,
6190        color_gamma: impl Into<Color128>,
6191    ) -> TextStyle {
6192        unsafe { text_make_style(font.as_ref().0.as_ptr(), layout_height_meters, color_gamma.into()) }
6193    }
6194
6195    /// Create a text style for use with other text functions! A text style is a font plus size/color/material
6196    /// parameters, and are used to keep text looking more consistent through the application by encouraging devs to
6197    /// re-use styles throughout the project.
6198    ///
6199    /// This function will create an unique Material for this style based on the provided Shader.
6200    /// <https://stereokit.net/Pages/StereoKit/Text/MakeStyle.html>
6201    /// * `font` - Font asset you want attached to this style.
6202    /// * `layout_height_meters`- Height of a text glyph in meters. StereoKit currently bases this on CapHeight.
6203    /// * `shader` - This style will create and use a unique Material based on the Shader that you provide here
6204    /// * `color_gamma` - The gamma space color of the text style. This will be embedded in the vertex color of the
6205    ///   text mesh.
6206    ///
6207    /// Returns a text style id for use with text rendering functions.
6208    ///
6209    /// see also [`text_make_style_shader`] same as [`TextStyle::from_font_and_shader`]
6210    /// ### Examples
6211    /// ```
6212    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
6213    /// use stereokit_rust::{system::{Assets, Text}, font::Font,
6214    ///                      util::named_colors, shader::Shader};
6215    ///
6216    /// let font = Font::default();
6217    /// let shader = Shader::from_file("shaders/water_pbr.hlsl.sks")
6218    ///                          .expect("Brick_pbr should be a valid shader");
6219    /// Assets::block_for_priority(i32::MAX);
6220    ///
6221    /// let text_style = Text::make_style_with_shader(&font, 0.02, shader, named_colors::WHITE);
6222    ///
6223    /// assert_eq!(text_style.get_material().get_id(), "sk/text_style/2/material");
6224    /// assert_eq!(text_style.get_layout_height(), 0.02);
6225    /// ```
6226    pub fn make_style_with_shader(
6227        font: impl AsRef<Font>,
6228        layout_height_meters: f32,
6229        shader: impl AsRef<Shader>,
6230        color_gamma: impl Into<Color128>,
6231    ) -> TextStyle {
6232        unsafe {
6233            text_make_style_shader(
6234                font.as_ref().0.as_ptr(),
6235                layout_height_meters,
6236                shader.as_ref().0.as_ptr(),
6237                color_gamma.into(),
6238            )
6239        }
6240    }
6241
6242    /// Create a text style for use with other text functions! A text style is a font plus size/color/material
6243    /// parameters, and are used to keep text looking more consistent through the application by encouraging devs to
6244    /// re-use styles throughout the project.
6245    ///
6246    /// This overload allows you to set the specific Material that is used. This can be helpful if you’re keeping styles
6247    /// similar enough to re-use the material and save on draw calls. If you don’t know what that means, then prefer
6248    /// using the overload that takes a Shader, or takes neither a Shader nor a Material!
6249    /// <https://stereokit.net/Pages/StereoKit/Text/MakeStyle.html>
6250    /// * `font` - Font asset you want attached to this style.
6251    /// * `layout_height_meters`- Height of a text glyph in meters. StereoKit currently bases this on CapHeight.
6252    /// * `material` - Which material should be used to render the text with? Note that this does NOT duplicate the
6253    ///   material, so some parameters of this Material instance will get overwritten, like the texture used for the
6254    ///   glyph atlas. You should either use a new Material, or a Material that was already used with this same font.
6255    /// * `color_gamma` - The gamma space color of the text style. This will be embedded in the vertex color of the
6256    ///   text mesh.
6257    ///
6258    /// Returns a text style id for use with text rendering functions.
6259    ///
6260    /// see also [`text_make_style_mat`]
6261    /// same as [`TextStyle::from_font_and_material`] same as [TextStyle::from_font_and_material]
6262    /// ### Examples
6263    /// ```
6264    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
6265    /// use stereokit_rust::{system::Text, font::Font, util::named_colors, material::Material};
6266    ///
6267    /// let font = Font::default();
6268    /// let material = Material::pbr().copy();
6269    ///
6270    /// let text_style = Text::make_style_with_material(&font, 0.02, &material, named_colors::WHITE);
6271    ///
6272    /// assert_eq!(text_style.get_material(), material);
6273    /// assert_eq!(text_style.get_layout_height(), 0.02);
6274    /// ```
6275    pub fn make_style_with_material(
6276        font: impl AsRef<Font>,
6277        layout_height_meters: f32,
6278        material: impl AsRef<Material>,
6279        color_gamma: impl Into<Color128>,
6280    ) -> TextStyle {
6281        unsafe {
6282            text_make_style_mat(
6283                font.as_ref().0.as_ptr(),
6284                layout_height_meters,
6285                material.as_ref().0.as_ptr(),
6286                color_gamma.into(),
6287            )
6288        }
6289    }
6290
6291    /// Renders text at the given location! Must be called every frame you want this text to be visible.
6292    /// <https://stereokit.net/Pages/StereoKit/Text/Add.html>
6293    /// * `text` - What text should be drawn?
6294    /// * `transform` - A Matrix representing the transform of the text mesh! Try Matrix::t_r_s().
6295    /// * `text_style` - Style information for rendering, see Text.MakeStyle or the TextStyle object. If None will use
6296    ///   the TextStyle::default()
6297    /// * `vertex_tint_linear` - The vertex color of the text gets multiplied by this color. This is a linear color
6298    ///   value, not a gamma corrected color value. If None will use Color128::WHITE
6299    /// * `position` - How should the text’s bounding rectangle be positioned relative to the transform? If None will
6300    ///   use Pivot::Center.
6301    /// * `align` - How should the text be aligned within the text’s bounding rectangle? If None will use
6302    ///   Align::Center.
6303    /// * `off_?` - An additional offset on the given axis. If None will use 0.0.
6304    ///
6305    /// see also [`text_add_at`]
6306    /// ### Examples
6307    /// ```
6308    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
6309    /// use stereokit_rust::{system::{Pivot, Align, TextFit, Text},
6310    ///                      font::Font, maths::{Vec3, Matrix},
6311    ///                      util::named_colors::{WHITE, GOLD, GREEN}};
6312    ///
6313    /// let font = Font::default();
6314    /// let style = Text::make_style(font, 0.28, WHITE);
6315    /// let transform1 = Matrix::t([0.7, 0.7, 0.0])  * Matrix::Y_180;
6316    /// let transform2 = Matrix::t([0.3, 0.1, 0.0])  * Matrix::Y_180;
6317    /// let transform3 = Matrix::t([-0.1,-0.5, 0.0]) * Matrix::Y_180;
6318    ///
6319    /// test_steps!( // !!!! Get a proper main loop !!!!
6320    ///    Text::add_at(token, "Many", transform1, Some(style), Some(GOLD.into()),
6321    ///             Some(Pivot::TopCenter), Some(Align::TopLeft), None, None, None);
6322    ///    
6323    ///    Text::add_at(token, "Texts!", transform2, Some(style), Some(GREEN.into()),
6324    ///             Some(Pivot::Center), Some(Align::TopLeft), None, None, Some(-0.3));
6325    ///
6326    ///    Text::add_at(token, "----/****", transform3, Some(style), None,
6327    ///             None, None, None, None, None);
6328    /// );
6329    /// ```
6330    #[allow(clippy::too_many_arguments)]
6331    pub fn add_at(
6332        _token: &MainThreadToken,
6333        text: impl AsRef<str>,
6334        transform: impl Into<Matrix>,
6335        text_style: Option<TextStyle>,
6336        vertex_tint_linear: Option<Color128>,
6337        position: Option<Pivot>,
6338        align: Option<Align>,
6339        off_x: Option<f32>,
6340        off_y: Option<f32>,
6341        off_z: Option<f32>,
6342    ) {
6343        let c_str = CString::new(text.as_ref()).unwrap();
6344        let style = text_style.unwrap_or_default();
6345        let vertex_tint_linear = vertex_tint_linear.unwrap_or(Color128::WHITE);
6346        let position = position.unwrap_or(Pivot::Center);
6347        let align = align.unwrap_or(Align::Center);
6348        let off_x = off_x.unwrap_or(0.0);
6349        let off_y = off_y.unwrap_or(0.0);
6350        let off_z = off_z.unwrap_or(0.0);
6351        unsafe {
6352            text_add_at(
6353                c_str.as_ptr(),
6354                &transform.into(),
6355                style,
6356                position,
6357                align,
6358                off_x,
6359                off_y,
6360                off_z,
6361                vertex_tint_linear,
6362            )
6363        }
6364    }
6365
6366    /// Renders text at the given location! Must be called every frame you want this text to be visible.
6367    /// <https://stereokit.net/Pages/StereoKit/Text/Add.html>
6368    /// * `text` - What text should be drawn?
6369    /// * `transform` - A Matrix representing the transform of the text mesh! Try Matrix::t_r_s().
6370    /// * `size` - This is the Hierarchy space rectangle that the text should try to fit inside of. This allows for text
6371    ///   wrapping or scaling based on the value provided to the ‘fit’ parameter.
6372    /// * `text_fit` - Describe how the text should behave when one of its size dimensions conflicts with the provided
6373    ///   ‘size’ parameter.
6374    /// * `text_style` - Style information for rendering, see Text.MakeStyle or the TextStyle object. If None will use
6375    ///   the TextStyle::default()
6376    /// * `vertex_tint_linear` - The vertex color of the text gets multiplied by this color. This is a linear color
6377    ///   value, not a gamma corrected color value. If None will use Color128::WHITE
6378    /// * `position` - How should the text’s bounding rectangle be positioned relative to the transform? If None will
6379    ///   use Pivot::Center.
6380    /// * `align` - How should the text be aligned within the text’s bounding rectangle? If None will use
6381    ///   Align::Center.
6382    /// * `off_?` - An additional offset on the given axis. If None will use 0.0.
6383    ///
6384    /// Returns the vertical space used by this text.
6385    ///
6386    /// see also [`text_add_in`]
6387    /// ### Examples
6388    /// ```
6389    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
6390    /// use stereokit_rust::{system::{ Align, Pivot, TextFit, Text},
6391    ///                      font::Font, maths::{Vec3, Matrix},
6392    ///                      util::named_colors::{WHITE, GOLD, GREEN}};
6393    ///
6394    /// let font = Font::default();
6395    /// let style = Text::make_style(font, 0.28, WHITE);
6396    /// let transform1 = Matrix::Y_180;
6397    ///
6398    /// test_steps!( // !!!! Get a proper main loop !!!!
6399    ///    let size = Text::add_in(token, "Many", transform1, [1.1, 1.0], TextFit::Wrap,
6400    ///             Some(style), Some(GOLD.into()), Some(Pivot::BottomRight),
6401    ///             Some(Align::TopLeft), None, None, None);
6402    ///    
6403    ///    let size = Text::add_in(token, "Texts!", transform1, [1.0, 1.0-size], TextFit::Clip,
6404    ///             Some(style),None, None,
6405    ///             None, None, None, None);
6406    ///
6407    ///    Text::add_in(token, "----/****", transform1, [0.3, 1.0-size], TextFit::Squeeze,
6408    ///             Some(style), Some(GREEN.into()), Some(Pivot::YTop),
6409    ///             Some(Align::Center),None, None, Some(-0.7));
6410    /// );
6411    /// ```
6412    #[allow(clippy::too_many_arguments)]
6413    pub fn add_in(
6414        _token: &MainThreadToken,
6415        text: impl AsRef<str>,
6416        transform: impl Into<Matrix>,
6417        size: impl Into<Vec2>,
6418        fit: TextFit,
6419        text_style: Option<TextStyle>,
6420        vertex_tint_linear: Option<Color128>,
6421        position: Option<Pivot>,
6422        align: Option<Align>,
6423        off_x: Option<f32>,
6424        off_y: Option<f32>,
6425        off_z: Option<f32>,
6426    ) -> f32 {
6427        let c_str = CString::new(text.as_ref()).unwrap();
6428        let style = text_style.unwrap_or_default();
6429        let vertex_tint_linear = vertex_tint_linear.unwrap_or(Color128::WHITE);
6430        let position = position.unwrap_or(Pivot::Center);
6431        let align = align.unwrap_or(Align::Center);
6432        let off_x = off_x.unwrap_or(0.0);
6433        let off_y = off_y.unwrap_or(0.0);
6434        let off_z = off_z.unwrap_or(0.0);
6435        unsafe {
6436            text_add_in(
6437                c_str.as_ptr(),
6438                &transform.into(),
6439                size.into(),
6440                fit,
6441                style,
6442                position,
6443                align,
6444                off_x,
6445                off_y,
6446                off_z,
6447                vertex_tint_linear,
6448            )
6449        }
6450    }
6451
6452    /// Sometimes you just need to know how much room some text takes up! This finds the size of the text in meters when
6453    /// using the indicated style!
6454    /// <https://stereokit.net/Pages/StereoKit/Text/Size.html>
6455    /// * text_style - if None will use the TextStyle::default()
6456    /// * max_width - Width of the available space in meters.
6457    ///
6458    /// Returns size of the text in meters
6459    ///
6460    /// see also [`text_size_layout`] [`text_size_layout_constrained`]
6461    #[deprecated(since = "0.40.0", note = "please Text::use size_layout")]
6462    pub fn size(text: impl AsRef<str>, text_style: Option<TextStyle>, max_width: Option<f32>) -> Vec2 {
6463        let c_str = CString::new(text.as_ref()).unwrap();
6464        let style = text_style.unwrap_or_default();
6465        if let Some(max_width) = max_width {
6466            unsafe { text_size_layout_constrained(c_str.as_ptr(), style, max_width) }
6467        } else {
6468            unsafe { text_size_layout(c_str.as_ptr(), style) }
6469        }
6470    }
6471
6472    /// Sometimes you just need to know how much room some text takes up! This finds the layout size of the text in
6473    /// meters when using the indicated style!  This does not include ascender and descender size, so rendering using
6474    /// this as a clipping size will result in ascenders and descenders getting clipped.
6475    /// <https://stereokit.net/Pages/StereoKit/Text/SizeLayout.html>
6476    /// * `text` - Text you want to find the size of.
6477    /// * `text_style` - if None will use the TextStyle::default()
6478    /// * `max_width` - Width of the available space in meters if you need to know how much layout space text will take
6479    ///   when constrained to a certain width? This will find it using the indicated text style!
6480    ///
6481    /// Returns size of the text in meters
6482    ///
6483    /// see also [`text_size_layout`] [`text_size_layout_constrained`]
6484    /// ### Examples
6485    /// ```
6486    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
6487    /// use stereokit_rust::{system::{Text, TextStyle}, font::Font,
6488    ///                      util::named_colors::{WHITE, GOLD, GREEN},
6489    ///                      mesh::Mesh, material::{Material, Cull}, maths::Matrix};
6490    ///
6491    /// let font = Font::default();
6492    /// let style = Text::make_style(font, 0.70, WHITE);
6493    /// let transform1 = Matrix::Y_180;
6494    /// let text = "Yo!";
6495    ///
6496    /// let size = Text::size_layout(text, Some(style), None);
6497    /// let cube = Mesh::generate_cube([size.x, size.y, size.y], None);
6498    /// let mut material = Material::pbr().copy();
6499    /// material.face_cull(Cull::Front);
6500    ///
6501    /// test_steps!( // !!!! Get a proper main loop !!!!
6502    ///    Text::add_at(token, text, transform1, Some(style), Some(GOLD.into()),
6503    ///             None, None, None, None, None);
6504    ///    
6505    ///    cube.draw(token, &material, transform1, Some(GREEN.into()), None);
6506    /// );
6507    /// ```
6508    pub fn size_layout(text: impl AsRef<str>, text_style: Option<TextStyle>, max_width: Option<f32>) -> Vec2 {
6509        let c_str = CString::new(text.as_ref()).unwrap();
6510        let style = text_style.unwrap_or_default();
6511        if let Some(max_width) = max_width {
6512            unsafe { text_size_layout_constrained(c_str.as_ptr(), style, max_width) }
6513        } else {
6514            unsafe { text_size_layout(c_str.as_ptr(), style) }
6515        }
6516    }
6517
6518    /// This modifies a text layout size to include the tallest and lowest possible values for the glyphs in this font.
6519    /// This is for when you need to be careful about avoiding clipping that would happen if you only used the layout size.
6520    /// <https://stereokit.net/Pages/StereoKit/Text/SizeRender.html>
6521    /// * `size_layout` - A size previously calculated using `Text.SizeLayout`.
6522    /// * `text_style` -The same style as used for calculating the sizeLayout. If None will use the TextStyle::default()
6523    /// * `y_offset` - Since the render size will ascend from the initial position, this will be the offset from the
6524    ///   initial position upwards. You should add it to your Y position.
6525    ///
6526    /// Returns the sizeLayout modified to account for the size of the most extreme glyphs.
6527    ///
6528    /// see also [`text_size_layout`] [`text_size_layout_constrained`]
6529    /// ### Examples
6530    /// ```
6531    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
6532    /// use stereokit_rust::{system::{Text, TextStyle}, font::Font,
6533    ///                      util::named_colors::{WHITE, GOLD, GREEN},
6534    ///                      mesh::Mesh, material::{Material, Cull}, maths::Matrix};
6535    ///
6536    /// let font = Font::default();
6537    /// let style = Text::make_style(font, 0.45, WHITE);
6538    /// let transform_text = Matrix::Y_180;
6539    /// let text = "Yo!";
6540    ///
6541    /// let size = Text::size_layout(text, Some(style), None);
6542    /// let mut render_yoff = 0.0;
6543    /// let render_size = Text::size_render(size, Some(style), &mut render_yoff);
6544    /// let cube = Mesh::generate_cube([render_size.x, render_size.y, render_size.y], None);
6545    /// let transform_cube = Matrix::t([0.0, render_yoff/2.0, 0.0]);
6546    /// let mut material = Material::pbr().copy();
6547    /// material.face_cull(Cull::Front);
6548    ///
6549    /// test_steps!( // !!!! Get a proper main loop !!!!
6550    ///    Text::add_at(token, text, transform_text, Some(style), Some(GOLD.into()),
6551    ///             None, None, None, None, None);
6552    ///    
6553    ///    cube.draw(token, &material, transform_cube, Some(GREEN.into()), None);
6554    /// );
6555    /// ```
6556    pub fn size_render(size_layout: impl Into<Vec2>, text_style: Option<TextStyle>, y_offset: &mut f32) -> Vec2 {
6557        let style = text_style.unwrap_or_default();
6558        unsafe { text_size_render(size_layout.into(), style, y_offset) }
6559    }
6560}
6561
6562/// A settings flag that lets you describe the behavior of how StereoKit will refresh data about the world mesh, if
6563/// applicable. This is used with World.RefreshType.
6564/// <https://stereokit.net/Pages/StereoKit/WorldRefresh.html>
6565///
6566/// see also [`World`]
6567#[derive(Debug, Copy, Clone, PartialEq, Eq)]
6568#[repr(u32)]
6569pub enum WorldRefresh {
6570    /// Refreshing occurs when the user leaves the area that was most recently scanned. This area is a sphere that is
6571    /// 0.5 of the World::refresh_radius.
6572    Area = 0,
6573    /// Refreshing happens at timer intervals. If an update doesn’t happen in time, the next update will happen as soon
6574    /// as possible. The timer interval is configurable via World::refresh_nterval.
6575    Timer = 1,
6576}
6577
6578/// For use with World::from_spatial_node, this indicates the type of
6579/// node that's being bridged with OpenXR.
6580/// <https://stereokit.net/Pages/StereoKit/SpatialNodeType.html>
6581///
6582/// see also [`World`]
6583#[derive(Debug, Copy, Clone, PartialEq, Eq)]
6584#[repr(u32)]
6585pub enum SpatialNodeType {
6586    /// Static spatial nodes track the pose of a fixed location in
6587    /// the world relative to reference spaces. The tracking of static
6588    /// nodes may slowly adjust the pose over time for better accuracy but
6589    /// the pose is relatively stable in the short term, such as between
6590    /// rendering frames. For example, a QR code tracking library can use a
6591    /// static node to represent the location of the tracked QR code.
6592    Static = 0,
6593    /// Dynamic spatial nodes track the pose of a physical object
6594    /// that moves continuously relative to reference spaces. The pose of
6595    /// dynamic spatial nodes can be very different within the duration of
6596    /// a rendering frame. It is important for the application to use the
6597    /// correct timestamp to query the space location. For example, a color
6598    /// camera mounted in front of a HMD is also tracked by the HMD so a
6599    /// web camera library can use a dynamic node to represent the camera
6600    /// location.
6601    Dynamic = 1,
6602}
6603
6604/// World contains information about the real world around the user. This includes things like play boundaries, scene
6605/// understanding, and other various things.
6606/// <https://stereokit.net/Pages/StereoKit/World.html>
6607pub struct World;
6608
6609unsafe extern "C" {
6610    pub fn world_has_bounds() -> Bool32T;
6611    pub fn world_get_bounds_size() -> Vec2;
6612    pub fn world_get_bounds_pose() -> Pose;
6613    pub fn world_from_spatial_graph(spatial_graph_node_id: *mut u8, dynamic: SpatialNodeType, qpc_time: i64) -> Pose;
6614    pub fn world_from_perception_anchor(perception_spatial_anchor: *mut c_void) -> Pose;
6615    pub fn world_try_from_spatial_graph(
6616        spatial_graph_node_id: *mut u8,
6617        dynamic: SpatialNodeType,
6618        qpc_time: i64,
6619        out_pose: *mut Pose,
6620    ) -> Bool32T;
6621    pub fn world_try_from_perception_anchor(perception_spatial_anchor: *mut c_void, out_pose: *mut Pose) -> Bool32T;
6622    pub fn world_raycast(ray: Ray, out_intersection: *mut Ray) -> Bool32T;
6623    pub fn world_set_occlusion_enabled(enabled: Bool32T);
6624    pub fn world_get_occlusion_enabled() -> Bool32T;
6625    pub fn world_set_raycast_enabled(enabled: Bool32T);
6626    pub fn world_get_raycast_enabled() -> Bool32T;
6627    pub fn world_set_occlusion_material(material: MaterialT);
6628    pub fn world_get_occlusion_material() -> MaterialT;
6629    pub fn world_set_refresh_type(refresh_type: WorldRefresh);
6630    pub fn world_get_refresh_type() -> WorldRefresh;
6631    pub fn world_set_refresh_radius(radius_meters: f32);
6632    pub fn world_get_refresh_radius() -> f32;
6633    pub fn world_set_refresh_interval(every_seconds: f32);
6634    pub fn world_get_refresh_interval() -> f32;
6635    pub fn world_get_tracked() -> BtnState;
6636    pub fn world_get_origin_mode() -> OriginMode;
6637    pub fn world_get_origin_offset() -> Pose;
6638    pub fn world_set_origin_offset(offset: Pose);
6639}
6640
6641impl World {
6642    /// Off by default. This tells StereoKit to load up and display an occlusion surface that allows the real world to
6643    /// occlude the application’s digital content! Most systems may allow you to customize the visual appearance of this
6644    /// occlusion surface via the World::occlusion_material. Check [`crate::sk::SystemInfo::get_world_occlusion_present`] to see if
6645    /// occlusion can be enabled. This will reset itself to false if occlusion isn’t possible. Loading occlusion data
6646    /// is asynchronous, so occlusion may not occur immediately after setting this flag.
6647    /// <https://stereokit.net/Pages/StereoKit/World/OcclusionEnabled.html>
6648    ///
6649    /// see also [world_set_occlusion_enabled]
6650    /// ### Examples
6651    /// ```
6652    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
6653    /// use stereokit_rust::{system::World};
6654    ///
6655    /// let occlusion_is_present = sk.get_system().get_world_occlusion_present();
6656    ///
6657    /// // By default, occlusion is disabled.
6658    /// assert_eq!(World::get_occlusion_enabled(), false);
6659    ///
6660    /// World::occlusion_enabled(true);
6661    /// if occlusion_is_present {
6662    ///     assert_eq!(World::get_occlusion_enabled(), true);
6663    /// } else {
6664    ///     assert_eq!(World::get_occlusion_enabled(), false);
6665    /// }
6666    ///
6667    /// World::occlusion_enabled(false);
6668    /// assert_eq!(World::get_occlusion_enabled(), false);
6669    /// ```
6670    pub fn occlusion_enabled(enabled: bool) {
6671        unsafe { world_set_occlusion_enabled(enabled as Bool32T) }
6672    }
6673
6674    /// By default, this is a black(0,0,0,0) opaque unlit material that will occlude geometry, but won’t show up as
6675    /// visible anywhere. You can override this with whatever material you would like.
6676    /// <https://stereokit.net/Pages/StereoKit/World/OcclusionMaterial.html>
6677    ///
6678    /// see also [world_set_occlusion_material]
6679    /// ### Examples
6680    /// ```
6681    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
6682    /// use stereokit_rust::{system::World, util::named_colors, material::Material};
6683    ///
6684    /// let occlusion_is_present = sk.get_system().get_world_occlusion_present();
6685    ///
6686    /// assert_eq!(World::get_occlusion_material().get_id(), "sk/world/material");
6687    ///
6688    /// let mut material = Material::unlit().copy();
6689    /// material.color_tint(named_colors::RED);
6690    ///
6691    /// World::occlusion_enabled(true);
6692    /// World::occlusion_material(&material);
6693    ///
6694    /// if occlusion_is_present {
6695    ///     assert_eq!(World::get_occlusion_enabled(), true);
6696    ///     assert_eq!(World::get_occlusion_material(), material);
6697    /// } else {
6698    ///     assert_eq!(World::get_occlusion_enabled(), false);
6699    ///     assert_eq!(World::get_occlusion_material(), material);
6700    /// }
6701    /// ```
6702    pub fn occlusion_material(material: impl AsRef<Material>) {
6703        unsafe { world_set_occlusion_material(material.as_ref().0.as_ptr()) }
6704    }
6705
6706    /// This is relative to the base reference point and is NOT in world space! The origin StereoKit uses is actually a
6707    /// base reference point combined with an offset! You can use this to read or set the offset from the OriginMode
6708    /// reference point.
6709    /// <https://stereokit.net/Pages/StereoKit/World/OriginOffset.html>
6710    ///
6711    /// see also [world_set_origin_offset] [`crate::sk::SkSettings::origin`]
6712    /// ### Examples
6713    /// ```
6714    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
6715    /// use stereokit_rust::{maths::{Vec3, Pose}, system::World};
6716    ///
6717    /// let origin_offset = World::get_origin_offset();
6718    ///
6719    /// xr_mode_stop_here!();
6720    /// // These are the expected results for offscreen tests on a PC:
6721    /// assert_eq!(origin_offset, Pose::ZERO);
6722    ///
6723    /// let offset = Pose::new([0.0, 0.0, 0.01], None);
6724    /// if false {World::origin_offset(offset);}
6725    /// ```
6726    pub fn origin_offset(offset: impl Into<Pose>) {
6727        unsafe { world_set_origin_offset(offset.into()) }
6728    }
6729
6730    /// Off by default. This tells StereoKit to load up collision meshes for the environment, for use with
6731    /// World::raycast. Check [`crate::sk::SystemInfo::get_world_raycast_present`] to see if raycasting can be enabled. This will reset
6732    /// itself to false if raycasting isn’t possible. Loading raycasting data is asynchronous, so collision surfaces may
6733    /// not be available immediately after setting this flag.
6734    /// <https://stereokit.net/Pages/StereoKit/World/RaycastEnabled.html>
6735    ///
6736    /// see also [world_set_raycast_enabled]
6737    /// ### Examples
6738    /// ```
6739    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
6740    /// use stereokit_rust::system::World;
6741    ///
6742    /// let raycast_is_present = sk.get_system().get_world_raycast_present();
6743    ///
6744    /// assert_eq!(World::get_raycast_enabled(), false);
6745    ///
6746    /// World::raycast_enabled(true);
6747    ///
6748    /// if raycast_is_present {
6749    ///     assert_eq!(World::get_raycast_enabled(), true);
6750    /// } else {
6751    ///     assert_eq!(World::get_raycast_enabled(), false);
6752    /// }
6753    /// World::raycast_enabled(false);
6754    /// assert_eq!(World::get_raycast_enabled(), false);
6755    ///
6756    /// ```
6757    pub fn raycast_enabled(enabled: bool) {
6758        unsafe { world_set_raycast_enabled(enabled as Bool32T) }
6759    }
6760
6761    /// The refresh interval speed, in seconds. This is only applicable when using WorldRefresh::Timer for the refresh
6762    /// type. Note that the system may not be able to refresh as fast as you wish, and in that case, StereoKit will
6763    /// always refresh as soon as the previous refresh finishes.
6764    /// <https://stereokit.net/Pages/StereoKit/World/RefreshInterval.html>
6765    ///
6766    /// see also [world_set_refresh_interval]
6767    /// ### Examples
6768    /// ```
6769    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
6770    /// use stereokit_rust::system::World;
6771    ///
6772    /// let occlusion_is_present = sk.get_system().get_world_occlusion_present();
6773    ///
6774    /// World::occlusion_enabled(true);
6775    /// World::refresh_interval(0.01);
6776    ///
6777    /// let occlusion_enabled = World::get_occlusion_enabled();
6778    /// let refresh_interval  = World::get_refresh_interval();
6779    ///
6780    /// offscreen_mode_stop_here!();
6781    /// // These are the expected results for OpenXR tests on a PC:
6782    /// assert_eq!(refresh_interval, 0.01);
6783    /// if occlusion_is_present {
6784    ///     assert_eq!(occlusion_enabled, true);
6785    /// } else {
6786    ///     assert_eq!(occlusion_enabled, false);
6787    /// }
6788    /// ```
6789    pub fn refresh_interval(speed: f32) {
6790        unsafe { world_set_refresh_interval(speed) }
6791    }
6792
6793    /// Radius, in meters, of the area that StereoKit should scan for world data. Default is 4. When using the
6794    /// WorldRefresh::Area refresh type, the world data will refresh when the user has traveled half this radius from
6795    /// the center of where the most recent refresh occurred.
6796    /// <https://stereokit.net/Pages/StereoKit/World/RefreshRadius.html>
6797    ///
6798    /// see also [world_set_refresh_radius]
6799    /// ### Examples
6800    /// ```
6801    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
6802    /// use stereokit_rust::system::World;
6803    ///
6804    /// World::refresh_radius(3.5);
6805    ///
6806    /// let refresh_radius  = World::get_refresh_radius();
6807    ///
6808    /// offscreen_mode_stop_here!();
6809    /// // These are the expected results for OpenXR tests on a PC:
6810    /// assert_eq!(refresh_radius, 3.5);
6811    /// ```
6812    pub fn refresh_radius(distance: f32) {
6813        unsafe { world_set_refresh_radius(distance) }
6814    }
6815
6816    /// What information should StereoKit use to determine when the next world data refresh happens? See the
6817    /// WorldRefresh enum for details.
6818    /// <https://stereokit.net/Pages/StereoKit/World/RefreshType.html>
6819    ///
6820    /// see also [world_set_refresh_type]
6821    /// ### Examples
6822    /// ```
6823    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
6824    /// use stereokit_rust::system::{World, WorldRefresh};
6825    ///
6826    /// World::refresh_type(WorldRefresh::Timer);
6827    ///
6828    /// let refresh_type  = World::get_refresh_type();
6829    ///
6830    /// offscreen_mode_stop_here!();
6831    /// // These are the expected results for OpenXR tests on a PC:
6832    /// assert_eq!(refresh_type, WorldRefresh::Timer);
6833    /// ```
6834    pub fn refresh_type(refresh_type: WorldRefresh) {
6835        unsafe { world_set_refresh_type(refresh_type) }
6836    }
6837
6838    /// Converts a Windows.Perception.Spatial.SpatialAnchor’s pose into SteroKit’s coordinate system. This can be great
6839    /// for interacting with some of the UWP spatial APIs such as WorldAnchors.
6840    ///
6841    /// This method only works on UWP platforms, check Sk.System.perception_bridge_present to see if this is available.
6842    /// <https://stereokit.net/Pages/StereoKit/World/FromPerceptionAnchor.html>
6843    ///
6844    /// see also [world_from_perception_anchor]
6845    #[allow(clippy::not_unsafe_ptr_arg_deref)]
6846    pub fn from_perception_anchor(perception_spatial_anchor: *mut c_void) -> Option<Pose> {
6847        let mut pose = Pose::IDENTITY;
6848        if unsafe { world_try_from_perception_anchor(perception_spatial_anchor, &mut pose) != 0 } {
6849            Some(pose)
6850        } else {
6851            None
6852        }
6853    }
6854    // TODO : Ask for the non try version
6855
6856    /// Converts a Windows Mirage spatial node GUID into a Pose based on its current position and rotation! Check
6857    /// Sk::System::spatial_bridge_present to see if this is available to use. Currently only on HoloLens, good for use
6858    /// with the Windows QR code package.
6859    /// <https://stereokit.net/Pages/StereoKit/World/FromSpatialNode.html>
6860    /// * `spatial_graph_node_id` - A Windows Mirage spatial node GUID acquired from a windows MR API call.
6861    /// * `spatial_node_type` - Type of spatial node to locate.
6862    /// * `qpc_time` : A windows performance counter timestamp at which the node should be located, obtained from
6863    ///   another API or with System.Diagnostics.Stopwatch.GetTimestamp().
6864    ///
6865    /// see also [world_try_from_spatial_graph]
6866    /// ### Examples
6867    /// ```
6868    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
6869    /// use stereokit_rust::system::{World, SpatialNodeType};
6870    ///
6871    /// let spatial_bridge_is_present = sk.get_system().get_spatial_bridge_present();
6872    ///
6873    /// World::refresh_radius(3.5);
6874    ///
6875    /// if spatial_bridge_is_present {
6876    ///     World::from_spatial_node("A test", SpatialNodeType::Static, 0);
6877    /// }
6878    /// ```
6879    pub fn from_spatial_node(
6880        spatial_graph_node_id: impl AsRef<str>,
6881        spatial_node_type: SpatialNodeType,
6882        qpc_time: i64,
6883    ) -> Option<Pose> {
6884        let c_str = CString::new(spatial_graph_node_id.as_ref()).unwrap();
6885        let mut pose = Pose::IDENTITY;
6886        if unsafe {
6887            world_try_from_spatial_graph(c_str.as_ptr() as *mut u8, spatial_node_type, qpc_time, &mut pose) != 0
6888        } {
6889            Some(pose)
6890        } else {
6891            None
6892        }
6893    }
6894
6895    /// World::raycast_enabled must be set to true first! Sk::System::world_raycast_present must also be true.
6896    /// This does a ray intersection with whatever represents the environment at the moment! In this case, it’s a
6897    /// watertight collection of low resolution meshes calculated by the Scene Understanding extension, which is only
6898    /// provided by the Microsoft HoloLens runtime.
6899    /// <https://stereokit.net/Pages/StereoKit/World/Raycast.html>
6900    /// * `ray` - A world space ray that you’d like to try intersecting with the world mesh.
6901    ///
6902    /// Returns The location of the intersection, and direction of the world’s surface at that point if found.
6903    /// see also [world_raycast]
6904    /// ### Examples
6905    /// ```
6906    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
6907    /// use stereokit_rust::{system::{Assets, World}, maths::{Vec3,Ray}};
6908    /// Assets::block_for_priority(i32::MAX);
6909    ///
6910    /// let raycast_is_present = sk.get_system().get_world_raycast_present();
6911    ///
6912    /// assert_eq!(World::get_raycast_enabled(), false);
6913    ///
6914    /// World::raycast_enabled(true);
6915    /// let ray = Ray::new(Vec3::ZERO, Vec3::ONE);
6916    ///
6917    /// if raycast_is_present {
6918    ///     assert_eq!(World::raycast(ray), None);
6919    /// } else {
6920    ///     assert_eq!(World::raycast(ray), None);
6921    /// }
6922    /// ```
6923    pub fn raycast(ray: impl Into<Ray>) -> Option<Ray> {
6924        let mut intersection = Ray::default();
6925        if unsafe { world_raycast(ray.into(), &mut intersection) != 0 } { Some(intersection) } else { None }
6926    }
6927
6928    /// This is the orientation and center point of the system’s boundary/guardian. This can be useful to find the floor
6929    /// height! Not all systems have a boundary, so be sure to check [`World::has_bounds`] first.
6930    /// <https://stereokit.net/Pages/StereoKit/World/BoundsPose.html>
6931    ///
6932    /// see also [world_get_bounds_pose]
6933    /// ### Examples
6934    /// ```
6935    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
6936    /// use stereokit_rust::{system::World, maths::Pose};
6937    ///
6938    /// let bounds_pose = World::get_bounds_pose();
6939    ///
6940    /// xr_mode_stop_here!();
6941    /// // These are the expected results for offscreen tests on a PC:
6942    /// if World::has_bounds(){
6943    ///     // These are results for a non OpenXR environment:
6944    ///     assert_eq!(bounds_pose, Pose::IDENTITY);
6945    /// } else {
6946    ///     // These are results for a non OpenXR environment:
6947    ///     assert_eq!(bounds_pose, Pose::IDENTITY);
6948    /// }
6949    /// ```
6950    pub fn get_bounds_pose() -> Pose {
6951        unsafe { world_get_bounds_pose() }
6952    }
6953
6954    /// This is the size of a rectangle within the play boundary/guardian’s space, in meters if one exists. Check
6955    /// [`World::get_bounds_pose`] for the center point and orientation of the boundary, and check [`World::has_bounds`] to see if it
6956    /// exists at all!
6957    /// <https://stereokit.net/Pages/StereoKit/World/BoundsSize.html>
6958    ///
6959    /// see also [world_get_bounds_size]
6960    /// ### Examples
6961    /// ```
6962    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
6963    /// use stereokit_rust::{system::World, maths::Vec2};
6964    ///
6965    /// let bounds_size = World::get_bounds_size();
6966    ///
6967    /// if World::has_bounds(){
6968    ///     // These are results for a non OpenXR environment:
6969    ///     // Sometime it's ZERO (Monado/simulator) and sometimes it's a valid size (real OpenXR):
6970    /// } else {
6971    ///     // These are results for a non OpenXR environment:
6972    ///     assert_eq!(bounds_size, Vec2::ZERO);
6973    /// }
6974    /// ```
6975    pub fn get_bounds_size() -> Vec2 {
6976        unsafe { world_get_bounds_size() }
6977    }
6978
6979    /// This refers to the play boundary, or guardian system that the system may have! Not all systems have this, so
6980    /// it’s always a good idea to check this first!
6981    /// <https://stereokit.net/Pages/StereoKit/World/HasBounds.html>
6982    ///
6983    /// see also [world_has_bounds]
6984    /// see example in [`World::get_bounds_size`] [`World::get_bounds_pose`]
6985    pub fn has_bounds() -> bool {
6986        unsafe { world_has_bounds() != 0 }
6987    }
6988
6989    /// Off by default. This tells StereoKit to load up and display an occlusion surface that allows the real world to
6990    /// occlude the application’s digital content! Most systems may allow you to customize the visual appearance of this
6991    /// occlusion surface via the World::occlusion_material. Check SK::System::world_occlusion_present to see if
6992    /// occlusion can be enabled. This will reset itself to false if occlusion isn’t possible. Loading occlusion data
6993    /// is asynchronous, so occlusion may not occur immediately after setting this flag.
6994    /// <https://stereokit.net/Pages/StereoKit/World/OcclusionEnabled.html>
6995    ///
6996    /// see also [world_get_occlusion_enabled]
6997    /// see example in [`World::occlusion_enabled`]
6998    pub fn get_occlusion_enabled() -> bool {
6999        unsafe { world_get_occlusion_enabled() != 0 }
7000    }
7001
7002    /// By default, this is a black(0,0,0,0) opaque unlit material that will occlude geometry, but won’t show up as
7003    /// visible anywhere. You can override this with whatever material you would like.
7004    /// <https://stereokit.net/Pages/StereoKit/World/OcclusionMaterial.html>
7005    ///
7006    /// see also [world_get_occlusion_material]
7007    /// see example in [`World::occlusion_material`]
7008    pub fn get_occlusion_material() -> Material {
7009        Material(NonNull::new(unsafe { world_get_occlusion_material() }).unwrap())
7010    }
7011
7012    /// The mode or “reference space” that StereoKit uses for determining its base origin. This is determined by the
7013    /// initial value provided in [`crate::sk::SkSettings.origin`], as well as by support from the underlying runtime. The mode
7014    /// reported here will not necessarily be the one requested in initialization, as fallbacks are implemented using
7015    /// different available modes.
7016    /// <https://stereokit.net/Pages/StereoKit/World/OriginMode.html>
7017    ///
7018    /// see also [world_get_origin_mode]
7019    /// ### Examples
7020    /// ```
7021    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
7022    /// use stereokit_rust::system::World;
7023    ///
7024    /// let origin_mode_init = sk.get_settings().origin;
7025    ///
7026    /// let origin_mode = World::get_origin_mode();
7027    ///
7028    /// assert_eq!(origin_mode_init, origin_mode);
7029    /// ```
7030    pub fn get_origin_mode() -> OriginMode {
7031        unsafe { world_get_origin_mode() }
7032    }
7033
7034    /// This reports the status of the device's positional tracking. If the room is too dark, or a hand is covering
7035    /// tracking sensors, or some other similar 6dof tracking failure, this would report as not tracked.
7036    ///
7037    /// Note that this does not factor in the status of rotational tracking. Rotation is typically done via
7038    /// gyroscopes/accelerometers, which don't really fail the same way positional tracking system can.
7039    /// <https://stereokit.net/Pages/StereoKit/World/Tracked.html>
7040    ///
7041    /// see also [world_get_tracked]
7042    /// ### Examples
7043    /// ```
7044    /// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
7045    /// use stereokit_rust::system::{World, BtnState};
7046    ///
7047    /// let is_tracked = World::get_tracked();
7048    ///
7049    /// xr_mode_stop_here!();
7050    /// // These are the expected results for offscreen tests on a PC:
7051    /// assert_eq!(is_tracked, BtnState::Active);
7052    /// ```
7053    pub fn get_tracked() -> BtnState {
7054        unsafe { world_get_tracked() }
7055    }
7056
7057    /// This is relative to the base reference point and is NOT in world space! The origin StereoKit uses is actually a
7058    /// base reference point combined with an offset! You can use this to read or set the offset from the OriginMode
7059    /// reference point.
7060    /// <https://stereokit.net/Pages/StereoKit/World/OriginOffset.html>
7061    ///
7062    /// see also [world_get_origin_offset]
7063    /// see example in [`World::origin_offset`]
7064    pub fn get_origin_offset() -> Pose {
7065        unsafe { world_get_origin_offset() }
7066    }
7067
7068    /// Off by default. This tells StereoKit to load up collision meshes for the environment, for use with
7069    /// World::raycast. Check SK::System::world_raycast_present to see if raycasting can be enabled. This will reset
7070    /// itself to false if raycasting isn’t possible. Loading raycasting data is asynchronous, so collision surfaces may
7071    /// not be available immediately after setting this flag.
7072    /// <https://stereokit.net/Pages/StereoKit/World/RaycastEnabled.html>
7073    ///
7074    /// see also [world_get_raycast_enabled]
7075    /// see example in [`World::raycast_enabled`]
7076    pub fn get_raycast_enabled() -> bool {
7077        unsafe { world_get_raycast_enabled() != 0 }
7078    }
7079
7080    /// The refresh interval speed, in seconds. This is only applicable when using WorldRefresh::Timer for the refresh
7081    /// type. Note that the system may not be able to refresh as fast as you wish, and in that case, StereoKit will
7082    /// always refresh as soon as the previous refresh finishes.
7083    /// <https://stereokit.net/Pages/StereoKit/World/RefreshInterval.html>
7084    ///
7085    /// see also [world_get_refresh_interval]
7086    /// see example in [`World::refresh_interval`]
7087    pub fn get_refresh_interval() -> f32 {
7088        unsafe { world_get_refresh_interval() }
7089    }
7090
7091    /// Radius, in meters, of the area that StereoKit should scan for world data. Default is 4. When using the
7092    /// WorldRefresh::Area refresh type, the world data will refresh when the user has traveled half this radius from
7093    /// the center of where the most recent refresh occurred.
7094    /// <https://stereokit.net/Pages/StereoKit/World/RefreshRadius.html>
7095    ///
7096    /// see also [world_get_refresh_radius]
7097    /// see example in [`World::refresh_radius`]
7098    pub fn get_refresh_radius() -> f32 {
7099        unsafe { world_get_refresh_radius() }
7100    }
7101
7102    /// What information should StereoKit use to determine when the next world data refresh happens? See the
7103    /// WorldRefresh enum for details.
7104    /// <https://stereokit.net/Pages/StereoKit/World/RefreshType.html>
7105    ///
7106    /// see also [world_get_refresh_type]
7107    /// see example in [`World::refresh_type`]
7108    pub fn get_refresh_type() -> WorldRefresh {
7109        unsafe { world_get_refresh_type() }
7110    }
7111}