diff options
| -rw-r--r-- | engine-ecs-macros/src/lib.rs | 44 | ||||
| -rw-r--r-- | engine-ecs/examples/component_events.rs | 2 | ||||
| -rw-r--r-- | engine-ecs/examples/component_removed_event.rs | 2 | ||||
| -rw-r--r-- | engine-ecs/src/actions.rs | 25 | ||||
| -rw-r--r-- | engine-ecs/src/component.rs | 70 | ||||
| -rw-r--r-- | engine-ecs/src/entity.rs | 9 | ||||
| -rw-r--r-- | engine-ecs/src/lib.rs | 22 | ||||
| -rw-r--r-- | engine-ecs/src/pair.rs | 61 | ||||
| -rw-r--r-- | engine-ecs/src/phase.rs | 2 | ||||
| -rw-r--r-- | engine-ecs/src/query/term.rs | 113 | ||||
| -rw-r--r-- | engine-ecs/src/sole.rs | 34 | ||||
| -rw-r--r-- | engine-ecs/src/uid.rs | 45 | ||||
| -rw-r--r-- | engine/src/asset.rs | 82 | ||||
| -rw-r--r-- | engine/src/rendering/backend/opengl.rs | 2 | ||||
| -rw-r--r-- | engine/src/rendering/shader.rs | 769 | ||||
| -rw-r--r-- | engine/src/rendering/shader/cursor.rs | 2 | ||||
| -rw-r--r-- | engine/src/rendering/shader/reflection.rs | 713 | ||||
| -rw-r--r-- | engine/src/ui/dear_imgui.rs | 3 | ||||
| -rw-r--r-- | engine/src/windowing.rs | 11 |
19 files changed, 1099 insertions, 912 deletions
diff --git a/engine-ecs-macros/src/lib.rs b/engine-ecs-macros/src/lib.rs index 9bc829b..a95cfe4 100644 --- a/engine-ecs-macros/src/lib.rs +++ b/engine-ecs-macros/src/lib.rs @@ -45,8 +45,6 @@ pub fn component_derive(input: TokenStream) -> TokenStream let item_ident = item.ident(); - let (impl_generics, type_generics, where_clause) = item.generics().split_for_impl(); - let ecs_path = find_engine_ecs_crate_path().unwrap_or_else(|| syn_path!(ecs)); assert!( @@ -80,14 +78,8 @@ pub fn component_derive(input: TokenStream) -> TokenStream #id_var - impl #impl_generics Component for #item_ident #type_generics - #where_clause + impl Component for #item_ident { - fn id() -> Uid - { - *#id_var_ident - } - fn type_reflection() -> Option<&'static #ecs_path::reflection::Type> { struct SpecializationTarget<T>(std::marker::PhantomData<T>); @@ -134,8 +126,7 @@ pub fn component_derive(input: TokenStream) -> TokenStream } } - impl #impl_generics SystemInput for #item_ident #type_generics - #where_clause + impl SystemInput for #item_ident { } @@ -146,7 +137,18 @@ pub fn component_derive(input: TokenStream) -> TokenStream #ecs_path::component::Parts::builder() .name(<Self as Component>::name(&self)) .type_reflection(<Self as Component>::type_reflection()) - .build(<Self as Component>::id(), self) + .build( + <Self as #ecs_path::component::WithAssociatedId>::id(), + self + ) + } + } + + impl #ecs_path::component::WithAssociatedId for #item_ident + { + fn id() -> Uid + { + *#id_var_ident } } } @@ -203,11 +205,6 @@ pub fn sole_derive(input: TokenStream) -> TokenStream impl Sole for #item_ident { - fn id() -> Uid - { - *#id_var_ident - } - fn type_reflection() -> Option<&'static #ecs_path::reflection::Type> { struct SpecializationTarget<T>(std::marker::PhantomData<T>); @@ -262,7 +259,18 @@ pub fn sole_derive(input: TokenStream) -> TokenStream .name(<Self as Sole>::name(&self)) .is_sole(true) .type_reflection(<Self as Sole>::type_reflection()) - .build(<Self as Sole>::id(), self) + .build( + <Self as #ecs_path::component::WithAssociatedId>::id(), + self + ) + } + } + + impl #ecs_path::component::WithAssociatedId for #item_ident + { + fn id() -> Uid + { + *#id_var_ident } } } diff --git a/engine-ecs/examples/component_events.rs b/engine-ecs/examples/component_events.rs index 82d9b6c..b32df8b 100644 --- a/engine-ecs/examples/component_events.rs +++ b/engine-ecs/examples/component_events.rs @@ -1,5 +1,5 @@ use engine_ecs::actions::Actions; -use engine_ecs::component::Component; +use engine_ecs::component::WithAssociatedId; use engine_ecs::event::component::{Changed, EventMatchExt, Removed}; use engine_ecs::pair::Pair; use engine_ecs::phase::UPDATE; diff --git a/engine-ecs/examples/component_removed_event.rs b/engine-ecs/examples/component_removed_event.rs index 23dfc92..40d9bc8 100644 --- a/engine-ecs/examples/component_removed_event.rs +++ b/engine-ecs/examples/component_removed_event.rs @@ -1,5 +1,5 @@ use engine_ecs::actions::Actions; -use engine_ecs::component::Component; +use engine_ecs::component::WithAssociatedId; use engine_ecs::event::component::{EventMatchExt, Removed}; use engine_ecs::pair::Pair; use engine_ecs::phase::UPDATE; diff --git a/engine-ecs/src/actions.rs b/engine-ecs/src/actions.rs index 69605b3..f1a1541 100644 --- a/engine-ecs/src/actions.rs +++ b/engine-ecs/src/actions.rs @@ -1,12 +1,18 @@ use std::borrow::Cow; use crate::bundle::Bundle; -use crate::component::{Component, IntoParts, Parts as ComponentParts}; +use crate::component::{ + Component, + IntoParts, + Parts as ComponentParts, + RemovableTuple as RemovableComponentTuple, +}; use crate::entity::Name as EntityName; use crate::event::component::Removed; use crate::pair::Pair; +use crate::sole::Sole; use crate::system::{Metadata as SystemMetadata, Param as SystemParam}; -use crate::uid::{Uid, WithUidTuple}; +use crate::uid::Uid; use crate::{ActionQueue, World}; /// Used to to queue up actions for a [`World`] to perform. @@ -174,9 +180,9 @@ impl Actions<'_> } /// Queues up removing component(s) from a entity at the end of the current tick. - pub fn remove_comps<Ids: WithUidTuple>(&mut self, entity_uid: Uid) + pub fn remove_comps<Components: RemovableComponentTuple>(&mut self, entity_uid: Uid) { - self.remove_components(entity_uid, Ids::uids()); + self.remove_components(entity_uid, Components::ids()); } /// Queues up setting the target of a entity's pair at the end of the current tick. @@ -299,6 +305,16 @@ impl Actions<'_> }); } + /// Queues up a entity to spawn at the end of the current tick, returning the [`Uid`] + /// that the entity will have. + pub fn create_sole<SoleT: Sole>(&mut self, sole: SoleT) -> Uid + { + self.action_queue + .push(Action::CreateSole(sole.into_parts())); + + SoleT::id() + } + /// Stops the [`World`]. The world will finish the current tick and that tick will be /// the last. pub fn stop(&mut self) @@ -334,5 +350,6 @@ pub(crate) enum Action pair_id: Uid, new_pair: ComponentParts, }, + CreateSole(ComponentParts), Stop, } diff --git a/engine-ecs/src/component.rs b/engine-ecs/src/component.rs index 400b12c..d424e16 100644 --- a/engine-ecs/src/component.rs +++ b/engine-ecs/src/component.rs @@ -3,6 +3,7 @@ use std::fmt::Debug; use std::ops::{Deref, DerefMut}; use engine_ecs_macros::Component; +use seq_macro::seq; use crate::event::component::Changed; use crate::event::Submitter as EventSubmitter; @@ -23,13 +24,9 @@ pub mod local; pub(crate) mod storage; -pub trait Component: SystemInput + Any + IntoParts +/// A component that is not a pair and is not a sole. +pub trait Component: WithAssociatedId + SystemInput + Any + IntoParts { - /// Returns the ID of this component. - fn id() -> Uid - where - Self: Sized; - fn type_reflection() -> Option<&'static TypeReflection> where Self: Sized; @@ -38,32 +35,50 @@ pub trait Component: SystemInput + Any + IntoParts fn name(&self) -> &'static str; } -impl dyn Component +pub trait WithAssociatedId { - pub fn downcast_mut<Real: 'static>(&mut self) -> Option<&mut Real> - { - (self as &mut dyn Any).downcast_mut() - } + /// Returns the ID of this component. + fn id() -> Uid; +} - pub fn downcast_ref<Real: 'static>(&self) -> Option<&Real> - { - (self as &dyn Any).downcast_ref() - } +/// A component that is removable from it's entity. +/// +/// This trait is implemented for [`crate::pair::Pair`] so it does not have [`Component`] +/// as supertrait. +pub trait Removable: WithAssociatedId {} - pub fn is<Other: 'static>(&self) -> bool - { - (self as &dyn Any).is::<Other>() - } -} +impl<ComponentT: Component> Removable for ComponentT {} -impl Debug for dyn Component +/// Implemented by tuples of types implementing [`Removable`]. +/// +/// This trait is sealed so it cannot be implemented by types outside of this module. +pub trait RemovableTuple: sealed::Sealed { - fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result - { - formatter.debug_struct("Component").finish_non_exhaustive() - } + fn ids() -> impl IntoIterator<Item = Uid>; +} + +macro_rules! gen_removable_tuple_impl { + ($c: tt) => { + seq!(I in 0..=$c { + impl<#(RemovableT~I: Removable,)*> RemovableTuple for (#(RemovableT~I,)*) + { + fn ids() -> impl IntoIterator<Item = Uid> + { + [#(RemovableT~I::id(),)*] + } + } + + impl<#(RemovableT~I: Removable,)*> sealed::Sealed for (#(RemovableT~I,)*) + { + } + }); + }; } +seq!(C in 0..=16 { + gen_removable_tuple_impl!(C); +}); + #[derive(Debug)] pub struct Handle<'a, DataT: ?Sized + 'static> { @@ -394,3 +409,8 @@ pub struct Info pub name: &'static str, pub is_sole: bool, } + +mod sealed +{ + pub trait Sealed {} +} diff --git a/engine-ecs/src/entity.rs b/engine-ecs/src/entity.rs index 7515f73..4d472ad 100644 --- a/engine-ecs/src/entity.rs +++ b/engine-ecs/src/entity.rs @@ -232,9 +232,16 @@ impl<'a> Handle<'a> } } + /// Returns whether or not this entity contains the specified component. + #[must_use] + pub fn has_component<ComponentT: Component>(&self) -> bool + { + self.has_component_by_id(ComponentT::id()) + } + /// Returns whether or not this entity contains a component with the specified `Uid`. #[must_use] - pub fn has_component(&self, component_uid: Uid) -> bool + pub fn has_component_by_id(&self, component_uid: Uid) -> bool { self.archetype .contains_component_with_exact_id(component_uid) diff --git a/engine-ecs/src/lib.rs b/engine-ecs/src/lib.rs index a752f6a..188ca7a 100644 --- a/engine-ecs/src/lib.rs +++ b/engine-ecs/src/lib.rs @@ -22,6 +22,7 @@ use crate::component::{ Info as ComponentInfo, IntoParts as IntoComponentParts, Parts as ComponentParts, + WithAssociatedId, }; use crate::entity::{ Declaration as EntityDeclaration, @@ -666,6 +667,27 @@ impl World &ComponentAddingFlags { allow_soles: false }, ); } + Action::CreateSole(sole_parts) => { + if let Err(EntityAlreadyExistsError) = + self.data.component_storage.create_entity(sole_parts.id) + { + tracing::error!( + name = sole_parts.name, + "Can not create sole that already exists" + ); + continue; + } + + let name = sole_parts.name; + + Self::add_entity_components( + sole_parts.id, + [sole_parts, EntityName { name: name.into() }.into_parts()], + &mut self.data.component_storage, + &EventSubmitter::new(&self.data.new_events), + &ComponentAddingFlags { allow_soles: true }, + ); + } Action::Stop => { self.stop.store(true, Ordering::Relaxed); } diff --git a/engine-ecs/src/pair.rs b/engine-ecs/src/pair.rs index 834077c..efeead9 100644 --- a/engine-ecs/src/pair.rs +++ b/engine-ecs/src/pair.rs @@ -8,6 +8,8 @@ use crate::component::{ HandleMut as ComponentHandleMut, IntoParts as IntoComponentParts, Parts as ComponentParts, + Removable as RemovableComponent, + WithAssociatedId as ComponentWithAssociatedId, }; use crate::entity::{ Handle as EntityHandle, @@ -21,7 +23,7 @@ use crate::query::{ TermsBuilderInterface, }; use crate::reflection::Type as TypeReflection; -use crate::uid::{PairParams as UidPairParams, Uid, With as WithUid}; +use crate::uid::{PairParams as UidPairParams, Uid}; use crate::util::impl_multiple; use crate::{Component, EntityComponentRef, World}; @@ -265,7 +267,7 @@ where _term_metadata: QueryTermMetadata, ) { - terms_builder.present([Pair::<Relation, Target>::uid()]); + terms_builder.present([Pair::<Relation, Target>::id()]); } fn fields( @@ -276,7 +278,7 @@ where { let target_component = search_result .entity_handle - .get_matching_components(Pair::<Relation, Target>::uid()) + .get_matching_components(Pair::<Relation, Target>::id()) .next() .expect("Not possible"); @@ -308,7 +310,7 @@ where _term_metadata: QueryTermMetadata, ) { - terms_builder.present([Pair::<Relation, Target>::uid()]); + terms_builder.present([Pair::<Relation, Target>::id()]); } fn fields( @@ -319,7 +321,7 @@ where { let target_component = search_result .entity_handle - .get_matching_components(Pair::<Relation, Target>::uid()) + .get_matching_components(Pair::<Relation, Target>::id()) .next() .expect("Not possible"); @@ -355,7 +357,7 @@ where _term_metadata: QueryTermMetadata, ) { - terms_builder.present([Self::uid()]); + terms_builder.present([Self::id()]); } fn fields( @@ -366,7 +368,7 @@ where { let first_matching_comp = search_result .entity_handle - .get_matching_components(Self::uid()) + .get_matching_components(Self::id()) .next() .expect("Not possible"); @@ -378,12 +380,12 @@ where } } -impl<Relation, Target> WithUid for Pair<Relation, Target> +impl<Relation, Target> ComponentWithAssociatedId for Pair<Relation, Target> where Relation: Component, Target: Component, { - fn uid() -> Uid + fn id() -> Uid { Uid::new_pair(&UidPairParams { relation: Relation::id(), @@ -392,15 +394,28 @@ where } } -impl<Relation> WithUid for Pair<Relation, Wildcard> +impl<Relation, Target> RemovableComponent for Pair<Relation, Target> where Relation: Component, + Target: Component, { - fn uid() -> Uid +} + +// TODO: Implement RemovableComponent for Pair<Relation, Wildcard> +// and Pair<Wildcard, Target>. +// +// This should only be done after removal of wildcard pairs is added in lib.rs + +impl<Relation> Pair<Relation, Wildcard> +where + Relation: Component, +{ + #[must_use] + pub fn id() -> Uid { Uid::new_pair(&UidPairParams { relation: Relation::id(), - target: Wildcard::uid(), + target: Wildcard::id(), }) } } @@ -464,19 +479,17 @@ impl<'query, Relation, Target> WithWildcard<'query, Relation, Target> assert!(component_id.is_pair()); assert!( - Relation::uid() == Wildcard::uid() + Relation::uid() == Wildcard::id() || component_id.relation() == Relation::uid() ); assert!( - Target::uid() == Wildcard::uid() || component_id.target() == Target::uid() + Target::uid() == Wildcard::id() || component_id.target() == Target::uid() ); - assert!(Relation::uid() == Wildcard::uid() || Target::uid() == Wildcard::uid()); + assert!(Relation::uid() == Wildcard::id() || Target::uid() == Wildcard::id()); - assert!( - !(Relation::uid() == Wildcard::uid() && Target::uid() == Wildcard::uid()) - ); + assert!(!(Relation::uid() == Wildcard::id() && Target::uid() == Wildcard::id())); WithWildcard { world, @@ -641,11 +654,9 @@ impl<'query, Relation, Target> MultipleWithWildcard<'query, Relation, Target> Relation: ComponentOrWildcard, Target: ComponentOrWildcard, { - assert!(Relation::uid() == Wildcard::uid() || Target::uid() == Wildcard::uid()); + assert!(Relation::uid() == Wildcard::id() || Target::uid() == Wildcard::id()); - assert!( - !(Relation::uid() == Wildcard::uid() && Target::uid() == Wildcard::uid()) - ); + assert!(!(Relation::uid() == Wildcard::id() && Target::uid() == Wildcard::id())); MultipleWithWildcard { entity_handle, @@ -691,7 +702,7 @@ impl<'a, Relation: Component> IntoIterator WithWildcardIter { inner: self .entity_handle - .get_matching_components(Pair::<Relation, Wildcard>::uid()), + .get_matching_components(Pair::<Relation, Wildcard>::id()), world: self.world, _pd: PhantomData, } @@ -736,7 +747,7 @@ pub struct Wildcard(Infallible); impl Wildcard { #[must_use] - pub fn uid() -> Uid + pub fn id() -> Uid { Uid::wildcard() } @@ -761,7 +772,7 @@ impl ComponentOrWildcard for Wildcard { fn uid() -> Uid { - Wildcard::uid() + Wildcard::id() } } diff --git a/engine-ecs/src/phase.rs b/engine-ecs/src/phase.rs index 64c1593..8d09ab4 100644 --- a/engine-ecs/src/phase.rs +++ b/engine-ecs/src/phase.rs @@ -56,7 +56,7 @@ pub(crate) fn check_parents( continue; }; - if !parent_ent.has_component(Phase::id()) { + if !parent_ent.has_component::<Phase>() { let parent_ent_name = parent_ent.get::<EntityName>(); tracing::warn!( diff --git a/engine-ecs/src/query/term.rs b/engine-ecs/src/query/term.rs index 980ee87..f5fd531 100644 --- a/engine-ecs/src/query/term.rs +++ b/engine-ecs/src/query/term.rs @@ -5,7 +5,9 @@ use crate::component::{ Component, Handle as ComponentHandle, HandleMut as ComponentHandleMut, + WithAssociatedId as _, }; +use crate::pair::{Pair, Wildcard}; use crate::query::{ FoundByTraversal, SearchResult, @@ -17,19 +19,61 @@ use crate::query::{ Traversal, TraversalKind, }; -use crate::uid::With as WithUid; use crate::World; -pub struct With<WithUidT> +pub struct With<T> +{ + _pd: PhantomData<T>, +} + +impl<'query, ComponentT: Component> Term<'query> for With<ComponentT> +{ + type Fields = (); + + fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( + terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, + _term_metadata: TermMetadata, + ) + { + terms_builder.present([ComponentT::id()]); + } + + fn fields( + _world: &'query World, + _search_result: &SearchResult<'query, '_>, + _term_metadata: TermMetadata, + ) -> Self::Fields + { + } +} + +impl<'query, Relation, Target> Term<'query> for With<Pair<Relation, Target>> where - WithUidT: WithUid, + Relation: Component, + Target: Component, { - _pd: PhantomData<WithUidT>, + type Fields = (); + + fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( + terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, + _term_metadata: TermMetadata, + ) + { + terms_builder.present([Pair::<Relation, Target>::id()]); + } + + fn fields( + _world: &'query World, + _search_result: &SearchResult<'query, '_>, + _term_metadata: TermMetadata, + ) -> Self::Fields + { + } } -impl<'query, WithUidT> Term<'query> for With<WithUidT> +impl<'query, Relation> Term<'query> for With<Pair<Relation, Wildcard>> where - WithUidT: WithUid, + Relation: Component, { type Fields = (); @@ -38,7 +82,7 @@ where _term_metadata: TermMetadata, ) { - terms_builder.present([WithUidT::uid()]); + terms_builder.present([Pair::<Relation, Wildcard>::id()]); } fn fields( @@ -50,16 +94,59 @@ where } } -pub struct Without<WithUidT> +pub struct Without<T> +{ + _pd: PhantomData<T>, +} + +impl<'query, ComponentT: Component> Term<'query> for Without<ComponentT> +{ + type Fields = (); + + fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( + terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, + _term_metadata: TermMetadata, + ) + { + terms_builder.absent([ComponentT::id()]); + } + + fn fields( + _world: &'query World, + _search_result: &SearchResult<'query, '_>, + _term_metadata: TermMetadata, + ) -> Self::Fields + { + } +} + +impl<'query, Relation, Target> Term<'query> for Without<Pair<Relation, Target>> where - WithUidT: WithUid, + Relation: Component, + Target: Component, { - _pd: PhantomData<WithUidT>, + type Fields = (); + + fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( + terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, + _term_metadata: TermMetadata, + ) + { + terms_builder.absent([Pair::<Relation, Target>::id()]); + } + + fn fields( + _world: &'query World, + _search_result: &SearchResult<'query, '_>, + _term_metadata: TermMetadata, + ) -> Self::Fields + { + } } -impl<'query, WithUidT> Term<'query> for Without<WithUidT> +impl<'query, Relation> Term<'query> for Without<Pair<Relation, Wildcard>> where - WithUidT: WithUid, + Relation: Component, { type Fields = (); @@ -68,7 +155,7 @@ where _term_metadata: TermMetadata, ) { - terms_builder.absent([WithUidT::uid()]); + terms_builder.absent([Pair::<Relation, Wildcard>::id()]); } fn fields( diff --git a/engine-ecs/src/sole.rs b/engine-ecs/src/sole.rs index 4047b48..9168414 100644 --- a/engine-ecs/src/sole.rs +++ b/engine-ecs/src/sole.rs @@ -4,18 +4,14 @@ use std::fmt::Debug; use crate::component::{ HandleMut as ComponentHandleMut, IntoParts as IntoComponentParts, + WithAssociatedId as ComponentWithAssociatedId, }; use crate::system::{Metadata as SystemMetadata, Param as SystemParam}; -use crate::uid::Uid; use crate::World; /// A component which has a single instance in the [`World`]. -pub trait Sole: Any + IntoComponentParts +pub trait Sole: Any + IntoComponentParts + ComponentWithAssociatedId { - fn id() -> Uid - where - Self: Sized; - fn type_reflection() -> Option<&'static crate::reflection::Type> where Self: Sized; @@ -24,32 +20,6 @@ pub trait Sole: Any + IntoComponentParts fn name(&self) -> &'static str; } -impl dyn Sole -{ - pub fn downcast_mut<Real: 'static>(&mut self) -> Option<&mut Real> - { - (self as &mut dyn Any).downcast_mut() - } - - pub fn downcast_ref<Real: 'static>(&self) -> Option<&Real> - { - (self as &dyn Any).downcast_ref() - } - - pub fn is<Other: 'static>(&self) -> bool - { - (self as &dyn Any).is::<Other>() - } -} - -impl Debug for dyn Sole -{ - fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result - { - formatter.debug_struct("Sole").finish_non_exhaustive() - } -} - /// Holds a reference to a singleton component. #[derive(Debug)] pub struct Single<'world, SoleT: Sole> diff --git a/engine-ecs/src/uid.rs b/engine-ecs/src/uid.rs index 78ca2ad..6b1a4b5 100644 --- a/engine-ecs/src/uid.rs +++ b/engine-ecs/src/uid.rs @@ -1,10 +1,7 @@ use std::fmt::{Debug, Display, Formatter}; use std::sync::atomic::{AtomicU32, Ordering}; -use seq_macro::seq; - -use crate::component::Component; -use crate::util::{gen_mask_64, Array, BitMask, NumberExt}; +use crate::util::{gen_mask_64, BitMask, NumberExt}; static NEXT: AtomicU32 = AtomicU32::new(Uid::FIRST_UNIQUE_ID); @@ -165,43 +162,3 @@ pub struct PairParams pub relation: Uid, pub target: Uid, } - -pub trait With: 'static -{ - fn uid() -> Uid; -} - -impl<ComponentT: Component> With for ComponentT -{ - fn uid() -> Uid - { - Self::id() - } -} - -pub trait WithUidTuple -{ - type UidsArray: Array<Uid>; - - fn uids() -> Self::UidsArray; -} - -macro_rules! impl_with_uid_tuple { - ($c: tt) => { - seq!(I in 0..=$c { - impl<#(WithUid~I: With,)*> WithUidTuple for (#(WithUid~I,)*) - { - type UidsArray = [Uid; $c + 1]; - - fn uids() -> Self::UidsArray - { - [#(WithUid~I::uid(),)*] - } - } - }); - }; -} - -seq!(C in 0..=16 { - impl_with_uid_tuple!(C); -}); diff --git a/engine/src/asset.rs b/engine/src/asset.rs index 31d6e06..e8753bc 100644 --- a/engine/src/asset.rs +++ b/engine/src/asset.rs @@ -332,6 +332,88 @@ impl Assets Some(metadata_lut.get(&id)?.label.clone().into_label()) } + pub fn get_status<AssetT: Asset>(&self, handle: &Handle<AssetT>) -> Status + { + self.get_status_by_id(handle.id()) + } + + pub fn get_status_by_id(&self, asset_id: Id) -> Status + { + let Some(asset_id) = asset_id.into_valid() else { + return Status::NotFound; + }; + + let metadata_lut = self.metadata_lut.borrow(); + + let Some(asset_metadata) = metadata_lut.get(&asset_id) else { + return Status::NotFound; + }; + + let mut is_asset_loading = false; + + match &asset_metadata.state { + AssetState::DependenciesPending { .. } => { + return Status::Pending; + } + AssetState::Failed { reason, .. } => { + return Status::Failed(*reason); + } + AssetState::Ready => { + return Status::Ready; + } + AssetState::Loading => { + // TODO: It might be possible to just return Status::Pending here + // since asset states are propagated to their related assets + is_asset_loading = true; + } + AssetState::NotStored => {} + } + + if matches!(asset_metadata.relation, AssetRelation::Parent { .. }) { + return if is_asset_loading { + Status::Pending + } else { + Status::NotFound + }; + } + + let parent_asset_state = (|| { + let parent_asset_id = match &asset_metadata.relation { + AssetRelation::Child { parent } => *parent, + AssetRelation::Parent { .. } => { + // label.name is Some so the asset can not be a parent + unreachable!() + } + }; + + let parent_asset_metadata = metadata_lut.get(&parent_asset_id)?; + + match &parent_asset_metadata.state { + AssetState::Failed { reason, .. } => Some(Status::Failed(*reason)), + AssetState::Ready + | AssetState::NotStored + | AssetState::Loading + | AssetState::DependenciesPending { .. } => None, + } + })(); + + match parent_asset_state { + Some(Status::Failed(FailureReason::Dependency)) => { + // It would make no sense for a asset's status to be Status::Failed if the + // parent asset has a missing dependency + + if is_asset_loading { + Status::Pending + } else { + Status::NotFound + } + } + Some(parent_asset_state) => parent_asset_state, + None if is_asset_loading => Status::Pending, + None => Status::NotFound, + } + } + pub fn get_status_by_label(&self, label: &Label<'_>) -> Status { let id_lut = self.id_lut.borrow(); diff --git a/engine/src/rendering/backend/opengl.rs b/engine/src/rendering/backend/opengl.rs index 0a04d6e..b8ac04b 100644 --- a/engine/src/rendering/backend/opengl.rs +++ b/engine/src/rendering/backend/opengl.rs @@ -116,11 +116,11 @@ use crate::rendering::shader::cursor::{ BindingLocation as ShaderBindingLocation, BindingValue as ShaderBindingValue, }; +use crate::rendering::shader::reflection::Stage as ShaderStage; use crate::rendering::shader::{ Error as ShaderError, Program as ShaderProgram, ProgramMetadata as ShaderProgramMetadata, - Stage as ShaderStage, }; use crate::rendering::{ AssetOrValue, diff --git a/engine/src/rendering/shader.rs b/engine/src/rendering/shader.rs index 3ba3a41..b357b2c 100644 --- a/engine/src/rendering/shader.rs +++ b/engine/src/rendering/shader.rs @@ -15,10 +15,7 @@ use shader_slang::{ EntryPoint as SlangEntryPoint, GlobalSession as SlangGlobalSession, Module as SlangModule, - ParameterCategory as SlangParameterCategory, - ScalarType as SlangScalarType, Session as SlangSession, - TypeKind as SlangTypeKind, }; use crate::asset::{ @@ -39,6 +36,7 @@ use crate::ecs::{declare_entity, pair, Sole}; use crate::mesh::vertex_buffer::VertexLabel; pub mod cursor; +pub mod reflection; pub const STD_VERT_IN_SEM_NAME_POSITION: &str = "STD_POSITION"; pub const STD_VERT_IN_SEM_NAME_NORMAL: &str = "STD_NORMAL"; @@ -113,68 +111,14 @@ pub struct EntryPoint impl EntryPoint { #[must_use] - pub fn function(&self) -> FunctionReflection<'_> + pub fn function_reflection(&self) -> self::reflection::Function<'_> { - FunctionReflection { + self::reflection::Function { inner: self.inner.function_reflection(), } } } -pub struct FunctionReflection<'a> -{ - inner: &'a shader_slang::reflection::Function, -} - -impl FunctionReflection<'_> -{ - #[must_use] - pub fn name(&self) -> Option<&str> - { - self.inner.name() - } -} - -pub struct EntryPointReflection<'a> -{ - inner: &'a shader_slang::reflection::EntryPoint, -} - -impl<'a> EntryPointReflection<'a> -{ - #[must_use] - pub fn name(&self) -> Option<&str> - { - self.inner.name() - } - - #[must_use] - pub fn name_override(&self) -> Option<&str> - { - self.inner.name_override() - } - - #[must_use] - pub fn stage(&self) -> Stage - { - Stage::from_slang_stage(self.inner.stage()) - } - - #[must_use] - pub fn parameters(&self) -> impl ExactSizeIterator<Item = VariableLayout<'a>> - { - self.inner - .parameters() - .map(|param| VariableLayout { inner: param }) - } - - #[must_use] - pub fn var_layout(&self) -> Option<VariableLayout<'a>> - { - Some(VariableLayout { inner: self.inner.var_layout()? }) - } -} - #[derive(Clone)] pub struct Program { @@ -207,11 +151,12 @@ impl Program Ok(Blob { inner: blob }) } - pub fn reflection(&self, target: u32) -> Result<ProgramReflection<'_>, Error> + pub fn reflection(&self, target: u32) + -> Result<self::reflection::Program<'_>, Error> { let reflection = self.inner.layout(i64::from(target))?; - Ok(ProgramReflection { inner: reflection }) + Ok(self::reflection::Program { inner: reflection }) } } @@ -225,619 +170,6 @@ impl Debug for Program } } -pub struct ProgramReflection<'a> -{ - inner: &'a shader_slang::reflection::Shader, -} - -impl<'a> ProgramReflection<'a> -{ - #[must_use] - pub fn get_entry_point_by_index(&self, index: u32) - -> Option<EntryPointReflection<'a>> - { - Some(EntryPointReflection { - inner: self.inner.entry_point_by_index(index)?, - }) - } - - #[must_use] - pub fn get_entry_point_by_name(&self, name: &str) - -> Option<EntryPointReflection<'a>> - { - Some(EntryPointReflection { - inner: self.inner.find_entry_point_by_name(name)?, - }) - } - - #[must_use] - pub fn entry_points( - &self, - ) -> impl ExactSizeIterator<Item = EntryPointReflection<'a>> + use<'a> - { - self.inner - .entry_points() - .map(|entry_point| EntryPointReflection { inner: entry_point }) - } - - #[must_use] - pub fn global_params_type_layout(&self) -> Option<TypeLayout<'a>> - { - Some(TypeLayout { - inner: self.inner.global_params_type_layout()?, - }) - } - - #[must_use] - pub fn global_params_var_layout(&self) -> Option<VariableLayout<'a>> - { - Some(VariableLayout { - inner: self.inner.global_params_var_layout()?, - }) - } - - #[must_use] - pub fn get_type(&self, name: &str) -> Option<TypeReflection<'a>> - { - Some(TypeReflection { - inner: self.inner.find_type_by_name(name)?, - }) - } - - #[must_use] - pub fn get_type_layout(&self, ty: &TypeReflection<'a>) -> Option<TypeLayout<'a>> - { - Some(TypeLayout { - inner: self - .inner - .type_layout(ty.inner, shader_slang::LayoutRules::Default)?, - }) - } -} - -#[derive(Clone, Copy)] -pub struct VariableLayout<'a> -{ - inner: &'a shader_slang::reflection::VariableLayout, -} - -impl<'a> VariableLayout<'a> -{ - #[must_use] - pub fn name(&self) -> Option<&'a str> - { - self.inner.name() - } - - #[must_use] - pub fn semantic_name(&self) -> Option<&str> - { - self.inner.semantic_name() - } - - #[must_use] - pub fn binding_index(&self) -> u32 - { - self.inner - .offset(shader_slang::ParameterCategory::DescriptorTableSlot) as u32 - - // self.inner.binding_index() - } - - #[must_use] - pub fn varying_input_offset(&self) -> Option<usize> - { - if !self - .inner - .categories() - .any(|category| category == SlangParameterCategory::VaryingInput) - { - return None; - } - - Some(self.inner.offset(SlangParameterCategory::VaryingInput)) - } - - #[must_use] - pub fn binding_space(&self) -> u32 - { - self.inner.binding_space() - } - - #[must_use] - pub fn semantic_index(&self) -> usize - { - self.inner.semantic_index() - } - - #[must_use] - pub fn offset(&self) -> usize - { - self.inner.offset(shader_slang::ParameterCategory::Uniform) - } - - #[must_use] - pub fn ty(&self) -> Option<TypeReflection<'a>> - { - self.inner.ty().map(|ty| TypeReflection { inner: ty }) - } - - #[must_use] - pub fn type_layout(&self) -> Option<TypeLayout<'a>> - { - Some(TypeLayout { inner: self.inner.type_layout()? }) - } -} - -#[derive(Clone, Copy)] -pub struct TypeLayout<'a> -{ - inner: &'a shader_slang::reflection::TypeLayout, -} - -impl<'a> TypeLayout<'a> -{ - #[must_use] - pub fn kind(&self) -> TypeKind - { - TypeKind::from_slang_type_kind(self.inner.kind()) - } - - #[must_use] - pub fn scalar_type(&self) -> Option<ScalarType> - { - Some(ScalarType::from_slang_scalar_type( - self.inner.scalar_type()?, - )) - } - - #[must_use] - pub fn resource_shape(&self) -> Option<ResourceShape> - { - Some(ResourceShape::from_bits_retain( - self.inner.resource_shape()? as u32, - )) - } - - #[must_use] - pub fn get_field_by_name(&self, name: &str) -> Option<VariableLayout<'a>> - { - let index = self.inner.find_field_index_by_name(name); - - if index < 0 { - return None; - } - - let index = u32::try_from(index.cast_unsigned()).expect("Should not happend"); - - let field = self.inner.field_by_index(index)?; - - Some(VariableLayout { inner: field }) - } - - #[must_use] - pub fn parameter_category(&self) -> ParameterCategory - { - ParameterCategory::from_slang_parameter_category(self.inner.parameter_category()) - } - - #[must_use] - pub fn binding_range_descriptor_set_index(&self, index: i64) -> i64 - { - self.inner.binding_range_descriptor_set_index(index) - } - - #[must_use] - pub fn get_field_binding_range_offset_by_name(&self, name: &str) -> Option<u64> - { - let field_index = self.inner.find_field_index_by_name(name); - - if field_index < 0 { - return None; - } - - let field_binding_range_offset = - self.inner.field_binding_range_offset(field_index); - - if field_binding_range_offset < 0 { - return None; - } - - Some(field_binding_range_offset.cast_unsigned()) - } - - #[must_use] - pub fn ty(&self) -> Option<TypeReflection<'a>> - { - self.inner.ty().map(|ty| TypeReflection { inner: ty }) - } - - #[must_use] - pub fn fields(&self) -> FieldIter<'a> - { - FieldIter { - type_layout: *self, - cnt: self.field_cnt(), - index: 0, - } - } - - #[must_use] - pub fn field_cnt(&self) -> u32 - { - self.inner.field_count() - } - - #[must_use] - pub fn element_cnt(&self) -> Option<usize> - { - self.inner.element_count() - } - - #[must_use] - pub fn row_cnt(&self) -> Option<u32> - { - self.inner.row_count() - } - - #[must_use] - pub fn column_cnt(&self) -> Option<u32> - { - self.inner.column_count() - } - - #[must_use] - pub fn element_type_layout(&self) -> Option<TypeLayout<'a>> - { - self.inner - .element_type_layout() - .map(|type_layout| TypeLayout { inner: type_layout }) - } - - #[must_use] - pub fn element_var_layout(&self) -> Option<VariableLayout<'a>> - { - self.inner - .element_var_layout() - .map(|var_layout| VariableLayout { inner: var_layout }) - } - - #[must_use] - pub fn container_var_layout(&self) -> Option<VariableLayout<'a>> - { - self.inner - .container_var_layout() - .map(|var_layout| VariableLayout { inner: var_layout }) - } - - #[must_use] - pub fn uniform_size(&self) -> Option<usize> - { - // tracing::debug!( - // "uniform_size: {:?} categories: {:?}", - // self.inner.name(), - // self.inner.categories().collect::<Vec<_>>(), - // ); - - if !self - .inner - .categories() - .any(|category| category == SlangParameterCategory::Uniform) - { - return None; - } - - // let category = self.inner.categories().next().unwrap(); - - // println!( - // "AARGH size Category: {category:?} Category count: {}", - // self.inner.category_count() - // ); - - // Some(self.inner.size(category)) - - Some(self.inner.size(SlangParameterCategory::Uniform)) - } - - #[must_use] - pub fn stride(&self) -> usize - { - self.inner.stride(self.inner.categories().next().unwrap()) - } -} - -pub struct FieldIter<'a> -{ - type_layout: TypeLayout<'a>, - cnt: u32, - index: u32, -} - -impl<'a> Iterator for FieldIter<'a> -{ - type Item = VariableLayout<'a>; - - fn next(&mut self) -> Option<Self::Item> - { - if self.index == self.cnt { - return None; - } - - let Some(field) = self.type_layout.inner.field_by_index(self.index) else { - unreachable!(); - }; - - self.index += 1; - - Some(VariableLayout { inner: field }) - } - - fn size_hint(&self) -> (usize, Option<usize>) - { - let len = (self.cnt - self.index) as usize; - - (len, Some(len)) - } -} - -impl ExactSizeIterator for FieldIter<'_> -{ - fn len(&self) -> usize - { - (self.cnt - self.index) as usize - } -} - -impl DoubleEndedIterator for FieldIter<'_> -{ - fn next_back(&mut self) -> Option<Self::Item> - { - if self.cnt == 0 || self.index == self.cnt - 1 { - return None; - } - - let Some(field) = self.type_layout.inner.field_by_index(self.cnt - 1) else { - unreachable!(); - }; - - self.cnt -= 1; - - Some(VariableLayout { inner: field }) - } -} - -pub struct TypeReflection<'a> -{ - inner: &'a shader_slang::reflection::Type, -} - -impl TypeReflection<'_> -{ - #[must_use] - pub fn kind(&self) -> TypeKind - { - TypeKind::from_slang_type_kind(self.inner.kind()) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[non_exhaustive] -pub enum TypeKind -{ - None, - Struct, - Enum, - Array, - Matrix, - Vector, - Scalar, - ConstantBuffer, - Resource, - SamplerState, - TextureBuffer, - ShaderStorageBuffer, - ParameterBlock, - GenericTypeParameter, - Interface, - OutputStream, - MeshOutput, - Specialized, - Feedback, - Pointer, - DynamicResource, - Count, -} - -impl TypeKind -{ - fn from_slang_type_kind(type_kind: SlangTypeKind) -> Self - { - match type_kind { - SlangTypeKind::None => Self::None, - SlangTypeKind::Struct => Self::Struct, - SlangTypeKind::Enum => Self::Enum, - SlangTypeKind::Array => Self::Array, - SlangTypeKind::Matrix => Self::Matrix, - SlangTypeKind::Vector => Self::Vector, - SlangTypeKind::Scalar => Self::Scalar, - SlangTypeKind::ConstantBuffer => Self::ConstantBuffer, - SlangTypeKind::Resource => Self::Resource, - SlangTypeKind::SamplerState => Self::SamplerState, - SlangTypeKind::TextureBuffer => Self::TextureBuffer, - SlangTypeKind::ShaderStorageBuffer => Self::ShaderStorageBuffer, - SlangTypeKind::ParameterBlock => Self::ParameterBlock, - SlangTypeKind::GenericTypeParameter => Self::GenericTypeParameter, - SlangTypeKind::Interface => Self::Interface, - SlangTypeKind::OutputStream => Self::OutputStream, - SlangTypeKind::MeshOutput => Self::MeshOutput, - SlangTypeKind::Specialized => Self::Specialized, - SlangTypeKind::Feedback => Self::Feedback, - SlangTypeKind::Pointer => Self::Pointer, - SlangTypeKind::DynamicResource => Self::DynamicResource, - SlangTypeKind::Count => Self::Count, - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[non_exhaustive] -pub enum ScalarType -{ - None, - Void, - Bool, - Int32, - Uint32, - Int64, - Uint64, - Float16, - Float32, - Float64, - Int8, - Uint8, - Int16, - Uint16, - Intptr, - Uintptr, - Bfloat16, - FloatE4m3, - FloatE5m2, -} - -impl ScalarType -{ - fn from_slang_scalar_type(scalar_type: SlangScalarType) -> Self - { - match scalar_type { - SlangScalarType::None => Self::None, - SlangScalarType::Void => Self::Void, - SlangScalarType::Bool => Self::Bool, - SlangScalarType::Int32 => Self::Int32, - SlangScalarType::Uint32 => Self::Uint32, - SlangScalarType::Int64 => Self::Int64, - SlangScalarType::Uint64 => Self::Uint64, - SlangScalarType::Float16 => Self::Float16, - SlangScalarType::Float32 => Self::Float32, - SlangScalarType::Float64 => Self::Float64, - SlangScalarType::Int8 => Self::Int8, - SlangScalarType::Uint8 => Self::Uint8, - SlangScalarType::Int16 => Self::Int16, - SlangScalarType::Uint16 => Self::Uint16, - SlangScalarType::Intptr => Self::Intptr, - SlangScalarType::Uintptr => Self::Uintptr, - SlangScalarType::Bfloat16 => Self::Bfloat16, - SlangScalarType::FloatE4m3 => Self::FloatE4m3, - SlangScalarType::FloatE5m2 => Self::FloatE5m2, - #[allow(unreachable_patterns)] - _ => unimplemented!("conversion from slang scalar type"), - } - } -} - -bitflags! { -#[derive(Debug, Copy, Clone)] -pub struct ResourceShape: u32 { - const BASE = shader_slang::ResourceShape::SlangResourceBaseShapeMask as u32; - const NONE = shader_slang::ResourceShape::SlangResourceNone as u32; - const TEXTURE_1D = shader_slang::ResourceShape::SlangTexture1d as u32; - const TEXTURE_2D = shader_slang::ResourceShape::SlangTexture2d as u32; - const TEXTURE_3D = shader_slang::ResourceShape::SlangTexture3d as u32; - const TEXTURE_CUBE = shader_slang::ResourceShape::SlangTextureCube as u32; - const TEXTURE_BUFFER = shader_slang::ResourceShape::SlangTextureBuffer as u32; - const STRUCTURED_BUFFER = shader_slang::ResourceShape::SlangStructuredBuffer as u32; - const BYTE_ADDRESS_BUFFER = shader_slang::ResourceShape::SlangByteAddressBuffer as u32; - const UNKNOWN = shader_slang::ResourceShape::SlangResourceUnknown as u32; - const ACCELERATION_STRUCTURE = shader_slang::ResourceShape::SlangAccelerationStructure as u32; - const TEXTURE_SUBPASS = shader_slang::ResourceShape::SlangTextureSubpass as u32; - const EXT_SHAPE = shader_slang::ResourceShape::SlangResourceExtShapeMask as u32; - const TEXTURE_FEEDBACK_FLAG = shader_slang::ResourceShape::SlangTextureFeedbackFlag as u32; - const TEXTURE_SHADOW_FLAG = shader_slang::ResourceShape::SlangTextureShadowFlag as u32; - const TEXTURE_ARRAY_FLAG = shader_slang::ResourceShape::SlangTextureArrayFlag as u32; - const TEXTURE_MULTISAMPLE_FLAG = shader_slang::ResourceShape::SlangTextureMultisampleFlag as u32; - const TEXTURE_COMBINED_FLAG = shader_slang::ResourceShape::SlangTextureCombinedFlag as u32; - const TEXTURE_1D_ARRAY = shader_slang::ResourceShape::SlangTexture1dArray as u32; - const TEXTURE_2D_ARRAY = shader_slang::ResourceShape::SlangTexture2dArray as u32; - const TEXTURE_CUBE_ARRAY = shader_slang::ResourceShape::SlangTextureCubeArray as u32; - const TEXTURE_2D_MULTISAMPLE = shader_slang::ResourceShape::SlangTexture2dMultisample as u32; - const TEXTURE_2D_MULTISAMPLE_ARRAY = shader_slang::ResourceShape::SlangTexture2dMultisampleArray as u32; - const TEXTURE_SUBPASS_MULTISAMPLE = shader_slang::ResourceShape::SlangTextureSubpassMultisample as u32; -} -} - -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub enum ParameterCategory -{ - None, - Mixed, - ConstantBuffer, - ShaderResource, - UnorderedAccess, - VaryingInput, - VaryingOutput, - SamplerState, - Uniform, - DescriptorTableSlot, - SpecializationConstant, - PushConstantBuffer, - RegisterSpace, - Generic, - RayPayload, - HitAttributes, - CallablePayload, - ShaderRecord, - ExistentialTypeParam, - ExistentialObjectParam, - SubElementRegisterSpace, - Subpass, - MetalArgumentBufferElement, - MetalAttribute, - MetalPayload, - Count, -} - -impl ParameterCategory -{ - fn from_slang_parameter_category(parameter_category: SlangParameterCategory) -> Self - { - match parameter_category { - SlangParameterCategory::None => Self::None, - SlangParameterCategory::Mixed => Self::Mixed, - SlangParameterCategory::ConstantBuffer => Self::ConstantBuffer, - SlangParameterCategory::ShaderResource => Self::ShaderResource, - SlangParameterCategory::UnorderedAccess => Self::UnorderedAccess, - SlangParameterCategory::VaryingInput => Self::VaryingInput, - SlangParameterCategory::VaryingOutput => Self::VaryingOutput, - SlangParameterCategory::SamplerState => Self::SamplerState, - SlangParameterCategory::Uniform => Self::Uniform, - SlangParameterCategory::DescriptorTableSlot => Self::DescriptorTableSlot, - SlangParameterCategory::SpecializationConstant => { - Self::SpecializationConstant - } - SlangParameterCategory::PushConstantBuffer => Self::PushConstantBuffer, - SlangParameterCategory::RegisterSpace => Self::RegisterSpace, - SlangParameterCategory::Generic => Self::Generic, - SlangParameterCategory::RayPayload => Self::RayPayload, - SlangParameterCategory::HitAttributes => Self::HitAttributes, - SlangParameterCategory::CallablePayload => Self::CallablePayload, - SlangParameterCategory::ShaderRecord => Self::ShaderRecord, - SlangParameterCategory::ExistentialTypeParam => Self::ExistentialTypeParam, - SlangParameterCategory::ExistentialObjectParam => { - Self::ExistentialObjectParam - } - SlangParameterCategory::SubElementRegisterSpace => { - Self::SubElementRegisterSpace - } - SlangParameterCategory::Subpass => Self::Subpass, - SlangParameterCategory::MetalArgumentBufferElement => { - Self::MetalArgumentBufferElement - } - SlangParameterCategory::MetalAttribute => Self::MetalAttribute, - SlangParameterCategory::MetalPayload => Self::MetalPayload, - SlangParameterCategory::Count => Self::Count, - } - } -} - pub struct Blob { inner: SlangBlob, @@ -857,55 +189,6 @@ impl Blob } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[non_exhaustive] -pub enum Stage -{ - None, - Vertex, - Hull, - Domain, - Geometry, - Fragment, - Compute, - RayGeneration, - Intersection, - AnyHit, - ClosestHit, - Miss, - Callable, - Mesh, - Amplification, - Dispatch, - Count, -} - -impl Stage -{ - fn from_slang_stage(stage: shader_slang::Stage) -> Self - { - match stage { - shader_slang::Stage::None => Self::None, - shader_slang::Stage::Vertex => Self::Vertex, - shader_slang::Stage::Hull => Self::Hull, - shader_slang::Stage::Domain => Self::Domain, - shader_slang::Stage::Geometry => Self::Geometry, - shader_slang::Stage::Fragment => Self::Fragment, - shader_slang::Stage::Compute => Self::Compute, - shader_slang::Stage::RayGeneration => Self::RayGeneration, - shader_slang::Stage::Intersection => Self::Intersection, - shader_slang::Stage::AnyHit => Self::AnyHit, - shader_slang::Stage::ClosestHit => Self::ClosestHit, - shader_slang::Stage::Miss => Self::Miss, - shader_slang::Stage::Callable => Self::Callable, - shader_slang::Stage::Mesh => Self::Mesh, - shader_slang::Stage::Amplification => Self::Amplification, - shader_slang::Stage::Dispatch => Self::Dispatch, - shader_slang::Stage::Count => Self::Count, - } - } -} - builder! { #[builder(name = SettingsBuilder, derives=(Debug))] #[derive(Debug)] @@ -982,7 +265,8 @@ impl Context unreachable!(); }; - let program_reflection = ProgramReflection { inner: program_reflection }; + let program_reflection = + self::reflection::Program { inner: program_reflection }; Some(VertexDescription::new( &program_reflection @@ -1020,15 +304,15 @@ impl VertexDescription { #[tracing::instrument(skip_all, fields(vs_entry_point_name = vs_entrypoint.name()))] pub fn new( - vs_entrypoint: &EntryPointReflection<'_>, + vs_entrypoint: &self::reflection::EntryPointReflection<'_>, ) -> Result<Self, VertexDescriptionError> { - if vs_entrypoint.stage() != Stage::Vertex { + if vs_entrypoint.stage() != self::reflection::Stage::Vertex { return Err(VertexDescriptionError::EntrypointNotInVertexStage); } let inputs = VarInputDfsIter::new(vs_entrypoint).inspect(|var_input| { - if var_input.type_layout.kind() != TypeKind::Struct { + if var_input.type_layout.kind() != self::reflection::TypeKind::Struct { return; } @@ -1047,7 +331,9 @@ impl VertexDescription Ok(Self { inputs: inputs - .filter(|var_input| var_input.type_layout.kind() != TypeKind::Struct) + .filter(|var_input| { + var_input.type_layout.kind() != self::reflection::TypeKind::Struct + }) .map(|var_input| { let name = var_input.var_layout.name().unwrap_or("<unnamed>"); @@ -1069,10 +355,15 @@ impl VertexDescription ); } - let (TypeKind::Scalar | TypeKind::Vector, Some(scalar_type)) = ( + let ( + self::reflection::TypeKind::Scalar + | self::reflection::TypeKind::Vector, + Some(scalar_type), + ) = ( var_input.type_layout.kind(), var_input.type_layout.scalar_type(), - ) else { + ) + else { return Err(VertexDescriptionError::UnsupportedVertexInputType { name: name.to_owned(), }); @@ -1099,8 +390,8 @@ pub struct VertexInputDescription { pub semantic_name: VertexInputSemName, pub index: usize, - pub type_kind: TypeKind, - pub scalar_type: ScalarType, + pub type_kind: self::reflection::TypeKind, + pub scalar_type: self::reflection::ScalarType, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -1214,12 +505,16 @@ pub struct Error(#[from] shader_slang::Error); struct VarInputDfsIter<'a> { - stack: Vec<(VariableLayout<'a>, TypeLayout<'a>, usize)>, + stack: Vec<( + self::reflection::VariableLayout<'a>, + self::reflection::TypeLayout<'a>, + usize, + )>, } impl<'a> VarInputDfsIter<'a> { - fn new(entry_point: &EntryPointReflection<'a>) -> Self + fn new(entry_point: &self::reflection::EntryPointReflection<'a>) -> Self { Self { stack: entry_point @@ -1251,7 +546,7 @@ impl<'a> Iterator for VarInputDfsIter<'a> } }; - if type_layout.kind() == TypeKind::Struct { + if type_layout.kind() == self::reflection::TypeKind::Struct { self.stack.extend(type_layout.fields().map(|field| { let Some(field_type_layout) = field.type_layout() else { // I do not know in which cases type_layout can return @@ -1269,8 +564,8 @@ impl<'a> Iterator for VarInputDfsIter<'a> struct VarInput<'a> { - var_layout: VariableLayout<'a>, - type_layout: TypeLayout<'a>, + var_layout: self::reflection::VariableLayout<'a>, + type_layout: self::reflection::TypeLayout<'a>, index: usize, } diff --git a/engine/src/rendering/shader/cursor.rs b/engine/src/rendering/shader/cursor.rs index 24d0135..7750623 100644 --- a/engine/src/rendering/shader/cursor.rs +++ b/engine/src/rendering/shader/cursor.rs @@ -8,7 +8,7 @@ use crate::color::{Color, Rgb, Rgba}; use crate::data_types::matrix::Matrix; use crate::data_types::vector::Vec3; use crate::rendering::object::Id as RenderingObjectId; -use crate::rendering::shader::{ +use crate::rendering::shader::reflection::{ ResourceShape, ScalarType, TypeKind, diff --git a/engine/src/rendering/shader/reflection.rs b/engine/src/rendering/shader/reflection.rs new file mode 100644 index 0000000..c6d9248 --- /dev/null +++ b/engine/src/rendering/shader/reflection.rs @@ -0,0 +1,713 @@ +use bitflags::bitflags; + +pub struct Function<'a> +{ + pub(super) inner: &'a shader_slang::reflection::Function, +} + +impl Function<'_> +{ + #[must_use] + pub fn name(&self) -> Option<&str> + { + self.inner.name() + } +} + +pub struct EntryPointReflection<'a> +{ + inner: &'a shader_slang::reflection::EntryPoint, +} + +impl<'a> EntryPointReflection<'a> +{ + #[must_use] + pub fn name(&self) -> Option<&str> + { + self.inner.name() + } + + #[must_use] + pub fn name_override(&self) -> Option<&str> + { + self.inner.name_override() + } + + #[must_use] + pub fn stage(&self) -> Stage + { + Stage::from_slang_stage(self.inner.stage()) + } + + #[must_use] + pub fn parameters(&self) -> impl ExactSizeIterator<Item = VariableLayout<'a>> + { + self.inner + .parameters() + .map(|param| VariableLayout { inner: param }) + } + + #[must_use] + pub fn var_layout(&self) -> Option<VariableLayout<'a>> + { + Some(VariableLayout { inner: self.inner.var_layout()? }) + } +} + +pub struct Program<'a> +{ + pub(super) inner: &'a shader_slang::reflection::Shader, +} + +impl<'a> Program<'a> +{ + #[must_use] + pub fn get_entry_point_by_index(&self, index: u32) + -> Option<EntryPointReflection<'a>> + { + Some(EntryPointReflection { + inner: self.inner.entry_point_by_index(index)?, + }) + } + + #[must_use] + pub fn get_entry_point_by_name(&self, name: &str) + -> Option<EntryPointReflection<'a>> + { + Some(EntryPointReflection { + inner: self.inner.find_entry_point_by_name(name)?, + }) + } + + #[must_use] + pub fn entry_points( + &self, + ) -> impl ExactSizeIterator<Item = EntryPointReflection<'a>> + use<'a> + { + self.inner + .entry_points() + .map(|entry_point| EntryPointReflection { inner: entry_point }) + } + + #[must_use] + pub fn global_params_type_layout(&self) -> Option<TypeLayout<'a>> + { + Some(TypeLayout { + inner: self.inner.global_params_type_layout()?, + }) + } + + #[must_use] + pub fn global_params_var_layout(&self) -> Option<VariableLayout<'a>> + { + Some(VariableLayout { + inner: self.inner.global_params_var_layout()?, + }) + } + + #[must_use] + pub fn get_type(&self, name: &str) -> Option<TypeReflection<'a>> + { + Some(TypeReflection { + inner: self.inner.find_type_by_name(name)?, + }) + } + + #[must_use] + pub fn get_type_layout(&self, ty: &TypeReflection<'a>) -> Option<TypeLayout<'a>> + { + Some(TypeLayout { + inner: self + .inner + .type_layout(ty.inner, shader_slang::LayoutRules::Default)?, + }) + } +} + +#[derive(Clone, Copy)] +pub struct VariableLayout<'a> +{ + inner: &'a shader_slang::reflection::VariableLayout, +} + +impl<'a> VariableLayout<'a> +{ + #[must_use] + pub fn name(&self) -> Option<&'a str> + { + self.inner.name() + } + + #[must_use] + pub fn semantic_name(&self) -> Option<&str> + { + self.inner.semantic_name() + } + + #[must_use] + pub fn binding_index(&self) -> u32 + { + self.inner + .offset(shader_slang::ParameterCategory::DescriptorTableSlot) as u32 + + // self.inner.binding_index() + } + + #[must_use] + pub fn varying_input_offset(&self) -> Option<usize> + { + if !self + .inner + .categories() + .any(|category| category == shader_slang::ParameterCategory::VaryingInput) + { + return None; + } + + Some( + self.inner + .offset(shader_slang::ParameterCategory::VaryingInput), + ) + } + + #[must_use] + pub fn binding_space(&self) -> u32 + { + self.inner.binding_space() + } + + #[must_use] + pub fn semantic_index(&self) -> usize + { + self.inner.semantic_index() + } + + #[must_use] + pub fn offset(&self) -> usize + { + self.inner.offset(shader_slang::ParameterCategory::Uniform) + } + + #[must_use] + pub fn ty(&self) -> Option<TypeReflection<'a>> + { + self.inner.ty().map(|ty| TypeReflection { inner: ty }) + } + + #[must_use] + pub fn type_layout(&self) -> Option<TypeLayout<'a>> + { + Some(TypeLayout { inner: self.inner.type_layout()? }) + } +} + +#[derive(Clone, Copy)] +pub struct TypeLayout<'a> +{ + inner: &'a shader_slang::reflection::TypeLayout, +} + +impl<'a> TypeLayout<'a> +{ + #[must_use] + pub fn kind(&self) -> TypeKind + { + TypeKind::from_slang_type_kind(self.inner.kind()) + } + + #[must_use] + pub fn scalar_type(&self) -> Option<ScalarType> + { + Some(ScalarType::from_slang_scalar_type( + self.inner.scalar_type()?, + )) + } + + #[must_use] + pub fn resource_shape(&self) -> Option<ResourceShape> + { + Some(ResourceShape::from_bits_retain( + self.inner.resource_shape()? as u32, + )) + } + + #[must_use] + pub fn get_field_by_name(&self, name: &str) -> Option<VariableLayout<'a>> + { + let index = self.inner.find_field_index_by_name(name); + + if index < 0 { + return None; + } + + let index = u32::try_from(index.cast_unsigned()).expect("Should not happend"); + + let field = self.inner.field_by_index(index)?; + + Some(VariableLayout { inner: field }) + } + + #[must_use] + pub fn parameter_category(&self) -> ParameterCategory + { + ParameterCategory::from_slang_parameter_category(self.inner.parameter_category()) + } + + #[must_use] + pub fn binding_range_descriptor_set_index(&self, index: i64) -> i64 + { + self.inner.binding_range_descriptor_set_index(index) + } + + #[must_use] + pub fn get_field_binding_range_offset_by_name(&self, name: &str) -> Option<u64> + { + let field_index = self.inner.find_field_index_by_name(name); + + if field_index < 0 { + return None; + } + + let field_binding_range_offset = + self.inner.field_binding_range_offset(field_index); + + if field_binding_range_offset < 0 { + return None; + } + + Some(field_binding_range_offset.cast_unsigned()) + } + + #[must_use] + pub fn ty(&self) -> Option<TypeReflection<'a>> + { + self.inner.ty().map(|ty| TypeReflection { inner: ty }) + } + + #[must_use] + pub fn fields(&self) -> FieldIter<'a> + { + FieldIter { + type_layout: *self, + cnt: self.field_cnt(), + index: 0, + } + } + + #[must_use] + pub fn field_cnt(&self) -> u32 + { + self.inner.field_count() + } + + #[must_use] + pub fn element_cnt(&self) -> Option<usize> + { + self.inner.element_count() + } + + #[must_use] + pub fn row_cnt(&self) -> Option<u32> + { + self.inner.row_count() + } + + #[must_use] + pub fn column_cnt(&self) -> Option<u32> + { + self.inner.column_count() + } + + #[must_use] + pub fn element_type_layout(&self) -> Option<TypeLayout<'a>> + { + self.inner + .element_type_layout() + .map(|type_layout| TypeLayout { inner: type_layout }) + } + + #[must_use] + pub fn element_var_layout(&self) -> Option<VariableLayout<'a>> + { + self.inner + .element_var_layout() + .map(|var_layout| VariableLayout { inner: var_layout }) + } + + #[must_use] + pub fn container_var_layout(&self) -> Option<VariableLayout<'a>> + { + self.inner + .container_var_layout() + .map(|var_layout| VariableLayout { inner: var_layout }) + } + + #[must_use] + pub fn uniform_size(&self) -> Option<usize> + { + if !self + .inner + .categories() + .any(|category| category == shader_slang::ParameterCategory::Uniform) + { + return None; + } + + Some(self.inner.size(shader_slang::ParameterCategory::Uniform)) + } + + #[must_use] + pub fn stride(&self) -> usize + { + self.inner.stride(self.inner.categories().next().unwrap()) + } +} + +pub struct FieldIter<'a> +{ + type_layout: TypeLayout<'a>, + cnt: u32, + index: u32, +} + +impl<'a> Iterator for FieldIter<'a> +{ + type Item = VariableLayout<'a>; + + fn next(&mut self) -> Option<Self::Item> + { + if self.index == self.cnt { + return None; + } + + let Some(field) = self.type_layout.inner.field_by_index(self.index) else { + unreachable!(); + }; + + self.index += 1; + + Some(VariableLayout { inner: field }) + } + + fn size_hint(&self) -> (usize, Option<usize>) + { + let len = (self.cnt - self.index) as usize; + + (len, Some(len)) + } +} + +impl ExactSizeIterator for FieldIter<'_> +{ + fn len(&self) -> usize + { + (self.cnt - self.index) as usize + } +} + +impl DoubleEndedIterator for FieldIter<'_> +{ + fn next_back(&mut self) -> Option<Self::Item> + { + if self.cnt == 0 || self.index == self.cnt - 1 { + return None; + } + + let Some(field) = self.type_layout.inner.field_by_index(self.cnt - 1) else { + unreachable!(); + }; + + self.cnt -= 1; + + Some(VariableLayout { inner: field }) + } +} + +pub struct TypeReflection<'a> +{ + inner: &'a shader_slang::reflection::Type, +} + +impl TypeReflection<'_> +{ + #[must_use] + pub fn kind(&self) -> TypeKind + { + TypeKind::from_slang_type_kind(self.inner.kind()) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[non_exhaustive] +pub enum TypeKind +{ + None, + Struct, + Enum, + Array, + Matrix, + Vector, + Scalar, + ConstantBuffer, + Resource, + SamplerState, + TextureBuffer, + ShaderStorageBuffer, + ParameterBlock, + GenericTypeParameter, + Interface, + OutputStream, + MeshOutput, + Specialized, + Feedback, + Pointer, + DynamicResource, + Count, +} + +impl TypeKind +{ + fn from_slang_type_kind(type_kind: shader_slang::TypeKind) -> Self + { + match type_kind { + shader_slang::TypeKind::None => Self::None, + shader_slang::TypeKind::Struct => Self::Struct, + shader_slang::TypeKind::Enum => Self::Enum, + shader_slang::TypeKind::Array => Self::Array, + shader_slang::TypeKind::Matrix => Self::Matrix, + shader_slang::TypeKind::Vector => Self::Vector, + shader_slang::TypeKind::Scalar => Self::Scalar, + shader_slang::TypeKind::ConstantBuffer => Self::ConstantBuffer, + shader_slang::TypeKind::Resource => Self::Resource, + shader_slang::TypeKind::SamplerState => Self::SamplerState, + shader_slang::TypeKind::TextureBuffer => Self::TextureBuffer, + shader_slang::TypeKind::ShaderStorageBuffer => Self::ShaderStorageBuffer, + shader_slang::TypeKind::ParameterBlock => Self::ParameterBlock, + shader_slang::TypeKind::GenericTypeParameter => Self::GenericTypeParameter, + shader_slang::TypeKind::Interface => Self::Interface, + shader_slang::TypeKind::OutputStream => Self::OutputStream, + shader_slang::TypeKind::MeshOutput => Self::MeshOutput, + shader_slang::TypeKind::Specialized => Self::Specialized, + shader_slang::TypeKind::Feedback => Self::Feedback, + shader_slang::TypeKind::Pointer => Self::Pointer, + shader_slang::TypeKind::DynamicResource => Self::DynamicResource, + shader_slang::TypeKind::Count => Self::Count, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[non_exhaustive] +pub enum ScalarType +{ + None, + Void, + Bool, + Int32, + Uint32, + Int64, + Uint64, + Float16, + Float32, + Float64, + Int8, + Uint8, + Int16, + Uint16, + Intptr, + Uintptr, + Bfloat16, + FloatE4m3, + FloatE5m2, +} + +impl ScalarType +{ + fn from_slang_scalar_type(scalar_type: shader_slang::ScalarType) -> Self + { + match scalar_type { + shader_slang::ScalarType::None => Self::None, + shader_slang::ScalarType::Void => Self::Void, + shader_slang::ScalarType::Bool => Self::Bool, + shader_slang::ScalarType::Int32 => Self::Int32, + shader_slang::ScalarType::Uint32 => Self::Uint32, + shader_slang::ScalarType::Int64 => Self::Int64, + shader_slang::ScalarType::Uint64 => Self::Uint64, + shader_slang::ScalarType::Float16 => Self::Float16, + shader_slang::ScalarType::Float32 => Self::Float32, + shader_slang::ScalarType::Float64 => Self::Float64, + shader_slang::ScalarType::Int8 => Self::Int8, + shader_slang::ScalarType::Uint8 => Self::Uint8, + shader_slang::ScalarType::Int16 => Self::Int16, + shader_slang::ScalarType::Uint16 => Self::Uint16, + shader_slang::ScalarType::Intptr => Self::Intptr, + shader_slang::ScalarType::Uintptr => Self::Uintptr, + shader_slang::ScalarType::Bfloat16 => Self::Bfloat16, + shader_slang::ScalarType::FloatE4m3 => Self::FloatE4m3, + shader_slang::ScalarType::FloatE5m2 => Self::FloatE5m2, + #[allow(unreachable_patterns)] + _ => unimplemented!("conversion from slang scalar type"), + } + } +} + +bitflags! { +#[derive(Debug, Copy, Clone)] +pub struct ResourceShape: u32 { + const BASE = shader_slang::ResourceShape::SlangResourceBaseShapeMask as u32; + const NONE = shader_slang::ResourceShape::SlangResourceNone as u32; + const TEXTURE_1D = shader_slang::ResourceShape::SlangTexture1d as u32; + const TEXTURE_2D = shader_slang::ResourceShape::SlangTexture2d as u32; + const TEXTURE_3D = shader_slang::ResourceShape::SlangTexture3d as u32; + const TEXTURE_CUBE = shader_slang::ResourceShape::SlangTextureCube as u32; + const TEXTURE_BUFFER = shader_slang::ResourceShape::SlangTextureBuffer as u32; + const STRUCTURED_BUFFER = shader_slang::ResourceShape::SlangStructuredBuffer as u32; + const BYTE_ADDRESS_BUFFER = shader_slang::ResourceShape::SlangByteAddressBuffer as u32; + const UNKNOWN = shader_slang::ResourceShape::SlangResourceUnknown as u32; + const ACCELERATION_STRUCTURE = shader_slang::ResourceShape::SlangAccelerationStructure as u32; + const TEXTURE_SUBPASS = shader_slang::ResourceShape::SlangTextureSubpass as u32; + const EXT_SHAPE = shader_slang::ResourceShape::SlangResourceExtShapeMask as u32; + const TEXTURE_FEEDBACK_FLAG = shader_slang::ResourceShape::SlangTextureFeedbackFlag as u32; + const TEXTURE_SHADOW_FLAG = shader_slang::ResourceShape::SlangTextureShadowFlag as u32; + const TEXTURE_ARRAY_FLAG = shader_slang::ResourceShape::SlangTextureArrayFlag as u32; + const TEXTURE_MULTISAMPLE_FLAG = shader_slang::ResourceShape::SlangTextureMultisampleFlag as u32; + const TEXTURE_COMBINED_FLAG = shader_slang::ResourceShape::SlangTextureCombinedFlag as u32; + const TEXTURE_1D_ARRAY = shader_slang::ResourceShape::SlangTexture1dArray as u32; + const TEXTURE_2D_ARRAY = shader_slang::ResourceShape::SlangTexture2dArray as u32; + const TEXTURE_CUBE_ARRAY = shader_slang::ResourceShape::SlangTextureCubeArray as u32; + const TEXTURE_2D_MULTISAMPLE = shader_slang::ResourceShape::SlangTexture2dMultisample as u32; + const TEXTURE_2D_MULTISAMPLE_ARRAY = shader_slang::ResourceShape::SlangTexture2dMultisampleArray as u32; + const TEXTURE_SUBPASS_MULTISAMPLE = shader_slang::ResourceShape::SlangTextureSubpassMultisample as u32; +} +} + +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum ParameterCategory +{ + None, + Mixed, + ConstantBuffer, + ShaderResource, + UnorderedAccess, + VaryingInput, + VaryingOutput, + SamplerState, + Uniform, + DescriptorTableSlot, + SpecializationConstant, + PushConstantBuffer, + RegisterSpace, + Generic, + RayPayload, + HitAttributes, + CallablePayload, + ShaderRecord, + ExistentialTypeParam, + ExistentialObjectParam, + SubElementRegisterSpace, + Subpass, + MetalArgumentBufferElement, + MetalAttribute, + MetalPayload, + Count, +} + +impl ParameterCategory +{ + fn from_slang_parameter_category( + parameter_category: shader_slang::ParameterCategory, + ) -> Self + { + match parameter_category { + shader_slang::ParameterCategory::None => Self::None, + shader_slang::ParameterCategory::Mixed => Self::Mixed, + shader_slang::ParameterCategory::ConstantBuffer => Self::ConstantBuffer, + shader_slang::ParameterCategory::ShaderResource => Self::ShaderResource, + shader_slang::ParameterCategory::UnorderedAccess => Self::UnorderedAccess, + shader_slang::ParameterCategory::VaryingInput => Self::VaryingInput, + shader_slang::ParameterCategory::VaryingOutput => Self::VaryingOutput, + shader_slang::ParameterCategory::SamplerState => Self::SamplerState, + shader_slang::ParameterCategory::Uniform => Self::Uniform, + shader_slang::ParameterCategory::DescriptorTableSlot => { + Self::DescriptorTableSlot + } + shader_slang::ParameterCategory::SpecializationConstant => { + Self::SpecializationConstant + } + shader_slang::ParameterCategory::PushConstantBuffer => { + Self::PushConstantBuffer + } + shader_slang::ParameterCategory::RegisterSpace => Self::RegisterSpace, + shader_slang::ParameterCategory::Generic => Self::Generic, + shader_slang::ParameterCategory::RayPayload => Self::RayPayload, + shader_slang::ParameterCategory::HitAttributes => Self::HitAttributes, + shader_slang::ParameterCategory::CallablePayload => Self::CallablePayload, + shader_slang::ParameterCategory::ShaderRecord => Self::ShaderRecord, + shader_slang::ParameterCategory::ExistentialTypeParam => { + Self::ExistentialTypeParam + } + shader_slang::ParameterCategory::ExistentialObjectParam => { + Self::ExistentialObjectParam + } + shader_slang::ParameterCategory::SubElementRegisterSpace => { + Self::SubElementRegisterSpace + } + shader_slang::ParameterCategory::Subpass => Self::Subpass, + shader_slang::ParameterCategory::MetalArgumentBufferElement => { + Self::MetalArgumentBufferElement + } + shader_slang::ParameterCategory::MetalAttribute => Self::MetalAttribute, + shader_slang::ParameterCategory::MetalPayload => Self::MetalPayload, + shader_slang::ParameterCategory::Count => Self::Count, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[non_exhaustive] +pub enum Stage +{ + None, + Vertex, + Hull, + Domain, + Geometry, + Fragment, + Compute, + RayGeneration, + Intersection, + AnyHit, + ClosestHit, + Miss, + Callable, + Mesh, + Amplification, + Dispatch, + Count, +} + +impl Stage +{ + fn from_slang_stage(stage: shader_slang::Stage) -> Self + { + match stage { + shader_slang::Stage::None => Self::None, + shader_slang::Stage::Vertex => Self::Vertex, + shader_slang::Stage::Hull => Self::Hull, + shader_slang::Stage::Domain => Self::Domain, + shader_slang::Stage::Geometry => Self::Geometry, + shader_slang::Stage::Fragment => Self::Fragment, + shader_slang::Stage::Compute => Self::Compute, + shader_slang::Stage::RayGeneration => Self::RayGeneration, + shader_slang::Stage::Intersection => Self::Intersection, + shader_slang::Stage::AnyHit => Self::AnyHit, + shader_slang::Stage::ClosestHit => Self::ClosestHit, + shader_slang::Stage::Miss => Self::Miss, + shader_slang::Stage::Callable => Self::Callable, + shader_slang::Stage::Mesh => Self::Mesh, + shader_slang::Stage::Amplification => Self::Amplification, + shader_slang::Stage::Dispatch => Self::Dispatch, + shader_slang::Stage::Count => Self::Count, + } + } +} diff --git a/engine/src/ui/dear_imgui.rs b/engine/src/ui/dear_imgui.rs index 0047394..349cf6c 100644 --- a/engine/src/ui/dear_imgui.rs +++ b/engine/src/ui/dear_imgui.rs @@ -9,7 +9,6 @@ use dear_imgui_rs::{ MouseButton as ImguiMouseButton, }; use ecs::component::local::Local; -use ecs::component::Component; use ecs::error::Context as _; use ecs::event::component::{Changed, EventMatchExt}; use ecs::pair::Pair; @@ -211,7 +210,7 @@ fn handle_window_changed( let Some(event_match) = observe .iter() - .find(|event_match| event_match.get_entity().has_component(TargetWindow::id())) + .find(|event_match| event_match.get_entity().has_component::<TargetWindow>()) else { return; }; diff --git a/engine/src/windowing.rs b/engine/src/windowing.rs index 3e27075..b76d942 100644 --- a/engine/src/windowing.rs +++ b/engine/src/windowing.rs @@ -23,7 +23,6 @@ use winit::keyboard::PhysicalKey; use winit::window::{Window as WinitWindow, WindowId as WinitWindowId}; use crate::ecs::actions::Actions; -use crate::ecs::component::Component; use crate::ecs::event::component::{Added, Changed, EventMatchExt, Removed}; use crate::ecs::pair::{ChildOf, Pair}; use crate::ecs::phase::{Phase, PRE_UPDATE as PRE_UPDATE_PHASE}; @@ -90,7 +89,7 @@ impl crate::ecs::extension::Extension for Extension collector.spawn_declared_entity(&PHASE); - collector.add_system(*PHASE, update_stuff); + collector.add_system(*PHASE, update); collector.add_observer(handle_window_changed); collector.add_observer(handle_window_removed); @@ -112,7 +111,7 @@ fn handle_window_creation_ready( unreachable!(); }; - if ent.has_component(Window::id()) || ent.has_component(WindowClosed::id()) { + if ent.has_component::<Window>() || ent.has_component::<WindowClosed>() { continue; } @@ -128,7 +127,7 @@ fn handle_window_creation_ready( } #[tracing::instrument(skip_all)] -fn update_stuff( +fn update( mut context: Single<Context>, mut keyboard: Single<Keyboard>, mut mouse: Single<Mouse>, @@ -153,7 +152,7 @@ fn update_stuff( update_inputs(context, keyboard, mouse, mouse_buttons); - receive_app_messages(context, &mut actions, world); + handle_app_messages(context, &mut actions, world); if context.shared_state.thread_panicked.load(Ordering::Relaxed) { cold_path(); @@ -181,7 +180,7 @@ fn update_stuff( Ok(()) } -fn receive_app_messages(context: &mut Context, actions: &mut Actions, world: &World) +fn handle_app_messages(context: &mut Context, actions: &mut Actions, world: &World) { let Context { ref mut windows, ref shared_state, .. |
