use std::{borrow::Cow, collections::BTreeMap};
use super::Result;
use awsm_renderer_core::pipeline::primitive::FrontFace;
use crate::{
gltf::{
buffers::mesh::{get_position_from_buffer, get_vec3_from_buffer, get_vec4_from_buffer},
error::AwsmGltfError,
},
meshes::buffer_info::{MeshBufferVertexAttributeInfo, MeshBufferVisibilityVertexAttributeInfo},
};
pub(super) fn create_visibility_vertices(
attribute_data: &BTreeMap<MeshBufferVertexAttributeInfo, Cow<'_, [u8]>>,
triangle_indices: &[[usize; 3]],
front_face: FrontFace,
visibility_vertex_bytes: &mut Vec<u8>,
) -> Result<()> {
static BARYCENTRICS: [[f32; 2]; 3] = [
[1.0, 0.0], [0.0, 1.0], [0.0, 0.0], ];
let positions = attribute_data
.iter()
.find_map(|(attr_info, data)| match attr_info {
MeshBufferVertexAttributeInfo::Visibility(
MeshBufferVisibilityVertexAttributeInfo::Positions { .. },
) => Some(&data[..]),
_ => None,
})
.ok_or_else(|| AwsmGltfError::Positions("missing positions".to_string()))?;
let normals = attribute_data
.iter()
.find_map(|(attr_info, data)| match attr_info {
MeshBufferVertexAttributeInfo::Visibility(
MeshBufferVisibilityVertexAttributeInfo::Normals { .. },
) => Some(&data[..]),
_ => None,
})
.ok_or_else(|| AwsmGltfError::AttributeData("missing normals".to_string()))?;
let tangents = attribute_data
.iter()
.find_map(|(attr_info, data)| match attr_info {
MeshBufferVertexAttributeInfo::Visibility(
MeshBufferVisibilityVertexAttributeInfo::Tangents { .. },
) => Some(&data[..]),
_ => None,
});
if positions.len() % 12 != 0 {
return Err(AwsmGltfError::Positions(format!(
"Position buffer length ({}) is not a multiple of 12 (3 * f32).",
positions.len()
)));
}
if normals.len() % 12 != 0 {
return Err(AwsmGltfError::AttributeData(format!(
"Normal buffer length ({}) is not a multiple of 12 (3 * f32).",
normals.len()
)));
}
if let Some(tangents) = tangents {
if tangents.len() % 16 != 0 {
return Err(AwsmGltfError::AttributeData(format!(
"Tangent buffer length ({}) is not a multiple of 16 (4 * f32).",
tangents.len()
)));
}
}
for (triangle_index, triangle) in triangle_indices.iter().enumerate() {
let vertex_indices = match front_face {
FrontFace::Cw => [triangle[0], triangle[2], triangle[1]],
_ => [triangle[0], triangle[1], triangle[2]],
};
let barycentrics = match front_face {
FrontFace::Cw => [BARYCENTRICS[0], BARYCENTRICS[2], BARYCENTRICS[1]],
_ => BARYCENTRICS,
};
for (bary, &vertex_index) in barycentrics.iter().zip(vertex_indices.iter()) {
let position = get_position_from_buffer(positions, vertex_index)?;
let normal = get_vec3_from_buffer(normals, vertex_index, "normal")?;
let tangent = if let Some(tangents) = tangents {
get_vec4_from_buffer(tangents, vertex_index, "tangent")?
} else {
[0.0, 0.0, 0.0, 1.0] };
visibility_vertex_bytes.extend_from_slice(&position[0].to_le_bytes());
visibility_vertex_bytes.extend_from_slice(&position[1].to_le_bytes());
visibility_vertex_bytes.extend_from_slice(&position[2].to_le_bytes());
visibility_vertex_bytes.extend_from_slice(&(triangle_index as u32).to_le_bytes());
visibility_vertex_bytes.extend_from_slice(&bary[0].to_le_bytes());
visibility_vertex_bytes.extend_from_slice(&bary[1].to_le_bytes());
visibility_vertex_bytes.extend_from_slice(&normal[0].to_le_bytes());
visibility_vertex_bytes.extend_from_slice(&normal[1].to_le_bytes());
visibility_vertex_bytes.extend_from_slice(&normal[2].to_le_bytes());
visibility_vertex_bytes.extend_from_slice(&tangent[0].to_le_bytes());
visibility_vertex_bytes.extend_from_slice(&tangent[1].to_le_bytes());
visibility_vertex_bytes.extend_from_slice(&tangent[2].to_le_bytes());
visibility_vertex_bytes.extend_from_slice(&tangent[3].to_le_bytes());
visibility_vertex_bytes.extend_from_slice(&(vertex_index as u32).to_le_bytes());
}
}
Ok(())
}