Module agb::display::affine

source ·
Expand description

Affine matrices for the Game Boy Advance

An affine matrix represents an affine transformation, an affine transformation being one which preserves parallel lines (note that this therefore cannot represent perspective seen in games like Super Mario Kart). Affine matrices are used in two places on the GBA, for affine backgrounds and for affine objects.

Linear Algebra

As a matrix, they can be manipulated using linear algebra. The short version of this section is to beware that the matrix is the inverse of the normal transformation matrices.

One quick thing to point out at the start as it will become very relevant is that matrix-matrix multiplication is not commutative, meaning swapping the order changes the result, or A × BB × A. However, matrices are, at least in the case they are used here, associative, meaning (AB)C = A(BC).

Normal (wrong on GBA!) transformation matrices

As a start, normal transformation matrices will transform a shape from it’s original position to it’s new position. Generally when people talk about transformation matrices they are talking about them in this sense.

If A and B are transformation matrices, then matrix C = A × B represents the transformation A performed on B, or alternatively C is transformation B followed by transformation A.

This is not what they represent on the GBA! If you are looking up more information about transformation matrices bear this in mind.

Correct (on GBA) transformation matrices

On the GBA, the affine matrix works the other way around. The GBA wants to know for each pixel what colour it should render, to do this it applies the affine transformation matrix to the pixel it is rendering to lookup correct pixel in the texture.

This describes the inverse of the previously given transformation matrices.

Above I described the matrix C = A × B, but what the GBA wants is the inverse of C, or C-1 = (AB)-1 = B-1 × A-1. This means that if we have the matrices I and J in the form the GBA expects then

Transformation K = I × J is the transformation I followed by the transformation J.

Beware if you are used to the other way around!

Example, rotation around the center

To rotate something around its center, you will need to move the thing such that the center is at (0, 0) and then you can rotate it. After that you can move it where you actually want it.

These can be done in the order I stated, A = Move To Origin × Rotate × Move to Final Position. Or in code,

use agb::fixnum::{Vector2D, Num, num};
use agb::display::affine::AffineMatrix;

// size of our thing is 10 pixels by 10 pixels
let size_of_thing: Vector2D<Num<i32, 8>> = (10, 10).into();
// rotation by a quarter turn
let rotation: Num<i32, 8> = num!(0.25);
// the final position
let position: Vector2D<Num<i32, 8>> = (100, 100).into();

// now lets calculate the final transformation matrix!
let a = AffineMatrix::from_translation(-size_of_thing / 2)
    * AffineMatrix::from_rotation(rotation)
    * AffineMatrix::from_translation(position);

Structs

  • An affine matrix stored in a way that is efficient for the GBA to perform operations on. This implements multiplication.
  • An affine matrix that can be used in affine backgrounds
  • An affine matrix that can be used in affine objects
  • The error emitted upon a conversion that could not be performed due to overflowing the destination data size