Nugget
Loading...
Searching...
No Matches
Functions
psyqo::GteMath Namespace Reference

Functions

PSYQO_GTE_MATH_INLINE void matrixVecMul3 (const Matrix33 &m, const Vec3 &v, Vec3 *out)
 Multiplies a vector by a matrix.
 
PSYQO_GTE_MATH_INLINE void matrixVecMul3xy (const Matrix33 &m, const Vec3 &v, Vec2 *out)
 Multiplies a vector by a matrix, keeping only x and y.
 
PSYQO_GTE_MATH_INLINE FixedPoint matrixVecMul3z (const Matrix33 &m, const Vec3 &v)
 Multiplies a vector by a matrix, keeping only z.
 
PSYQO_GTE_MATH_INLINE Matrix33 fromColumns (const Vec3 &c0, const Vec3 &c1, const Vec3 &c2)
 Builds a matrix from three column vectors.
 
PSYQO_GTE_MATH_INLINE void multiplyMatrix33 (const Matrix33 &m1, const Matrix33 &m2, Matrix33 *out)
 Multiplies two matrices.
 
PSYQO_GTE_MATH_INLINE void crossProductVec3 (const Vec3 &v1, const Vec3 &v2, Vec3 *out)
 Cross product of two vectors.
 
PSYQO_GTE_MATH_INLINE FixedPoint inverseSquareRootSeed (FixedPoint<> x)
 The seed for an inverse square root, from the GTE's leading-bit count.
 
void normalizeVec3 (Vec3 *v)
 Normalises a vector in place.
 
PSYQO_GTE_MATH_INLINE void fastNormalizeVec3 (Vec3 *v)
 Normalises a vector in place, without the exact square root.
 
PSYQO_GTE_MATH_INLINE Vec3 cubic (const Vec3 &a, const Vec3 &b, const Vec3 &c, const Vec3 &d, FixedPoint<> t)
 Evaluates a cubic Bezier at t.
 
PSYQO_GTE_MATH_INLINE Vec3 cubicDerivative (const Vec3 &a, const Vec3 &b, const Vec3 &c, const Vec3 &d, FixedPoint<> t)
 Evaluates the derivative of a cubic Bezier at t.
 

Function Documentation

◆ crossProductVec3()

PSYQO_GTE_MATH_INLINE void psyqo::GteMath::crossProductVec3 ( const Vec3 v1,
const Vec3 v2,
Vec3 out 
)

Cross product of two vectors.

2.56x on hardware, but read the clobber list before reaching for it.

CLOBBERS: R11, R22 and R33 - the ROTATION MATRIX DIAGONAL - plus IR1-3 and MAC1-3. The GTE's cross product takes its first operand from those three matrix elements rather than from a vector register, so calling this destroys a loaded rotation matrix. That makes it unsafe inside a projection loop unless you reload RT afterwards. It is free at load time, when nothing owns RT yet.

◆ cubic()

PSYQO_GTE_MATH_INLINE Vec3 psyqo::GteMath::cubic ( const Vec3 a,
const Vec3 b,
const Vec3 c,
const Vec3 d,
FixedPoint<>  t 
)

Evaluates a cubic Bezier at t.

A cubic Bezier is a weighted sum of four control points, and MVMVA computes Mx * Vx + Tx. Load three control points as the matrix COLUMNS and the Bernstein weights as the vector, and the fourth term rides in the translation register. One GTE op plus three multiplies, against twelve multiplies in software.

This is the operation that justifies the header on its own: a curve sampled once per frame is how you get smooth camera motion along a 3D path, and that is a realtime cost rather than a load-time one.

Verified against psyqo::Bezier::cubic: worst component deviation 3 raw out of 4096.

CLOBBERS: the rotation matrix (RT), the translation vector (TR), V0, IR1-3, MAC1-3.

◆ cubicDerivative()

PSYQO_GTE_MATH_INLINE Vec3 psyqo::GteMath::cubicDerivative ( const Vec3 a,
const Vec3 b,
const Vec3 c,
const Vec3 d,
FixedPoint<>  t 
)

Evaluates the derivative of a cubic Bezier at t.

The derivative is a quadratic Bezier over the differences of consecutive control points, so it is only THREE terms and needs no translation vector at all - one MVMVA and nothing else.

The factor of three that belongs in a true derivative is dropped. The usual consumer is a tangent that gets crossed and normalised, where only the direction survives; scale it yourself if you need the real magnitude.

CLOBBERS: the rotation matrix (RT), V0, IR1-3, MAC1-3. Not TR.

◆ fastNormalizeVec3()

PSYQO_GTE_MATH_INLINE void psyqo::GteMath::fastNormalizeVec3 ( Vec3 v)

Normalises a vector in place, without the exact square root.

Same as normalizeVec3 here. SoftMath draws a distinction between an exact normalize and a fast one; on this path there is no reason for two, and the "fast" one in SoftMath seeds inverseSquareRoot with x * 2, which moves the wrong way as the vector shrinks.

CLOBBERS: LZCS and LZCR only.

◆ fromColumns()

PSYQO_GTE_MATH_INLINE Matrix33 psyqo::GteMath::fromColumns ( const Vec3 c0,
const Vec3 c1,
const Vec3 c2 
)

Builds a matrix from three column vectors.

Matrix33 stores ROWS. Several GTE formulations want the matrix built from columns - a weighted sum of three vectors is one MVMVA only if those vectors are the columns - so this scatters each one across the three rows. Getting it backwards produces plausible-looking garbage, which is why it is a named function rather than an open-coded initialiser at each site.

◆ inverseSquareRootSeed()

PSYQO_GTE_MATH_INLINE FixedPoint psyqo::GteMath::inverseSquareRootSeed ( FixedPoint<>  x)

The seed for an inverse square root, from the GTE's leading-bit count.

The seed wants HALF the exponent, since the target is 1/sqrt(x) and not 1/x. With lzcr = 31 - floor(log2(x.raw())), that is (5 + lzcr) / 2 in 20.12. Shifting by the whole count is a seed for the wrong function: it is correct only where x == 0.0625 and diverges either side, and because SoftMath::inverseSquareRoot is four Newton steps with no convergence check, a seed outside the basin explodes rather than degrading. Swept over all 4096 representable values below 1.0, the halved exponent has a worst relative error of 0.48% and no failures; the unhalved one breaks 199 of them.

CLOBBERS: LZCS and LZCR only. Safe to call with a matrix loaded.

NOTE: LZCS/LZCR do not interlock the way the cop2 commands do - they are the one corner of the GTE where the hardware will not stall for you - so the write must be Safe.

◆ matrixVecMul3()

PSYQO_GTE_MATH_INLINE void psyqo::GteMath::matrixVecMul3 ( const Matrix33 m,
const Vec3 v,
Vec3 out 
)

Multiplies a vector by a matrix.

Drop-in for SoftMath::matrixVecMul3. 2.15x on hardware even paying the matrix upload here.

CLOBBERS: the rotation matrix (RT), V0, IR1-3, MAC1-3.

◆ matrixVecMul3xy()

PSYQO_GTE_MATH_INLINE void psyqo::GteMath::matrixVecMul3xy ( const Matrix33 m,
const Vec3 v,
Vec2 out 
)

Multiplies a vector by a matrix, keeping only x and y.

CLOBBERS: the rotation matrix (RT), V0, IR1-3, MAC1-3.

◆ matrixVecMul3z()

PSYQO_GTE_MATH_INLINE FixedPoint psyqo::GteMath::matrixVecMul3z ( const Matrix33 m,
const Vec3 v 
)

Multiplies a vector by a matrix, keeping only z.

CLOBBERS: the rotation matrix (RT), V0, IR1-3, MAC1-3.

◆ multiplyMatrix33()

PSYQO_GTE_MATH_INLINE void psyqo::GteMath::multiplyMatrix33 ( const Matrix33 m1,
const Matrix33 m2,
Matrix33 out 
)

Multiplies two matrices.

out = m2 * m1, matching SoftMath::multiplyMatrix33's convention. Column j of the product is m2 applied to column j of m1, so this is three MVMVA against 27 fixed-point multiplies: 5.46x on hardware.

Aliasing is fine: the result is accumulated before anything is written back, so out may be &m1 or &m2.

CLOBBERS: the rotation matrix (RT), V0, IR1-3, MAC1-3.

◆ normalizeVec3()

void psyqo::GteMath::normalizeVec3 ( Vec3 v)

Normalises a vector in place.

Drop-in for SoftMath::normalizeVec3, which reaches 1/sqrt through squareRoot's shift-subtract loop at about 3588 cycles a vector. This keeps the squared length on the CPU - three multiplies - and takes only the seed from the GTE, then uses the existing Newton refinement. Measured against the exact version over 800 vectors, worst component deviation is 10 raw out of 4096, i.e. 0.24%.

A zero-length vector is left as (0, 0, 1) rather than dividing by zero: SoftMath::squareRoot returns 0 for x.raw() <= 1 and normalizeVec3 then divides by it.

CLOBBERS: LZCS and LZCR only.