use glam::Affine3A;
use crate::light::LightingEnvironment;
use crate::material::PbrMaterial;
use crate::mesh::Mesh;
use crate::aabb::Aabb;
#[derive(Debug)]
pub struct SceneNode {
pub name: String,
pub local_transform: Affine3A,
pub mesh_index: Option<usize>,
pub children: Vec<SceneNode>,
pub visible: bool,
}
#[derive(Debug)]
pub struct Scene {
pub meshes: Vec<Mesh>,
pub materials: Vec<PbrMaterial>,
pub nodes: Vec<SceneNode>,
pub lighting: LightingEnvironment,
}
impl Default for Scene {
fn default() -> Self {
Self {
meshes: Vec::new(),
materials: vec![PbrMaterial::default()],
nodes: Vec::new(),
lighting: LightingEnvironment::default(),
}
}
}
impl Scene {
pub fn single_mesh(name: impl Into<String>, mesh: Mesh, material: PbrMaterial) -> Self {
let material_index = 0;
let mut mesh = mesh;
for sub in &mut mesh.sub_meshes {
sub.material_index = material_index;
}
Self {
meshes: vec![mesh],
materials: vec![material],
nodes: vec![SceneNode {
name: name.into(),
local_transform: Affine3A::IDENTITY,
mesh_index: Some(0),
children: Vec::new(),
visible: true,
}],
lighting: LightingEnvironment::default(),
}
}
pub fn compute_aabb(&self) -> Aabb {
let mut out = Aabb::empty();
for node in &self.nodes {
out = out.union(&self.compute_node_aabb(node, Affine3A::IDENTITY));
}
out
}
fn compute_node_aabb(&self, node: &SceneNode, parent_transform: Affine3A) -> Aabb {
if !node.visible {
return Aabb::empty();
}
let world = parent_transform * node.local_transform;
let mut out = Aabb::empty();
if let Some(mesh_idx) = node.mesh_index {
if let Some(mesh) = self.meshes.get(mesh_idx) {
out = Aabb::from_transformed_aabb(&mesh.aabb, &world);
}
}
for child in &node.children {
out = out.union(&self.compute_node_aabb(child, world));
}
out
}
pub fn with_default_lighting(self) -> Self {
Self {
lighting: LightingEnvironment::default(),
..self
}
}
pub fn with_lighting(mut self, lighting: LightingEnvironment) -> Self {
self.lighting = lighting;
self
}
}