use crate::{
Arena, DirectionalLight, Material, Mesh, MeshId, ObjectId, Texture, TextureId, Transform,
};
#[derive(Clone, Debug)]
pub struct RenderObject {
pub mesh: MeshId,
pub texture: Option<TextureId>,
pub transform: Transform,
pub material: Material,
pub visible: bool,
}
pub struct Scene {
pub meshes: Arena<Mesh>,
pub textures: Arena<Texture>,
pub objects: Arena<RenderObject>,
pub light: DirectionalLight,
}
impl Scene {
#[must_use]
pub fn new() -> Self {
Self {
meshes: Arena::new(),
textures: Arena::new(),
objects: Arena::new(),
light: DirectionalLight::default(),
}
}
pub fn spawn(&mut self, object: RenderObject) -> ObjectId {
self.objects.insert(object)
}
}
impl Default for Scene {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Material, Rgb, Transform};
#[test]
fn spawn_returns_reachable_object() {
let mut scene = Scene::new();
let mesh = scene.meshes.insert(Mesh::triangle(1.0, 1.0).unwrap());
let object = scene.spawn(RenderObject {
mesh,
texture: None,
transform: Transform::default(),
material: Material::new(Rgb::new(1.0, 0.5, 0.25)),
visible: true,
});
let fetched = scene.objects.get(object).unwrap();
assert_eq!(fetched.mesh, mesh);
assert!(fetched.visible);
assert_eq!(fetched.material.tint, Rgb::new(1.0, 0.5, 0.25));
}
#[test]
fn removed_object_does_not_leak_into_scene() {
let mut scene = Scene::new();
let mesh = scene.meshes.insert(Mesh::plane(1.0, 1.0).unwrap());
let object = scene.spawn(RenderObject {
mesh,
texture: None,
transform: Transform::default(),
material: Material::default(),
visible: true,
});
assert_eq!(scene.objects.len(), 1);
let _ = scene.objects.remove(object);
assert!(scene.objects.is_empty());
}
}