commit 3a2c64c30f0b2fc03b986a67a36d689ac3feb4d4
Author: Bradley Gannon <bradley@bradleygannon.com>
Date: Thu, 11 Dec 2025 14:14:11 -0500
Add Pixel and Image structs, PPM output, and test image
Complete Chapters 1 and 2
Diffstat:
4 files changed, 72 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,2 @@
+*.ppm
+/target+
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "stocking"
+version = "0.1.0"
diff --git a/Cargo.toml b/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "stocking"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]
diff --git a/src/main.rs b/src/main.rs
@@ -0,0 +1,56 @@
+#[derive(Clone, Copy, Default)]
+struct Pixel {
+ red: f32,
+ green: f32,
+ blue: f32,
+}
+
+struct Image {
+ data: Vec<Vec<Pixel>>,
+}
+
+fn scale_f32_to_u8(value: f32) -> u8 {
+ (value * 255.) as u8
+}
+
+impl Image {
+ fn new(width: usize, height: usize) -> Self {
+ Image {
+ data: vec![vec![Pixel::default(); width]; height],
+ }
+ }
+ fn to_ppm_string(&self) -> String {
+ let mut output = "P3\n".to_string();
+ let height = self.data.len();
+ let width = if height > 0 { self.data[0].len() } else { 0 };
+ output += &format!("{width} {height}\n");
+ output += "255\n";
+ for (row_idx, row_data) in self.data.iter().enumerate() {
+ eprintln!("Scanlines remaining: {}", height - row_idx);
+ for Pixel { red, green, blue } in row_data.iter() {
+ output += &format!(
+ "{} {} {}\n",
+ scale_f32_to_u8(*red),
+ scale_f32_to_u8(*green),
+ scale_f32_to_u8(*blue)
+ );
+ }
+ }
+ eprintln!("Done");
+ output
+ }
+}
+
+fn main() {
+ let (width, height) = (256, 256);
+ let mut image = Image::new(width, height);
+ for i in 0..width {
+ for j in 0..height {
+ let red = i as f32 / (width - 1) as f32;
+ let green = j as f32 / (height - 1) as f32;
+ let blue = 0.;
+ image.data[j][i] = Pixel { red, green, blue };
+ }
+ }
+ println!("{}", image.to_ppm_string());
+}