49 lines
1.5 KiB
Rust
49 lines
1.5 KiB
Rust
use image::{RgbImage};
|
|
use crate::{Color, Point3};
|
|
use crate::texture::Texture;
|
|
|
|
pub struct ImageTexture {
|
|
image: Option<RgbImage>
|
|
}
|
|
|
|
impl ImageTexture {
|
|
pub fn new(path: &str) -> Self {
|
|
let image = image::open(path)
|
|
.map(|i|i.into_rgb8())
|
|
.ok();
|
|
Self {
|
|
image
|
|
}
|
|
}
|
|
fn value_from_image(image: &RgbImage, u: f64, v: f64) -> Color {
|
|
// Clamp input texture coordinates to [0,1] x [1,0]
|
|
let u = u.clamp(0.0, 1.0);
|
|
let v = v.abs().clamp(0.0, 1.0); // Flip V to image coordinates
|
|
|
|
let i = match (u * image.width() as f64) as i32 {
|
|
i if i >= image.width() as i32 => image.width() as i32 - 1,
|
|
i => i
|
|
};
|
|
let j = match (v * image.height() as f64) as i32 {
|
|
j if j >= image.height() as i32 => image.height() as i32 - 1,
|
|
j => j
|
|
};
|
|
let color_scale = 1.0 / 255.0;
|
|
let pixel = image.get_pixel(i as u32, j as u32);
|
|
let x = pixel.0[0] as f64 * color_scale;
|
|
let y = pixel.0[1] as f64 * color_scale;
|
|
let z = pixel.0[2] as f64 * color_scale;
|
|
Color::new(x, y, z)
|
|
}
|
|
}
|
|
|
|
impl Texture for ImageTexture {
|
|
fn value(&self, u: f64, v: f64, _point: &Point3) -> Color {
|
|
match &self.image {
|
|
Some(i) => ImageTexture::value_from_image(i, u, v),
|
|
// If we have no texture data, then return solid cyan as a debugging aid.
|
|
_ => Color::new(0.0, 1.0, 1.0)
|
|
}
|
|
}
|
|
}
|