1use super::prelude::*;
2use crate::linalg::vector::Vector;
3use const_default::ConstDefault;
4use std::io::Write;
5use std::ops::{Mul, MulAssign};
6
7#[derive(Debug, Clone, Copy, PartialEq)]
9pub struct Colour(pub Vector<f64, 3>);
10
11pub struct Image<const W: usize, const H: usize> {
15 pub rows: Vec<Vec<Colour>>,
16}
17
18impl Colour {
19 pub const WHITE: Colour = Colour::new(1.0, 1.0, 1.0);
20 pub const BLACK: Colour = Colour::new(0.0, 0.0, 0.0);
21
22 pub const fn new(r: f64, g: f64, b: f64) -> Self {
23 debug_assert!(0.0 <= r && r <= 1.0);
24 debug_assert!(0.0 <= g && g <= 1.0);
25 debug_assert!(0.0 <= b && b <= 1.0);
26 Self(Vector::new([r, g, b]))
27 }
28
29 pub const fn r(&self) -> f64 {
31 *self.0.x()
32 }
33
34 pub const fn g(&self) -> f64 {
36 *self.0.y()
37 }
38
39 pub const fn b(&self) -> f64 {
41 *self.0.z()
42 }
43
44 pub fn map<F>(self, f: F) -> Self
45 where
46 F: Fn(f64) -> f64,
47 {
48 Colour(self.0.map(f))
49 }
50
51 pub fn to_pixel(&self) -> Pixel {
52 let r = self.r().clamp(0.0, 1.0);
54 let g = self.g().clamp(0.0, 1.0);
55 let b = self.b().clamp(0.0, 1.0);
56
57 let r = (r * 255.0) as u8;
58 let g = (g * 255.0) as u8;
59 let b = (b * 255.0) as u8;
60 Pixel::new(r, g, b)
61 }
62}
63
64impl ConstDefault for Colour {
65 const DEFAULT: Self = Colour::new(0.0, 0.0, 0.0);
66}
67
68impl<const W: usize, const H: usize> Image<W, H> {
69 pub fn new(rows: Vec<Vec<Colour>>) -> Self {
73 assert_eq!(rows.len(), H);
74 for row in rows.iter() {
75 assert_eq!(row.len(), W);
76 }
77
78 unsafe { Self::new_unchecked(rows) }
79 }
80
81 pub unsafe fn new_unchecked(rows: Vec<Vec<Colour>>) -> Self {
88 Self { rows }
89 }
90
91 pub fn gen<F>(mut f: F) -> Self
95 where
96 F: FnMut(usize, usize) -> Colour,
97 {
98 let mut rows = Vec::<Vec<Colour>>::with_capacity(H);
99 for y in 0..H {
100 let mut row_data = Vec::<Colour>::with_capacity(W);
101 for x in 0..W {
102 row_data.push(f(x, y));
103 }
104 rows.push(row_data);
105 }
106
107 unsafe { Self::new_unchecked(rows) }
108 }
109
110 pub fn to_ppm(&self) -> Ppm<W, H> {
112 let mut pixel_rows = Vec::<Vec<Pixel>>::with_capacity(H);
113 for colour_row in self.rows.iter() {
114 let mut pixel_row = Vec::<Pixel>::with_capacity(W);
115 for colour in colour_row.iter() {
116 pixel_row.push(colour.to_pixel());
117 }
118 pixel_rows.push(pixel_row);
119 }
120 Ppm::new(pixel_rows)
121 }
122
123 pub fn write_as_png<OUT: Write>(&self, writer: OUT) {
124 let mut encoder = png::Encoder::new(writer, W as u32, H as u32);
125 encoder.set_color(png::ColorType::Rgb);
126 encoder.set_depth(png::BitDepth::Eight);
127 let mut png_writer = encoder.write_header().unwrap();
128 let image_data: Vec<u8> = self
129 .rows
130 .iter()
131 .flat_map(|row| row.iter().flat_map(|colour| colour.to_pixel().into_iter()))
132 .collect();
133 png_writer.write_image_data(&image_data).unwrap();
134 }
135}
136
137impl From<Vector<f64, 3>> for Colour {
138 fn from(v: Vector<f64, 3>) -> Self {
139 Self::new(*v.x(), *v.y(), *v.z()) }
141}
142
143impl Mul<Colour> for Colour {
144 type Output = Colour;
145
146 fn mul(self, rhs: Colour) -> Self::Output {
147 Colour(self.0 * rhs.0)
148 }
149}
150
151impl MulAssign<Colour> for Colour {
152 fn mul_assign(&mut self, rhs: Colour) {
153 self.0 *= rhs.0;
154 }
155}