use super::{DIRECTION_MATCH_COS_TOL, geometry::BounceRefractionGeometry};
use crate::optics::{
birefringence::{AbsorptionTensor3, BiaxialIndicatrix},
materials::GemMaterial,
polarization::StokesVector,
raytracer::{NUM_CHANNELS, environment::EnvironmentSource, uniaxial_fresnel::UniaxialFrame},
studio_rig::StudioRig,
};
use glam::Vec3;
pub(crate) struct RayMaterialContext<'a> {
pub(crate) material: &'a GemMaterial,
pub(crate) lambdas: [f32; NUM_CHANNELS],
pub(crate) hero_idx: usize,
pub(crate) c_axis: Vec3,
pub(crate) is_anisotropic: bool,
pub(crate) enable_internal_mode_coupling: bool,
}
pub(crate) struct RayWavelengthCache {
pub(crate) n_o_ch: [f32; NUM_CHANNELS],
pub(crate) hero_indicatrix: Option<BiaxialIndicatrix>,
pub(crate) biaxial_ch: [Option<BiaxialIndicatrix>; NUM_CHANNELS],
pub(crate) tensor_ch: [AbsorptionTensor3; NUM_CHANNELS],
pub(crate) zoned: Option<crate::optics::raytracer::zoned::ZonedCache>,
}
pub(in crate::optics::raytracer) struct ExitSplitCtx<'a> {
pub(in crate::optics::raytracer) plane_soa: &'a crate::simd::PlanesSoA32,
pub(in crate::optics::raytracer) tools: &'a [crate::geometry::tool::ToolPrimitive],
pub(in crate::optics::raytracer) environment: EnvironmentSource<'a>,
pub(in crate::optics::raytracer) studio_rig: Option<StudioRig>,
pub(in crate::optics::raytracer) observer: Vec3,
pub(in crate::optics::raytracer) split_radiance: &'a mut [f32; NUM_CHANNELS],
pub(in crate::optics::raytracer) enabled: bool,
pub(in crate::optics::raytracer) compat: [u8; NUM_CHANNELS],
pub(in crate::optics::raytracer) split_mis_weight: f32,
}
const _: () = assert!(
NUM_CHANNELS <= 8,
"ExitSplitCtx::compat packs one bit per channel into a u8"
);
pub(in crate::optics::raytracer) struct BounceContext<'m, 'b> {
pub(in crate::optics::raytracer) ctx: &'b RayMaterialContext<'m>,
pub(in crate::optics::raytracer) cache: &'b RayWavelengthCache,
pub(in crate::optics::raytracer) geo: &'b BounceRefractionGeometry,
}
pub(super) struct UniaxialBounceContext<'m, 'b> {
pub(super) ctx: &'b RayMaterialContext<'m>,
pub(super) geo: &'b BounceRefractionGeometry,
pub(super) frame: &'b UniaxialFrame,
}
#[derive(Clone, Copy)]
pub(in crate::optics::raytracer) struct BounceRay {
pub(in crate::optics::raytracer) k_hat: Vec3,
pub(in crate::optics::raytracer) normal: Vec3,
}
pub(in crate::optics::raytracer) struct BounceState<'a> {
pub(in crate::optics::raytracer) stokes: &'a mut [StokesVector; NUM_CHANNELS],
pub(in crate::optics::raytracer) path_pdf: &'a mut [f32; NUM_CHANNELS],
}
pub(in crate::optics::raytracer) struct ExitEvent<'a, 'b> {
pub(in crate::optics::raytracer) exit: &'a mut ExitSplitCtx<'b>,
pub(in crate::optics::raytracer) hit_point: Vec3,
}
#[derive(Clone, Copy)]
pub(in crate::optics::raytracer) struct RngDraw {
pub(in crate::optics::raytracer) rng_seed: u32,
pub(in crate::optics::raytracer) bounce: u32,
}
#[derive(Clone, Copy)]
pub(in crate::optics::raytracer) struct PathModeState {
pub(in crate::optics::raytracer) current_plane_normal: Vec3,
pub(in crate::optics::raytracer) inside_gem: bool,
pub(in crate::optics::raytracer) is_extraordinary: bool,
}
pub(super) fn narrow_compat(
compat: &mut [u8; NUM_CHANNELS],
dirs: &[Option<Vec3>; NUM_CHANNELS],
hero: usize,
hero_match: [bool; NUM_CHANNELS],
) {
for a in 0..NUM_CHANNELS {
for b in (a + 1)..NUM_CHANNELS {
let matches = if a == hero {
hero_match[b]
} else if b == hero {
hero_match[a]
} else if let (Some(da), Some(db)) = (dirs[a], dirs[b]) {
da.dot(db) >= DIRECTION_MATCH_COS_TOL
} else {
true
};
if !matches {
compat[a] &= !(1u8 << b);
compat[b] &= !(1u8 << a);
}
}
}
}