pbrt/src/textures/image.rs

212 lines
5.7 KiB
Rust

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<MIPMap>,
}
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::<RGB>(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<SpectrumTexture> {
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<FloatTexture> {
todo!()
}
}