use crate::asset::Handle as AssetHandle; use crate::image::Image; use crate::matrix::Matrix; use crate::shader::{TypeKind, TypeLayout, VariableLayout}; use crate::vector::Vec3; /// Shader cursor #[derive(Clone)] pub struct Cursor<'a> { type_layout: TypeLayout<'a>, binding_location: BindingLocation, } impl<'a> Cursor<'a> { pub fn new(var_layout: VariableLayout<'a>) -> Self { let binding_location = BindingLocation { binding_index: var_layout.binding_index(), binding_size: 0, byte_offset: var_layout.offset(), }; Self { type_layout: var_layout.type_layout().unwrap(), binding_location, } } pub fn field(&self, name: &str) -> Self { let Some(field_var_layout) = self.type_layout.get_field_by_name(name) else { panic!("Field '{name}' does not exist"); }; let field_type_kind = field_var_layout.ty().unwrap().kind(); let field_var_layout = match field_type_kind { TypeKind::ConstantBuffer => field_var_layout .type_layout() .expect("Constant buffer field has no type layout") .element_var_layout() .expect("Constant buffer field type layout has no element var layout"), TypeKind::Array | TypeKind::Matrix | TypeKind::Scalar | TypeKind::Vector | TypeKind::Struct | TypeKind::Resource => field_var_layout, type_kind => unimplemented!("Type kind {type_kind:?} is not yet supported"), }; Self { type_layout: field_var_layout.type_layout().unwrap(), binding_location: BindingLocation { binding_index: self.binding_location.binding_index + field_var_layout.binding_index(), binding_size: if field_type_kind == TypeKind::ConstantBuffer { field_var_layout .type_layout() .unwrap() .uniform_size() .unwrap() } else { self.binding_location.binding_size }, byte_offset: self.binding_location.byte_offset + field_var_layout.offset(), }, } } pub fn element(mut self, index: usize) -> Self { let element_type_layout = self.type_layout.element_type_layout().unwrap(); self.binding_location.byte_offset += index * element_type_layout.stride(); self.type_layout = element_type_layout; self } pub fn with_field(self, name: &str, func: impl FnOnce(Self) -> Self) -> Self { let _ = func(self.field(name)); self } pub fn binding_location(&self) -> &BindingLocation { &self.binding_location } pub fn into_binding_location(self) -> BindingLocation { self.binding_location } } #[derive(Debug, Clone)] pub struct BindingLocation { pub binding_index: u32, pub binding_size: usize, pub byte_offset: usize, } #[derive(Debug, Clone)] pub enum BindingValue { Uint(u32), Int(i32), Float(f32), FVec3(Vec3), FMat4x4(Matrix), Texture(AssetHandle), } impl From for BindingValue { fn from(value: u32) -> Self { BindingValue::Uint(value) } } impl From for BindingValue { fn from(value: i32) -> Self { BindingValue::Int(value) } } impl From for BindingValue { fn from(value: f32) -> Self { BindingValue::Float(value) } } impl From> for BindingValue { fn from(vec: Vec3) -> Self { BindingValue::FVec3(vec) } } impl From> for BindingValue { fn from(matrix: Matrix) -> Self { BindingValue::FMat4x4(matrix) } }