Resource Micro Management

Resource Micro Management

In this post, I’m taking a brief break from graphics to talk about under-the-hood architecture-specifically, how I handle resources in my game. By “resources,” I mean all the external assets the game relies on, such as textures, models, and sounds.

Raylib provides a straightforward way to load and manage resources, but because it’s a C library, you have to manually unload every single resource when you are done with it. This can be tedious and highly error-prone, leading to memory leaks if you have a lot of assets to juggle.

Textures From The Sky

Textures From The Sky

We left off the last post with a beautiful 3D terrain, but it had a bit of a flaw. We ran into a problem with coloring flat plains that happen to sit at or below sea level, they were incorrectly painted as water. In this post, we will solve that problem and apply the final texture to our terrain.

heightmap and colormap

The main issue was that we tried to automatically generate the colors for our terrain based solely on the height of each point, without any context of whether it was actually sea or land.

Coloring Book

Coloring Book

In this post, we will continue building our world by adding colors and textures to our terrain. We will also explore how to use heightmaps to create a more compelling landscape.

First, I owe you a better render of the results from the previous post. I wasn’t entirely happy with the way the terrain looked in the video, so here it is again, this time as a high-quality image. The gray clouds you see are simply the raw heightmap applied as a texture directly onto the terrain:

The World is Flat Enough

The World is Flat Enough

Before we can move our camera in a 3D space, we need to define the world that we will be moving in.

It took me a while to decide how I wanted to represent the world in my game. At first, I wanted to keep the low-poly aesthetic from the 80s, but I also wanted to retain the “real world maps” feel used in the original games.

Eventually, I decided to go with a more “realistic” world and take advantage of the fact that we are no longer limited by 80s hardware. So, 3D semi-realistic it is.

Models And Cameras, Oh My!

Models And Cameras, Oh My!

In the previous post, we explored how to move a 3D model using angles. However, a camera is not a model. It does not have a generic transform component, so we need to find another way to rotate it.

“raylib” defines a data structure called a “Quaternion”. It is a mathematical construct used to represent rotations in 3D space safely, without suffering from gimbal lock - a notorious problem that occurs when relying solely on Euler angles.

Orientation Is Everything

Orientation Is Everything

Let’s continue exploring model movement. In this example, we will take all three angles into account: roll, pitch, and yaw.

But before we start, let’s go back to the basics. What we did in the last post was apply a transformation to the model.

(This isn’t going to be a linear algebra lesson; you can find more about linear transformations in 3D space in this article.)

As a reminder, if we want to apply multiple transformations, we can combine them into a single transformation. We do this by multiplying the transformation matrices together (applied sequentially as Yaw $\rightarrow$ Pitch $\rightarrow$ Roll):

Moving Around

Moving Around

In the last post, I set up the window and the camera. Now it’s time to add some movement to the plane.

First, let’s remember an aircraft always move forward (if it’s not falling) and it can change its direction by changing its orientation, what we know as “pitch”, “yaw”, and “roll”.

But for demonstration purposes, I’ll move an object in 3D instead of the camera.

Model Transformation

Let’s start with placing model on our surface. The first vector is its position, the scalar is its scale, and the last one is its color (if not textured).

Its Just a Window

Its Just a Window

This post is diving directory into “raylib” usage. Feel free to skip it if you are not interested in the technical details of the implementation.

Without further ado, let’s start with the basics.

Creating a window in a specific size and title is as simple as calling the InitWindow function with the desired width, height, and title. The main loop of the program is a simple while loop that checks if the window should close, and if not, it begins drawing, clears the background, draws some text, and ends drawing.

Tech Stack

Tech Stack

When I started this project, I didn’t have a clear idea of the tech stack I would be using. I just knew I wanted to dive into low-level graphics programming and leverage my past experience with C++.

During my research, I discovered raylib, a simple and easy-to-use graphics library. It simplifies the starting point tremendously and saves me from having to build a rendering engine from scratch.

I explored options like Rust, Go, and Zig, but since raylib is written in C, I ultimately chose C++ to take advantage of its native C compatibility.

Getting Started

Getting Started

Welcome to the development, or more precisely, the remake, of the classic 1989 F-15 II flight simulator by MicroProse.

The purpose of this blog is to document the project’s journey, explain the decisions made along the way, and share the lessons I learn.

I kicked off the project by selecting a technology stack and researching modern OpenGL workflows. For the core language, I chose to return to C++, a language I was once familiar with and am excited to dive back into.