use super::error::{AwsmMeshError, Result};
use awsm_renderer_core::pipeline::vertex::VertexFormat;
use slotmap::new_key_type;
pub struct MeshBufferInfos {
infos: slotmap::SlotMap<MeshBufferInfoKey, MeshBufferInfo>,
}
impl Default for MeshBufferInfos {
fn default() -> Self {
Self::new()
}
}
impl MeshBufferInfos {
pub fn new() -> Self {
Self {
infos: slotmap::SlotMap::with_key(),
}
}
pub fn insert(&mut self, info: MeshBufferInfo) -> MeshBufferInfoKey {
self.infos.insert(info)
}
pub fn get(&self, key: MeshBufferInfoKey) -> Result<&MeshBufferInfo> {
self.infos
.get(key)
.ok_or(AwsmMeshError::BufferInfoNotFound(key))
}
pub fn remove(&mut self, key: MeshBufferInfoKey) -> Option<MeshBufferInfo> {
self.infos.remove(key)
}
}
#[derive(Debug, Clone)]
pub struct MeshBufferInfo {
pub visibility_geometry_vertex: Option<MeshBufferVertexInfo>,
pub transparency_geometry_vertex: Option<MeshBufferVertexInfo>,
pub triangles: MeshBufferTriangleInfo,
pub geometry_morph: Option<MeshBufferGeometryMorphInfo>,
pub material_morph: Option<MeshBufferMaterialMorphInfo>,
pub skin: Option<MeshBufferSkinInfo>,
}
#[derive(Debug, Clone)]
pub struct MeshBufferVertexInfo {
pub count: usize,
}
impl MeshBufferVertexInfo {
pub const VISIBILITY_GEOMETRY_BYTE_SIZE: usize = 56;
pub const TRANSPARENCY_GEOMETRY_BYTE_SIZE: usize = 40;
pub const INSTANCING_BYTE_SIZE: usize = 64;
pub fn checked_visibility_geometry_size(&self) -> Option<usize> {
self.count.checked_mul(Self::VISIBILITY_GEOMETRY_BYTE_SIZE)
}
pub fn visibility_geometry_size(&self) -> usize {
self.checked_visibility_geometry_size()
.expect("visibility geometry size overflow")
}
pub fn checked_transparency_geometry_size(&self) -> Option<usize> {
self.count
.checked_mul(Self::TRANSPARENCY_GEOMETRY_BYTE_SIZE)
}
pub fn transparency_geometry_size(&self) -> usize {
self.checked_transparency_geometry_size()
.expect("transparency geometry size overflow")
}
}
#[derive(Debug, Clone)]
pub struct MeshBufferTriangleInfo {
pub count: usize,
pub vertex_attribute_indices: MeshBufferAttributeIndexInfo,
pub vertex_attributes: Vec<MeshBufferVertexAttributeInfo>,
pub vertex_attributes_size: usize,
pub triangle_data: MeshBufferTriangleDataInfo,
}
impl MeshBufferTriangleInfo {
pub fn vertex_attribute_stride(&self) -> usize {
self.vertex_attributes
.iter()
.map(|attr| attr.vertex_size())
.sum()
}
pub fn debug_get_attribute_vec_f32(
&self,
info: &MeshBufferVertexAttributeInfo,
data: &[u8],
) -> Vec<Vec<f32>> {
let mut out = Vec::new();
let mut offset = 0;
while offset < data.len() {
for attr in &self.vertex_attributes {
if std::mem::discriminant(attr) == std::mem::discriminant(info) {
let attr_data = &data[offset..offset + attr.vertex_size()];
let mut values = Vec::new();
for value in
attr_data
.chunks(attr.data_size())
.map(|chunk| match attr.data_size() {
1 => chunk[0] as f32,
2 => u16::from_le_bytes(chunk.try_into().unwrap()) as f32,
4 => f32::from_le_bytes(chunk.try_into().unwrap()),
_ => {
panic!("Unsupported vertex attribute data size for debugging")
}
})
{
values.push(value);
}
out.push(values);
}
offset += attr.vertex_size();
}
}
out
}
}
#[derive(Debug, Clone)]
pub struct MeshBufferAttributeIndexInfo {
pub count: usize,
}
impl MeshBufferAttributeIndexInfo {
pub fn debug_to_vec(&self, data: &[u8]) -> Vec<Vec<usize>> {
data.chunks(12)
.map(|chunk| {
chunk
.chunks(4)
.map(|c| u32::from_le_bytes(c.try_into().unwrap()) as usize)
.collect()
})
.collect()
}
}
impl MeshBufferAttributeIndexInfo {
pub fn total_size(&self) -> usize {
self.count * 4 }
}
#[derive(Debug, Clone)]
pub struct MeshBufferTriangleDataInfo {
pub size_per_triangle: usize,
pub total_size: usize,
}
#[derive(Debug, Clone)]
pub struct MeshBufferGeometryMorphInfo {
pub targets_len: usize,
pub vertex_stride_size: usize, pub values_size: usize,
}
#[derive(Debug, Clone)]
pub struct MeshBufferMaterialMorphInfo {
pub attributes: MeshBufferMaterialMorphAttributes, pub targets_len: usize,
pub vertex_stride_size: usize, pub values_size: usize,
}
#[derive(Hash, Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct MeshBufferMaterialMorphAttributes {
pub normal: bool,
pub tangent: bool,
}
#[derive(Debug, Clone)]
pub struct MeshBufferSkinInfo {
pub set_count: usize,
pub index_weights_size: usize, }
impl MeshBufferInfo {
pub fn triangle_count(&self) -> usize {
self.triangles.count
}
pub fn has_vertex_attribute(&self, attr: &MeshBufferVertexAttributeInfo) -> bool {
self.triangles
.vertex_attributes
.iter()
.any(|a| a.variant_equals(attr))
}
}
#[derive(Hash, Debug, Clone, Copy, PartialEq, Eq)]
pub enum MeshBufferVisibilityVertexAttributeInfo {
Positions {
data_size: usize,
component_len: usize,
},
Normals {
data_size: usize,
component_len: usize,
},
Tangents {
data_size: usize,
component_len: usize,
},
}
impl MeshBufferVisibilityVertexAttributeInfo {
pub fn vertex_size(&self) -> usize {
match self {
MeshBufferVisibilityVertexAttributeInfo::Positions {
component_len,
data_size,
} => *component_len * *data_size,
MeshBufferVisibilityVertexAttributeInfo::Normals {
component_len,
data_size,
} => *component_len * *data_size,
MeshBufferVisibilityVertexAttributeInfo::Tangents {
component_len,
data_size,
} => *component_len * *data_size,
}
}
}
#[derive(Hash, Debug, Clone, Copy, PartialEq, Eq)]
pub enum MeshBufferCustomVertexAttributeInfo {
Colors {
index: u32,
data_size: usize,
component_len: usize,
},
TexCoords {
index: u32,
data_size: usize,
component_len: usize,
},
}
impl MeshBufferCustomVertexAttributeInfo {
pub fn vertex_format(&self) -> VertexFormat {
match self {
MeshBufferCustomVertexAttributeInfo::Colors { component_len, .. } => {
match component_len {
4 => VertexFormat::Float32x4,
3 => VertexFormat::Float32x3,
2 => VertexFormat::Float32x2,
1 => VertexFormat::Unorm8x4, _ => panic!("Unsupported color attribute component length"),
}
}
MeshBufferCustomVertexAttributeInfo::TexCoords { component_len, .. } => {
match component_len {
2 => VertexFormat::Float32x2,
3 => VertexFormat::Float32x3,
4 => VertexFormat::Float32x4,
_ => panic!("Unsupported texcoord attribute component length"),
}
}
}
}
pub fn vertex_size(&self) -> usize {
match self {
MeshBufferCustomVertexAttributeInfo::Colors {
component_len,
data_size,
index: _,
} => *component_len * *data_size,
MeshBufferCustomVertexAttributeInfo::TexCoords {
component_len,
data_size,
index: _,
} => *component_len * *data_size,
}
}
}
#[derive(Hash, Debug, Clone, Copy, PartialEq, Eq)]
pub enum MeshBufferVertexAttributeInfo {
Visibility(MeshBufferVisibilityVertexAttributeInfo),
Custom(MeshBufferCustomVertexAttributeInfo),
}
impl MeshBufferVertexAttributeInfo {
pub fn variant_equals(&self, other: &Self) -> bool {
match self {
MeshBufferVertexAttributeInfo::Visibility(vis_self) => match other {
MeshBufferVertexAttributeInfo::Visibility(vis_other) => {
std::mem::discriminant(vis_self) == std::mem::discriminant(vis_other)
}
_ => false,
},
MeshBufferVertexAttributeInfo::Custom(custom_self) => match other {
MeshBufferVertexAttributeInfo::Custom(custom_other) => {
std::mem::discriminant(custom_self) == std::mem::discriminant(custom_other)
}
_ => false,
},
}
}
}
impl MeshBufferVertexAttributeInfo {
pub fn is_visibility_attribute(&self) -> bool {
matches!(self, MeshBufferVertexAttributeInfo::Visibility(_))
}
pub fn is_custom_attribute(&self) -> bool {
matches!(self, MeshBufferVertexAttributeInfo::Custom(_))
}
fn primary_val(&self) -> usize {
match self {
MeshBufferVertexAttributeInfo::Visibility(vis) => match vis {
MeshBufferVisibilityVertexAttributeInfo::Positions { .. } => 0,
MeshBufferVisibilityVertexAttributeInfo::Normals { .. } => 1,
MeshBufferVisibilityVertexAttributeInfo::Tangents { .. } => 2,
},
MeshBufferVertexAttributeInfo::Custom(custom) => match custom {
MeshBufferCustomVertexAttributeInfo::Colors { .. } => 3,
MeshBufferCustomVertexAttributeInfo::TexCoords { .. } => 4,
},
}
}
fn secondary_val(&self) -> u32 {
match self {
MeshBufferVertexAttributeInfo::Visibility(_) => 0,
MeshBufferVertexAttributeInfo::Custom(custom) => match custom {
MeshBufferCustomVertexAttributeInfo::Colors { index, .. } => *index,
MeshBufferCustomVertexAttributeInfo::TexCoords { index, .. } => *index,
},
}
}
pub fn force_data_size(&mut self, new_size: usize) {
match self {
MeshBufferVertexAttributeInfo::Visibility(vis) => match vis {
MeshBufferVisibilityVertexAttributeInfo::Positions { data_size, .. } => {
*data_size = new_size
}
MeshBufferVisibilityVertexAttributeInfo::Normals { data_size, .. } => {
*data_size = new_size
}
MeshBufferVisibilityVertexAttributeInfo::Tangents { data_size, .. } => {
*data_size = new_size
}
},
MeshBufferVertexAttributeInfo::Custom(custom) => match custom {
MeshBufferCustomVertexAttributeInfo::Colors { data_size, .. } => {
*data_size = new_size
}
MeshBufferCustomVertexAttributeInfo::TexCoords { data_size, .. } => {
*data_size = new_size
}
},
}
}
pub fn data_size(&self) -> usize {
match self {
MeshBufferVertexAttributeInfo::Visibility(vis) => match vis {
MeshBufferVisibilityVertexAttributeInfo::Positions { data_size, .. } => *data_size,
MeshBufferVisibilityVertexAttributeInfo::Normals { data_size, .. } => *data_size,
MeshBufferVisibilityVertexAttributeInfo::Tangents { data_size, .. } => *data_size,
},
MeshBufferVertexAttributeInfo::Custom(custom) => match custom {
MeshBufferCustomVertexAttributeInfo::Colors { data_size, .. } => *data_size,
MeshBufferCustomVertexAttributeInfo::TexCoords { data_size, .. } => *data_size,
},
}
}
pub fn component_len(&self) -> usize {
match self {
MeshBufferVertexAttributeInfo::Visibility(vis) => match vis {
MeshBufferVisibilityVertexAttributeInfo::Positions { component_len, .. } => {
*component_len
}
MeshBufferVisibilityVertexAttributeInfo::Normals { component_len, .. } => {
*component_len
}
MeshBufferVisibilityVertexAttributeInfo::Tangents { component_len, .. } => {
*component_len
}
},
MeshBufferVertexAttributeInfo::Custom(custom) => match custom {
MeshBufferCustomVertexAttributeInfo::Colors { component_len, .. } => *component_len,
MeshBufferCustomVertexAttributeInfo::TexCoords { component_len, .. } => {
*component_len
}
},
}
}
pub fn vertex_size(&self) -> usize {
match self {
MeshBufferVertexAttributeInfo::Visibility(vis) => vis.vertex_size(),
MeshBufferVertexAttributeInfo::Custom(custom) => custom.vertex_size(),
}
}
}
impl PartialOrd for MeshBufferVertexAttributeInfo {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for MeshBufferVertexAttributeInfo {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match self.primary_val().cmp(&other.primary_val()) {
std::cmp::Ordering::Equal => self.secondary_val().cmp(&other.secondary_val()),
ordering => ordering,
}
}
}
new_key_type! {
pub struct MeshBufferInfoKey;
}