tirbofish/dropbear · commit
2a0f08a88f896659e57a758b7dd2decf9d4ed541
feature: automatic component inspection
Signature present but could not be verified.
Unverified
@@ -3,7 +3,7 @@ use std::mem::size_of; use glam::DMat4; use slank::include_slang; use wgpu::{BufferAddress, CompareFunction, DepthBiasState, StencilState, VertexAttribute, VertexFormat}; -use crate::buffer::{StorageBuffer, UniformBuffer}; +use crate::buffer::{StorageBuffer}; use crate::entity::{EntityTransform, Transform}; use crate::graphics::SharedGraphicsContext; use crate::lighting::{Light, LightArrayUniform, LightComponent, MAX_LIGHTS}; @@ -87,18 +87,12 @@ impl DropbearShaderPipeline for LightCubePipeline { cache: None, }); - let mut storage_buffer = None; - - storage_buffer = Some(StorageBuffer::new( + let storage_buffer = StorageBuffer::new( &graphics.device, "light cube pipeline storage buffer", - )); + ); - let light_buffer: &wgpu::Buffer = if let Some(buf) = &storage_buffer { - buf.buffer() - } else { - panic!("A storage buffer should have been created"); - }; + let light_buffer: &wgpu::Buffer = storage_buffer.buffer(); let light_bind_group = graphics.device.create_bind_group(&wgpu::BindGroupDescriptor { layout: &graphics.layouts.light_array_bind_group_layout, @@ -113,7 +107,7 @@ impl DropbearShaderPipeline for LightCubePipeline { shader, pipeline_layout, pipeline, - storage_buffer, + storage_buffer: Some(storage_buffer), light_bind_group, } } @@ -1,6 +1,5 @@ use std::sync::Arc; use wgpu::{CompareFunction, DepthBiasState, StencilState}; -use crate::buffer::{StorageBuffer, UniformBuffer}; use crate::graphics::{InstanceRaw, SharedGraphicsContext}; use crate::model; use crate::model::Vertex; @@ -4,7 +4,7 @@ use syn::{ parse::{Parse, ParseStream}, parse_macro_input, parse_quote, spanned::Spanned, - DeriveInput, FnArg, GenericArgument, Ident, Item, ItemFn, ItemMod, ItemEnum, LitStr, PathArguments, + FnArg, GenericArgument, Ident, ItemFn, ItemEnum, LitStr, PathArguments, ReturnType, Token, Type, }; use std::path::Path; @@ -1235,98 +1235,6 @@ fn is_double_type(ty: &Type) -> bool { matches!(ty, Type::Path(path) if path.path.segments.last().map(|s| s.ident == "f64").unwrap_or(false)) } -fn transform_function(mut func: ItemFn) -> ItemFn { - let inputs = func.sig.inputs.clone(); - let output = func.sig.output.clone(); - let block = func.block; - - let inner_type = extract_inner_type(&output); - let is_void = is_unit_type(&inner_type); - - let mut new_inputs = inputs.clone(); - - if !is_void { - let out_ptr_type: Type = parse_quote! { *mut #inner_type }; - - new_inputs.push(FnArg::Typed(syn::PatType { - attrs: vec![], - pat: Box::new(parse_quote! { out_result }), - colon_token: Default::default(), - ty: Box::new(out_ptr_type), - })); - } - - let pointer_check = if !is_void { - quote! { - if out_result.is_null() { - return crate::scripting::native::DropbearNativeError::NullPointer.code(); - } - } - } else { - quote! {} - }; - - let success_handling = if !is_void { - quote! { - unsafe { *out_result = val; } - crate::scripting::native::DropbearNativeError::Success.code() - } - } else { - quote! { - crate::scripting::native::DropbearNativeError::Success.code() - } - }; - - let new_body = quote! { - { - #pointer_check - - let logic = || #output { - #block - }; - - match logic() { - DropbearNativeResult::Ok(val) => { - #success_handling - } - DropbearNativeResult::Err(e) => { - e.code() - } - } - } - }; - - func.sig.inputs = new_inputs; - func.sig.output = parse_quote! { -> i32 }; - func.sig.abi = Some(parse_quote! { extern "C" }); - func.sig.unsafety = Some(parse_quote! { unsafe }); - - func.attrs.push(parse_quote! { #[unsafe(no_mangle)] }); - - func.block = Box::new(syn::parse2(new_body).expect("Failed to parse new body")); - - func -} - -/// Helper to dig into Result<T, E> and get T -fn extract_inner_type(output: &ReturnType) -> Type { - match output { - ReturnType::Type(_, ty) => { - if let Type::Path(type_path) = &**ty { - if let Some(segment) = type_path.path.segments.last() { - if let PathArguments::AngleBracketed(args) = &segment.arguments { - if let Some(GenericArgument::Type(inner)) = args.args.first() { - return inner.clone(); - } - } - } - } - parse_quote! { () } - } - ReturnType::Default => parse_quote! { () }, - } -} - /// Helper to check if type is () fn is_unit_type(ty: &Type) -> bool { if let Type::Tuple(tuple) = ty { @@ -5,7 +5,7 @@ use dropbear_engine::animation::AnimationComponent; use dropbear_engine::asset::ASSET_REGISTRY; use dropbear_engine::entity::MeshRenderer; use dropbear_engine::graphics::SharedGraphicsContext; -use crate::component::{Component, ComponentDescriptor, SerializedComponent}; +use crate::component::{Component, ComponentDescriptor, InspectableComponent, SerializedComponent}; #[typetag::serde] impl SerializedComponent for AnimationComponent {} @@ -60,7 +60,9 @@ impl Component for AnimationComponent { fn save(&self, _world: &World, _entity: Entity) -> Box<dyn SerializedComponent> { Box::new(self.clone()) } +} +impl InspectableComponent for AnimationComponent { fn inspect(&mut self, ui: &mut Ui) { CollapsingHeader::new("Animation").default_open(true).show(ui, |ui| { ui.label("Active animation:"); @@ -8,7 +8,7 @@ use std::sync::Arc; use egui::{CollapsingHeader, Ui}; use hecs::{Entity, World}; use dropbear_engine::graphics::SharedGraphicsContext; -use crate::component::{Component, ComponentDescriptor, ComponentInitFuture, SerializedComponent}; +use crate::component::{Component, ComponentDescriptor, ComponentInitFuture, InspectableComponent, SerializedComponent}; use crate::ptr::WorldPtr; use crate::scripting::result::DropbearNativeResult; use crate::types::NVector3; @@ -70,7 +70,9 @@ impl Component for Camera { Box::new(SerializableCamera::default()) } } +} +impl InspectableComponent for Camera { fn inspect(&mut self, ui: &mut Ui) { CollapsingHeader::new("Camera3D").show(ui, |ui| { ui.label("Not implemented yet!"); @@ -41,6 +41,8 @@ pub struct ComponentRegistry { removers: HashMap<TypeId, RemoveFn>, /// Functions that find entities with a component. finders: HashMap<TypeId, FindFn>, + /// Allows for inspecting the component in the Resource Inspector dock. + inspectors: HashMap<TypeId, InspectFn>, } /// Describes a handy little future for [`Component::init`], which deals with initialising a component from its serialized form. @@ -61,6 +63,9 @@ type UpdateFn = Box<dyn Fn(&mut hecs::World, f32, Arc<SharedGraphicsContext>) + type DefaultFn = Box<dyn Fn() -> Box<dyn SerializedComponent> + Send + Sync>; type RemoveFn = Box<dyn Fn(&mut hecs::World, hecs::Entity) + Send + Sync>; type FindFn = Box<dyn Fn(&hecs::World) -> Vec<hecs::Entity> + Send + Sync>; +type InspectFn = Box<dyn Fn(&mut hecs::World, hecs::Entity, &mut egui::Ui) + Send + Sync>; + +// fn inspect(&mut self, ui: &mut egui::Ui); impl ComponentRegistry { pub fn new() -> Self { @@ -75,13 +80,14 @@ impl ComponentRegistry { defaults: HashMap::new(), removers: HashMap::new(), finders: HashMap::new(), + inspectors: HashMap::new(), } } /// Register a component type with the registry pub fn register<T>(&mut self) where - T: Component + Send + Sync + 'static, + T: Component + InspectableComponent + Send + Sync + 'static, T::SerializedForm: 'static + Default, T::RequiredComponentTypes: Send + Sync, { @@ -142,6 +148,12 @@ impl ComponentRegistry { component.update_component(world_ref, entity, dt, graphics.clone()); } })); + + self.inspectors.insert(type_id, Box::new(|world, entity, ui| { + if let Ok(mut comp) = world.get::<&mut T>(entity) { + comp.inspect(ui); + } + })); } /// Get descriptor for a specific component type @@ -344,60 +356,10 @@ impl ComponentRegistry { continue; }; - match desc.fqtn.as_str() { - "dropbear_engine::entity::EntityTransform" => { - if let Ok(mut comp) = world.get::<&mut EntityTransform>(entity) { - comp.inspect(ui); - } - } - "eucalyptus_core::properties::CustomProperties" => { - if let Ok(mut comp) = world.get::<&mut crate::properties::CustomProperties>(entity) { - comp.inspect(ui); - } - } - "dropbear_engine::lighting::Light" => { - if let Ok(mut comp) = world.get::<&mut dropbear_engine::lighting::Light>(entity) { - comp.inspect(ui); - } - } - "eucalyptus_core::states::Script" => { - if let Ok(mut comp) = world.get::<&mut crate::states::Script>(entity) { - comp.inspect(ui); - } - } - "dropbear_engine::entity::MeshRenderer" => { - if let Ok(mut comp) = world.get::<&mut MeshRenderer>(entity) { - comp.inspect(ui); - } - } - "dropbear_engine::camera::Camera" => { - if let Ok(mut comp) = world.get::<&mut dropbear_engine::camera::Camera>(entity) { - comp.inspect(ui); - } - } - "eucalyptus_core::physics::rigidbody::RigidBody" => { - if let Ok(mut comp) = world.get::<&mut crate::physics::rigidbody::RigidBody>(entity) { - comp.inspect(ui); - } - } - "eucalyptus_core::physics::collider::ColliderGroup" => { - if let Ok(mut comp) = world.get::<&mut crate::physics::collider::ColliderGroup>(entity) { - comp.inspect(ui); - } - } - "eucalyptus_core::physics::kcc::KCC" => { - if let Ok(mut comp) = world.get::<&mut crate::physics::kcc::KCC>(entity) { - comp.inspect(ui); - } - } - "dropbear_engine::animation::AnimationComponent" => { - if let Ok(mut comp) = world.get::<&mut dropbear_engine::animation::AnimationComponent>(entity) { - comp.inspect(ui); - } - } - _ => { - ui.label(format!("{} (no inspector)", desc.type_name)); - } + if let Some(inspector) = self.inspectors.get(&type_id) { + inspector(world, entity, ui); + } else { + ui.label(format!("{} (no inspector)", desc.type_name)); } } } @@ -447,7 +409,7 @@ pub struct ComponentDescriptor { } /// Defines a type that can be considered a component of an entity. -pub trait Component: Sized + Sync + Send { +pub trait Component: Sync + Send { /// A custom format of the component for saving the state of the component to disk. /// /// To have your type available, you must include this blanket trait: @@ -481,14 +443,16 @@ pub trait Component: Sized + Sync + Send { /// Called when saving the scene to disk. Returns the [`Self::SerializedForm`] of the component that can be /// saved to disk. fn save(&self, world: &hecs::World, entity: hecs::Entity) -> Box<dyn SerializedComponent>; - - /// In the editor, how the component will be represented in the `Resource Viewer` dock. - fn inspect(&mut self, ui: &mut egui::Ui); } #[typetag::serde] impl SerializedComponent for SerializedMeshRenderer {} +pub trait InspectableComponent: Send + Sync { + /// In the editor, how the component will be represented in the `Resource Viewer` dock. + fn inspect(&mut self, ui: &mut egui::Ui); +} + // sample for MeshRenderer impl Component for MeshRenderer { type SerializedForm = SerializedMeshRenderer; @@ -738,8 +702,10 @@ impl Component for MeshRenderer { texture_override, }) } +} - fn inspect(&mut self, ui: &mut Ui) { +impl InspectableComponent for MeshRenderer { + fn inspect(&mut self, ui: &mut egui::Ui) { CollapsingHeader::new("Mesh Renderer").show(ui, |ui| { ui.label("Not implemented yet (MeshRenderer)"); }); @@ -251,7 +251,7 @@ impl ProjectConfig { let scene_entry = scene_entry?; let path = scene_entry.path(); - if path.is_file() && path.extension().and_then(|s| s.to_str()) == Some("eucs") { + if path.is_file() && path.extension().and_then(|s| s.to_str()) == Some("eucs") && path.extension().and_then(|s| s.to_str()) != Some("bak") { match SceneConfig::read_from(&path) { Ok(scene) => { log::debug!("Loaded scene config: {}", scene.scene_name); @@ -262,13 +262,21 @@ impl ProjectConfig { if io_err.kind() == std::io::ErrorKind::NotFound { log::warn!("Scene file {:?} not found", path); } else { - if let Some(scene) = deal_with_bad_scene(&path, &e, &project_root) { - scene_configs.push(scene); + if let Some(first) = scene_configs.first() { + log::warn!("Unable to load scene {}: [{:?}], loading the first available scene [{}]", path.display(), &e, first.scene_name); + } else { + if let Some(scene) = deal_with_bad_scene(&path, &e, &project_root) { + scene_configs.push(scene); + } } } } else { - if let Some(scene) = deal_with_bad_scene(&path, &e, &project_root) { - scene_configs.push(scene); + if let Some(first) = scene_configs.first() { + log::warn!("Unable to load scene {}: [{:?}], loading the first available scene [{}]", path.display(), &e, first.scene_name); + } else { + if let Some(scene) = deal_with_bad_scene(&path, &e, &project_root) { + scene_configs.push(scene); + } } } } @@ -12,7 +12,7 @@ use hecs::{Entity, World}; use jni::objects::{JObject, JValue}; use jni::JNIEnv; use dropbear_engine::graphics::SharedGraphicsContext; -use crate::component::{Component, ComponentDescriptor, ComponentInitFuture, SerializedComponent}; +use crate::component::{Component, ComponentDescriptor, ComponentInitFuture, InspectableComponent, SerializedComponent}; use crate::states::SerializedLight; #[typetag::serde] @@ -73,7 +73,9 @@ impl Component for Light { Box::new(SerializedLight::default()) } } +} +impl InspectableComponent for Light { fn inspect(&mut self, ui: &mut Ui) { CollapsingHeader::new("Light").default_open(true).show(ui, |ui| { ui.label("Not implemented yet"); @@ -36,7 +36,7 @@ use glam::DQuat; use hecs::{Entity, World}; use rapier3d::prelude::{Rotation, SharedShape, TypedShape, Vector}; use dropbear_engine::animation::AnimationComponent; -use crate::component::{Component, ComponentDescriptor, SerializedComponent}; +use crate::component::{Component, ComponentDescriptor, InspectableComponent, SerializedComponent}; use crate::physics::PhysicsState; use crate::ptr::PhysicsStatePtr; @@ -72,7 +72,7 @@ impl Component for ColliderGroup { } } - async fn first_time(graphics: Arc<SharedGraphicsContext>) -> anyhow::Result<Self::RequiredComponentTypes> + async fn first_time(_: Arc<SharedGraphicsContext>) -> anyhow::Result<Self::RequiredComponentTypes> where Self: Sized { @@ -91,7 +91,9 @@ impl Component for ColliderGroup { fn save(&self, _world: &World, _entity: Entity) -> Box<dyn SerializedComponent> { Box::new(self.clone()) } +} +impl InspectableComponent for ColliderGroup { fn inspect(&mut self, ui: &mut Ui) { CollapsingHeader::new("Colliders").default_open(true).show(ui, |ui| { ui.label("Not implemented yet!"); @@ -22,7 +22,7 @@ use rapier3d::math::Rotation; use rapier3d::prelude::QueryFilter; use dropbear_engine::animation::AnimationComponent; use dropbear_engine::graphics::SharedGraphicsContext; -use crate::component::{Component, ComponentDescriptor, SerializedComponent}; +use crate::component::{Component, ComponentDescriptor, InspectableComponent, SerializedComponent}; use crate::ptr::WorldPtr; /// The kinematic character controller (kcc) component. @@ -69,7 +69,9 @@ impl Component for KCC { fn save(&self, _world: &World, _entity: Entity) -> Box<dyn SerializedComponent> { Box::new(self.clone()) } +} +impl InspectableComponent for KCC { fn inspect(&mut self, ui: &mut Ui) { egui::CollapsingHeader::new("Kinematic Character Controller").default_open(true).show(ui, |ui| { ui.label("Not implemented yet!") @@ -221,7 +221,9 @@ impl Component for RigidBody { fn save(&self, _world: &World, _entity: Entity) -> Box<dyn SerializedComponent> { Box::new(self.clone()) } +} +impl crate::component::InspectableComponent for RigidBody { fn inspect(&mut self, ui: &mut Ui) { CollapsingHeader::new("RigidBody").default_open(true).show(ui, |ui| { ui.label("Not implemented yet!"); @@ -6,7 +6,7 @@ use std::sync::Arc; use egui::{CollapsingHeader, ComboBox, DragValue, Grid, RichText, TextEdit, Ui}; use hecs::{Entity, World}; use dropbear_engine::graphics::SharedGraphicsContext; -use crate::component::{Component, ComponentDescriptor, ComponentInitFuture, SerializedComponent}; +use crate::component::{Component, ComponentDescriptor, ComponentInitFuture, InspectableComponent, SerializedComponent}; use crate::ptr::WorldPtr; use crate::scripting::native::DropbearNativeError; use crate::scripting::result::DropbearNativeResult; @@ -56,7 +56,9 @@ impl Component for CustomProperties { fn save(&self, _world: &World, _entity: Entity) -> Box<dyn SerializedComponent> { Box::new(self.clone()) } +} +impl InspectableComponent for CustomProperties { fn inspect(&mut self, ui: &mut Ui) { CollapsingHeader::new("Custom Properties").default_open(true).show(ui, |ui| { ui.vertical(|ui| { @@ -27,7 +27,7 @@ use egui::{CollapsingHeader, TextEdit, Ui}; use hecs::{Entity, World}; use dropbear_engine::model::AlphaMode; use dropbear_engine::texture::TextureWrapMode; -use crate::component::{Component, ComponentDescriptor, ComponentInitFuture, SerializedComponent}; +use crate::component::{Component, ComponentDescriptor, ComponentInitFuture, InspectableComponent, SerializedComponent}; use crate::properties::Value; /// A global "singleton" that contains the configuration of a project. @@ -193,7 +193,9 @@ impl Component for Script { fn save(&self, _world: &World, _entity: Entity) -> Box<dyn SerializedComponent> { Box::new(self.clone()) } +} +impl InspectableComponent for Script { fn inspect(&mut self, ui: &mut Ui) { CollapsingHeader::new("Logic") .default_open(true) @@ -11,7 +11,7 @@ use ::jni::JNIEnv; use egui::{CollapsingHeader, Ui}; use hecs::{Entity, World}; use dropbear_engine::graphics::SharedGraphicsContext; -use crate::component::{Component, ComponentDescriptor, SerializedComponent}; +use crate::component::{Component, ComponentDescriptor, InspectableComponent, SerializedComponent}; use crate::types::{NTransform, NVector3}; #[typetag::serde] @@ -46,7 +46,9 @@ impl Component for EntityTransform { fn save(&self, _: &World, _: Entity) -> Box<dyn SerializedComponent> { Box::new(self.clone()) } +} +impl InspectableComponent for EntityTransform { fn inspect(&mut self, ui: &mut Ui) { CollapsingHeader::new("Entity Transform").show(ui, |ui| { CollapsingHeader::new("Local").show(ui, |ui| { @@ -179,31 +179,7 @@ typedef struct NChannelValuesFfi { typedef NChannelValuesFfi NChannelValues; -typedef struct NRange { - float start; - float end; -} NRange; - -typedef void* SceneLoaderPtr; - -typedef struct NAttenuation { - float constant; - float linear; - float quadratic; -} NAttenuation; - -typedef struct NColour { - uint8_t r; - uint8_t g; - uint8_t b; - uint8_t a; -} NColour; - -typedef struct AxisLock { - bool x; - bool y; - bool z; -} AxisLock; +typedef void* InputStatePtr; typedef struct IndexNative { uint32_t index; @@ -216,83 +192,19 @@ typedef struct NCollider { uint32_t id; } NCollider; -typedef struct u64Array { - uint64_t* values; - size_t length; - size_t capacity; -} u64Array; - -typedef void* InputStatePtr; - -typedef void* AssetRegistryPtr; - typedef struct RayHit { NCollider collider; double distance; } RayHit; -typedef struct NShapeCastHit { - NCollider collider; - double distance; - NVector3 witness1; - NVector3 witness2; - NVector3 normal1; - NVector3 normal2; - NShapeCastStatus status; -} NShapeCastHit; +typedef void* SceneLoaderPtr; typedef struct RigidBodyContext { IndexNative index; uint64_t entity_id; } RigidBodyContext; -typedef struct ConnectedGamepadIds { - u64Array ids; -} ConnectedGamepadIds; - -typedef void* PhysicsStatePtr; - -typedef struct i32Array { - int32_t* values; - size_t length; - size_t capacity; -} i32Array; - -typedef struct f64ArrayArray { - double* values; - size_t length; - size_t capacity; -} f64ArrayArray; - -typedef struct NSkin { - const char* name; - i32Array joints; - f64ArrayArray inverse_bind_matrices; - const int32_t* skeleton_root; -} NSkin; - -typedef struct NSkinArray { - NSkin* values; - size_t length; - size_t capacity; -} NSkinArray; - -typedef struct NColliderArray { - NCollider* values; - size_t length; - size_t capacity; -} NColliderArray; - -typedef struct IndexNativeArray { - IndexNative* values; - size_t length; - size_t capacity; -} IndexNativeArray; - -typedef struct CharacterCollisionArray { - uint64_t entity_id; - IndexNativeArray collisions; -} CharacterCollisionArray; +typedef void* CommandBufferPtr; typedef struct NVector4 { double x; @@ -306,6 +218,12 @@ typedef struct NVector2 { double y; } NVector2; +typedef struct i32Array { + int32_t* values; + size_t length; + size_t capacity; +} i32Array; + typedef struct NModelVertex { NVector3 position; NVector3 normal; @@ -336,38 +254,60 @@ typedef struct NMeshArray { size_t capacity; } NMeshArray; -typedef struct NMaterial { +typedef struct f64ArrayArray { + double* values; + size_t length; + size_t capacity; +} f64ArrayArray; + +typedef struct NSkin { const char* name; - uint64_t diffuse_texture; - uint64_t normal_texture; - NVector4 tint; - NVector3 emissive_factor; - float metallic_factor; - float roughness_factor; - const float* alpha_cutoff; - bool double_sided; - float occlusion_strength; - float normal_scale; - NVector2 uv_tiling; - const uint64_t* emissive_texture; - const uint64_t* metallic_roughness_texture; - const uint64_t* occlusion_texture; -} NMaterial; + i32Array joints; + f64ArrayArray inverse_bind_matrices; + const int32_t* skeleton_root; +} NSkin; -typedef struct NMaterialArray { - NMaterial* values; +typedef struct NSkinArray { + NSkin* values; size_t length; size_t capacity; -} NMaterialArray; +} NSkinArray; -typedef struct NTransform { - NVector3 position; +typedef struct NNodeTransform { + NVector3 translation; NQuaternion rotation; NVector3 scale; -} NTransform; +} NNodeTransform; + +typedef struct NNode { + const char* name; + const int32_t* parent; + i32Array children; + NNodeTransform transform; +} NNode; + +typedef struct NNodeArray { + NNode* values; + size_t length; + size_t capacity; +} NNodeArray; + +typedef void* AssetRegistryPtr; typedef void* GraphicsContextPtr; +typedef struct u64Array { + uint64_t* values; + size_t length; + size_t capacity; +} u64Array; + +typedef struct ConnectedGamepadIds { + u64Array ids; +} ConnectedGamepadIds; + +typedef void* WorldPtr; + typedef struct f64Array { double* values; size_t length; @@ -399,34 +339,94 @@ typedef struct NAnimationArray { size_t capacity; } NAnimationArray; -typedef struct Progress { - size_t current; - size_t total; - const char* message; -} Progress; +typedef struct NColliderArray { + NCollider* values; + size_t length; + size_t capacity; +} NColliderArray; -typedef struct NNodeTransform { - NVector3 translation; +typedef struct IndexNativeArray { + IndexNative* values; + size_t length; + size_t capacity; +} IndexNativeArray; + +typedef struct CharacterCollisionArray { + uint64_t entity_id; + IndexNativeArray collisions; +} CharacterCollisionArray; + +typedef void* PhysicsStatePtr; + +typedef struct AxisLock { + bool x; + bool y; + bool z; +} AxisLock; + +typedef struct NRange { + float start; + float end; +} NRange; + +typedef struct NTransform { + NVector3 position; NQuaternion rotation; NVector3 scale; -} NNodeTransform; +} NTransform; -typedef struct NNode { +typedef struct NColour { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; +} NColour; + +typedef struct NShapeCastHit { + NCollider collider; + double distance; + NVector3 witness1; + NVector3 witness2; + NVector3 normal1; + NVector3 normal2; + NShapeCastStatus status; +} NShapeCastHit; + +typedef struct NMaterial { const char* name; - const int32_t* parent; - i32Array children; - NNodeTransform transform; -} NNode; + uint64_t diffuse_texture; + uint64_t normal_texture; + NVector4 tint; + NVector3 emissive_factor; + float metallic_factor; + float roughness_factor; + const float* alpha_cutoff; + bool double_sided; + float occlusion_strength; + float normal_scale; + NVector2 uv_tiling; + const uint64_t* emissive_texture; + const uint64_t* metallic_roughness_texture; + const uint64_t* occlusion_texture; +} NMaterial; -typedef struct NNodeArray { - NNode* values; +typedef struct NMaterialArray { + NMaterial* values; size_t length; size_t capacity; -} NNodeArray; +} NMaterialArray; -typedef void* CommandBufferPtr; +typedef struct NAttenuation { + float constant; + float linear; + float quadratic; +} NAttenuation; -typedef void* WorldPtr; +typedef struct Progress { + size_t current; + size_t total; + const char* message; +} Progress; int32_t dropbear_gamepad_is_button_pressed(InputStatePtr input, uint64_t gamepad_id, int32_t button_ordinal, bool* out0); int32_t dropbear_gamepad_get_left_stick_position(InputStatePtr input, uint64_t gamepad_id, NVector2* out0);