81 lines
2.4 KiB
Rust
81 lines
2.4 KiB
Rust
use image::{DynamicImage, ImageReader};
|
|
use log::trace;
|
|
|
|
use crate::{
|
|
objects::{hit::Hit, materials::traits::Material},
|
|
ray::Ray,
|
|
vec3::Vec3,
|
|
};
|
|
|
|
// TODO: overhaul texture implementation so we can support textures for arbitrary materials.
|
|
// Basically remove this struct, and instead make lambertian/metal/dielectric/take either a texture
|
|
// or a flat colour
|
|
// I think we can use an enum ColourSource with a function to fetch a specific colour depending on
|
|
// if we have a texture/flat colour. and yeah.
|
|
#[derive(Debug)]
|
|
pub struct Texture {
|
|
source: DynamicImage,
|
|
width: u32,
|
|
height: u32,
|
|
stride: usize,
|
|
}
|
|
|
|
impl Texture {
|
|
pub fn new(texture: &str) -> Self {
|
|
let img = ImageReader::open(texture).unwrap().decode().unwrap(); // FIXME: unwraps
|
|
trace!(
|
|
"texture '{}' is {} by {} pixels, with {} bytes total",
|
|
texture,
|
|
img.width(),
|
|
img.height(),
|
|
img.as_bytes().len()
|
|
);
|
|
let stride = match img.color() {
|
|
// TODO: support other types of image
|
|
image::ColorType::L8 => todo!(),
|
|
image::ColorType::La8 => todo!(),
|
|
image::ColorType::Rgb8 => 3,
|
|
image::ColorType::Rgba8 => 4,
|
|
image::ColorType::L16 => todo!(),
|
|
image::ColorType::La16 => todo!(),
|
|
image::ColorType::Rgb16 => todo!(),
|
|
image::ColorType::Rgba16 => todo!(),
|
|
image::ColorType::Rgb32F => todo!(),
|
|
image::ColorType::Rgba32F => todo!(),
|
|
_ => 3,
|
|
};
|
|
Self {
|
|
width: img.width(),
|
|
height: img.height(),
|
|
source: img,
|
|
stride,
|
|
}
|
|
}
|
|
|
|
fn _idx(&self, u: f32, v: f32) -> usize {
|
|
let x: usize = (u * ((self.width - 1) as f32)) as usize;
|
|
let y: usize = (v * ((self.height - 1) as f32)) as usize;
|
|
|
|
y * self.width as usize + x
|
|
}
|
|
|
|
fn _at(&self, u: f32, v: f32) -> Vec3 {
|
|
let b = self.source.as_bytes();
|
|
let idx = self._idx(u, v);
|
|
|
|
Vec3::from_u8(
|
|
b[self.stride * idx],
|
|
b[self.stride * idx + 2],
|
|
b[self.stride * idx + 1],
|
|
)
|
|
}
|
|
}
|
|
|
|
impl Material for Texture {
|
|
fn scatter(&self, hit: &Hit, _ray: &Ray) -> Option<(Option<Ray>, Vec3)> {
|
|
let (u, v) = hit.uv();
|
|
let col = self._at(u, 1. - v);
|
|
Some((None, col))
|
|
}
|
|
}
|