math

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:

- If X is zero or positive, returns X.
- If X is negative, returns -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:

- If X is positive, returns
`1`

. - If X is negative, returns
`-1`

. - If X is zero, returns
`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:

- If X < mininum, returns the minumum.
- If X is between mininum and maximum, returns X.
- If X > maximum, returns the maximum.

`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.

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)`

.

`int cmp(num a, num b)`

Compares two numbers and returns the result:

- If A > B, returns
`1`

. - If A = B, returns
`0`

. - If A < B, returns
`-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 x^y. Uses a simple multiplication loop.

`fixed fpow(fixed x, fixed y)`

returns x^y. 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:

- sin is already built into ZDoom.
- cos is already built into ZDoom.
`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))`

.

`fixed VectorLength3D(fixed x, fixed y, fixed z)`

A 3D version of VectorLength. Returns the length of the 3D vector.

- 2D:
`fixed dot2(fixed x1, fixed y1, fixed x2, fixed y2)`

- 3D:
`fixed dot3(fixed x1, fixed y1, fixed z1, fixed x2, fixed y2, fixed z2)`

Returns the dot product of two vectors. Shorthand for writing out `FixedMul(x1, x2) + FixedMul(y1, y2) + …`

.

- 2D:
`fixed, fixed normalize2d(fixed x, fixed y)`

- 3D:
`fixed, fixed, fixed normalize3d(fixed x, fixed y, fixed z)`

Normalizes the vector and returns 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.

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

`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.

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

// 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.

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

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))`

.

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.

math.txt · Last modified: 2019/07/05 22:38 by korshun