use crate::Float; use crate::core::geometry::{Point2f, VectorLike}; use crate::core::texture::{ FloatTexture, SpectrumTexture, TextureEvalContext, TextureMapping2D, }; use crate::spectra::sampled::{SampledSpectrum, SampledWavelengths}; use crate::utils::Ptr; use crate::utils::math::square; use crate::utils::noise::noise_2d; use num_traits::Float as NumFloat; fn inside_polka_dot(st: Point2f) -> bool { let s_cell = (st[0] + 0.5).floor(); let t_cell = (st[1] + 0.5).floor(); if noise_2d(s_cell + 0.5, t_cell + 0.5) > 0. { let radius = 0.35; let max_shift = 0.5 + radius; let s_center = s_cell + max_shift * noise_2d(s_cell + 1.5, t_cell + 2.8); let t_center = t_cell + max_shift * noise_2d(s_cell + 4.5, t_cell + 9.8); let dst = st - Point2f::new(s_center, t_center); if dst.norm_squared() < square(radius) { return true; } } return false; } #[repr(C)] #[derive(Debug, Clone, Copy)] pub struct FloatDotsTexture { pub mapping: TextureMapping2D, pub outside_dot: Ptr, pub inside_dot: Ptr, } impl FloatDotsTexture { pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float { let c = self.mapping.map(ctx); let target_texture = if inside_polka_dot(c.st) { self.inside_dot } else { self.outside_dot }; if !target_texture.is_null() { target_texture.evaluate(ctx) } else { 0.0 } } } #[repr(C)] #[derive(Clone, Copy, Debug)] pub struct SpectrumDotsTexture { pub mapping: TextureMapping2D, pub outside_dot: Ptr, pub inside_dot: Ptr, } impl SpectrumDotsTexture { pub fn evaluate( &self, ctx: &TextureEvalContext, lambda: &SampledWavelengths, ) -> SampledSpectrum { let c = self.mapping.map(ctx); let target_texture = if inside_polka_dot(c.st) { self.inside_dot } else { self.outside_dot }; if !target_texture.is_null() { target_texture.evaluate(ctx, lambda) } else { SampledSpectrum::new(0.0) } } }