refactor: scene deserialization organisation

This commit is contained in:
2026-05-02 18:02:53 +02:00
parent a44e61c1f7
commit eb90c36ae8
8 changed files with 160 additions and 172 deletions

View File

@@ -1,44 +1,20 @@
use std::fmt::Debug;
use std::sync::Arc;
use log::warn;
use serde::Deserialize;
use crate::{
camera::Camera,
objects::{
cube::Cube,
materials::{
dielectric::Dielectric,
lambertian::{Lambertian, Metal},
normal::Normal,
traits::Material,
},
quad::Quad,
sphere::Sphere,
traits::Hittable,
triangle::Triangle,
},
scenes::raw_camera::RawCamera,
vec3::Vec3,
objects::{materials::traits::Material, traits::Hittable},
scenes::{hittable_def::HittableDef, material_def::MaterialDef, raw_camera::RawCamera},
};
#[derive(Debug)]
pub struct Scene {
pub camera: Camera,
pub materials: Vec<Arc<dyn Material>>,
pub _materials: Vec<Arc<dyn Material>>,
pub objects: Vec<Arc<dyn Hittable>>,
}
impl Debug for Scene {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Scene")
.field("camera", &self.camera)
.field("materials", &self.materials)
.field("objects", &self.objects)
.finish()
}
}
impl Scene {
pub fn render(&mut self) {
self.camera.render(&self.objects);
@@ -70,138 +46,8 @@ impl<'de> Deserialize<'de> for Scene {
.collect();
Ok(Self {
camera: Camera::from(conc.camera),
materials: mats,
_materials: mats,
objects: objs,
})
}
}
#[derive(Deserialize)]
#[serde(untagged)]
enum RawMaterial {
Ref(u32),
Direct(MaterialDef),
}
impl RawMaterial {
pub fn into_arc(self, materials: &Vec<Arc<dyn Material>>) -> Option<Arc<dyn Material>> {
match self {
RawMaterial::Ref(r) => {
if r as usize >= materials.len() {
warn!("Sphere specified nonexistent material {}; skipping...", r);
return None;
}
Some(materials.get(r as usize).unwrap().clone())
}
RawMaterial::Direct(m) => Some(m.into_arc()),
}
}
}
#[derive(Deserialize)]
struct RawSphere {
pub center: Vec3,
pub radius: f32,
pub material: RawMaterial,
}
#[derive(Deserialize)]
struct RawTriangle {
pub p1: Vec3,
pub p2: Vec3,
pub p3: Vec3,
pub material: RawMaterial,
}
#[derive(Deserialize)]
struct RawQuad {
pub p1: Vec3,
pub p2: Vec3,
pub p3: Vec3,
pub p4: Vec3,
pub material: RawMaterial,
}
#[derive(Deserialize)]
struct RawCube {
pub p1: Vec3,
pub p2: Vec3,
pub p3: Vec3,
pub p4: Vec3,
pub p5: Vec3,
pub p6: Vec3,
pub p7: Vec3,
pub p8: Vec3,
pub material: RawMaterial,
}
#[derive(Deserialize)]
#[serde(tag = "type", rename_all = "lowercase")]
enum HittableDef {
Sphere(RawSphere),
Triangle(RawTriangle),
Quad(RawQuad),
Cube(RawCube),
}
impl HittableDef {
fn into_arc(self, materials: &Vec<Arc<dyn Material>>) -> Option<Arc<dyn Hittable>> {
// THOUGHT: i think this can be done better; in the map/filter call up there?
match self {
HittableDef::Sphere(s) => {
let material = s.material.into_arc(materials);
if let Some(m) = material {
Some(Arc::new(Sphere::new(s.center, s.radius, m)))
} else {
None
}
}
HittableDef::Triangle(t) => {
let material = t.material.into_arc(materials);
if let Some(m) = material {
Some(Arc::new(Triangle::new(t.p1, t.p2, t.p3, m)))
} else {
None
}
}
HittableDef::Quad(q) => {
let material = q.material.into_arc(materials);
if let Some(m) = material {
Some(Arc::new(Quad::new(q.p1, q.p2, q.p3, q.p4, m)))
} else {
None
}
}
HittableDef::Cube(c) => {
let material = c.material.into_arc(materials);
if let Some(m) = material {
Some(Arc::new(Cube::new(
c.p1, c.p2, c.p3, c.p4, c.p5, c.p6, c.p7, c.p8, m,
)))
} else {
None
}
}
}
}
}
#[derive(Deserialize)]
#[serde(tag = "type", rename_all = "lowercase")]
enum MaterialDef {
Lambertian(Lambertian),
Metal(Metal),
Dielectric(Dielectric),
Normal(Normal),
}
impl MaterialDef {
fn into_arc(self) -> Arc<dyn Material> {
match self {
MaterialDef::Lambertian(l) => Arc::new(l),
MaterialDef::Metal(m) => Arc::new(m),
MaterialDef::Dielectric(d) => Arc::new(d),
MaterialDef::Normal(n) => Arc::new(n),
}
}
}