use crate::Arena; use crate::core::texture::{ CreateFloatTexture, CreateSpectrumTexture, FloatTexture, FloatTextureTrait, SpectrumTexture, SpectrumTextureTrait, }; use crate::core::texture::{TexInfo, get_texture_cache}; use crate::utils::mipmap::{MIPMap, MIPMapFilterOptions}; use crate::utils::{FileLoc, TextureParameterDictionary}; use anyhow::Result; use shared::Float; use shared::core::color::ColorEncoding; use shared::core::color::RGB; use shared::core::geometry::Vector2f; use shared::core::image::WrapMode; use shared::core::spectrum::SpectrumTrait; use shared::core::texture::{SpectrumType, TextureEvalContext, TextureMapping2D}; use shared::spectra::{ RGBAlbedoSpectrum, RGBIlluminantSpectrum, RGBUnboundedSpectrum, SampledSpectrum, SampledWavelengths, }; use shared::utils::Transform; use std::path::Path; use std::sync::Arc; // use crate::utils::{FileLoc, TextureParameterDictionary}; #[derive(Clone, Debug)] pub struct ImageTextureBase { pub mapping: TextureMapping2D, pub filename: String, pub scale: Float, pub invert: bool, pub mipmap: Arc, } impl ImageTextureBase { pub fn new( mapping: TextureMapping2D, filename: String, filter_options: MIPMapFilterOptions, wrap_mode: WrapMode, scale: Float, invert: bool, encoding: ColorEncoding, ) -> Self { let tex_info = TexInfo { filename: filename.clone(), filter_options, wrap_mode, encoding, }; let cache_mutex = get_texture_cache(); { let cache = cache_mutex.lock().unwrap(); if let Some(mipmap) = cache.get(&tex_info) { return Self { mapping, filename, scale, invert, mipmap: mipmap.clone(), }; } } let path = Path::new(&filename); let mipmap_raw = MIPMap::create_from_file(path, filter_options, wrap_mode, encoding) .expect("Failed to create MIPMap from file"); let mipmap_arc = Arc::new(mipmap_raw); { let mut cache = cache_mutex.lock().unwrap(); let stored_mipmap = cache.entry(tex_info).or_insert(mipmap_arc); Self { mapping, filename, scale, invert, mipmap: stored_mipmap.clone(), } } } pub fn clear_cache() { let mut cache = get_texture_cache().lock().unwrap(); cache.clear(); } pub fn multiply_scale(&mut self, s: Float) { self.scale *= s; } } #[derive(Clone, Debug)] pub struct SpectrumImageTexture { pub base: ImageTextureBase, pub spectrum_type: SpectrumType, } impl SpectrumImageTexture { #[allow(clippy::too_many_arguments)] pub fn new( mapping: TextureMapping2D, filename: String, filter_options: MIPMapFilterOptions, wrap_mode: WrapMode, scale: Float, invert: bool, encoding: ColorEncoding, spectrum_type: SpectrumType, ) -> Self { let base = ImageTextureBase::new( mapping, filename, filter_options, wrap_mode, scale, invert, encoding, ); Self { base, spectrum_type, } } } impl SpectrumTextureTrait for SpectrumImageTexture { fn evaluate(&self, ctx: &TextureEvalContext, lambda: &SampledWavelengths) -> SampledSpectrum { let mut c = self.base.mapping.map(ctx); c.st[1] = 1. - c.st[1]; let dst0 = Vector2f::new(c.dsdx, c.dtdx); let dst1 = Vector2f::new(c.dsdy, c.dtdy); let rgb_unclamp = self.base.scale * self.base.mipmap.filter::(c.st, dst0, dst1); let rgb = RGB::clamp_zero(&rgb_unclamp); if let Some(cs) = self.base.mipmap.get_rgb_colorspace() { match self.spectrum_type { SpectrumType::Unbounded => { return RGBUnboundedSpectrum::new(&cs, rgb).sample(lambda); } SpectrumType::Albedo => { return RGBAlbedoSpectrum::new(&cs, rgb).sample(lambda); } _ => return RGBIlluminantSpectrum::new(&cs, rgb).sample(lambda), } } assert!(rgb[0] == rgb[1] && rgb[1] == rgb[2]); SampledSpectrum::new(rgb[0]) } } impl CreateSpectrumTexture for SpectrumImageTexture { fn create( _render_from_texture: Transform, _parameters: TextureParameterDictionary, _spectrum_type: SpectrumType, _loc: FileLoc, ) -> Result { todo!() } } #[derive(Debug, Clone)] pub struct FloatImageTexture { pub base: ImageTextureBase, } impl FloatImageTexture { pub fn new( mapping: TextureMapping2D, filename: String, filter_options: MIPMapFilterOptions, wrap_mode: WrapMode, scale: Float, invert: bool, encoding: ColorEncoding, ) -> Self { Self { base: ImageTextureBase::new( mapping, filename, filter_options, wrap_mode, scale, invert, encoding, ), } } } impl FloatTextureTrait for FloatImageTexture { fn evaluate(&self, _ctx: &TextureEvalContext) -> Float { todo!() } } impl CreateFloatTexture for FloatImageTexture { fn create( _render_from_texture: Transform, _parameters: TextureParameterDictionary, _loc: FileLoc, _arena: &Arena, ) -> Result { todo!() } }