Table of Contents

Math

ACSUtils provides a rich math library and covers for several missing ZDoom functions.

Notes

What is "num"?

num means “any numeric type” (either int or fixed). Functions accepting num accept both ints and fixeds, e.g:

num max(num a, num b)

translates to:

“The function max accepts two numbers and returns a number. If both arguments are ints, it returns an int, and if both arguments are fixeds, it returns a fixed”.

This allows max to be used both ways:

max(2, 5) == 5
max(2.0, 5.0) == 5.0
Don't mix ints and fixeds when using num. nums in a function signature are either all int or all fixed! E.g., this is incorrect:
max(5, 2.0)

It will return 2.0 because max uses a simple a > b comparison that only works correctly if both numbers are ints or both numbers are fixeds. 2.0 (65536) is greater than 5.

However, not all arguments of a function may be num. Some arguments may be required to be int or fixed, or the function may always return int or fixed:

num OneOfTheArgumentsIsRequiredToBeInt(num a, int b)
fixed ThisFunctionAlwaysReturnsFixed(num a, num b)

Angles

All angles throughout ACSUtils are fixed-point angles (turns), and they are allowed to be outside the 0.0..1.0 range. All such cases are handled correctly by both ZDoom and ACSUtils.

Also, ZDoom expects inverted actor pitch (positive = looking down) in GetActorPitch and SetActorPitch. ACSUtils doesn't invert pitch angles, so remember to invert pitch when retrieving it with GetActorPitch and when setting it with SetActorPitch.

Constants

ACSUtils provides a set of mathematical constants. All fixed-point constants have a lot of digits after the point to maximize precision. Actually more digits than needed.

Pi and Tau

The numbers Pi and Tau.

e

#define MATH_E 2.7182818284590452353602874713526624977572470937

The number e. Called MATH_E to avoid conflicts with variable name e.

Significant square roots and logarithms

Precalculated to maximum precision. The precalculated logarithms are used to implement ln and log10.

Generic math functions

abs

num abs(num x)

Returns the absolute value of X:

Beware of using this function with INT_MIN.

abs(INT_MIN) == INT_MIN because -INT_MIN == INT_MIN. This is the only case when abs returns a negative number.

sgn

int sgn(int x)

Returns the sign of X:

Example usage

// Make X velocity 15.0, but with the same sign as foo
int xvel = sgn(foo) * 15.0;

min

num min(num a, num b)

Returns the lesser of two numbers.

max

num max(num a, num b)

Returns the greater of two numbers.

clamp

num clamp(num x, num mininum, num maximum)

Limits X to the specified range:

lerp

fixed lerp(fixed a, fixed b, fixed alpha)

Linear interpolation function commonly used in game development. Performs linear interpolation (or extrapolation) between A and B and returns the result.

Alpha can be outside of 0.0..1.0 range. In that case, it's linear extrapolation.

example usage

Simple movement animation between two points:

for (int time = 0; time < 1.0; time += 0.05)
{
    int x = lerp(x1, x2, time); 
    int y = lerp(y1, y2, time);
    DrawSomething(x, y);
    Delay(1);
}

IntDiv

fixed IntDiv(int a, int b)

An equivalent of FixedDiv for integers that works for any two integers as long as the result fits into a fixed-point number. Divides integer A by integer B and returns the result as a fixed-point number.

If the result is greater than 32767, the function returns 0.

Can also be used as a more readable alternative to FixedDiv(a<<16, b<<16).

cmp

int cmp(num a, num b)

Compares two numbers and returns the result:

fract

fixed fract(fixed x)

Returns the fractional part of X, e.g fract(12.345) == 0.345.

The result is not affected by the sign of the number, e.g. fract(-12.345) == 0.345. The result is always between 0.0 and 1.0.

ipow

int ipow(int x, int y)

Returns xy. Uses a simple multiplication loop.

fpow

fixed fpow(fixed x, fixed y)

returns xy. Supports powers below 1.0. Uses a simple loop with FixedMul or FixedDiv, depending on whether the power is below 1.0.

Trigonometry

ACSUtils provides a full set of trigonometric functions:

Inverse trigonometric functions:

Vector math

Vector math functions come in 2D and 3D versions. All vector math functions operate only on fixed-point vectors. No integer versions are available.

Vectors are passed as arguments named x, y, z.

If a function returns a vector, it uses Multiple return values, returning vector components in the same XYZ order, so r1 is X, r2 is Y and r3 is Z.

If a function accepts more than one vector, the first vector is passed as x1, y1, z1, and the second one as x2, y2, z2.

Length

These functions return the length of the input vector. VectorLength3D is implemented efficiently as VectorLength(VectorLength(x, y), z).

Dot product

These functions return the sum of components of a vector obtained by componentwise multiplication of the two input vectors, also known as the dot product. They are shorthands for writing out FixedMul(x1, x2) + FixedMul(y1, y2) + ….

Normalization

These functions return the input vector scaled to have length 1.0, also known as normalizing the input vector, and return the result using Multiple return values.

Examples

normalize3d(x, y, z);
x = r1;
y = r2;
z = r2;
normalize2d(x, y);
int normalizedX = r1;
int normalziedY = r2;

RotateVector

fixed, fixed RotateVector(fixed x, fixed y, fixed angle)

Rotates the vector by the angle and returns the result using Multiple return values.

Example usage

RotateVector(x, y, angle);
int newX = r1;
int newY = r2;
// Rotate a point around the origin
// Use RotatePoint instead of this example code
RotateVector(x - originX, y - originY, angle);
int newX = r1 + originX;
int newY = r2 + originY;

RotateVectorCS

fixed, fixed RotateVector(fixed x, fixed y, fixed cos, fixed sin)

A faster version of RotateVector that accepts cos(angle) and sin(angle) instead of computing them.

Example usage

int c = cos(angle);
int s = sin(angle);

// Rotate first vector
RotateVectorCS(x1, y1, c, s);
x1 = r1;
y1 = r2;

// Rotate second vector without recalculating sine and cosine
RotateVectorCS(x2, y2, c, s);
x2 = r1;
y2 = r2;

RotatePoint

fixed, fixed RotatePoint(fixed x, fixed y, fixed originX, fixed originY, fixed angle)

Rotates the point around the specified origin by the angle and returns the result using Multiple return values.

Example usage

RotatePoint(x, y, originX, originY, angle);
int newX = r1;
int newY = r2;

SqVectorLength

Returns vector length squared.

Because this function returns a fixed, it won't work correctly for vectors longer than 256.0.

VectorToAngles

fixed, fixed VectorToAngles(fixed x, fixed y, fixed z)

Converts the vector's direction to a pair of angles (angle, pitch) and returns them using Multiple return values.

Remember that ZDoom uses negated pitch angles on actors. ACSUtils functions don't use negated pitches.

Example usage

// This function makes the actor look in the direction
// specified as a 3D vector.
function void LookInDirection(int tid, int x, int y, int z)
{
    VectorToAngles(x, y, z);
    int angle = r1;
    int pitch = r2;
    SetActorAngle(tid, angle);
    SetActorPitch(tid, -pitch); // SetActorPitch expects negated pitch.
}

AnglesToVector

fixed, fixed, fixed AnglesToVector(fixed angle, fixed pitch)

Converts a pair of angles (angle, pitch) to a 3D vector of length 1.0, which points in the same direction, and returns it using Multiple return values.

Remember that ZDoom uses negated pitch angles on actors. ACSUtils functions don't use negated pitches.

Example usage

AnglesToVector(GetActorAngle(0), -GetActorPitch(0)); // Un-negate actor pitch
int dirX = r1;
int dirY = r2;
int dirZ = r3;

Logarithms

Base-2 logarithms are the fundamental algorithm. All other bases are implemented using the property “log_b(x) = log_2(x) / log_2(b) if b > 1”.

All logarithm functions return a fixed, but there are two versions of every logarithm function: one accepting an integer X and one accepting a fixed-point X. The integer-accepting functions have the i prefix.

log2

Returns the base-2 logarithm of X.

log10

Returns the base-10 logarithm of X. Implemented by dividing log2(X) by the precalculated constant LOG2_10.

ln

Returns the natual (base-e) logarithm of X. Implemented by dividing log2(X) by the precalculated constant LOG2_E.

logb

Returns an arbitrary-base logarithm of X. Calculates FixedDiv(log2(x), log2(base)).

Only bases higher than 1.0 are supported.
Using these functions with bases very close to 1.0 may produce a result that doesn't fit into a fixed.

Note that even the integer version has a fixed-point base.