stereokit_rust/
system.rs

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