Sonic Battle (GBA) Renderer Series - Appendix: Notes

Posted on November 07, 2018

Table of Contents

Welcome to the second appendix of the Sonic Battle (GBA) Renderer series.


This page is a collection of notes and implementation details. Links to specific locations in this doc are scattered across the series.


Coordinate system

The series uses the OpenGL coordinate system:

  • -Z: forward
  • X: right
  • Y: up

For rotation:

  • Right-handed
  • Heading (Z axis) is applied first
  • Pitch (X axis) is applied next
  • Roll (Y axis) is never used

The default camera view direction is straight down, towards the terrain:

The camera will usually be tilted for a lateral view:


On the GBA the term draw doesn’t make much sense. What we do instead is write tilemap/sprite properties into specific memory locations and the hardware takes care of the rest. That’s a recurring pattern on the GBA by the way (the memory-mapped I/O principle)! Because there’s no operating system to speak of, practically everything on the GBA is controlled by writing to memory addresses called registers. From configuring video modes and input handling callbacks to controlling the audio output.

Long story short, draw makes sense for the demo implementation because it uses modern graphics APIs through the Oryol framework.

Canvas/screen space

Top - view-space, bottom - canvas space

Our renderer calculates the view-space position of the items we want to display. That’s not enough however. The positions need to be converted to canvas coordinates for the GBA.

Gabriel Gambetta explains it in his Computer Graphics from scratch series.

Affine matrix intricacies

There’s a few gotchas described in Tonc.

One that stands out is that the GBA actually expects the inverse of the affine matrix.

Another detail is that it takes fixed-point numbers in the 8.8 format (8 bits for integer value, 8 bits for fractional value). The GBA deals natively in 32 bits, so 16 bit data types are less precise and even underperform! Tonc recommends that the standard 32-bit signed representation always be used until the final conversion is necessary.