psychopath/src/accel/light_array.rs

80 lines
1.8 KiB
Rust

use mem_arena::MemArena;
use crate::{
bbox::BBox,
math::{Normal, Point, Vector},
shading::surface_closure::SurfaceClosure,
};
use super::LightAccel;
#[derive(Debug, Copy, Clone)]
pub struct LightArray<'a> {
indices: &'a [usize],
aprx_energy: f32,
}
impl<'a> LightArray<'a> {
#[allow(dead_code)]
pub fn from_objects<'b, T, F>(
arena: &'a MemArena,
objects: &mut [T],
info_getter: F,
) -> LightArray<'a>
where
F: 'b + Fn(&T) -> (&'b [BBox], f32),
{
let mut indices = Vec::new();
let mut aprx_energy = 0.0;
for (i, thing) in objects.iter().enumerate() {
let (_, power) = info_getter(thing);
if power > 0.0 {
indices.push(i);
aprx_energy += power;
}
}
LightArray {
indices: arena.copy_slice(&indices),
aprx_energy: aprx_energy,
}
}
}
impl<'a> LightAccel for LightArray<'a> {
fn select(
&self,
inc: Vector,
pos: Point,
nor: Normal,
nor_g: Normal,
sc: &SurfaceClosure,
time: f32,
n: f32,
) -> Option<(usize, f32, f32)> {
let _ = (inc, pos, nor, nor_g, sc, time); // Not using these, silence warnings
assert!(n >= 0.0 && n <= 1.0);
if self.indices.is_empty() {
return None;
}
let n2 = n * self.indices.len() as f32;
let i = if n == 1.0 {
*self.indices.last().unwrap()
} else {
self.indices[n2 as usize]
};
let whittled_n = n2 - i as f32;
let pdf = 1.0 / self.indices.len() as f32;
Some((i, pdf, whittled_n))
}
fn approximate_energy(&self) -> f32 {
self.aprx_energy
}
}