Files
2026-02-02 04:50:13 +01:00

502 lines
16 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Copyright (C) 2006-2010 - Frictional Games
*
* This file is part of HPL1 Engine.
*/
#ifndef HPL_MATH_H
#define HPL_MATH_H
#include "hpl1/engine/math/BoundingVolume.h"
#include "hpl1/engine/math/MathTypes.h"
#include "hpl1/engine/math/MeshTypes.h"
#include "hpl1/engine/graphics/Color.h"
namespace hpl {
class cMath {
public:
//////////////////////////////////////////////////////
////////// RANDOM GENERATION ////////////////////////
//////////////////////////////////////////////////////
/**
* Generates a random integer from min to max
* \param alMin
* \param alMax
* \return
*/
static int RandRectl(int alMin, int alMax);
/**
* Generates a random float from min to max
* \param alMin
* \param alMax
* \return
*/
static float RandRectf(float alMin, float alMax);
/**
* Generates a random float from min to max
*/
static cVector2f RandRectVector2f(const cVector3f &avMin, const cVector3f &avMax);
/**
* Generates a random float from min to max
*/
static cVector3f RandRectVector3f(const cVector3f &avMin, const cVector3f &avMax);
/**
* Generates a random float from min to max
*/
static cColor RandRectColor(const cColor &aMin, const cColor &aMax);
/**
* Randomize the rand funcs.
* \param alSeed the seed, -1 = random seed.
*/
static void Randomize(int alSeed = -1);
//////////////////////////////////////////////////////
////////// COLLSION //////////////////////////////////
//////////////////////////////////////////////////////
static bool BoxCollision(cRect2l aRect1, cRect2l aRect2);
static bool BoxCollision(cRect2f aRect1, cRect2f aRect2);
static bool PointBoxCollision(cVector2f avPoint, cRect2f aRect);
static bool BoxFit(cRect2l aRectSrc, cRect2l aRectDest);
static bool BoxFit(cRect2f aRectSrc, cRect2f aRectDest);
static float Dist2D(const cVector2f &avPosA, const cVector2f &avPosB);
static float Dist2D(const cVector3f &avPosA, const cVector3f &avPosB);
static float SqrDist2D(const cVector2f &avPosA, const cVector2f &avPosB);
static float SqrDist2D(const cVector3f &avPosA, const cVector3f &avPosB);
static cRect2f &ClipRect(cRect2f &aRectSrc, const cRect2f &aRectDest);
/**
* Checks collison between two bounding volumes.
* \return true if collision, else false.
*/
static bool CheckCollisionBV(cBoundingVolume &aBV1, cBoundingVolume &aBV2);
static bool PointBVCollision(const cVector3f &avPoint, cBoundingVolume &aBV2);
/**
* Creates a clip rect for a bounding volume in screen space.
* \return false if behind near clip.
*/
static bool GetClipRectFromBV(cRect2l &aDestRect, cBoundingVolume &aBV,
const cMatrixf &a_mtxView, const cMatrixf &a_mtxProj,
float afNearClipPlane, const cVector2l &avScreenSize);
static bool CheckSphereInPlanes(const cVector3f &avCenter, float afRadius,
const cPlanef *apPlanes, int alPlaneCount);
//////////////////////////////////////////////////////
////////// FLOAT OPERATIONS ////////////////////////
//////////////////////////////////////////////////////
/**
* Get fraction part of a float
* \param afVal
* \return
*/
static float GetFraction(float afVal);
/**
* Moldus (%) of a float
* \param afDividend
* \param afDivisor
* \return
*/
static float Modulus(float afDividend, float afDivisor);
static float ToRad(float afAngle);
static float ToDeg(float afAngle);
/**
* Get the Log 2 of an int.
*/
static int Log2ToInt(int alX);
/**
* Checks if the number is a power of two.
*/
static bool IsPow2(int alX);
/**
* Wraps a value (afX) between min and max. Example: Wrap(-1, 0,10) returns 9.
* \param afMin The minimum value. Must be lower than max.
* \param afMax The maximum value. Must be higher than min and NOT 0.
*/
static float Wrap(float afX, float afMin, float afMax);
/**
* Clamps a value between min and max. Example Clamp(-1, 0,1) return 0.
*/
static float Clamp(float afX, float afMin, float afMax);
inline static float Max(float afX, float afY) {
if (afX > afY)
return afX;
return afY;
}
inline static float Min(float afX, float afY) {
if (afX < afY)
return afX;
return afY;
}
inline static int Max(int alX, int alY) {
if (alX > alY)
return alX;
return alY;
}
inline static int Min(int alX, int alY) {
if (alX < alY)
return alX;
return alY;
}
inline static float Abs(float afX) { return afX < 0 ? -afX : afX; }
inline static int Abs(int alX) { return alX < 0 ? -alX : alX; }
static float GetAngleDistance(float afAngle1, float afAngle2, float afMaxAngle);
static float GetAngleDistanceRad(float afAngle1, float afAngle2);
static float GetAngleDistanceDeg(float afAngle1, float afAngle2);
static float TurnAngle(float afAngle, float afFinalAngle, float afSpeed, float afMaxAngle);
static float TurnAngleRad(float afAngle, float afFinalAngle, float afSpeed);
static float TurnAngleDeg(float afAngle, float afFinalAngle, float afSpeed);
static float InterpolateFloat(float afA, float afB, float afT);
template<typename Vector>
static decltype(Vector::x) & GetVectorX(Vector &v) {
return v.x;
}
template<typename Vector>
static decltype(Vector::y) & GetVectorY(Vector &v) {
return v.y;
}
template<typename Vector>
static decltype(Vector::z) & GetVectorZ(Vector &v) {
return v.z;
}
//////////////////////////////////////////////////////
////////// VECTOR 2D ///////////////////////////////
//////////////////////////////////////////////////////
/**
* Get the angle a vector at aStartPos has to have to look at aGoalPos
* \param &aStartPos
* \param &avGoalPos
* \return
*/
static float GetAngleFromPoints2D(const cVector2f &aStartPos, const cVector2f &avGoalPos);
/**
* Get a vector from an angle and a length
* \param afAngle
* \param afLength
* \return
*/
static cVector2f GetVectorFromAngle2D(float afAngle, float afLength);
/**
* Get angle and length of a vector
* \param &avVec
* \param *apAngle
* \param *apLength
*/
static void GetAngleFromVector(const cVector2f &avVec, float *apAngle, float *apLength);
/**
* Project Src on Dest
* \param &avSrcVec
* \param &avDestVec
* \return
*/
static cVector2f ProjectVector2D(const cVector2f &avSrcVec, const cVector2f &avDestVec);
//////////////////////////////////////////////////////
////////// VECTOR 3D ///////////////////////////////
//////////////////////////////////////////////////////
static inline cVector3f Vector3ToRad(const cVector3f &avVec) {
return cVector3f(ToRad(avVec.x), ToRad(avVec.y), ToRad(avVec.z));
}
static inline cVector3f Vector3ToDeg(const cVector3f &avVec) {
return cVector3f(ToDeg(avVec.x), ToDeg(avVec.y), ToDeg(avVec.z));
}
static inline cVector3f Vector3Normalize(const cVector3f &avVec) {
cVector3f vNorm = avVec;
vNorm.Normalise();
return vNorm;
}
static inline float Vector3DistSqr(const cVector3f &avStartPos, const cVector3f &avEndPos) {
float fDX = avEndPos.x - avStartPos.x;
float fDY = avEndPos.y - avStartPos.y;
float fDZ = avEndPos.z - avStartPos.z;
return fDX * fDX + fDY * fDY + fDZ * fDZ;
}
static inline float Vector3Dist(const cVector3f &avStartPos, const cVector3f &avEndPos) {
return sqrt(Vector3DistSqr(avStartPos, avEndPos));
}
static cVector3f GetAngleFromPoints3D(const cVector3f &avStartPos, const cVector3f &avGoalPos);
/**
* Vector cross product, A x B = R
* \param avVecA
* \param avVecB
* \return
*/
static cVector3f Vector3Cross(const cVector3f &avVecA, const cVector3f &avVecB);
/**
* Vector dot product, A * B = R
* \param avVecA
* \param avVecB
* \return
*/
static float Vector3Dot(const cVector3f &avVecA, const cVector3f &avVecB);
/**
* Project Src on Dest
* \param &avSrcVec, must be normalized
* \param &avDestVec, must be normalized
* \return
*/
static cVector3f ProjectVector3D(const cVector3f &avSrcVec, const cVector3f &avDestVec);
/**
* Calculates the angle between two vectors.
* \param avVecA
* \param avVecB
* \return
*/
static float Vector3Angle(const cVector3f &avVecA, const cVector3f &avVecB);
/**
* Unprojects a vector from screen size and coords.
*/
static cVector3f Vector3UnProject(const cVector3f &avVec, const cRect2f &aScreenRect,
cMatrixf a_mtxViewProj);
/**
* Calculates distance from a point to a plane
* \param aPlane The plane must be normalised!
* \param avVec
* \return >0 if in front of plane, 0 if on plane and <0 if behind plane
*/
static float PlaneToPointDist(const cPlanef &aPlane, const cVector3f &avVec);
/**
* Get the line defining the intersection of 2 planes.
* \param aPA
* \param aPB
* \param avDir The direction of the line will be placed here
* \param avPoint A point on the line will be placed here.
*/
static void PlaneIntersectionLine(const cPlanef &aPA, const cPlanef &aPB,
cVector3f &avDir, cVector3f &avPoint);
/**
* Checks intersection with a frustum, an array of alPairNum plane pairs(alPairNum*2 planes), and a line,
*/
static bool CheckFrustumLineIntersection(const cPlanef *apPlanePairs, const cVector3f &avPoint1,
const cVector3f &avPoint2, int alPairNum);
/**
* Checks intersection with a a frustum, an array of alPairNum plane pairs(alPairNum * 2 planes), and a quad mesh.
* \param apPoints the points of the quad mesh, every 4 points is a face.
*/
static bool CheckFrustumQuadMeshIntersection(const cPlanef *apPlanePairs, tVector3fVec *apPoints,
int alPairNum);
//////////////////////////////////////////////////////
////////// QUATERNIONS ///////////////////////////////
//////////////////////////////////////////////////////
/**
* Spherical Linear Interpolation between quaternions A and B
* \param afT The amount in-between the quaternions. 0.0 is A and 1 is B.
* \param abShortestPath Move the the shortest path.
* \return
*/
static cQuaternion QuaternionSlerp(float afT, const cQuaternion &aqA, const cQuaternion &aqB,
bool abShortestPath);
static float QuaternionDot(const cQuaternion &aqA, const cQuaternion &aqB);
//////////////////////////////////////////////////////
////////// MATRIX ////////////////////////////////////
//////////////////////////////////////////////////////
/**
* Spherical Linear Interpolation between matrix A and B
* \param afT The amount in-between the quaternions. 0.0 is A and 1 is B.
* \param abShortestPath Move the the shortest path.
* \return
*/
static cMatrixf MatrixSlerp(float afT, const cMatrixf &a_mtxA, const cMatrixf &a_mtxB,
bool abShortestPath);
/**
* Matrix mulitplication, A * B = R. This means that B is applied BEFORE A.
*/
static cMatrixf MatrixMul(const cMatrixf &a_mtxA, const cMatrixf &a_mtxB);
/**
* Multiply and matrix and a 3d vector
*/
static cVector3f MatrixMul(const cMatrixf &a_mtxA, const cVector3f &avB);
/**
* Multiply and matrix and a 3d vector and divide the result with W.
*/
static cVector3f MatrixMulDivideW(const cMatrixf &a_mtxA, const cVector3f &avB);
/**
* Multiply matrix and a float.
*/
static cMatrixf MatrixMulScalar(const cMatrixf &a_mtxA, float afB);
/**
* Creates a rotation matrix along all axes according to order.
*/
static cMatrixf MatrixRotate(cVector3f avRot, eEulerRotationOrder aOrder);
/**
* Create a rotation matrix around the X-axis according to the right hand rule
*/
static cMatrixf MatrixRotateX(float afAngle);
/**
* Create a rotation matrix around the Y-axis according to the right hand rule
*/
static cMatrixf MatrixRotateY(float afAngle);
/**
* Create a rotation matrix around the Z-axis according to the right hand rule
*/
static cMatrixf MatrixRotateZ(float afAngle);
static cMatrixf MatrixScale(cVector3f avScale);
static cMatrixf MatrixTranslate(cVector3f avTrans);
/**
* Creates a matrix from a quaternion.
* \return
*/
static cMatrixf MatrixQuaternion(const cQuaternion &aqRot);
/**
* Get the minor of a matrix.
*/
static inline float MatrixMinor(const cMatrixf &a_mtxA,
const size_t r0, const size_t r1, const size_t r2,
const size_t c0, const size_t c1, const size_t c2);
/**
* Get the adjoint of a matrix.
*/
static inline cMatrixf MatrixAdjoint(const cMatrixf &a_mtxA);
/**
* Get the determinant of a matrix.
*/
static inline float MatrixDeterminant(const cMatrixf &a_mtxA);
/**
* Gets the inverse of a matrix.
*/
static cMatrixf MatrixInverse(const cMatrixf &a_mtxA);
/**
* Converts the matrix into Euler angles, XYZ only supported at the moment.
* \param &a_mtxA
* \param aOrder
*/
static cVector3f MatrixToEulerAngles(const cMatrixf &a_mtxA, eEulerRotationOrder aOrder);
/**
* Create a char string from the matrix
*/
static const char *MatrixToChar(const cMatrixf &a_mtxA);
//////////////////////////////////////////////////////
////////// POLYGONS //////////////////////////////////
//////////////////////////////////////////////////////
/**
* Creates an array with 4d tangent vectors for triangles. alIndexNum % 3 must be 0.
* \param apDestArray The destination array, must be 4 * number of vertices large
* \param apIndexArray The indices
* \param alIndexNum Number of indices
* \param apVertexArray Vertices indexed by the indices
* \param apTexArray The texture coords
* \param apNormalArray The normals
* \param alVertexNum Number of vertex, normals and texcoords.
* \return true if success, else false
*/
static bool CreateTriTangentVectors(float *apDestArray,
const unsigned int *apIndexArray, int alIndexNum,
const float *apVertexArray, int alVtxStride,
const float *apTexArray,
const float *apNormalArray, int alVertexNum);
/**
* Creates triangle data for a triangle mesh. alIndexNum % 3 must be 0.
* \param avTriangles Where the data will be stored. If empty, this function resizes it.
* \param apIndexArray The indices
* \param alIndexNum Number of indices
* \param apVertexArray Vertices indexed by the indices
* \param alVertexNum Number of vertices
* \return true if success, else false
*/
static bool CreateTriangleData(tTriangleDataVec &avTriangles,
const unsigned int *apIndexArray, int alIndexNum,
const float *apVertexArray, int alVtxStride, int alVertexNum);
/**
* Creates edges for a triangle mesh. alIndexNum % 3 must be 0.
* \param avEdges An empty edge vector, this is where the edges will be stored.
* \param apIndexArray The indices
* \param alIndexNum Number of indices
* \param apVertexArray Vertices indexed by the indices
* \param alVertexNum Number of vertices
* \return true if success, else false
*/
static bool CreateEdges(tTriEdgeVec &avEdges,
const unsigned int *apIndexArray, int alIndexNum,
const float *apVertexArray, int alVtxStride, int alVertexNum,
bool *apIsDoubleSided);
};
} // namespace hpl
#endif // HPL_MATH_H