use crate::Float; use crate::core::texture::{ GPUFloatTexture, GPUSpectrumTexture, TextureEvalContext, TextureMapping2D, TextureMapping3D, TextureMapping3DTrait, }; use crate::spectra::{SampledSpectrum, SampledWavelengths}; use crate::utils::{Ptr, math::square}; use num_traits::Float as NumFloat; fn checkerboard( ctx: &TextureEvalContext, map2d: Ptr, map3d: Ptr, ) -> Float { let d = |x: Float| -> Float { let y = x / 2. - (x / 2.).floor() - 0.5; return x / 2. + y * (1. - 2. * y.abs()); }; let bf = |x: Float, r: Float| -> Float { if (x.floor() - r) == (x + r).floor() { return 1. - 2. * (x.floor() as i32 & 1) as Float; } (d(x + r) - 2. * d(x) + d(x - r)) / square(r) }; if !map2d.is_null() { assert!(map3d.is_null()); let c = map2d.map(&ctx); let ds = 1.5 * c.dsdx.abs().max(c.dsdy.abs()); let dt = 1.5 * c.dtdx.abs().max(c.dtdy.abs()); // Integrate product of 2D checkerboard function and triangle filter 0.5 - bf(c.st[0], ds) * bf(c.st[1], dt) / 2. } else { assert!(!map3d.is_null()); let c = map3d.map(&ctx); let dx = 1.5 * c.dpdx.x().abs().max(c.dpdy.x().abs()); let dy = 1.5 * c.dpdx.y().abs().max(c.dpdy.y().abs()); let dz = 1.5 * c.dpdx.z().abs().max(c.dpdy.z().abs()); 0.5 - bf(c.p.x(), dx) * bf(c.p.y(), dy) * bf(c.p.z(), dz) } } #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct FloatCheckerboardTexture { pub map2d: Ptr, pub map3d: Ptr, pub tex: [Ptr; 2], } impl FloatCheckerboardTexture { pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float { let w = checkerboard(&ctx, self.map2d, self.map3d); let mut t0 = 0.0; let mut t1 = 0.0; if w != 1.0 { if let Some(tex) = self.tex[0].get() { t0 = tex.evaluate(ctx); } } if w != 0.0 { if let Some(tex) = self.tex[1].get() { t1 = tex.evaluate(ctx); } } (1.0 - w) * t0 + w * t1 } } #[repr(C)] #[derive(Clone, Copy, Debug)] pub struct SpectrumCheckerboardTexture { pub map2d: Ptr, pub map3d: Ptr, pub tex: [Ptr; 2], } impl SpectrumCheckerboardTexture { pub fn evaluate( &self, ctx: &TextureEvalContext, lambda: &SampledWavelengths, ) -> SampledSpectrum { let w = checkerboard(ctx, self.map2d, self.map3d); let mut t0 = SampledSpectrum::new(0.); let mut t1 = SampledSpectrum::new(0.); if w != 1.0 { if let Some(tex) = self.tex[0].get() { t0 = tex.evaluate(ctx, lambda); } } if w != 0.0 { if let Some(tex) = self.tex[1].get() { t1 = tex.evaluate(ctx, lambda); } } t0 * (1.0 - w) + t1 * w } }