ACSUtils provides a rich math library and covers for several missing ZDoom functions.
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
num
. num
s 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)
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
.
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.
#define PI 3.1415926535897932384626433832795
#define TAU 6.2831853071795864769252867665590
The numbers Pi and Tau.
#define MATH_E 2.7182818284590452353602874713526624977572470937
The number e. Called MATH_E
to avoid conflicts with variable name e
.
Precalculated to maximum precision. The precalculated logarithms are used to implement ln
and log10
.
#define SQRT_2 1.41421356237
– sqrt(2)#define LOG2_E 1.44269504089
– log2(e)#define LOG2_10 3.32192809489
– log2(10)
num abs(num x)
Returns the absolute value of X:
INT_MIN
.
abs(INT_MIN) == INT_MIN
because -INT_MIN == INT_MIN
. This is the only case when abs
returns a negative number.
int sgn(int x)
Returns the sign of X:
1
.-1
.0
.// Make X velocity 15.0, but with the same sign as foo int xvel = sgn(foo) * 15.0;
num min(num a, num b)
Returns the lesser of two numbers.
num max(num a, num b)
Returns the greater of two numbers.
num clamp(num x, num mininum, num maximum)
Limits X to the specified range:
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.
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); }
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.
Can also be used as a more readable alternative to FixedDiv(a<<16, b<<16)
.
int cmp(num a, num b)
Compares two numbers and returns the result:
1
.0
.-1
.
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
.
int ipow(int x, int y)
Returns xy. Uses a simple multiplication loop.
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
.
ACSUtils provides a full set of trigonometric functions:
fixed tan(fixed angle)
– implemented as FixedDiv(sin(x), cos(x))
.fixed cot(fixed angle)
– implemented as FixedDiv(cos(x), sin(x))
.fixed sec(fixed angle)
– implemented as FixedDiv(1.0, sin(x))
.fixed cosec(fixed angle)
– implemented as FixedDiv(1.0, cos(x))
.Inverse trigonometric functions:
fixed atan(fixed x)
– implemented as VectorAngle(1.0, x)
.fixed acot(fixed x)
– implemented as 0.25 - atan(x)
.fixed asin(fixed x)
– implemented as atan(FixedDiv(x, FixedSqrt(1.0 - FixedMul(x, x))))
.fixed acos(fixed x)
– implemented as ang(2 * atan(FixedSqrt(FixedDiv(1.0 - x, 1.0 + x))))
.fixed asec(fixed x)
– implemented as acos(FixedDiv(1.0, x))
.fixed acosec(fixed x)
– implemented as asin(FixedDiv(1.0, x))
.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
.
fixed VectorLength3D(fixed x, fixed y, fixed Z)
These functions return the length of the input vector. VectorLength3D
is implemented efficiently as VectorLength(VectorLength(x, y), z)
.
fixed dot2(fixed x1, fixed y1, fixed x2, fixed y2)
fixed dot3(fixed x1, fixed y1, fixed z1, fixed x2, fixed y2, fixed z2)
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) + …
.
fixed, fixed normalize2d(fixed x, fixed y)
fixed, fixed, fixed normalize3d(fixed x, fixed y, fixed z)
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.
normalize3d(x, y, z); x = r1; y = r2; z = r2;
normalize2d(x, y); int normalizedX = r1; int normalziedY = r2;
fixed, fixed RotateVector(fixed x, fixed y, fixed angle)
Rotates the vector by the angle and returns the result using Multiple return values.
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;
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.
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;
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.
RotatePoint(x, y, originX, originY, angle); int newX = r1; int newY = r2;
fixed SqVectorLength(fixed x, fixed y)
fixed SqVectorLength3D(fixed x, fixed y, fixed z)
Returns vector length squared.
256.0
.
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.
// 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. }
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.
AnglesToVector(GetActorAngle(0), -GetActorPitch(0)); // Un-negate actor pitch int dirX = r1; int dirY = r2; int dirZ = r3;
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.
fixed log2(fixed x)
fixed ilog2(int x)
Returns the base-2 logarithm of X.
fixed log10(fixed x)
fixed ilog10(int x)
Returns the base-10 logarithm of X. Implemented by dividing log2(X) by the precalculated constant LOG2_10
.
fixed ln(fixed x)
fixed iln(int x)
Returns the natual (base-e) logarithm of X. Implemented by dividing log2(X) by the precalculated constant LOG2_E
.
fixed logb(fixed x, fixed base)
fixed ilogb(int x, fixed base)
Returns an arbitrary-base logarithm of X. Calculates FixedDiv(log2(x), log2(base))
.
1.0
are supported.
1.0
may produce a result that doesn't fit into a fixed.
Note that even the integer version has a fixed-point base.