use awsm_renderer_core::pipeline::primitive::FrontFace;
use slotmap::new_key_type;
use crate::bounds::Aabb;
use crate::materials::Material;
use crate::meshes::buffer_info::{
MeshBufferGeometryMorphInfo, MeshBufferMaterialMorphInfo, MeshBufferSkinInfo,
MeshBufferVertexAttributeInfo,
};
use crate::meshes::morphs::{GeometryMorphKey, MaterialMorphKey};
use crate::meshes::skins::SkinKey;
new_key_type! {
pub struct GeometryKey;
}
pub struct GeometrySource {
pub positions: Vec<[f32; 3]>,
pub normals: Vec<[f32; 3]>,
pub uvs0: Option<Vec<[f32; 2]>>,
pub tangents: Option<Vec<[f32; 4]>>,
pub indices: Vec<u32>,
pub front_face: FrontFace,
pub vertex_attributes: Vec<MeshBufferVertexAttributeInfo>,
pub custom_attribute_bytes: Vec<u8>,
pub attribute_index_bytes: Vec<u8>,
pub aabb: Option<Aabb>,
pub geometry_morph_key: Option<GeometryMorphKey>,
pub geometry_morph_info: Option<MeshBufferGeometryMorphInfo>,
pub material_morph_key: Option<MaterialMorphKey>,
pub material_morph_info: Option<MeshBufferMaterialMorphInfo>,
pub skin_key: Option<SkinKey>,
pub skin_info: Option<MeshBufferSkinInfo>,
}
impl GeometrySource {
pub fn vertex_count(&self) -> usize {
self.positions.len()
}
pub fn triangle_count(&self) -> usize {
self.indices.len() / 3
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum GeometryKind {
Visibility,
Transparency,
Both,
}
pub fn geometry_kind(material: &Material, is_hud: bool) -> GeometryKind {
if is_hud {
GeometryKind::Both
} else if material.is_transparency_pass() {
GeometryKind::Transparency
} else {
GeometryKind::Visibility
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct GeometryReps {
pub visibility: bool,
pub transparency: bool,
}
impl GeometryReps {
pub fn from_kinds(kinds: impl IntoIterator<Item = GeometryKind>) -> Self {
let mut reps = Self::default();
for k in kinds {
match k {
GeometryKind::Visibility => reps.visibility = true,
GeometryKind::Transparency => reps.transparency = true,
GeometryKind::Both => {
reps.visibility = true;
reps.transparency = true;
}
}
}
reps
}
pub fn count(&self) -> usize {
self.visibility as usize + self.transparency as usize
}
}
#[cfg(test)]
mod tests {
use super::{geometry_kind, GeometryKind};
use crate::materials::Material;
use awsm_materials::{pbr::PbrMaterial, MaterialAlphaMode};
fn pbr(alpha: MaterialAlphaMode) -> Material {
Material::Pbr(Box::new(PbrMaterial::new(alpha, false)))
}
#[test]
fn opaque_and_mask_are_visibility() {
assert_eq!(
geometry_kind(&pbr(MaterialAlphaMode::Opaque), false),
GeometryKind::Visibility
);
assert_eq!(
geometry_kind(&pbr(MaterialAlphaMode::Mask { cutoff: 0.5 }), false),
GeometryKind::Visibility
);
}
#[test]
fn blend_is_transparency() {
assert_eq!(
geometry_kind(&pbr(MaterialAlphaMode::Blend), false),
GeometryKind::Transparency
);
}
#[test]
fn hud_overrides_to_both_regardless_of_material() {
assert_eq!(
geometry_kind(&pbr(MaterialAlphaMode::Opaque), true),
GeometryKind::Both
);
assert_eq!(
geometry_kind(&pbr(MaterialAlphaMode::Blend), true),
GeometryKind::Both
);
}
#[test]
fn matches_is_transparency_pass_for_non_hud() {
for alpha in [
MaterialAlphaMode::Opaque,
MaterialAlphaMode::Mask { cutoff: 0.5 },
MaterialAlphaMode::Blend,
] {
let m = pbr(alpha);
let expected = if m.is_transparency_pass() {
GeometryKind::Transparency
} else {
GeometryKind::Visibility
};
assert_eq!(geometry_kind(&m, false), expected);
}
}
use super::{GeometryKind::*, GeometryReps};
#[test]
fn reps_union_dedups_to_distinct_kinds_not_instance_count() {
let reps = GeometryReps::from_kinds([
Visibility,
Visibility,
Visibility,
Transparency,
Transparency,
]);
assert_eq!(
reps,
GeometryReps {
visibility: true,
transparency: true
}
);
assert_eq!(
reps.count(),
2,
"uploaded twice total, not once per instance"
);
}
#[test]
fn reps_single_kind_uploads_once() {
assert_eq!(
GeometryReps::from_kinds([Visibility, Visibility]).count(),
1
);
assert_eq!(
GeometryReps::from_kinds([Transparency, Transparency]).count(),
1
);
assert_eq!(GeometryReps::from_kinds([Both]).count(), 2);
assert_eq!(GeometryReps::from_kinds([]).count(), 0);
}
}