# math¶

This module provides mathematical utilities, including fixed-point numbers, sin, cos & div lookup tables, 2D vectors and rectangles.

## Fixed-Point Numbers¶

Fixed-point arithmetic allows you to treat some integer as if it were fractional, which is much faster than using floats on the GBA.

The `Fixed` type makes working with ‘24.8’ fixed-point values most convenient. These can be created using the `fp` template. For example:

```let a = fp(1.25)
let b = fp(8.5)
assert a + b == fp(9.75)
```

Working at other precisions can be done with the `FixedN` type, and using a different underlying integer type is supported with `FixedT`.

These are created with the `toFixed` template:

```let k = (1.5).toFixed(int8, 4)  # an 8-bit value with 4 bits of precision

static:
echo typeof(k)  # prints "FixedT[int8, 4]"
```

### Types¶

type FixedT[T: SomeInteger, N: static int] = distinct T

A fixed-point number based on type `T`, with `N` bits of precision.

type FixedN[N: static int] = FixedT[cint, N]

A signed 32-bit fixed-point number with `N` bits of precision.

type Fixed = FixedN[8]

A signed 32-bit fixed-point number with 8 bits of precision.

### Conversion Templates¶

Convert a value to fixed-point with 8 bits of precision.

template toFixed(n: SomeNumber, F: typedesc[FixedT]): untyped

Convert a number to the fixed-point type `F`.

template toFixed[T, N](n: FixedT, F: typedesc[FixedT[T,N]]): untyped

Convert from one fixed-point format to another.

template toFixed(n: SomeNumber|FixedT, T: typedesc[SomeInteger], N: static int): untyped

Convert a value to fixed-point, with a base type of `T` using `N` bits of precision.

template toInt(n: FixedT): int

Convert a fixed-point value to an integer.

template toFloat32(n: FixedT): float32

Convert a fixed-point value to floating point.

template raw[F: FixedT](a: F): untyped

### Arithmetic Operators¶

The basic operators available to fixed-point numbers are given below. These are implemented as templates to encourage the Nim compiler to evaluate them at compile-time.

Note

There are operators defined between fixed-point and integer types, so `fp(0.5) * 2` is allowed, and will give a fixed-point result.

However, there are no implicit converters defined, and you can’t mix fixed-point types of differing size and precision.

To add two fixed-point numbers of different precision together, one must be converted to the other:

```let a = fp(0.5)               # 8 bits precision
let b = (0.5).toFixed(10)     # 10 bits precision

# let sum1 = a + b            # Not allowed!

let sum2 = a + fp(b)          # Ok, both 8 fractional bits
let sum3 = a.toFixed(10) + b  # Ok, both 10 fractional bits
```
template `+`[F: FixedT](a, b: F): F
template `-`[F: FixedT](a, b: F): F
template `*`[F: FixedT](a, b: F): F
template `/`[F: FixedT](a, b: F): F
template `==`[F: FixedT](a, b: F): bool
template `<`[F: FixedT](a, b: F): bool
template `<=`[F: FixedT](a, b: F): bool
template `+`[F: FixedT](a: F): F
template `-`[F: FixedT](a: F): F
template `+=`[F: FixedT](a: var F, b: F)
template `-=`[F: FixedT](a: var F, b: F)
template `*=`[F: FixedT](a: var F, b: F)
template `/=`[F: FixedT](a: var F, b: F)
template `+`[F: FixedT, I: SomeInteger](a: F, b: I): F
template `-`[F: FixedT, I: SomeInteger](a: F, b: I): F
template `*`[F: FixedT, I: SomeInteger](a: F, b: I): F
template `/`[F: FixedT, I: SomeInteger](a: F, b: I): F
template `+`[F: FixedT, I: SomeInteger](a: I, b: F): F
template `-`[F: FixedT, I: SomeInteger](a: I, b: F): F
template `*`[F: FixedT, I: SomeInteger](a: I, b: F): F
template `==`[F: FixedT, I: SomeInteger](a: F, b: I): bool
template `<`[F: FixedT, I: SomeInteger](a: F, b: I): bool
template `<=`[F: FixedT, I: SomeInteger](a: F, b: I): bool
template `==`[F: FixedT, I: SomeInteger](a: I, b: F): bool
template `<`[F: FixedT, I: SomeInteger](a: I, b: F): bool
template `<=`[F: FixedT, I: SomeInteger](a: I, b: F): bool
template `+=`[F: FixedT, I: SomeInteger](a: var F, b: I)
template `-=`[F: FixedT, I: SomeInteger](a: var F, b: I)
template `*=`[F: FixedT, I: SomeInteger](a: var F, b: I)
template `/=`[F: FixedT, I: SomeInteger](a: var F, b: I)
template `shr`[F: FixedT, I: SomeInteger](a: F, b: I): F
template `shl`[F: FixedT, I: SomeInteger](a: F, b: I): F
template mul64[F: FixedT](a, b: F): F

Multiply two fixed-point values using 64-bit math (to help avoid overflows)

template div64[F: FixedT](a, b: F): F

Divide two fixed-point values using 64-bit math (to help avoid overflows)

template abs[F: FixedT](a: F): F

## General Math Functions¶

func flr(n: FixedT): cint

Convert a fixed-point number to an integer, always rounding down.

func ceil(n: FixedT): cint

Convert a fixed-point number to an integer, always rounding up.

Get the sign of a number.

Returns `-1` when `x` is negative, `1` when `x` is positive, or `0` when `x` is `0`.

(This procedure comes from the Nim standard library.)

func sgn(x: FixedT): cint

Get the sign of a fixed-point number.

Returns `-1` when `x` is negative, `1` when `x` is positive, or `0` when `x` is `0`.

Returns `1` or `-1` depending on the sign of `x`.

Note: This never returns `0`. Use `sgn` if you want something that does.

func approach[T: SomeNumber|FixedT](x: var T, target, step: T)

Move `x` towards `target` by `step` without exceeding target.

`step` should be a positive number.

func lerp[A: SomeNumber|FixedT, F: FixedT](a, b: A, t: F): A

Linear interpolation between `a` and `b` using the weight given by `t`.

`t` should be a fixed point value in the range of `0.0 .. 1.0`.

## Lookup Tables¶

type Angle = uint32

An angle value, where `0x10000` is equivalent to 2π.

func luSin(theta: Angle): FixedN[12]

Look-up a sine value.

Theta:

An unsigned integer angle, where `0x10000` is a full turn.

Returns a 20.12 fixed-point number between `-1.0` and `1.0`.

func luCos(theta: Angle): FixedN[12]

Look-up a cosine value.

Theta:

An unsigned integer angle, where `0x10000` is a full turn.

Returns a 20.12 fixed-point number between `-1.0` and `1.0`.

func luDiv(x: range[0..256]): FixedN[16]

Look-up a division value between 0 and 256.

Returns `1/x`, represented as a 16.16 fixed point number.

func luLerp[A: SomeInteger|FixedT, F: FixedT](lut: openArray[A], x: F): A

Linear interpolator for LUTs.

An LUT (lookup table) is essentially the discrete form of a function, `f(x)`. You can get values for non-integer `x` via (linear) interpolation between `f(x)` and `f(x+1)`.

Lut:

The LUT to interpolate from.

X:

Fixed-point number to interpolate at.

Example:

```let myLut* {.importc.}: array[100, int16]  # some array of data.

let n: int16 = luLerp(myLut, fp(10.75))    # get a value ¾ between the 10th and 11th entry of `myLut`.
```

## 2D Vectors¶

type Vec2i = object

Integer 2D vector/point type

Field

Type

`x` cint
`y` cint
type Vec2f = object

Fixed-point `24:8` 2D vector/point type

Field

Type

`x` Fixed
`y` Fixed
func vec2i(x, y: int): Vec2i

Initialise an integer vector

func vec2i(): Vec2i

Initialise an integer vector to 0,0

func vec2i(v: Vec2f): Vec2i

Convert an integer vector to a fixed-point vector

Initialise a fixed-point vector

func vec2f(): Vec2f

Initialise a fixed-point vector to 0,0

func vec2f(v: Vec2i): Vec2f

Convert a fixed-point vector to an integer vector

func `+`(a, b: Vec2i): Vec2i

func `-`(a, b: Vec2i): Vec2i

Subtract two vectors

func `*`(a, b: Vec2i): Vec2i

Component-wise multiplication of two vectors

func `*`(a: Vec2i, n: int): Vec2i

Scale vector by n

func `*`(n: int, a: Vec2i): Vec2i

Scale vector by n

func `/`(a, b: Vec2i): Vec2i

Component-wise division of two vectors

func `/`(a: Vec2i, n: int): Vec2i

Scale vector by 1/n

func `/`(n: int, a: Vec2i): Vec2i

Scale vector by 1/n

func dot(a, b: Vec2i): int

Dot product of two vectors

func `-`(a: Vec2i): Vec2i

Equivalent to a * -1

func `+=`(a: var Vec2i, b: Vec2i)

func `-=`(a: var Vec2i, b: Vec2i)

Vector compound subtraction

func `*=`(a: var Vec2i, b: Vec2i)

Vector component-wise compound multiplicatoin

func `*=`(a: var Vec2i, n: int)

Compound scale a vector by n

func `/=`(a: var Vec2i, b: Vec2i)

Vector component-wise compound division

func `/=`(a: var Vec2i, n: int)

Compound scale a vector by 1/n

func `+`(a, b: Vec2i): Vec2i

func `-`(a, b: Vec2i|Vec2f): Vec2f

Subtract two fixed-point vectors

func `*`(a: Vec2f, b: Vec2i|Vec2f): Vec2f

Component-wise multiplication of two vectors

func `*`(a: Vec2f, n: Fixed|int): Vec2f

Scale a fixed-point vector by n

func `*`(n: Fixed|int, a: Vec2f): Vec2f

Scale a fixed-point vector by n

func `/`(a: Vec2f, b: Vec2i|Vec2f): Vec2f

Component-wise division of two vectors

func `/`(a: Vec2f, n: Fixed|int): Vec2f

Scale a fixed-point vector by 1/n

func `/`(n: Fixed|int, a: Vec2f): Vec2f

Scale a fixed-point vector by 1/n

func dot(a, b: Vec2i): int

Dot product of two vectors

func `-`(a: Vec2f): Vec2f

Equivalent to a * -1

func `+=`(a: var Vec2i, b: Vec2i)

func `-=`(a: var Vec2i, b: Vec2i)

Vector compound subtraction

func `*=`(a: var Vec2f, b: Vec2i|Vec2f)

Vector component-wise compound multiplicatoin

func `/=`(a: var Vec2f, b: Vec2i|Vec2f)

Vector component-wise compound division

func `*=`(a: var Vec2f, n: Fixed|int)

Compound scale a vector by n

func `/=`(a: var Vec2f, n: Fixed|int)

Compound scale a vector by 1/n

### Vector Conversion¶

func initBgPoint(x = 0'i16, y = 0'i16): BgPoint

Create a new pair of values used by the BG scroll registers, e.g.

```bgofs[0] = initBgPoint(10, 20)
```
func toBgPoint(a: Vec2i): BgPoint

Convert a vector to a pair of values used by the BG scroll registers, e.g.

```bgofs[0] = pos.toBgPoint()
```
func toBgPoint(a: Vec2f): BgPoint

Convert a fixed-point vector to a pair of values used by the BG scroll registers, e.g.

```bgofs[0] = pos.toBgPoint()
```

## Rectangles¶

type Rect = object

Rectangle type. Ranges from `left..right-1`, `top..bottom-1`

Field

Type

func rectBounds(left, top, right, bottom: int): Rect
func rectAt(x, y, width, height: int): Rect
func x(r: Rect): int
func y(r: Rect): int
func w(r: Rect): int
func h(r: Rect): int
func width(r: Rect): int
func height(r: Rect): int
func `x=`(r: var Rect, x: int)
func `y=`(r: var Rect, y: int)
func `w=`(r: var Rect, w: int)
func `h=`(r: var Rect, h: int)
func `width=`(r: var Rect, w: int)
func `height=`(r: var Rect, h: int)
func move(r: var Rect, dx, dy: int)

Move rectangle by (`dx`, `dy`)

func move(r: var Rect, vec: Vec2i)

Move rectangle by `vec`

func inflate(r: var Rect, n: int)

Increase size of rectangle by `n` on all sides

func inflate(r: var Rect, dw, dh: int)

Increase size of rectangle by `dw` horizontally, `dh` vertically

func center(r: Rect): Vec2i

Get the center point of a rectangle

func `center=`(r: var Rect, p: Vec2i)

Set the center point of a rectangle

func topLeft(r: Rect): Vec2i
func topRight(r: Rect): Vec2i
func bottomLeft(r: Rect): Vec2i
func bottomRight(r: Rect): Vec2i