use crate::core::geometry::Lerp; use core::ops::{Add, Mul}; use num_traits::{Num, PrimInt}; use crate::core::image::DeviceImage; use crate::core::light::LightTrait; use crate::core::shape::Shape; use crate::core::texture::GPUFloatTexture; use crate::lights::*; use crate::spectra::{DenselySampledSpectrum, RGBColorSpace}; use crate::utils::Ptr; pub type Float = f32; #[cfg(not(feature = "use_f64"))] pub type FloatBits = u32; #[cfg(feature = "use_f64")] pub type FloatBits = u64; pub trait FloatBitOps: Copy { type Bits; fn to_bits_val(self) -> Self::Bits; fn exponent_val(self) -> i32; fn significand_val(self) -> Self::Bits; fn sign_bit_val(self) -> Self::Bits; fn from_bits_val(bits: Self::Bits) -> Self; } impl FloatBitOps for f32 { type Bits = u32; #[inline(always)] fn to_bits_val(self) -> u32 { self.to_bits() } // Shift 23, Mask 8 bits (0xFF), Bias 127 #[inline(always)] fn exponent_val(self) -> i32 { let bits = self.to_bits(); ((bits >> 23) & 0xFF) as i32 - 127 } // Mask bottom 23 bits #[inline(always)] fn significand_val(self) -> u32 { self.to_bits() & ((1 << 23) - 1) } // Mask top bit (31) #[inline(always)] fn sign_bit_val(self) -> u32 { self.to_bits() & 0x8000_0000 } #[inline(always)] fn from_bits_val(bits: u32) -> Self { Self::from_bits(bits) } } impl FloatBitOps for f64 { type Bits = u64; #[inline(always)] fn to_bits_val(self) -> u64 { self.to_bits() } // Shift 52, Mask 11 bits (0x7FF), Bias 1023 #[inline(always)] fn exponent_val(self) -> i32 { let bits = self.to_bits(); ((bits >> 52) & 0x7FF) as i32 - 1023 } // Mask bottom 52 bits #[inline(always)] fn significand_val(self) -> u64 { self.to_bits() & ((1u64 << 52) - 1) } // Mask top bit (63) #[inline(always)] fn sign_bit_val(self) -> u64 { self.to_bits() & 0x8000_0000_0000_0000 } #[inline(always)] fn from_bits_val(bits: u64) -> Self { Self::from_bits(bits) } } pub const MACHINE_EPSILON: Float = Float::EPSILON * 0.5; pub const SHADOW_EPSILON: Float = 0.0001; pub const ONE_MINUS_EPSILON: Float = 0.99999994; pub const PI: Float = core::f32::consts::PI; pub const INV_PI: Float = core::f32::consts::FRAC_1_PI; pub const INV_2_PI: Float = 0.159_154_943_091_895_335_77; pub const INV_4_PI: Float = 0.079_577_471_545_947_667_88; pub const PI_OVER_2: Float = core::f32::consts::FRAC_PI_2; pub const PI_OVER_4: Float = core::f32::consts::FRAC_PI_4; pub const SQRT_2: Float = core::f32::consts::SQRT_2; #[inline] pub fn gamma(n: i32) -> Float { n as Float * MACHINE_EPSILON / (1. - n as Float * MACHINE_EPSILON) } #[cfg(feature = "cpu_debug")] pub mod debug { use core::sync::atomic::AtomicU64; use core::sync::atomic::Ordering as SyncOrdering; pub static RARE_EVENT_TOTAL_CALLS: AtomicU64 = AtomicU64::new(0); pub static RARE_EVENT_CONDITION_MET: AtomicU64 = AtomicU64::new(0); #[macro_export] macro_rules! check_rare { ($frequency_threshold:expr, $condition:expr) => { use core::sync::atomic::{AtomicU64, Ordering as SyncOrdering}; const CHECK_INTERVAL: u64 = 4096; let total_calls = RARE_EVENT_TOTAL_CALLS.fetch_add(1, SyncOrdering::Relaxed); if $condition { RARE_EVENT_CONDITION_MET.fetch_add(1, SyncOrdering::Relaxed); } if (total_calls + 1) % CHECK_INTERVAL == 0 { let met_count = RARE_EVENT_CONDITION_MET.load(SyncOrdering::Relaxed); if met_count > 0 { let frequency = met_count as f64 / (total_calls + 1) as f64; if frequency > $frequency_threshold { panic!( "Rare event occurred with frequency {} which is > threshold {}", frequency, $frequency_threshold ); } } } }; } }