Brandon Eleuterio

Articles

Learning Rust – Part 1: Output an Image

Brandon Eleuterio

I recently started digging into Rust, a systems-level programming language that is similar to C++, but safer and easier to use.

It’s been a while since I’ve used a systems-level language like C++ (maybe 20 years?). I remember struggling my way through a C++ class at Virginia Tech in which we had to write a movie database. It was one of those huge freshman-level classes with a couple hundred students and I was lost from day one. I eventually hacked my way to a passing grade and walked away triumphant, although with very little understanding of C++.

Since then, my programming career has primarily consisted of web application and user interface coding with JavaScript and C# (much easier for me than C++). Rarely do I ever have to think about things like memory allocation and performance. But I feel like my brain is ready to switch into learning mode, so here we go!

Project Intro

As a guy who learns best by doing and who is visually inclined, I’ve decided to write a ray tracer. A ray tracer is a computer program that renders 3D graphics. Ray tracing techniques are used to generate graphics for video games and movies.

Since I’d rather not start from scratch, I found an online book called Ray Tracing in One Weekend. The book uses C++ guiding you through the steps to build a simple but interesting ray tracer. I’ll do my best to follow along coding in Rust.

My First Image

The first chapter involves creating a basic RGB image. After a few challenges like setting up a debugger in VSCode, casting variable types, and figuring out how to do nested for loops, I managed to render my first image in Rust!

And here’s the code that generates this image:

fn main() {
    const IMAGE_WIDTH: u32 = 256;
    const IMAGE_HEIGHT: u32 = 256;

    println!("P3");
    println!("{} {}", IMAGE_WIDTH, IMAGE_HEIGHT);
    println!("255");

    // Nested for loops stumped me initially
    for j in (0..IMAGE_HEIGHT).rev() {
        eprintln!("Scanlines remaining: {}", j);
        for i in 0..IMAGE_WIDTH {
            let r = i as f64 / (IMAGE_WIDTH as f64 - 1_f64);
            let g = j as f64 / (IMAGE_HEIGHT as f64 - 1_f64);
            let b = 0.25;

            let ir = (255.999 * r) as i32;
            let ig = (255.999 * g) as i32;
            let ib = (255.999 * b) as i32;

            println!("{} {} {}", ir, ig, ib);
        }
    }

    eprintln!("Done.");
}

My code for the entire project can be found on github. That’s all for now!

In the next chapter, I’ll refactor some of this code into reusable functions.

Tags:

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top