Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

102
math/aabb.cpp Normal file
View File

@@ -0,0 +1,102 @@
/* 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/>.
*
*/
#include "math/aabb.h"
namespace Math {
AABB::AABB() : _valid(false) {
}
AABB::AABB(const Math::Vector3d &min, const Math::Vector3d &max) : _valid(true), _min(min), _max(max) {
}
void AABB::reset() {
_valid = false;
}
void AABB::expand(const Math::Vector3d &v) {
if (!_valid) {
_min = v;
_max = v;
_valid = true;
} else {
if (v.x() < _min.x())
_min.x() = v.x();
if (v.y() < _min.y())
_min.y() = v.y();
if (v.z() < _min.z())
_min.z() = v.z();
if (v.x() > _max.x())
_max.x() = v.x();
if (v.y() > _max.y())
_max.y() = v.y();
if (v.z() > _max.z())
_max.z() = v.z();
}
}
void AABB::transform(const Math::Matrix4 &matrix) {
Math::Vector3d min = _min;
Math::Vector3d max = _max;
reset();
Math::Vector3d verts[8];
verts[0].set(min.x(), min.y(), min.z());
verts[1].set(max.x(), min.y(), min.z());
verts[2].set(min.x(), max.y(), min.z());
verts[3].set(min.x(), min.y(), max.z());
verts[4].set(max.x(), max.y(), min.z());
verts[5].set(max.x(), min.y(), max.z());
verts[6].set(min.x(), max.y(), max.z());
verts[7].set(max.x(), max.y(), max.z());
for (int i = 0; i < 8; ++i) {
matrix.transform(&verts[i], true);
expand(verts[i]);
}
}
bool AABB::collides(const AABB &aabb) const {
return (getMax().x() > aabb.getMin().x() &&
getMin().x() < aabb.getMax().x() &&
getMax().y() > aabb.getMin().y() &&
getMin().y() < aabb.getMax().y() &&
getMax().z() > aabb.getMin().z() &&
getMin().z() < aabb.getMax().z());
}
Math::Vector3d AABB::distance(const Math::Vector3d &point) const {
double dx = MAX(getMin().x() - point.x(), point.x() - getMax().x());
dx = MAX(dx, 0.0);
double dy = MAX(getMin().y() - point.y(), point.y() - getMax().y());
dy = MAX(dy, 0.0);
double dz = MAX(getMin().z() - point.z(), point.z() - getMax().z());
dz = MAX(dz, 0.0);
return Math::Vector3d(dx, dy, dz);
}
}

53
math/aabb.h Normal file
View File

@@ -0,0 +1,53 @@
/* 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/>.
*
*/
#ifndef MATH_AABB_H
#define MATH_AABB_H
#include "math/vector3d.h"
#include "math/matrix4.h"
namespace Math {
// Axis-aligned bounding box
class AABB {
public:
AABB();
AABB(const Math::Vector3d &min, const Math::Vector3d &max);
void reset();
void expand(const Math::Vector3d &v);
void transform(const Math::Matrix4 &matrix);
Math::Vector3d getMin() const { return _min; }
Math::Vector3d getMax() const { return _max; }
Math::Vector3d getSize() const { return _max - _min; }
bool isValid() const { return _valid; }
bool collides(const AABB &aabb) const;
Math::Vector3d distance(const Math::Vector3d &point) const;
private:
Math::Vector3d _min, _max;
bool _valid;
};
} // end of namespace Math
#endif

178
math/angle.cpp Normal file
View File

@@ -0,0 +1,178 @@
/* 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/>.
*
*/
#include "common/streamdebug.h"
#include "math/angle.h"
#include "math/utils.h"
namespace Math {
Angle::Angle(float degrees) :
_degrees(degrees) {
}
Angle::Angle(const Angle &a) :
_degrees(a._degrees) {
}
Angle &Angle::normalize(float low) {
_degrees = getDegrees(low);
return *this;
}
Angle &Angle::clampDegrees(float mag) {
_degrees = getDegrees(-180.f);
if (_degrees >= mag)
setDegrees(mag);
if (_degrees <= -mag)
setDegrees(-mag);
return *this;
}
Angle &Angle::clampDegrees(float min, float max) {
_degrees = getDegrees(-180.f);
if (_degrees >= max)
setDegrees(max);
if (_degrees <= min)
setDegrees(min);
return *this;
}
void Angle::setDegrees(float degrees) {
_degrees = degrees;
}
void Angle::setRadians(float radians) {
_degrees = rad2deg(radians);
}
float Angle::getDegrees() const {
return _degrees;
}
float Angle::getRadians() const {
return deg2rad(getDegrees());
}
float Angle::getDegrees(float low) const {
float degrees = _degrees;
if (degrees >= low + 360.f) {
float x = floor((degrees - low) / 360.f);
degrees -= 360.f * x;
} else if (degrees < low) {
float x = floor((degrees - low) / 360.f);
degrees -= 360.f * x;
}
return degrees;
}
float Angle::getRadians(float low) const {
float d = getDegrees(low);
return deg2rad(d);
}
float Angle::getCosine() const {
return cosf(getRadians());
}
float Angle::getSine() const {
return sinf(getRadians());
}
float Angle::getTangent() const {
return tanf(getRadians());
}
Angle &Angle::operator=(const Angle &a) {
_degrees = a._degrees;
return *this;
}
Angle &Angle::operator=(float degrees) {
setDegrees(degrees);
return *this;
}
Angle &Angle::operator+=(const Angle &a) {
setDegrees(_degrees + a._degrees);
return *this;
}
Angle &Angle::operator+=(float degrees) {
setDegrees(_degrees + degrees);
return *this;
}
Angle &Angle::operator-=(const Angle &a) {
setDegrees(_degrees - a._degrees);
return *this;
}
Angle &Angle::operator-=(float degrees) {
setDegrees(_degrees - degrees);
return *this;
}
Angle Angle::fromRadians(float radians) {
return Angle(rad2deg(radians));
}
Angle Angle::arcCosine(float x) {
Angle a;
a.setRadians(acosf(x));
return a;
}
Angle Angle::arcSine(float x) {
Angle a;
a.setRadians(asinf(x));
return a;
}
Angle Angle::arcTangent(float x) {
Angle a;
a.setRadians(atanf(x));
return a;
}
Angle Angle::arcTangent2(float y, float x) {
Angle a;
a.setRadians(atan2f(y, x));
return a;
}
Common::StreamDebug &operator<<(Common::StreamDebug &dbg, const Math::Angle &a) {
dbg.nospace() << "Angle(" << a.getDegrees(-180) << ")";
return dbg.space();
}
}

164
math/angle.h Normal file
View File

@@ -0,0 +1,164 @@
/* 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/>.
*
*/
#ifndef MATH_ANGLE_H
#define MATH_ANGLE_H
#include "common/scummsys.h"
namespace Common {
class StreamDebug;
}
namespace Math {
class Angle {
public:
/**
* Construct an angle object.
*
* \param degrees The angle, in degrees. Default is 0.
*/
Angle(float degrees = 0);
/**
* Construct and angle object, copying an already existing one.
*
* \param a The angle to copy.
*/
Angle(const Angle &a);
/**
* Normalize the angle in a [x; x + 360] range and return the object.
*
* \param low The lower bound of the range, in degrees.
*/
Angle &normalize(float low);
/**
* Clamp the angle to range [-mag, mag]
*
* \param mag The maximum distance from 0, in degrees.
*/
Angle &clampDegrees(float mag);
/**
* Clamp the angle to range [-min, max]
*
* \param min The lower bound of the range, in degrees.
* \param max The upper bound of the range, in degrees.
*/
Angle &clampDegrees(float min, float max);
void setDegrees(float degrees);
void setRadians(float radians);
float getDegrees() const;
float getRadians() const;
/**
* Returns the degrees of the angle, in the defined range.
*
* \param low The lower bound of the range, in degrees.
*/
float getDegrees(float low) const;
/**
* Returns the radianss of the angle, in the defined range.
*
* \param low The lower bound of the range, in degrees.
*/
float getRadians(float low) const;
float getCosine() const;
float getSine() const;
float getTangent() const;
Angle &operator=(const Angle &a);
Angle &operator=(float degrees);
Angle &operator+=(const Angle &a);
Angle &operator+=(float degrees);
Angle &operator-=(const Angle &a);
Angle &operator-=(float degrees);
/**
* Build an angle object.
*
* \param radians The angle, in radians.
*/
static Angle fromRadians(float radians);
static Angle arcCosine(float x);
static Angle arcSine(float x);
static Angle arcTangent(float x);
static Angle arcTangent2(float y, float x);
private:
float _degrees;
};
inline Angle operator-(const Angle &a) {
return Angle(-a.getDegrees());
}
inline Angle operator+(const Angle &a1, const Angle &a2) {
return Angle(a1.getDegrees() + a2.getDegrees());
}
inline Angle operator-(const Angle &a1, const Angle &a2) {
return Angle(a1.getDegrees() - a2.getDegrees());
}
inline Angle operator*(const Angle &a1, float f) {
return Angle(a1.getDegrees() * f);
}
inline Angle operator*(float f, const Angle &a2) {
return Angle(a2.getDegrees() * f);
}
inline Angle operator/(const Angle &a1, float f) {
return Angle(a1.getDegrees() / f);
}
inline Angle operator/(float f, const Angle &a2) {
return Angle(a2.getDegrees() / f);
}
inline bool operator==(const Angle &a1, const Angle &a2) {
return fabsf(a1.getDegrees() - a2.getDegrees()) < 0.001;
}
inline bool operator!=(const Angle &a1, const Angle &a2) {
return !(a1 == a2);
}
inline bool operator<(const Angle &a1, const Angle &a2) {
return a1.getDegrees() < a2.getDegrees();
}
inline bool operator>(const Angle &a1, const Angle &a2) {
return a1.getDegrees() > a2.getDegrees();
}
Common::StreamDebug &operator<<(Common::StreamDebug &dbg, const Math::Angle &a);
}
#endif

77
math/cosinetables.cpp Normal file
View File

@@ -0,0 +1,77 @@
/* 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/>.
*
*/
// Based on eos' cosine tables
#include "math/cosinetables.h"
namespace Math {
CosineTable::CosineTable(int nPoints) {
assert((nPoints >= 16) && (nPoints <= 65536)); // log2 space is in [4,16]
assert(nPoints % 4 == 0);
_nPoints = nPoints;
_radResolution = 2.0 * M_PI / _nPoints;
_refSize = _nPoints / 4;
_tableEOS = new float[_nPoints / 2];
_table = new float[_nPoints];
for (int i = 0; i < _nPoints; i++)
_table[i] = cos(i * _radResolution);
// Table contains cos(2*pi*i/_nPoints) for 0<=i<=_nPoints/4,
// followed by 3_nPoints/4<=i<_nPoints
for (int i = 0; i <= _nPoints / 4; i++)
_tableEOS[i] = cos(i * _radResolution);
for (int i = 1; i < _nPoints / 4; i++)
_tableEOS[_nPoints / 2 - i] = _tableEOS[i];
}
float CosineTable::at(int index) const {
assert((index >= 0) && (index < _nPoints));
return _table[index];
}
float CosineTable::atLegacy(int index) const {
assert((index >= 0) && (index < _nPoints));
if (index < _refSize)
// [0,pi/2)
return _tableEOS[index];
if ((index > _refSize) && (index < 2 * _refSize))
// (pi/2,pi)
return -_tableEOS[2 * _refSize - index];
if ((index >= 2 * _refSize) && (index < 3 * _refSize))
// [pi,3/2pi)
return -_tableEOS[index - 2 * _refSize];
if ((index > 3 * _refSize) && (index < _nPoints))
// (3/2pi,2pi)
return _tableEOS[_nPoints - index];
return 0.0f; // cos(pi/2) and cos(3pi/2) = 0
}
CosineTable::~CosineTable() {
delete[] _tableEOS;
delete[] _table;
}
} // End of namespace Math

86
math/cosinetables.h Normal file
View File

@@ -0,0 +1,86 @@
/* 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/>.
*
*/
#ifndef MATH_COSINETABLES_H
#define MATH_COSINETABLES_H
#include "common/scummsys.h"
namespace Math {
/**
* @defgroup math_cosinetables Cosine tables
* @ingroup math
*
* @brief Functions for working with cosine tables.
*
* @{
*/
class CosineTable {
public:
/**
* Construct a cosine table given the number of points.
*
* @param nPoints Number of distinct radian points that must be in range [16,65536] and be divisible by 4.
*/
CosineTable(int nPoints);
~CosineTable();
/**
* Get a pointer to a table.
*
* This table contains nPoints/2 entries.
* Prefer to use at()
* The layout of this table is as follows:
* - Entries 0 up to (including) nPoints/4:
* cos(0) till (including) cos(1/2*pi)
* - Entries (excluding) nPoints/4 up to nPoints/2:
* (excluding) cos(3/2*pi) till (excluding) cos(2*pi)
*/
const float *getTable() { return _tableEOS; }
/**
* Return cos(2*pi * index / nPoints )
* Index must be in range [0, nPoints - 1]
* Faster than atLegacy.
*/
float at(int index) const;
/**
* Returns cos(2*pi * index / nPoints )
* Index must be in range [0, nPoints - 1]
*/
float atLegacy(int index) const;
private:
float *_tableEOS;
float *_table;
double _radResolution; // Smallest radian increment
int _refSize; // _nPoints / 4
int _nPoints; // range of operator[]
};
/** @} */
} // End of namespace Math
#endif // MATH_COSINETABLES_H

209
math/dct.cpp Normal file
View File

@@ -0,0 +1,209 @@
/* 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/>.
*
*/
// Based on eos' (I)RDFT code which is in turn
// Based upon the (I)DCT code in FFmpeg
// Copyright (c) 2009 Peter Ross <pross@xvid.org>
// Copyright (c) 2010 Alex Converse <alex.converse@gmail.com>
// Copyright (c) 2010 Vitor Sessak
#include "math/dct.h"
#include "math/rdft.h"
namespace Math {
DCT::DCT(int bits, TransformType trans) : _bits(bits), _cos(1 << (_bits + 2) ), _trans(trans), _rdft(nullptr) {
int n = 1 << _bits;
_tCos = _cos.getTable();
_csc2 = new float[n / 2];
_rdft = new RDFT(_bits, (_trans == DCT_III) ? RDFT::IDFT_C2R : RDFT::DFT_R2C);
for (int i = 0; i < (n / 2); i++)
_csc2[i] = 0.5 / sin((M_PI / (2 * n) * (2 * i + 1)));
}
DCT::~DCT() {
delete _rdft;
delete[] _csc2;
}
void DCT::calc(float *data) const {
switch (_trans) {
case DCT_I:
calcDCTI(data);
break;
case DCT_II:
calcDCTII(data);
break;
case DCT_III:
calcDCTIII(data);
break;
case DST_I:
calcDSTI(data);
break;
default:
break;
}
}
/* sin((M_PI * x / (2*n)) */
#define SIN(n,x) (_tCos[(n) - (x)])
/* cos((M_PI * x / (2*n)) */
#define COS(n,x) (_tCos[x])
void DCT::calcDCTI(float *data) const {
int n = 1 << _bits;
float next = -0.5f * (data[0] - data[n]);
for (int i = 0; i < (n / 2); i++) {
float tmp1 = data[i ];
float tmp2 = data[n - i];
float s = SIN(n, 2 * i);
float c = COS(n, 2 * i);
c *= tmp1 - tmp2;
s *= tmp1 - tmp2;
next += c;
tmp1 = (tmp1 + tmp2) * 0.5f;
data[i ] = tmp1 - s;
data[n - i] = tmp1 + s;
}
_rdft->calc(data);
data[n] = data[1];
data[1] = next;
for (int i = 3; i <= n; i += 2)
data[i] = data[i - 2] - data[i];
}
void DCT::calcDCTII(float *data) const {
int n = 1 << _bits;
for (int i = 0; i < (n / 2); i++) {
float tmp1 = data[i ];
float tmp2 = data[n - i - 1];
float s = SIN(n, 2 * i + 1);
s *= tmp1 - tmp2;
tmp1 = (tmp1 + tmp2) * 0.5f;
data[i ] = tmp1 + s;
data[n - i - 1] = tmp1 - s;
}
_rdft->calc(data);
float next = data[1] * 0.5f;
data[1] *= -1;
for (int i = n - 2; i >= 0; i -= 2) {
float inr = data[i ];
float ini = data[i + 1];
float c = COS(n, i);
float s = SIN(n, i);
data[i ] = c * inr + s * ini;
data[i + 1] = next;
next += s * inr - c * ini;
}
}
void DCT::calcDCTIII(float *data) const {
int n = 1 << _bits;
float next = data[n - 1];
float inv_n = 1.0f / n;
for (int i = n - 2; i >= 2; i -= 2) {
float val1 = data[i ];
float val2 = data[i - 1] - data[i + 1];
float c = COS(n, i);
float s = SIN(n, i);
data[i ] = c * val1 + s * val2;
data[i + 1] = s * val1 - c * val2;
}
data[1] = 2 * next;
_rdft->calc(data);
for (int i = 0; i < (n / 2); i++) {
float tmp1 = data[i ] * inv_n;
float tmp2 = data[n - i - 1] * inv_n;
float csc = _csc2[i] * (tmp1 - tmp2);
tmp1 += tmp2;
data[i ] = tmp1 + csc;
data[n - i - 1] = tmp1 - csc;
}
}
void DCT::calcDSTI(float *data) const {
int n = 1 << _bits;
data[0] = 0;
for (int i = 1; i < (n / 2); i++) {
float tmp1 = data[i ];
float tmp2 = data[n - i];
float s = SIN(n, 2 * i);
s *= tmp1 + tmp2;
tmp1 = (tmp1 - tmp2) * 0.5f;
data[i ] = s + tmp1;
data[n - i] = s - tmp1;
}
data[n / 2] *= 2;
_rdft->calc(data);
data[0] *= 0.5f;
for (int i = 1; i < (n - 2); i += 2) {
data[i + 1] += data[i - 1];
data[i ] = -data[i + 2];
}
data[n - 1] = 0;
}
} // End of namespace Math

87
math/dct.h Normal file
View File

@@ -0,0 +1,87 @@
/* 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/>.
*
*/
// Based on eos' (I)RDFT code which is in turn
// Based upon the (I)DCT code in FFmpeg
// Copyright (c) 2009 Peter Ross <pross@xvid.org>
// Copyright (c) 2010 Alex Converse <alex.converse@gmail.com>
// Copyright (c) 2010 Vitor Sessak
#ifndef MATH_DCT_H
#define MATH_DCT_H
#include "math/cosinetables.h"
namespace Math {
class RDFT;
/**
* @defgroup math_dct Discrete Cosine Transforms
* @ingroup math
*
* @brief Discrete Cosine Transforms.
*
* @{
*/
/**
* (Inverse) Discrete Cosine Transforms.
*
* Used in engines:
* - Scumm
*/
class DCT {
public:
enum TransformType {
DCT_II,
DCT_III,
DCT_I,
DST_I
};
DCT(int bits, TransformType trans);
~DCT();
void calc(float *data) const;
private:
int _bits;
TransformType _trans;
CosineTable _cos;
const float *_tCos;
float *_csc2;
RDFT *_rdft;
void calcDCTI(float *data) const;
void calcDCTII(float *data) const;
void calcDCTIII(float *data) const;
void calcDSTI(float *data) const;
};
/** @} */
} // End of namespace Math
#endif // MATH_DCT_H

258
math/fft.cpp Normal file
View File

@@ -0,0 +1,258 @@
/* 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/>.
*
*/
// Based on eos' (I)FFT code which is in turn
// Based upon the (I)FFT code in FFmpeg
// Copyright (c) 2008 Loren Merritt
// Copyright (c) 2002 Fabrice Bellard
// Partly based on libdjbfft by D. J. Bernstein
#include "math/fft.h"
#include "math/cosinetables.h"
#include "math/utils.h"
#include "common/util.h"
namespace Math {
FFT::FFT(int bits, int inverse) : _bits(bits), _inverse(inverse) {
assert((_bits >= 2) && (_bits <= 16));
int n = 1 << bits;
int nPoints;
_tmpBuf = new Complex[n];
_expTab = new Complex[n / 2];
_revTab = new uint16[n];
_splitRadix = 1;
for (int i = 0; i < n; i++)
_revTab[-splitRadixPermutation(i, n, _inverse) & (n - 1)] = i;
for (int i = 0; i < ARRAYSIZE(_cosTables); i++) {
if (i + 4 <= _bits) {
nPoints = 1 << (i + 4);
_cosTables[i] = new CosineTable(nPoints);
}
else
_cosTables[i] = nullptr;
}
}
FFT::~FFT() {
for (int i = 0; i < ARRAYSIZE(_cosTables); i++) {
delete _cosTables[i];
}
delete[] _revTab;
delete[] _expTab;
delete[] _tmpBuf;
}
const uint16 *FFT::getRevTab() const {
return _revTab;
}
void FFT::permute(Complex *z) {
int np = 1 << _bits;
if (_tmpBuf) {
for (int j = 0; j < np; j++)
_tmpBuf[_revTab[j]] = z[j];
memcpy(z, _tmpBuf, np * sizeof(Complex));
return;
}
// Reverse
for (int j = 0; j < np; j++) {
int k = _revTab[j];
if (k < j)
SWAP(z[k], z[j]);
}
}
int FFT::splitRadixPermutation(int i, int n, int inverse) {
if (n <= 2)
return i & 1;
int m = n >> 1;
if (!(i & m))
return splitRadixPermutation(i, m, inverse) * 2;
m >>= 1;
if (inverse == !(i & m))
return splitRadixPermutation(i, m, inverse) * 4 + 1;
return splitRadixPermutation(i, m, inverse) * 4 - 1;
}
#define sqrthalf (float)M_SQRT1_2
#define BF(x, y, a, b) { \
x = a - b; \
y = a + b; \
}
#define BUTTERFLIES(a0, a1, a2, a3) { \
BF(t3, t5, t5, t1); \
BF(a2.re, a0.re, a0.re, t5); \
BF(a3.im, a1.im, a1.im, t3); \
BF(t4, t6, t2, t6); \
BF(a3.re, a1.re, a1.re, t4); \
BF(a2.im, a0.im, a0.im, t6); \
}
// force loading all the inputs before storing any.
// this is slightly slower for small data, but avoids store->load aliasing
// for addresses separated by large powers of 2.
#define BUTTERFLIES_BIG(a0, a1, a2, a3) { \
float r0 = a0.re, i0 = a0.im, r1 = a1.re, i1 = a1.im; \
BF(t3, t5, t5, t1); \
BF(a2.re, a0.re, r0, t5); \
BF(a3.im, a1.im, i1, t3); \
BF(t4, t6, t2, t6); \
BF(a3.re, a1.re, r1, t4); \
BF(a2.im, a0.im, i0, t6); \
}
#define TRANSFORM(a0, a1, a2, a3, wre, wim) { \
t1 = a2.re * wre + a2.im * wim; \
t2 = a2.im * wre - a2.re * wim; \
t5 = a3.re * wre - a3.im * wim; \
t6 = a3.im * wre + a3.re * wim; \
BUTTERFLIES(a0, a1, a2, a3) \
}
#define TRANSFORM_ZERO(a0, a1, a2, a3) { \
t1 = a2.re; \
t2 = a2.im; \
t5 = a3.re; \
t6 = a3.im; \
BUTTERFLIES(a0, a1, a2, a3) \
}
/* z[0...8n-1], w[1...2n-1] */
#define PASS(name) \
static void name(Complex *z, const float *wre, unsigned int n) { \
float t1, t2, t3, t4, t5, t6; \
int o1 = 2 * n; \
int o2 = 4 * n; \
int o3 = 6 * n; \
const float *wim = wre + o1; \
n--; \
\
TRANSFORM_ZERO(z[0], z[o1], z[o2], z[o3]); \
TRANSFORM(z[1], z[o1 + 1], z[o2 + 1], z[o3 + 1], wre[1], wim[-1]); \
do { \
z += 2; \
wre += 2; \
wim -= 2; \
TRANSFORM(z[0], z[o1], z[o2], z[o3], wre[0], wim[0]);\
TRANSFORM(z[1], z[o1 + 1], z[o2 + 1], z[o3 + 1], wre[1], wim[-1]);\
} while(--n);\
}
PASS(pass)
#undef BUTTERFLIES
#define BUTTERFLIES BUTTERFLIES_BIG
PASS(pass_big)
void FFT::fft4(Complex *z) {
float t1, t2, t3, t4, t5, t6, t7, t8;
BF(t3, t1, z[0].re, z[1].re);
BF(t8, t6, z[3].re, z[2].re);
BF(z[2].re, z[0].re, t1, t6);
BF(t4, t2, z[0].im, z[1].im);
BF(t7, t5, z[2].im, z[3].im);
BF(z[3].im, z[1].im, t4, t8);
BF(z[3].re, z[1].re, t3, t7);
BF(z[2].im, z[0].im, t2, t5);
}
void FFT::fft8(Complex *z) {
float t1, t2, t3, t4, t5, t6, t7, t8;
fft4(z);
BF(t1, z[5].re, z[4].re, -z[5].re);
BF(t2, z[5].im, z[4].im, -z[5].im);
BF(t3, z[7].re, z[6].re, -z[7].re);
BF(t4, z[7].im, z[6].im, -z[7].im);
BF(t8, t1, t3, t1);
BF(t7, t2, t2, t4);
BF(z[4].re, z[0].re, z[0].re, t1);
BF(z[4].im, z[0].im, z[0].im, t2);
BF(z[6].re, z[2].re, z[2].re, t7);
BF(z[6].im, z[2].im, z[2].im, t8);
TRANSFORM(z[1], z[3], z[5], z[7], sqrthalf, sqrthalf);
}
void FFT::fft16(Complex *z) {
float t1, t2, t3, t4, t5, t6;
fft8(z);
fft4(z + 8);
fft4(z + 12);
assert(_cosTables[0]);
const float * const cosTable = _cosTables[0]->getTable();
TRANSFORM_ZERO(z[0], z[4], z[8], z[12]);
TRANSFORM(z[2], z[6], z[10], z[14], sqrthalf, sqrthalf);
TRANSFORM(z[1], z[5], z[9], z[13], cosTable[1],cosTable[3]);
TRANSFORM(z[3], z[7], z[11], z[15], cosTable[3], cosTable[1]);
}
void FFT::fft(int n, int logn, Complex *z) {
switch (logn) {
case 2:
fft4(z);
break;
case 3:
fft8(z);
break;
case 4:
fft16(z);
break;
default:
fft((n / 2), logn - 1, z);
fft((n / 4), logn - 2, z + (n / 4) * 2);
fft((n / 4), logn - 2, z + (n / 4) * 3);
assert(_cosTables[logn - 4]);
if (n > 1024)
pass_big(z, _cosTables[logn - 4]->getTable(), (n / 4) / 2);
else
pass(z, _cosTables[logn - 4]->getTable(), (n / 4) / 2);
}
}
void FFT::calc(Complex *z) {
fft(1 << _bits, _bits, z);
}
} // End of namespace Math

95
math/fft.h Normal file
View File

@@ -0,0 +1,95 @@
/* 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/>.
*
*/
// Based on eos' (I)FFT code which is in turn
// based upon the (I)FFT code in FFmpeg
// Copyright (c) 2008 Loren Merritt
// Copyright (c) 2002 Fabrice Bellard
// Partly based on libdjbfft by D. J. Bernstein
#ifndef MATH_FFT_H
#define MATH_FFT_H
#include "common/scummsys.h"
namespace Math {
/**
* @defgroup math_fft Fast Fourier Transform (FFT)
* @ingroup math
*
* @brief API for the FFT algorithm.
*
* @{
*/
class CosineTable;
struct Complex;
/**
* (Inverse) Fast Fourier Transform.
*
* Used in engines:
* - SCUMM
*/
class FFT {
public:
FFT(int bits, int inverse);
~FFT();
const uint16 *getRevTab() const;
/** Perform the permutation needed BEFORE calling calc(). */
void permute(Complex *z);
/** Perform a complex FFT.
*
* The input data must be permuted before.
* No 1.0/sqrt(n) normalization is done.
*/
void calc(Complex *z);
private:
int _bits;
int _inverse;
uint16 *_revTab;
Complex *_expTab;
Complex *_tmpBuf;
int _splitRadix;
static int splitRadixPermutation(int i, int n, int inverse);
CosineTable *_cosTables[13];
void fft4(Complex *z);
void fft8(Complex *z);
void fft16(Complex *z);
void fft(int n, int logn, Complex *z);
};
/** @} */
} // End of namespace Math
#endif // MATH_FFT_H

105
math/frustum.cpp Normal file
View File

@@ -0,0 +1,105 @@
/* 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/>.
*
*/
#include "math/frustum.h"
namespace Math {
Frustum::Frustum() {
}
void Frustum::setup(const Math::Matrix4 &matrix) {
// Based on "Fast Extraction of Viewing Frustum Planes from the
// World-View-Projection matrix" by Gil Gribb and Klaus Hartmann.
// https://web.archive.org/web/20140211075800/http://www.cs.otago.ac.nz/postgrads/alexis/planeExtraction.pdf
_planes[0]._normal.x() = matrix.getValue(3, 0) + matrix.getValue(0, 0);
_planes[0]._normal.y() = matrix.getValue(3, 1) + matrix.getValue(0, 1);
_planes[0]._normal.z() = matrix.getValue(3, 2) + matrix.getValue(0, 2);
_planes[0]._d = matrix.getValue(3, 3) + matrix.getValue(0, 3);
_planes[1]._normal.x() = matrix.getValue(3, 0) - matrix.getValue(0, 0);
_planes[1]._normal.y() = matrix.getValue(3, 1) - matrix.getValue(0, 1);
_planes[1]._normal.z() = matrix.getValue(3, 2) - matrix.getValue(0, 2);
_planes[1]._d = matrix.getValue(3, 3) - matrix.getValue(0, 3);
_planes[2]._normal.x() = matrix.getValue(3, 0) - matrix.getValue(1, 0);
_planes[2]._normal.y() = matrix.getValue(3, 1) - matrix.getValue(1, 1);
_planes[2]._normal.z() = matrix.getValue(3, 2) - matrix.getValue(1, 2);
_planes[2]._d = matrix.getValue(3, 3) - matrix.getValue(1, 3);
_planes[3]._normal.x() = matrix.getValue(3, 0) + matrix.getValue(1, 0);
_planes[3]._normal.y() = matrix.getValue(3, 1) + matrix.getValue(1, 1);
_planes[3]._normal.z() = matrix.getValue(3, 2) + matrix.getValue(1, 2);
_planes[3]._d = matrix.getValue(3, 3) + matrix.getValue(1, 3);
_planes[4]._normal.x() = matrix.getValue(3, 0) + matrix.getValue(2, 0);
_planes[4]._normal.y() = matrix.getValue(3, 1) + matrix.getValue(2, 1);
_planes[4]._normal.z() = matrix.getValue(3, 2) + matrix.getValue(2, 2);
_planes[4]._d = matrix.getValue(3, 3) + matrix.getValue(2, 3);
_planes[5]._normal.x() = matrix.getValue(3, 0) - matrix.getValue(2, 0);
_planes[5]._normal.y() = matrix.getValue(3, 1) - matrix.getValue(2, 1);
_planes[5]._normal.z() = matrix.getValue(3, 2) - matrix.getValue(2, 2);
_planes[5]._d = matrix.getValue(3, 3) - matrix.getValue(2, 3);
for (int i = 0; i < 6; ++i) {
_planes[i].normalize();
}
}
bool Frustum::isInside(const Math::AABB &aabb) const {
Math::Vector3d min = aabb.getMin();
Math::Vector3d max = aabb.getMax();
for (int i = 0; i < 6; ++i) {
const Plane &plane = _planes[i];
Math::Vector3d positive = min;
if (plane._normal.x() >= 0.0f)
positive.x() = max.x();
if (plane._normal.y() >= 0.0f)
positive.y() = max.y();
if (plane._normal.z() >= 0.0f)
positive.z() = max.z();
float dist = _planes[i].getSignedDistance(positive);
if (dist < 0.0f)
return false;
}
return true;
}
bool Frustum::isTriangleInside(const Math::Vector3d &v0, const Math::Vector3d &v1, const Math::Vector3d &v2) const {
for (int i = 0; i < 6; ++i) {
const Plane &plane = _planes[i];
// Inside if any point is above the plane. On the plane is in
if (plane.getSignedDistance(v0) < 0.0f
&& plane.getSignedDistance(v1) < 0.0f
&& plane.getSignedDistance(v2) < 0.0f)
return false;
}
return true;
}
}

46
math/frustum.h Normal file
View File

@@ -0,0 +1,46 @@
/* 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/>.
*
*/
#ifndef MATH_FRUSTUM_H
#define MATH_FRUSTUM_H
#include "math/matrix4.h"
#include "math/plane.h"
#include "math/aabb.h"
namespace Math {
/* A volume defined by 6 planes */
class Frustum {
public:
Frustum();
void setup(const Math::Matrix4 &matrix);
bool isInside(const Math::AABB &aabb) const;
bool isTriangleInside(const Math::Vector3d &v0, const Math::Vector3d &v1, const Math::Vector3d &v2) const;
private:
Math::Plane _planes[6];
};
} // end of namespace Math
#endif

97
math/glmath.cpp Normal file
View File

@@ -0,0 +1,97 @@
/* 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/>.
*
*/
#include "math/glmath.h"
namespace Math {
// function based on gluUnProject from Mesa 5.0 glu GPLv2+ licensed sources
bool gluMathUnProject(const Vector3d &win, const Matrix4 &mvpMatrix, const Common::Rect &viewport, Vector3d &obj) {
Matrix4 A;
Vector4d in, out;
in.x() = (win.x() - viewport.left) * 2 / viewport.width() - 1.0;
in.y() = (win.y() - viewport.top) * 2 / viewport.height() - 1.0;
in.z() = 2 * win.z() - 1.0;
in.w() = 1.0;
A = mvpMatrix;
A.inverse();
out = A.transform(in);
if (out.w() == 0.0)
return false;
obj.x() = out.x() / out.w();
obj.y() = out.y() / out.w();
obj.z() = out.z() / out.w();
return true;
}
// function based on gluPerspective from Mesa 5.0 glu GPLv2+ licensed sources
Matrix4 makePerspectiveMatrix(double fovy, double aspect, double zNear, double zFar) {
double xmin, xmax, ymin, ymax;
ymax = zNear * tan(fovy * M_PI / 360.0);
ymin = -ymax;
xmin = ymin * aspect;
xmax = ymax * aspect;
return makeFrustumMatrix(xmin, xmax, ymin, ymax, zNear, zFar);
}
Matrix4 makeFrustumMatrix(double left, double right, double bottom, double top, double zNear, double zFar) {
Matrix4 proj;
proj(0, 0) = (2.0f * zNear) / (right - left);
proj(1, 1) = (2.0f * zNear) / (top - bottom);
proj(2, 0) = (right + left) / (right - left);
proj(2, 1) = (top + bottom) / (top - bottom);
proj(2, 2) = -(zFar + zNear) / (zFar - zNear);
proj(2, 3) = -1.0f;
proj(3, 2) = -(2.0f * zFar * zNear) / (zFar - zNear);
proj(3, 3) = 0.0f;
return proj;
}
Matrix4 makeLookAtMatrix(const Vector3d &eye, const Vector3d &center, const Vector3d &up) {
Vector3d f = (center - eye).getNormalized();
Vector3d u = up.getNormalized();
Vector3d s = Vector3d::crossProduct(f, u).getNormalized();
u = Vector3d::crossProduct(s, f);
Math::Matrix4 look;
look(0, 0) = s.x();
look(1, 0) = s.y();
look(2, 0) = s.z();
look(0, 1) = u.x();
look(1, 1) = u.y();
look(2, 1) = u.z();
look(0, 2) = -f.x();
look(1, 2) = -f.y();
look(2, 2) = -f.z();
look(3, 3) = 1.0;
return look;
}
}

75
math/glmath.h Normal file
View File

@@ -0,0 +1,75 @@
/* 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/>.
*
*/
#ifndef MATH_GLMATH_H
#define MATH_GLMATH_H
#include "common/rect.h"
#include "math/vector4d.h"
#include "math/matrix4.h"
namespace Math {
// function based on gluProject from Mesa 5.0 glu GPLv2+ licensed sources
template<typename T, typename S>
bool gluMathProject(const Vector3d &obj, const T model[16], const T proj[16], const S viewport[4], Vector3d &win) {
Vector4d in, out;
Matrix4 modelMatrix, projMatrix;
in.set(obj.x(), obj.y(), obj.z(), 1.0);
for (int i = 0; i < 4; i++) {
modelMatrix(0, i) = model[0 * 4 + i];
modelMatrix(1, i) = model[1 * 4 + i];
modelMatrix(2, i) = model[2 * 4 + i];
modelMatrix(3, i) = model[3 * 4 + i];
projMatrix(0, i) = proj[0 * 4 + i];
projMatrix(1, i) = proj[1 * 4 + i];
projMatrix(2, i) = proj[2 * 4 + i];
projMatrix(3, i) = proj[3 * 4 + i];
}
out = modelMatrix.transform(in);
in = projMatrix.transform(out);
if (in.w() == 0.0)
return false;
in.x() /= in.w();
in.y() /= in.w();
in.z() /= in.w();
win.x() = viewport[0] + (1 + in.x()) * viewport[2] / 2;
win.y() = viewport[1] + (1 + in.y()) * viewport[3] / 2;
win.z() = (1 + in.z()) / 2;
return true;
}
bool gluMathUnProject(const Vector3d &win, const Matrix4 &mvpMatrix, const Common::Rect &viewport, Vector3d &obj);
Matrix4 makePerspectiveMatrix(double fovy, double aspect, double zNear, double zFar);
Matrix4 makeFrustumMatrix(double left, double right, double bottom, double top, double zNear, double zFar);
Matrix4 makeLookAtMatrix(const Vector3d &eye, const Vector3d &center, const Vector3d &up);
}
#endif

191
math/line2d.cpp Normal file
View File

@@ -0,0 +1,191 @@
/* 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/>.
*
*/
#include "math/line2d.h"
#include "math/rect2d.h"
namespace Math {
/* Linear equation used to describe the line:
*
* Ax + By = C
*
*/
Line2d::Line2d(const Vector2d &direction, const Vector2d &point) {
_a = direction.getX();
_b = direction.getY();
_c = point.getY() * (point.getX() + direction.getX()) - point.getX() * (point.getY() + direction.getY());
}
Line2d Line2d::getPerpendicular(const Vector2d &point) const {
return Line2d(Vector2d(_a, _b), point);
}
Vector2d Line2d::getDirection() const {
return Vector2d(-_b, _a);
}
float Line2d::getDistanceTo(const Vector2d &point, Vector2d *intersection) const {
float dist = fabsf(_a * point.getX() + _b * point.getY() - _c) / sqrt(_a * _a + _b * _b);
if (intersection) {
intersectsLine(getPerpendicular(point), intersection);
}
return dist;
}
bool Line2d::intersectsLine(const Line2d &line, Vector2d *pos) const {
float a1 = _a;
float b1 = _b;
float c1 = _c;
float a2 = line._a;
float b2 = line._b;
float c2 = line._c;
float x, y;
const float det = a1 * b2 - b1 * a2;
if (fabsf(det) < epsilon) {
return false;
}
x = (c1 * b2 - c2 * b1) / det;
y = (a1 * c2 - a2 * c1) / det;
if (pos)
*pos = Vector2d(x, y);
return true;
}
bool Line2d::containsPoint(const Vector2d &point) const {
float n = _a * point.getX() + _b * point.getY() - _c;
return (fabsf(n) < epsilon);
}
Common::StreamDebug &operator<<(Common::StreamDebug &dbg, const Math::Line2d &line) {
if (fabsf(line._a) < epsilon) {
dbg.nospace() << "Line2d: <y = " << (-line._a / line._b) << " * x + " << line._c / line._b << ">";
} else {
dbg.nospace() << "Line2d: <x = " << (-line._b / line._a) << " * y + " << line._c / line._a << ">";
}
return dbg.space();
}
Segment2d::Segment2d() {
}
Segment2d::Segment2d(const Vector2d &b, const Vector2d &e) :
_begin(b), _end(e) {
}
Segment2d::Segment2d(const Segment2d &other) {
*this = other;
}
Vector2d Segment2d::begin() const {
return _begin;
}
Vector2d Segment2d::end() const {
return _end;
}
Vector2d Segment2d::middle() const {
return (_begin + _end) / 2.f;
}
Line2d Segment2d::getLine() const {
float y = _end.getY() - _begin.getY();
float x = _end.getX() - _begin.getX();
Vector2d v(x, y);
return Line2d(v, _begin);
}
Line2d Segment2d::getPerpendicular(const Vector2d &point) const {
return getLine().getPerpendicular(point);
}
bool Segment2d::intersectsSegment(const Segment2d &other, Vector2d *pos) {
float denom = ((other._end.getY() - other._begin.getY()) * (_end.getX() - _begin.getX())) -
((other._end.getX() - other._begin.getX()) * (_end.getY() - _begin.getY()));
float d = ((_end.getY() - _begin.getY()) * (other._end.getX() - other._begin.getX())) -
((_end.getX() - _begin.getX()) * (other._end.getY() - other._begin.getY()));
float nume_a = ((other._end.getX() - other._begin.getX()) * (_begin.getY() - other._begin.getY())) -
((other._end.getY() - other._begin.getY()) * (_begin.getX() - other._begin.getX()));
float nume_b = ((_end.getX() - _begin.getX()) * (other._begin.getY() - _begin.getY())) -
((_end.getY() - _begin.getY()) * (other._begin.getX() - _begin.getX()));
if (denom == 0.0f || d == 0.0f ) {
return false;
}
float ua = nume_a / denom;
float ub = nume_b / d;
if (ua < 0.0f || ua > 1.0f || ub < 0.0f || ub > 1.0f) {
return false;
}
// Get the intersection point.
if (pos)
*pos = _begin + (_end - _begin) * ua;
return true;
}
bool Segment2d::intersectsLine(const Line2d &line, Vector2d *pos) {
Vector2d p;
if (getLine().intersectsLine(line, &p) && containsPoint(p)) {
if (pos)
*pos = p;
return true;
}
return false;
}
bool Segment2d::containsPoint(const Vector2d &point) const {
if (getLine().containsPoint(point)) {
return Rect2d(_begin, _end).containsPoint(point);
}
return false;
}
Segment2d &Segment2d::operator=(const Segment2d &other) {
_begin = other._begin;
_end = other._end;
return *this;
}
}

73
math/line2d.h Normal file
View File

@@ -0,0 +1,73 @@
/* 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/>.
*
*/
#ifndef MATH_LINE2D_H
#define MATH_LINE2D_H
#include "math/vector2d.h"
namespace Math {
class Line2d {
public:
Line2d(const Vector2d &direction, const Vector2d &point);
Line2d getPerpendicular(const Vector2d &point = Vector2d()) const;
Vector2d getDirection() const;
float getDistanceTo(const Vector2d &point, Vector2d *intersection) const;
bool intersectsLine(const Line2d &line, Vector2d *pos) const;
bool containsPoint(const Vector2d &point) const;
friend Common::StreamDebug &operator<<(Common::StreamDebug &dbg, const Line2d &line);
private:
float _a, _b, _c;
};
class Segment2d {
public:
Segment2d();
Segment2d(const Vector2d &begin, const Vector2d &end);
Segment2d(const Segment2d &other);
Vector2d begin() const;
Vector2d end() const;
Vector2d middle() const;
Line2d getLine() const;
Line2d getPerpendicular(const Vector2d &point = Vector2d()) const;
bool containsPoint(const Vector2d &point) const;
bool intersectsLine(const Line2d &line, Vector2d *pos);
bool intersectsSegment(const Segment2d &line, Vector2d *pos);
Segment2d &operator=(const Segment2d &other);
private:
Math::Vector2d _begin, _end;
};
}
#endif

94
math/line3d.cpp Normal file
View File

@@ -0,0 +1,94 @@
/* 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/>.
*
*/
#include "math/line3d.h"
namespace Math {
Line3d::Line3d() {
}
Line3d::Line3d(const Vector3d &b, const Vector3d &e) :
_begin(b), _end(e) {
}
Line3d::Line3d(const Line3d &other) {
*this = other;
}
Math::Vector3d Line3d::begin() const {
return _begin;
}
Math::Vector3d Line3d::end() const {
return _end;
}
Math::Vector3d Line3d::middle() const {
return (_begin + _end) / 2.f;
}
bool Line3d::intersectLine2d(const Line3d &other, Math::Vector3d *pos, bool useXZ) {
float denom, nume_a, nume_b;
if (useXZ) {
denom = ((other._end.z() - other._begin.z()) * (_end.x() - _begin.x())) -
((other._end.x() - other._begin.x()) * (_end.z() - _begin.z()));
nume_a = ((other._end.x() - other._begin.x()) * (_begin.z() - other._begin.z())) -
((other._end.z() - other._begin.z()) * (_begin.x() - other._begin.x()));
nume_b = ((_end.x() - _begin.x()) * (_begin.z() - other._begin.z())) -
((_end.z() - _begin.z()) * (_begin.x() - other._begin.x()));
} else {
denom = ((other._end.y() - other._begin.y()) * (_end.x() - _begin.x())) -
((other._end.x() - other._begin.x()) * (_end.y() - _begin.y()));
nume_a = ((other._end.x() - other._begin.x()) * (_begin.y() - other._begin.y())) -
((other._end.y() - other._begin.y()) * (_begin.x() - other._begin.x()));
nume_b = ((_end.x() - _begin.x()) * (_begin.y() - other._begin.y())) -
((_end.y() - _begin.y()) * (_begin.x() - other._begin.x()));
}
if (denom == 0.0f) {
return false;
}
float ua = nume_a / denom;
float ub = nume_b / denom;
if (ua < 0 || ua > 1 || ub < 0 || ub > 1)
return false;
// Get the intersection point.
if (pos)
*pos = _begin + ua * (_end - _begin);
return true;
}
Line3d& Line3d::operator=(const Line3d &other) {
_begin = other._begin;
_end = other._end;
return *this;
}
}

58
math/line3d.h Normal file
View File

@@ -0,0 +1,58 @@
/* 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/>.
*
*/
#ifndef MATH_LINE3D_H
#define MATH_LINE3D_H
#include "common/scummsys.h"
#include "common/endian.h"
#include "math/vector3d.h"
namespace Math {
class Line3d {
public:
Line3d();
Line3d(const Vector3d &begin, const Vector3d &end);
Line3d(const Line3d &other);
Math::Vector3d begin() const;
Math::Vector3d end() const;
Math::Vector3d middle() const;
/**
* Check if this line segment intersects with another line segment
*
* The check is done in either a XY or a XZ 2D plane.
*/
bool intersectLine2d(const Line3d &other, Math::Vector3d *pos, bool useXZ);
Line3d& operator=(const Line3d &other);
private:
Math::Vector3d _begin, _end;
};
} // end of namespace Math
#endif

34
math/mathfwd.h Normal file
View File

@@ -0,0 +1,34 @@
/* 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/>.
*
*/
#ifndef MATH_FWD_H
#define MATH_FWD_H
namespace Math {
template<int r, int c> class Matrix;
typedef Matrix<2, 1> Vector2d;
typedef Matrix<3, 1> Vector3d;
}
#endif

519
math/matrix.h Normal file
View File

@@ -0,0 +1,519 @@
/* 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/>.
*
*/
#ifndef MATH_MATRIX_H
#define MATH_MATRIX_H
#include <string.h>
#include <assert.h>
#include "common/streamdebug.h"
/**
* \namespace Math
* This namespace contains some useful classes dealing with math and geometry.
*
* The most important classes are Matrix and its base classes.
* MatrixBase is a template class which is the base of all the matrices with
* many convenient functions.
* MatrixType is an intermediate class that, using template specialization,
* is able to create different kinds of matrices, like vectors or
* square matrices.
* Matrix is the actual matrix class and it is derived from MatrixType.
*
* MatrixBase and MatrixType have their constructors protected, so they can't
* be instantiated. But while MatrixBase is just a backend class, MatrixType
* can be used to create new kinds of matrices:
* \code
template<int dim>
class MatrixType<1, dim> : public MatrixBase<1, dim> {
...
};
* \endcode
* Given that declaration, every Matrix<1, dim>, with "dim" whatever positive
* number, will have the methods and members defined in MatrixType<1, dim>.
*
* This design allows us to have the equality of, say, the class "three-dimensional
* vector" and Matrix<3, 1>. Vector3d is not <b>a</b> Matrix<3, 1>, it <b>is</b> Matrix<3, 1>.
* Every method in MatrixBase and MatrixType returning a matrix returns a Matrix<\r, c>,
* and not a MatrixBase<\r, c>. This reduces code duplication, since otherwise many
* functions declared for Matrix would need to be declared for MatrixBase too,
* like many operators.
*/
namespace Math {
template<int rows, int cols> class Matrix;
/**
* \class MatrixBase
* The base class for all the matrices.
*/
template<int rows, int cols>
class MatrixBase {
public:
/**
* Convenient class for feeding a matrix.
*/
class Row {
public:
Row &operator<<(float value);
private:
Row(MatrixBase<rows, cols> *m, int row);
MatrixBase<rows, cols> *_matrix;
int _row;
int _col;
friend class MatrixBase<rows, cols>;
};
/**
* Returns true if this matrix's values are all 0.
*/
bool isZero() const;
Matrix<rows, cols> getNegative() const;
/**
* Returns an instance of Row for a particular row of this matrix.
* Row is a convenient class for feeding a matrix.
* \code
Matrix<3, 3> m;
m.getRow(0) << 0 << 0 << 0;
m.getRow(1) << 1 << 2 << 0;
m.getRow(2) << 0 << 0.5 << 1;
* \endcode
*
* \param row The row to be feeded.
*/
Row getRow(int row);
/**
* Returns a pointer to the internal data of this matrix.
*/
inline float *getData();
/**
* Returns a pointer to the internal data of this matrix.
*/
inline const float *getData() const;
/**
* Sets the internal data of this matrix.
*/
void setData(const float *data);
inline float getValue(int row, int col) const;
inline void setValue(int row, int col, float value);
inline float &operator()(int row, int col);
inline float operator()(int row, int col) const;
inline operator const Matrix<rows, cols>&() const { return getThis(); }
inline operator Matrix<rows, cols>&() { return getThis(); }
static Matrix<rows, cols> sum(const Matrix<rows, cols> &m1, const Matrix<rows, cols> &m2);
static Matrix<rows, cols> difference(const Matrix<rows, cols> &m1, const Matrix<rows, cols> &m2);
static Matrix<rows, cols> product(const Matrix<rows, cols> &m1, float factor);
static Matrix<rows, cols> product(const Matrix<rows, cols> &m1, const Matrix<rows, cols> &m2);
static Matrix<rows, cols> quotient(const Matrix<rows, cols> &m1, float factor);
static Matrix<rows, cols> quotient(const Matrix<rows, cols> &m1, const Matrix<rows, cols> &m2);
Matrix<rows, cols> &operator=(const Matrix<rows, cols> &m);
Matrix<rows, cols> &operator+=(const Matrix<rows, cols> &m);
Matrix<rows, cols> &operator-=(const Matrix<rows, cols> &m);
Matrix<rows, cols> &operator*=(float factor);
Matrix<rows, cols> &operator*=(const Matrix<rows, cols> &m);
Matrix<rows, cols> &operator/=(float factor);
Matrix<rows, cols> &operator/=(const Matrix<rows, cols> &m);
#if defined(_MSC_VER) && _MSC_VER < 1910 // HACK: C2248 bug in MSVC 2015
public:
#else
protected:
#endif
constexpr MatrixBase() = default;
MatrixBase(const float *data);
MatrixBase(const MatrixBase<rows, cols> &m);
MatrixBase &operator=(const MatrixBase<rows, cols> &m);
protected:
inline const Matrix<rows, cols> &getThis() const {
return *static_cast<const Matrix<rows, cols> *>(this); }
inline Matrix<rows, cols> &getThis() {
return *static_cast<Matrix<rows, cols> *>(this); }
private:
float _values[rows * cols] = { 0.0f };
};
/**
* \class MatrixType
* MatrixType is a class used to create different kinds of matrices.
*/
template<int r, int c>
class MatrixType : public MatrixBase<r, c> {
#if defined(_MSC_VER) && _MSC_VER < 1910 // HACK: C2248 bug in MSVC 2015
public:
#else
protected:
#endif
constexpr MatrixType() : MatrixBase<r, c>() { }
MatrixType(const float *data) : MatrixBase<r, c>(data) { }
MatrixType(const MatrixBase<r, c> &m) : MatrixBase<r, c>(m) { }
};
#define Vector(dim) Matrix<dim, 1>
/**
* \class Matrix The actual Matrix class.
* This template class must be instantiated passing it the number of the rows
* and the number of the columns.
*/
template<int r, int c>
class Matrix : public MatrixType<r, c> {
public:
constexpr Matrix() : MatrixType<r, c>() { }
Matrix(const float *data) : MatrixType<r, c>(data) { }
Matrix(const MatrixBase<r, c> &m) : MatrixType<r, c>(m) { }
};
template <int m, int n, int p>
Matrix<m, n> operator*(const Matrix<m, p> &m1, const Matrix<p, n> &m2);
template <int r, int c>
inline Matrix<r, c> operator+(const Matrix<r, c> &m1, const Matrix<r, c> &m2);
template <int r, int c>
inline Matrix<r, c> operator-(const Matrix<r, c> &m1, const Matrix<r, c> &m2);
template <int r, int c>
inline Matrix<r, c> operator*(const Matrix<r, c> &m1, float factor);
template <int r, int c>
inline Matrix<r, c> operator/(const Matrix<r, c> &m1, float factor);
template <int r, int c>
Matrix<r, c> operator*(float factor, const Matrix<r, c> &m1);
template <int r, int c>
Matrix<r, c> operator-(const Matrix<r, c> &m);
template <int r, int c>
bool operator==(const Matrix<r, c> &m1, const Matrix<r, c> &m2);
template <int r, int c>
bool operator!=(const Matrix<r, c> &m1, const Matrix<r, c> &m2);
// Constructors
template<int rows, int cols>
MatrixBase<rows, cols>::MatrixBase(const float *data) {
setData(data);
}
template<int rows, int cols>
MatrixBase<rows, cols>::MatrixBase(const MatrixBase<rows, cols> &m) {
setData(m._values);
}
template<int rows, int cols>
MatrixBase<rows, cols> &MatrixBase<rows, cols>::operator=(const MatrixBase<rows, cols> &m) {
setData(m._values);
return *this;
}
// Data management
template<int rows, int cols>
float *MatrixBase<rows, cols>::getData() {
return _values;
}
template<int rows, int cols>
const float *MatrixBase<rows, cols>::getData() const {
return _values;
}
template<int rows, int cols>
void MatrixBase<rows, cols>::setData(const float *data) {
::memcpy(_values, data, rows * cols * sizeof(float));
}
template<int rows, int cols>
float MatrixBase<rows, cols>::getValue(int row, int col) const {
assert(rows > row && cols > col && row >= 0 && col >= 0);
return _values[row * cols + col];
}
template<int rows, int cols>
void MatrixBase<rows, cols>::setValue(int row, int col, float v) {
operator()(row, col) = v;
}
// Operations helpers
template<int rows, int cols>
bool MatrixBase<rows, cols>::isZero() const {
for (int i = 0; i < rows * cols; ++i) {
if (_values[i] != 0.f) {
return false;
}
}
return true;
}
template <int r, int c>
Matrix<r, c> MatrixBase<r, c>::getNegative() const {
Matrix<r, c> result;
for (int i = 0; i < r * c; ++i) {
result._values[i] = -_values[i];
}
return result;
}
template <int r, int c>
Matrix<r, c> MatrixBase<r, c>::sum(const Matrix<r, c> &m1, const Matrix<r, c> &m2) {
Matrix<r, c> result;
for (int i = 0; i < r * c; ++i) {
result._values[i] = m1._values[i] + m2._values[i];
}
return result;
}
template <int r, int c>
Matrix<r, c> MatrixBase<r, c>::difference(const Matrix<r, c> &m1, const Matrix<r, c> &m2) {
Matrix<r, c> result;
for (int i = 0; i < r * c; ++i) {
result._values[i] = m1._values[i] - m2._values[i];
}
return result;
}
template <int r, int c>
Matrix<r, c> MatrixBase<r, c>::product(const Matrix<r, c> &m1, float factor) {
Matrix<r, c> result;
for (int i = 0; i < r * c; ++i) {
result._values[i] = m1._values[i] * factor;
}
return result;
}
template <int r, int c>
Matrix<r, c> MatrixBase<r, c>::product(const Matrix<r, c> &m1, const Matrix<r, c> &m2) {
Matrix<r, c> result;
for (int i = 0; i < r * c; ++i) {
result._values[i] = m1._values[i] * m2._values[i];
}
return result;
}
template <int r, int c>
Matrix<r, c> MatrixBase<r, c>::quotient(const Matrix<r, c> &m1, float factor) {
Matrix<r, c> result;
for (int i = 0; i < r * c; ++i) {
result._values[i] = m1._values[i] / factor;
}
return result;
}
template <int r, int c>
Matrix<r, c> MatrixBase<r, c>::quotient(const Matrix<r, c> &m1, const Matrix<r, c> &m2) {
Matrix<r, c> result;
for (int i = 0; i < r * c; ++i) {
result._values[i] = m1._values[i] / m2._values[i];
}
return result;
}
// Member operators
template<int rows, int cols>
float &MatrixBase<rows, cols>::operator()(int row, int col) {
assert(rows > row && cols > col && row >= 0 && col >= 0);
return _values[row * cols + col];
}
template<int rows, int cols>
float MatrixBase<rows, cols>::operator()(int row, int col) const {
return getValue(row, col);
}
template<int rows, int cols>
Matrix<rows, cols> &MatrixBase<rows, cols>::operator=(const Matrix<rows, cols> &m) {
setData(m._values);
return getThis();
}
template<int rows, int cols>
Matrix<rows, cols> &MatrixBase<rows, cols>::operator+=(const Matrix<rows, cols> &m) {
for (int i = 0; i < rows * cols; ++i) {
_values[i] += m._values[i];
}
return getThis();
}
template<int rows, int cols>
Matrix<rows, cols> &MatrixBase<rows, cols>::operator-=(const Matrix<rows, cols> &m) {
for (int i = 0; i < rows * cols; ++i) {
_values[i] -= m._values[i];
}
return getThis();
}
template<int rows, int cols>
Matrix<rows, cols> &MatrixBase<rows, cols>::operator*=(float factor) {
for (int i = 0; i < rows * cols; ++i) {
_values[i] *= factor;
}
return getThis();
}
template<int rows, int cols>
Matrix<rows, cols> &MatrixBase<rows, cols>::operator/=(float factor) {
for (int i = 0; i < rows * cols; ++i) {
_values[i] /= factor;
}
return getThis();
}
// Row
template<int rows, int cols>
typename MatrixBase<rows, cols>::Row MatrixBase<rows, cols>::getRow(int row) {
return Row(this, row);
}
template<int rows, int cols>
MatrixBase<rows, cols>::Row::Row(MatrixBase<rows, cols> *m, int row) :
_matrix(m), _row(row), _col(0) {
}
template<int rows, int cols>
typename MatrixBase<rows, cols>::Row &MatrixBase<rows, cols>::Row::operator<<(float value) {
assert(_col < cols);
_matrix->setValue(_row, _col++, value);
return *this;
}
// Global operators
template <int m, int n, int p>
Matrix<m, n> operator*(const Matrix<m, p> &m1, const Matrix<p, n> &m2) {
Matrix<m, n> result;
for (int row = 0; row < m; ++row) {
for (int col = 0; col < n; ++col) {
float sum(0.0f);
for (int j = 0; j < p; ++j)
sum += m1(row, j) * m2(j, col);
result(row, col) = sum;
}
}
return result;
}
template <int r, int c>
inline Matrix<r, c> operator+(const Matrix<r, c> &m1, const Matrix<r, c> &m2) {
return Matrix<r, c>::sum(m1, m2);
}
template <int r, int c>
inline Matrix<r, c> operator-(const Matrix<r, c> &m1, const Matrix<r, c> &m2) {
return Matrix<r, c>::difference(m1, m2);
}
template <int r, int c>
inline Matrix<r, c> operator*(const Matrix<r, c> &m1, const Matrix<r, c> &m2) {
return Matrix<r, c>::product(m1, m2);
}
template <int r, int c>
inline Matrix<r, c> operator*(const Matrix<r, c> &m1, float factor) {
return Matrix<r, c>::product(m1, factor);
}
template <int r, int c>
inline Matrix<r, c> operator/(const Matrix<r, c> &m1, const Matrix<r, c> &m2) {
return Matrix<r, c>::quotient(m1, m2);
}
template <int r, int c>
inline Matrix<r, c> operator/(const Matrix<r, c> &m1, float factor) {
return Matrix<r, c>::quotient(m1, factor);
}
template <int r, int c>
Matrix<r, c> operator*(float factor, const Matrix<r, c> &m1) {
return Matrix<r, c>::product(m1, factor);
}
template <int r, int c>
Matrix<r, c> operator-(const Matrix<r, c> &m) {
return m.getNegative();
}
template <int r, int c>
bool operator==(const Matrix<r, c> &m1, const Matrix<r, c> &m2) {
for (int row = 0; row < r; ++row) {
for (int col = 0; col < c; ++col) {
if (m1(row, col) != m2(row, col)) {
return false;
}
}
}
return true;
}
template <int r, int c>
bool operator!=(const Matrix<r, c> &m1, const Matrix<r, c> &m2) {
return !(m1 == m2);
}
template<int r, int c>
Common::StreamDebug &operator<<(Common::StreamDebug &dbg, const Math::Matrix<r, c> &m) {
dbg.nospace() << "Matrix<" << r << ", " << c << ">(";
for (int col = 0; col < c; ++col) {
dbg << m(0, col) << ", ";
}
for (int row = 1; row < r; ++row) {
dbg << "\n ";
for (int col = 0; col < c; ++col) {
dbg << m(row, col) << ", ";
}
}
dbg << ')';
return dbg.space();
}
}
#endif

64
math/matrix3.cpp Normal file
View File

@@ -0,0 +1,64 @@
/* 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/>.
*
*/
#include "math/matrix3.h"
namespace Math {
void swap (float &a, float &b) {
float c = a; a = b; b = c;
}
void Matrix<3, 3>::transpose() {
swap(operator()(0, 1), operator()(1, 0));
swap(operator()(0, 2), operator()(2, 0));
swap(operator()(1, 2), operator()(2, 1));
}
/**
* Generates a lookat matrix. For reference, see
* https://clb.confined.space/MathGeoLib/nightly/docs/float3x3_LookAt.php
*/
void Matrix<3, 3>::buildFromTargetDir(const Math::Vector3d &modelForward, const Math::Vector3d &targetDirection,
const Math::Vector3d &modelUp, const Math::Vector3d &worldUp) {
Math::Vector3d modelRight = Math::Vector3d::crossProduct(modelUp, modelForward);
modelRight.normalize();
Math::Vector3d worldRight = Math::Vector3d::crossProduct(worldUp, targetDirection);
worldRight.normalize();
Math::Vector3d perpWorldUp = Math::Vector3d::crossProduct(targetDirection, worldRight);
perpWorldUp.normalize();
Math::Matrix3 m1;
m1.getRow(0) << worldRight.x() << worldRight.y() << worldRight.z();
m1.getRow(1) << perpWorldUp.x() << perpWorldUp.y() << perpWorldUp.z();
m1.getRow(2) << targetDirection.x() << targetDirection.y() << targetDirection.z();
m1.transpose();
Math::Matrix3 m2;
m2.getRow(0) << modelRight.x() << modelRight.y() << modelRight.z();
m2.getRow(1) << modelUp.x() << modelUp.y() << modelUp.z();
m2.getRow(2) << modelForward.x() << modelForward.y() << modelForward.z();
this->operator=(m1 * m2);
}
} // end of namespace Math

80
math/matrix3.h Normal file
View File

@@ -0,0 +1,80 @@
/* 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/>.
*
*/
#ifndef MATH_MATRIX3_H
#define MATH_MATRIX3_H
#include "math/rotation3d.h"
#include "math/squarematrix.h"
#include "math/vector3d.h"
namespace Math {
template<>
class Matrix<3, 3> : public MatrixType<3, 3>, public Rotation3D<Matrix<3, 3> > {
public:
Matrix() : MatrixType<3, 3>(), Rotation3D<Matrix<3, 3> >() {}
Matrix(const MatrixBase<3, 3> &m) :
MatrixType<3, 3>(m), Rotation3D<Matrix<3, 3> >() {
}
void transpose();
/**
* Builds a matrix that maps the given local space forward direction vector to point towards the given
* target direction, and the given local up direction towards the given target world up direction.
*
* @param modelForward The forward direction in the local space of the object.
* @param targetDirection The desired world space direction the object should look at.
* @param modelUp The up direction in the local space of the object. This vector must be
* perpendicular to the vector localForward.
* @param worldUp The global up direction of the scene in world space. The worldUp and targetDirection
* vectors cannot be collinear, but they do not need to be perpendicular either.
* All the parameters MUST be normalized.
*/
void buildFromTargetDir(const Math::Vector3d &modelForward, const Math::Vector3d &targetDirection,
const Math::Vector3d &modelUp, const Math::Vector3d &worldUp);
inline Matrix<3, 3> operator*(const Matrix<3, 3> &m2) const {
Matrix<3, 3> result;
const float *d1 = getData();
const float *d2 = m2.getData();
float *r = result.getData();
for (int i = 0; i < 9; i += 3) {
for (int j = 0; j < 3; ++j) {
r[i + j] = (d1[i + 0] * d2[j + 0])
+ (d1[i + 1] * d2[j + 3])
+ (d1[i + 2] * d2[j + 6]);
}
}
return result;
}
};
typedef Matrix<3, 3> Matrix3;
} // end of namespace Math
#endif

130
math/matrix4.cpp Normal file
View File

@@ -0,0 +1,130 @@
/* 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/>.
*
*/
#include "math/matrix4.h"
#include "math/vector4d.h"
#include "math/squarematrix.h"
namespace Math {
Matrix<4, 4>::Matrix() :
MatrixType<4, 4>(), Rotation3D<Matrix4>() {
}
Matrix<4, 4>::Matrix(const MatrixBase<4, 4> &m) :
MatrixType<4, 4>(m), Rotation3D<Matrix4>() {
}
void Matrix<4, 4>::transform(Vector3d *v, bool trans) const {
Vector4d m;
m(0, 0) = v->x();
m(1, 0) = v->y();
m(2, 0) = v->z();
m(3, 0) = (trans ? 1.f : 0.f);
m = *this * m;
v->set(m(0, 0), m(1, 0), m(2, 0));
}
Vector3d Matrix<4, 4>::getPosition() const {
return Vector3d(getValue(0, 3), getValue(1, 3), getValue(2, 3));
}
void Matrix<4, 4>::setPosition(const Vector3d &v) {
setValue(0, 3, v.x());
setValue(1, 3, v.y());
setValue(2, 3, v.z());
}
Matrix3 Matrix<4, 4>::getRotation() const{
Matrix3 m2;
m2.setValue(0, 0, getValue(0, 0));
m2.setValue(0, 1, getValue(0, 1));
m2.setValue(0, 2, getValue(0, 2));
m2.setValue(1, 0, getValue(1, 0));
m2.setValue(1, 1, getValue(1, 1));
m2.setValue(1, 2, getValue(1, 2));
m2.setValue(2, 0, getValue(2, 0));
m2.setValue(2, 1, getValue(2, 1));
m2.setValue(2, 2, getValue(2, 2));
return m2;
}
void Matrix<4, 4>::setRotation(const Matrix3 &m) {
setValue(0, 0, m.getValue(0, 0));
setValue(0, 1, m.getValue(0, 1));
setValue(0, 2, m.getValue(0, 2));
setValue(1, 0, m.getValue(1, 0));
setValue(1, 1, m.getValue(1, 1));
setValue(1, 2, m.getValue(1, 2));
setValue(2, 0, m.getValue(2, 0));
setValue(2, 1, m.getValue(2, 1));
setValue(2, 2, m.getValue(2, 2));
}
void Matrix<4, 4>::translate(const Vector3d &vec) {
Vector3d v(vec);
transform(&v, false);
operator()(0, 3) += v.x();
operator()(1, 3) += v.y();
operator()(2, 3) += v.z();
}
/**
* Generates a lookat matrix. For reference, see
* https://clb.confined.space/MathGeoLib/nightly/docs/float3x3_LookAt.php
*/
void Matrix<4, 4>::buildFromTargetDir(const Math::Vector3d &modelForward, const Math::Vector3d &targetDirection,
const Math::Vector3d &modelUp, const Math::Vector3d &worldUp) {
Matrix3 rotation;
rotation.buildFromTargetDir(modelForward, targetDirection, modelUp, worldUp);
this->setRotation(rotation);
}
void Matrix<4, 4>::invertAffineOrthonormal() {
Matrix3 rotation(getRotation());
rotation.transpose();
Vector3d position(getPosition().getNegative());
rotation.transformVector(&position);
setRotation(rotation);
setPosition(position);
}
void swap(float &a, float &b);
void Matrix<4, 4>::transpose() {
swap(operator ()(0,1), operator ()(1,0));
swap(operator ()(0,2), operator ()(2,0));
swap(operator ()(0,3), operator ()(3,0));
swap(operator ()(1,2), operator ()(2,1));
swap(operator ()(1,3), operator ()(3,1));
swap(operator ()(2,3), operator ()(3,2));
}
} // end of namespace Math

247
math/matrix4.h Normal file
View File

@@ -0,0 +1,247 @@
/* 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/>.
*
*/
#ifndef MATH_MATRIX4_H
#define MATH_MATRIX4_H
#include "math/rotation3d.h"
#include "math/squarematrix.h"
#include "math/vector3d.h"
#include "math/vector4d.h"
#include "math/matrix3.h"
namespace Math {
// matrix 4 is a rotation matrix + position
template<>
class Matrix<4, 4> : public MatrixType<4, 4>, public Rotation3D<Matrix<4, 4> > {
public:
Matrix();
Matrix(const MatrixBase<4, 4> &m);
Matrix(const Angle &first, const Angle &second, const Angle &third, EulerOrder order) { buildFromEuler(first, second, third, order); }
void transform(Vector3d *v, bool translate) const;
Vector3d getPosition() const;
void setPosition(const Vector3d &v);
Matrix3 getRotation() const;
void setRotation(const Matrix3 &m);
void translate(const Vector3d &v);
/**
* Builds a matrix that maps the given local space forward direction vector to point towards the given
* target direction, and the given local up direction towards the given target world up direction.
*
* @param modelForward The forward direction in the local space of the object.
* @param targetDirection The desired world space direction the object should look at.
* @param modelUp The up direction in the local space of the object. This vector must be
* perpendicular to the vector localForward.
* @param worldUp The global up direction of the scene in world space. The worldUp and targetDirection
* vectors cannot be collinear, but they do not need to be perpendicular either.
* All the parameters MUST be normalized.
*/
void buildFromTargetDir(const Math::Vector3d &modelForward, const Math::Vector3d &targetDirection,
const Math::Vector3d &modelUp, const Math::Vector3d &worldUp);
/**
* Inverts a matrix in place.
* This function avoid having to do generic Gaussian elimination on the matrix
* by assuming that the top-left 3x3 part of the matrix is orthonormal
* (columns and rows 0, 1 and 2 orthogonal and unit length).
* See e.g. Eric Lengyel's Mathematics for 3D Game Programming and Computer Graphics, p. 82.
*/
void invertAffineOrthonormal();
void transpose();
inline Matrix<4, 4> operator*(const Matrix<4, 4> &m2) const {
Matrix<4, 4> result;
const float *d1 = getData();
const float *d2 = m2.getData();
float *r = result.getData();
for (int i = 0; i < 16; i += 4) {
for (int j = 0; j < 4; ++j) {
r[i + j] = (d1[i + 0] * d2[j + 0]) +
(d1[i + 1] * d2[j + 4]) +
(d1[i + 2] * d2[j + 8]) +
(d1[i + 3] * d2[j + 12]);
}
}
return result;
}
inline Vector4d transform(const Vector4d &v) const {
Vector4d result;
const float *d1 = getData();
const float *d2 = v.getData();
float *r = result.getData();
for (int i = 0; i < 4; i++) {
r[i] = d2[0] * d1[0 * 4 + i] +
d2[1] * d1[1 * 4 + i] +
d2[2] * d1[2 * 4 + i] +
d2[3] * d1[3 * 4 + i];
}
return result;
}
inline bool inverse() {
Matrix<4, 4> invMatrix;
float *inv = invMatrix.getData();
float *m = getData();
inv[0] = m[5] * m[10] * m[15] -
m[5] * m[11] * m[14] -
m[9] * m[6] * m[15] +
m[9] * m[7] * m[14] +
m[13] * m[6] * m[11] -
m[13] * m[7] * m[10];
inv[4] = -m[4] * m[10] * m[15] +
m[4] * m[11] * m[14] +
m[8] * m[6] * m[15] -
m[8] * m[7] * m[14] -
m[12] * m[6] * m[11] +
m[12] * m[7] * m[10];
inv[8] = m[4] * m[9] * m[15] -
m[4] * m[11] * m[13] -
m[8] * m[5] * m[15] +
m[8] * m[7] * m[13] +
m[12] * m[5] * m[11] -
m[12] * m[7] * m[9];
inv[12] = -m[4] * m[9] * m[14] +
m[4] * m[10] * m[13] +
m[8] * m[5] * m[14] -
m[8] * m[6] * m[13] -
m[12] * m[5] * m[10] +
m[12] * m[6] * m[9];
inv[1] = -m[1] * m[10] * m[15] +
m[1] * m[11] * m[14] +
m[9] * m[2] * m[15] -
m[9] * m[3] * m[14] -
m[13] * m[2] * m[11] +
m[13] * m[3] * m[10];
inv[5] = m[0] * m[10] * m[15] -
m[0] * m[11] * m[14] -
m[8] * m[2] * m[15] +
m[8] * m[3] * m[14] +
m[12] * m[2] * m[11] -
m[12] * m[3] * m[10];
inv[9] = -m[0] * m[9] * m[15] +
m[0] * m[11] * m[13] +
m[8] * m[1] * m[15] -
m[8] * m[3] * m[13] -
m[12] * m[1] * m[11] +
m[12] * m[3] * m[9];
inv[13] = m[0] * m[9] * m[14] -
m[0] * m[10] * m[13] -
m[8] * m[1] * m[14] +
m[8] * m[2] * m[13] +
m[12] * m[1] * m[10] -
m[12] * m[2] * m[9];
inv[2] = m[1] * m[6] * m[15] -
m[1] * m[7] * m[14] -
m[5] * m[2] * m[15] +
m[5] * m[3] * m[14] +
m[13] * m[2] * m[7] -
m[13] * m[3] * m[6];
inv[6] = -m[0] * m[6] * m[15] +
m[0] * m[7] * m[14] +
m[4] * m[2] * m[15] -
m[4] * m[3] * m[14] -
m[12] * m[2] * m[7] +
m[12] * m[3] * m[6];
inv[10] = m[0] * m[5] * m[15] -
m[0] * m[7] * m[13] -
m[4] * m[1] * m[15] +
m[4] * m[3] * m[13] +
m[12] * m[1] * m[7] -
m[12] * m[3] * m[5];
inv[14] = -m[0] * m[5] * m[14] +
m[0] * m[6] * m[13] +
m[4] * m[1] * m[14] -
m[4] * m[2] * m[13] -
m[12] * m[1] * m[6] +
m[12] * m[2] * m[5];
inv[3] = -m[1] * m[6] * m[11] +
m[1] * m[7] * m[10] +
m[5] * m[2] * m[11] -
m[5] * m[3] * m[10] -
m[9] * m[2] * m[7] +
m[9] * m[3] * m[6];
inv[7] = m[0] * m[6] * m[11] -
m[0] * m[7] * m[10] -
m[4] * m[2] * m[11] +
m[4] * m[3] * m[10] +
m[8] * m[2] * m[7] -
m[8] * m[3] * m[6];
inv[11] = -m[0] * m[5] * m[11] +
m[0] * m[7] * m[9] +
m[4] * m[1] * m[11] -
m[4] * m[3] * m[9] -
m[8] * m[1] * m[7] +
m[8] * m[3] * m[5];
inv[15] = m[0] * m[5] * m[10] -
m[0] * m[6] * m[9] -
m[4] * m[1] * m[10] +
m[4] * m[2] * m[9] +
m[8] * m[1] * m[6] -
m[8] * m[2] * m[5];
float det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
if (det == 0)
return false;
det = 1.0 / det;
for (int i = 0; i < 16; i++) {
m[i] = inv[i] * det;
}
return true;
}
};
typedef Matrix<4, 4> Matrix4;
} // end of namespace Math
#endif

159
math/mdct.cpp Normal file
View File

@@ -0,0 +1,159 @@
/* 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/>.
*
*/
// Based on xoreos' (I)RDFT code which is in turn
// Based upon the (I)MDCT code in FFmpeg
// Copyright (c) 2002 Fabrice Bellard
/** @file math/mdct.cpp
* (Inverse) Modified Discrete Cosine Transforms.
*/
#include "math/mdct.h"
#include "math/fft.h"
#include "math/utils.h"
#include "common/util.h"
namespace Math {
MDCT::MDCT(int bits, bool inverse, double scale) : _bits(bits), _fft(nullptr) {
_size = 1 << bits;
_fft = new FFT(_bits - 2, inverse);
const int size2 = _size >> 1;
const int size4 = _size >> 2;
_tCos = new float[size2];
_tSin = _tCos + size4;
const double theta = 1.0 / 8.0 + (scale < 0 ? size4 : 0);
scale = sqrt(ABS(scale));
for (int i = 0; i < size4; i++) {
const double alpha = 2 * (float)M_PI * (i + theta) / _size;
_tCos[i] = -cos(alpha) * scale;
_tSin[i] = -sin(alpha) * scale;
}
}
MDCT::~MDCT() {
delete[] _tCos;
delete _fft;
}
#define CMUL(dre, dim, are, aim, bre, bim) do { \
(dre) = (are) * (bre) - (aim) * (bim); \
(dim) = (are) * (bim) + (aim) * (bre); \
} while (0)
void MDCT::calcMDCT(float *output, const float *input) {
Complex *x = (Complex *) output;
const int size2 = _size >> 1;
const int size4 = _size >> 2;
const int size8 = _size >> 3;
const int size3 = _size * 3;
const uint16 *revTab = _fft->getRevTab();
// Pre rotation
for (int i = 0; i < size8; i++) {
float re = -input[2 * i + size3] - input[size3 - 1 - 2 * i];
float im = -input[2 * i + size4] + input[size4 - 1 - 2 * i];
int j = revTab[i];
CMUL(x[j].re, x[j].im, re, im, -_tCos[i], _tSin[i]);
re = input[2 * i ] - input[size2 - 1 - 2 * i];
im = -input[2 * i + size2] - input[_size - 1 - 2 * i];
j = revTab[size8 + i];
CMUL(x[j].re, x[j].im, re, im, -_tCos[size8 + i], _tSin[size8 + i]);
}
_fft->calc(x);
// Post rotation
for (int i = 0; i < size8; i++) {
float r0, i0, r1, i1;
CMUL(i1, r0, x[size8-i-1].re, x[size8-i-1].im, -_tSin[size8-i-1], -_tCos[size8-i-1]);
CMUL(i0, r1, x[size8+i ].re, x[size8+i ].im, -_tSin[size8+i ], -_tCos[size8+i ]);
x[size8 - i - 1].re = r0;
x[size8 - i - 1].im = i0;
x[size8 + i ].re = r1;
x[size8 + i ].im = i1;
}
}
void MDCT::calcIMDCT(float *output, const float *input) {
const int size2 = _size >> 1;
const int size4 = _size >> 2;
calcHalfIMDCT(output + size4, input);
for (int k = 0; k < size4; k++) {
output[ k ] = -output[size2 - k - 1];
output[_size - k - 1] = output[size2 + k ];
}
}
void MDCT::calcHalfIMDCT(float *output, const float *input) {
Complex *z = (Complex *) output;
const int size2 = _size >> 1;
const int size4 = _size >> 2;
const int size8 = _size >> 3;
const uint16 *revTab = _fft->getRevTab();
// Pre rotation
const float *in1 = input;
const float *in2 = input + size2 - 1;
for (int k = 0; k < size4; k++) {
const int j = revTab[k];
CMUL(z[j].re, z[j].im, *in2, *in1, _tCos[k], _tSin[k]);
in1 += 2;
in2 -= 2;
}
_fft->calc(z);
// Post rotation + reordering
for (int k = 0; k < size8; k++) {
float r0, i0, r1, i1;
CMUL(r0, i1, z[size8-k-1].im, z[size8-k-1].re, _tSin[size8-k-1], _tCos[size8-k-1]);
CMUL(r1, i0, z[size8+k ].im, z[size8+k ].re, _tSin[size8+k ], _tCos[size8+k ]);
z[size8 - k - 1].re = r0;
z[size8 - k - 1].im = i0;
z[size8 + k ].re = r1;
z[size8 + k ].im = i1;
}
}
} // End of namespace Math

65
math/mdct.h Normal file
View File

@@ -0,0 +1,65 @@
/* 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/>.
*
*/
// Based on xoreos' (I)RDFT code which is in turn
// Based upon the (I)MDCT code in FFmpeg
// Copyright (c) 2002 Fabrice Bellard
#ifndef MATH_MDCT_H
#define MATH_MDCT_H
#include "common/scummsys.h"
namespace Math {
class FFT;
/** (Inverse) Modified Discrete Cosine Transforms. */
class MDCT {
public:
MDCT(int bits, bool inverse, double scale);
~MDCT();
/** Compute MDCT of size N = 2^nbits. */
void calcMDCT(float *output, const float *input);
/** Compute inverse MDCT of size N = 2^nbits. */
void calcIMDCT(float *output, const float *input);
private:
int _bits;
int _size;
float *_tCos;
float *_tSin;
FFT *_fft;
/** Compute the middle half of the inverse MDCT of size N = 2^nbits,
* thus excluding the parts that can be derived by symmetry.
*/
void calcHalfIMDCT(float *output, const float *input);
};
} // End of namespace Math
#endif // MATH_MDCT_H

28
math/module.mk Normal file
View File

@@ -0,0 +1,28 @@
MODULE := math
MODULE_OBJS := \
aabb.o \
angle.o \
cosinetables.o \
dct.o \
fft.o \
frustum.o \
glmath.o \
line2d.o \
line3d.o \
matrix3.o \
matrix4.o \
mdct.o \
plane.o \
quat.o \
ray.o \
rdft.o \
rect2d.o \
sinetables.o \
sinewindows.o \
vector2d.o \
vector3d.o \
vector4d.o
# Include common rules
include $(srcdir)/rules.mk

44
math/plane.cpp Normal file
View File

@@ -0,0 +1,44 @@
/* 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/>.
*
*/
#include "math/plane.h"
namespace Math {
Plane::Plane() : _d(0.0f) {
}
Plane::Plane(const Math::Vector3d &normal, float d) : _normal(normal), _d(d) {
}
float Plane::getSignedDistance(const Math::Vector3d &p) const {
return _normal.x() * p.x() + _normal.y() * p.y() + _normal.z() * p.z() + _d;
}
void Plane::normalize() {
float mag = _normal.getMagnitude();
if (mag > 0.0f) {
_normal /= mag;
_d /= mag;
}
}
}

43
math/plane.h Normal file
View File

@@ -0,0 +1,43 @@
/* 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/>.
*
*/
#ifndef MATH_PLANE_H
#define MATH_PLANE_H
#include "math/vector3d.h"
namespace Math {
class Plane {
public:
Plane();
Plane(const Math::Vector3d &normal, float d);
float getSignedDistance(const Math::Vector3d &p) const;
void normalize();
Math::Vector3d _normal;
float _d;
};
} // end of namespace Math
#endif

294
math/quat.cpp Normal file
View File

@@ -0,0 +1,294 @@
/* 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/>.
*
*/
/*
* Quaternion-math originally borrowed from plib https://plib.sourceforge.net/index.html
* This code was originally made available under the LGPLv2 license (or later).
*
* Quaternion routines are Copyright (C) 1999
* Kevin B. Thompson <kevinbthompson@yahoo.com>
* Modified by Sylvan W. Clebsch <sylvan@stanford.edu>
* Largely rewritten by "Negative0" <negative0@earthlink.net>
*
* This code (and our modifications) is made available here under the GPLv2 (or later).
*
* Additional changes written based on the math presented in
* https://web.archive.org/web/20120710204808/http://www.swarthmore.edu/NatSci/mzucker1/e27/diebel2006attitude.pdf
*
*/
#include "common/streamdebug.h"
#include "math/quat.h"
#include "math/utils.h"
namespace Math {
Quaternion::Quaternion(const Matrix3 &m) {
fromMatrix(m);
normalize();
}
Quaternion::Quaternion(const Matrix4 &m) {
fromMatrix(m.getRotation());
}
Quaternion::Quaternion(const Vector3d &axis, const Angle &angle) {
float s = (angle / 2).getSine();
float c = (angle / 2).getCosine();
set(axis.x() * s, axis.y() * s, axis.z() * s, c);
}
Quaternion Quaternion::xAxis(const Angle &angle) {
Quaternion q(Vector3d(1.0f, 0.0f, 0.0f), angle);
return q;
}
Quaternion Quaternion::yAxis(const Angle &angle) {
Quaternion q(Vector3d(0.0f, 1.0f, 0.0f), angle);
return q;
}
Quaternion Quaternion::zAxis(const Angle &angle) {
Quaternion q(Vector3d(0.0f, 0.0f, 1.0f), angle);
return q;
}
Quaternion Quaternion::slerpQuat(const Quaternion& to, const float t) const {
Quaternion dst;
float scale0, scale1;
float flip = 1.0f;
float angle = this->dotProduct(to);
// Make sure the rotation is the short one
if (angle < 0.0f) {
angle = -angle;
flip = -1.0f;
}
// Spherical Interpolation
// Threshold of 1e-6
if (angle < 1.0f - (float) 1E-6f) {
float theta = acosf(angle);
float invSineTheta = 1.0f / sinf(theta);
scale0 = sinf((1.0f - t) * theta) * invSineTheta;
scale1 = (sinf(t * theta) * invSineTheta) * flip;
// Linear Interpolation
} else {
scale0 = 1.0f - t;
scale1 = t * flip;
}
// Apply the interpolation
dst = (*this * scale0) + (to * scale1);
return dst;
}
Quaternion& Quaternion::normalize() {
const float scale = sqrtf(square(x()) + square(y()) + square(z()) + square(w()));
// Already normalized if the scale is 1.0
if (scale != 1.0f && scale != 0.0f)
set(x() / scale, y() / scale, z() / scale, w() / scale);
return *this;
}
void Quaternion::transform(Vector3d &v) const {
const Vector3d im = Vector3d(x(), y(), z());
v += 2.0 * Vector3d::crossProduct(im, Vector3d::crossProduct(im, v) + w() * v);
}
void Quaternion::fromMatrix(const Matrix3 &m) {
float qx, qy, qz, qw;
float tr = m.getValue(0, 0) + m.getValue(1, 1) + m.getValue(2, 2);
float s;
if (tr > 0.0f) {
s = sqrtf(tr + 1.0f);
qw = s * 0.5f;
s = 0.5f / s;
qx = (m.getValue(2, 1) - m.getValue(1, 2)) * s;
qy = (m.getValue(0, 2) - m.getValue(2, 0)) * s;
qz = (m.getValue(1, 0) - m.getValue(0, 1)) * s;
} else {
int h = 0;
if (m.getValue(1, 1) > m.getValue(0, 0))
h = 1;
if (m.getValue(2, 2) > m.getValue(h, h))
h = 2;
if (h == 0) {
s = sqrt(m.getValue(0, 0) - (m.getValue(1,1) + m.getValue(2, 2)) + 1.0f);
qx = s * 0.5f;
s = 0.5f / s;
qy = (m.getValue(0, 1) + m.getValue(1, 0)) * s;
qz = (m.getValue(2, 0) + m.getValue(0, 2)) * s;
qw = (m.getValue(2, 1) - m.getValue(1, 2)) * s;
} else if (h == 1) {
s = sqrt(m.getValue(1, 1) - (m.getValue(2,2) + m.getValue(0, 0)) + 1.0f);
qy = s * 0.5f;
s = 0.5f / s;
qz = (m.getValue(1, 2) + m.getValue(2, 1)) * s;
qx = (m.getValue(0, 1) + m.getValue(1, 0)) * s;
qw = (m.getValue(0, 2) - m.getValue(2, 0)) * s;
} else {
s = sqrt(m.getValue(2, 2) - (m.getValue(0,0) + m.getValue(1, 1)) + 1.0f);
qz = s * 0.5f;
s = 0.5f / s;
qx = (m.getValue(2, 0) + m.getValue(0, 2)) * s;
qy = (m.getValue(1, 2) + m.getValue(2, 1)) * s;
qw = (m.getValue(1, 0) - m.getValue(0, 1)) * s;
}
}
set(qx, qy, qz, qw);
}
void Quaternion::toMatrix(Matrix4 &dst) const {
float two_xx = x() * (x() + x());
float two_xy = x() * (y() + y());
float two_xz = x() * (z() + z());
float two_wx = w() * (x() + x());
float two_wy = w() * (y() + y());
float two_wz = w() * (z() + z());
float two_yy = y() * (y() + y());
float two_yz = y() * (z() + z());
float two_zz = z() * (z() + z());
float newMat[16] = {
1.0f - (two_yy + two_zz), two_xy - two_wz, two_xz + two_wy, 0.0f,
two_xy + two_wz, 1.0f - (two_xx + two_zz), two_yz - two_wx, 0.0f,
two_xz - two_wy, two_yz + two_wx, 1.0f - (two_xx + two_yy), 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
dst.setData(newMat);
}
Matrix4 Quaternion::toMatrix() const {
Matrix4 dst;
toMatrix(dst);
return dst;
}
Quaternion Quaternion::inverse() const {
Quaternion q = *this;
q.normalize();
q.x() = -q.x();
q.y() = -q.y();
q.z() = -q.z();
return q;
}
Vector3d Quaternion::directionVector(const int col) const {
Matrix4 dirMat = toMatrix();
return Vector3d(dirMat.getValue(0, col), dirMat.getValue(1, col), dirMat.getValue(2, col));
}
Angle Quaternion::getAngleBetween(const Quaternion &to) {
Quaternion q = this->inverse() * to;
Angle diff(Math::rad2deg(2 * acos(q.w())));
return diff;
}
Quaternion Quaternion::fromEuler(const Angle &first, const Angle &second, const Angle &third, EulerOrder order) {
// First create a matrix with the rotation
Matrix4 rot(first, second, third, order);
// Convert this rotation matrix to a Quaternion
return Quaternion(rot);
}
void Quaternion::getEuler(Angle *first, Angle *second, Angle *third, EulerOrder order) const {
// Create a matrix from the Quaternion
Matrix4 rot = toMatrix();
// Convert the matrix to Euler Angles
Angle f, s, t;
rot.getEuler(&f, &s, &t, order);
// Assign the Angles if we have a reference
if (first != nullptr)
*first = f;
if (second != nullptr)
*second = s;
if (third != nullptr)
*third = t;
}
Quaternion& Quaternion::operator=(const Quaternion& quat) {
x() = quat.x();
y() = quat.y();
z() = quat.z();
w() = quat.w();
return *this;
}
Quaternion Quaternion::operator*(const Quaternion &o) const {
return Quaternion(
w() * o.x() + x() * o.w() + y() * o.z() - z() * o.y(),
w() * o.y() - x() * o.z() + y() * o.w() + z() * o.x(),
w() * o.z() + x() * o.y() - y() * o.x() + z() * o.w(),
w() * o.w() - x() * o.x() - y() * o.y() - z() * o.z()
);
}
Quaternion Quaternion::operator*(const float c) const {
return Quaternion(x() * c, y() * c, z() * c, w() * c);
}
Quaternion& Quaternion::operator*=(const Quaternion &o) {
*this = *this * o;
return *this;
}
Quaternion Quaternion::operator+(const Quaternion &o) const {
return Quaternion(x() + o.x(), y() + o.y(), z() + o.z(), w() + o.w());
}
Quaternion& Quaternion::operator+=(const Quaternion &o) {
*this = *this + o;
return *this;
}
bool Quaternion::operator==(const Quaternion &o) const {
float dw = fabs(w() - o.w());
float dx = fabs(x() - o.x());
float dy = fabs(y() - o.y());
float dz = fabs(z() - o.z());
// Threshold of equality
float th = 1E-5f;
if ((dw < th) && (dx < th) && (dy < th) && (dz < th)) {
return true;
}
return false;
}
bool Quaternion::operator!=(const Quaternion &o) const {
return !(*this == o);
}
} // End namespace Math

239
math/quat.h Normal file
View File

@@ -0,0 +1,239 @@
/* 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/>.
*
*/
// Quaternion-math borrowed from plib https://plib.sourceforge.net/index.html
// Which is covered by LGPL2
// And has this additional copyright note:
/*
Quaternion routines are Copyright (C) 1999
Kevin B. Thompson <kevinbthompson@yahoo.com>
Modified by Sylvan W. Clebsch <sylvan@stanford.edu>
Largely rewritten by "Negative0" <negative0@earthlink.net>
*/
#ifndef MATH_QUAT_H
#define MATH_QUAT_H
#include "common/scummsys.h"
#include "common/endian.h"
#include "math/rotation3d.h"
#include "math/vector.h"
#include "math/angle.h"
#include "math/vector4d.h"
#include "math/matrix4.h"
namespace Math {
class Quaternion : public Vector4d {
public:
/**
* Default Constructor, creates an identity Quaternion with no rotation.
*/
Quaternion() : Vector4d(0, 0, 0, 1.0) {}
/**
* Constructor from four floats in the order X,Y,Z,W
* The initial values should be normalized, otherwise call normalize() after creation
* @param lx The X value of the Quaternion
* @param ly The Y value of the Quaternion
* @param lz The Z value of the Quaternion
* @param lw The W value of the Quaternion
*/
Quaternion(float lx, float ly, float lz, float lw) : Vector4d(lx, ly, lz, lw) {}
/**
* Constructor from an existing Quaternion
* @param q The existing quaternion
* @return The new Quaternion
*/
Quaternion(const Quaternion &q) : Vector4d(q.x(), q.y(), q.z(), q.w()) {}
/**
* Constructor from a vector of four floats in the order X,Y,Z,W
* The initial values should be normalized, otherwise call normalize() after creation
* @param vec The vector of floats comprising the quaternion
* @return The new Quaternion
*/
Quaternion(const Vector4d &vec) : Vector4d(vec.x(), vec.y(), vec.z(), vec.w()) {}
/**
* Constructor from a rotation matrix
* @param m The rotation matrix
* @return The new Quaternion
*/
Quaternion(const Matrix3 &m);
/**
* Constructor from a rotation matrix
* @param m The rotation matrix
* @return The new Quaternion
*/
Quaternion(const Matrix4 &m);
/** Set the Quaternion from a rotation matrix
* @param m The matrix used to set the Quaternion
*/
void fromMatrix(const Matrix3 &m);
/**
* Constructor from an axis vector and the angle to rotate on that axis
* @param axis The axis to perform the rotation around
* @param angle The angle amount to rotate
* @return The new Quaternion
*/
Quaternion(const Vector3d &axis, const Angle &angle);
/**
* Constructs a Quaternion from Euler Coordinates
* @param first The Euler Angle for the first Axis
* @param second The Euler Angle for the second Axis
* @param third The Euler Angle for the third Axis
* @param order The Euler Order, specified in Rotation3D
* @return The new Quaternion
*/
static Quaternion fromEuler(const Angle &first, const Angle &second, const Angle &third, EulerOrder order);
/**
* Returns Euler Angles based on the Euler Order
* @param first The Euler Angle for the first Axis
* @param second The Euler Angle for the second Axis
* @param third The Euler Angle for the third Axis
* @param order The Euler Order, specified in Rotation3D
* @return The new Quaternion
*/
void getEuler(Angle *first, Angle *second, Angle *third, EulerOrder order) const;
/**
* Create a Quaternion from a rotation around the X Axis
* @param angle The Euler Angle for rotation
* @return The resulting Quaternion
*/
static Quaternion xAxis(const Angle &angle);
/**
* Create a Quaternion from a rotation around the Y Axis
* @param angle The Euler Angle for rotation
* @return The resulting Quaternion
*/
static Quaternion yAxis(const Angle &angle);
/**
* Create a Quaternion from a rotation around the Z Axis
* @param angle The Euler Angle for rotation
* @return The resulting Quaternion
*/
static Quaternion zAxis(const Angle &angle);
/**
* Normalize the Quaternion
* @return A reference to this quaternion
*/
Quaternion &normalize();
/**
* Rotate a vector by a Quaternion
* @param v The Vector to be rotated
*/
void transform(Vector3d &v) const;
/**
* Converts from this Quaternion to a Matrix4 representation
* @return The resulting matrix
*/
Matrix4 toMatrix() const;
/**
* Converts from this Quaternion to a Matrix4 representation
* @param dst The resulting matrix
*/
void toMatrix(Matrix4 &dst) const;
/**
* Make a new Quaternion that's the inverse of this Quaternion
* @return The resulting Quaternion
*/
Quaternion inverse() const;
/**
* Slerps between this quaternion and to by factor t
* @param to the quaternion to slerp between
* @param t factor to slerp by.
* @return the resulting quaternion.
*/
Quaternion slerpQuat(const Quaternion& to, const float t) const;
/**
* Get the direction vector specified by col
* @param col Column in the rotation matrix to get the direction vector from
* @return The resulting Vector3d
*/
Vector3d directionVector(const int col) const;
/**
* Get the angle between two quaternions
* @param to The quaternion we're comparing against
* @return The angle between the two
*/
Angle getAngleBetween(const Quaternion &to);
/**
* Assignment operator
* @param vec The source quaternion
* @return A reference to this Quaternion
*/
Quaternion& operator=(const Quaternion& quat);
/**
* Multiply two Quaternions
* @param quat The Quaternion multiplicand
* @return The result of the multiplication
*/
Quaternion operator*(const Quaternion &quat) const;
Quaternion& operator*=(const Quaternion &quat);
/**
* Multiply this Quaternion by a constant
* @param quat The Quaternion multiplicand
* @return The result of the multiplication
*/
Quaternion operator*(const float c) const;
/**
* Sum two quaternions
* @param quat The Quaternion to be added
* @return The result of the addition
*/
Quaternion operator+(const Quaternion &o) const;
Quaternion& operator+=(const Quaternion &o);
/**
* Compare quaternions
* @param quat The Quaternion to be compared
* @return The result of the comparison
*/
bool operator==(const Quaternion &o) const;
bool operator!=(const Quaternion &o) const;
};
} // end of namespace Math
#endif

120
math/ray.cpp Normal file
View File

@@ -0,0 +1,120 @@
/* 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/>.
*
*/
#include "math/ray.h"
#include "common/util.h"
namespace Math {
Ray::Ray() {
}
Ray::Ray(const Vector3d &origin, const Vector3d &direction) :
_origin(origin),
_direction(direction) {
}
void Ray::transform(const Matrix4 &matrix) {
matrix.transform(&_origin, true);
matrix.transform(&_direction, false);
_direction.normalize();
}
void Ray::rotate(const Quaternion &rot) {
rot.transform(_origin);
rot.transform(_direction);
_direction.normalize();
}
void Ray::rotateDirection(const Quaternion &rot) {
rot.transform(_direction);
_direction.normalize();
}
void Ray::translate(const Vector3d &v) {
_origin += v;
}
bool Ray::intersectAABB(const AABB &aabb) const {
Vector3d dirFrac;
dirFrac.x() = 1.0f / _direction.x();
dirFrac.y() = 1.0f / _direction.y();
dirFrac.z() = 1.0f / _direction.z();
float t1 = (aabb.getMin().x() - _origin.x()) * dirFrac.x();
float t2 = (aabb.getMax().x() - _origin.x()) * dirFrac.x();
float t3 = (aabb.getMin().y() - _origin.y()) * dirFrac.y();
float t4 = (aabb.getMax().y() - _origin.y()) * dirFrac.y();
float t5 = (aabb.getMin().z() - _origin.z()) * dirFrac.z();
float t6 = (aabb.getMax().z() - _origin.z()) * dirFrac.z();
float tMin = MAX(MAX(MIN(t1, t2), MIN(t3, t4)), MIN(t5, t6));
float tMax = MIN(MIN(MAX(t1, t2), MAX(t3, t4)), MAX(t5, t6));
// If tMax < 0, the ray is intersecting the AABB, but the whole AABB is in the opposite direction
if (tMax < 0) {
return false;
}
// If tMin > tMax, the ray doesn't intersect the AABB
if (tMin > tMax) {
return false;
}
return true;
}
// Algorithm adapted from https://www.lighthouse3d.com/tutorials/maths/ray-triangle-intersection/
bool Ray::intersectTriangle(const Vector3d &v0, const Vector3d &v1,
const Vector3d &v2, Vector3d &vout, float &fout) const {
const Vector3d e1 = v1 - v0;
const Vector3d e2 = v2 - v0;
const Vector3d h = Vector3d::crossProduct(_direction, e2);
float a = e1.dotProduct(h);
if (fabs(a) < 1e-6f)
return false;
float f = 1.0f / a;
const Vector3d s = _origin - v0;
float u = f * s.dotProduct(h);
if (u < 0.0f || u > 1.0f)
return false;
const Vector3d q = Vector3d::crossProduct(s, e1);
float v = f * _direction.dotProduct(q);
if (v < 0.0f || u + v > 1.0f)
return false;
float t = f * e2.dotProduct(q);
if (t < 1e-6f)
return false;
fout = t;
vout = _origin + t * _direction;
return true;
}
}

88
math/ray.h Normal file
View File

@@ -0,0 +1,88 @@
/* 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/>.
*
*/
#ifndef MATH_RAY_H
#define MATH_RAY_H
#include "math/aabb.h"
#include "math/matrix4.h"
#include "math/quat.h"
#include "math/vector3d.h"
namespace Math {
/**
* A three dimensional half-line
*/
class Ray {
public:
Ray();
Ray(const Vector3d &origin, const Vector3d &direction);
Vector3d& getOrigin() { return _origin; }
Vector3d getOrigin() const { return _origin; }
Vector3d& getDirection() { return _direction; }
Vector3d getDirection() const { return _direction; }
/**
* Apply a transformation to the ray
*/
void transform(const Matrix4 &matrix);
/**
* Rotate the ray using a quaternion - rotates both origin and direction
*/
void rotate(const Quaternion &rot);
/**
* Rotate the ray direction only using a quaternion - origin stays fixed
*/
void rotateDirection(const Quaternion &rot);
/**
* Translate the ray by a vector
*/
void translate(const Vector3d &v);
/**
* Test the intersection of the ray with an Axis Aligned Bounding Box
*/
bool intersectAABB(const AABB &aabb) const;
/**
* Test and return the intersection of the ray with a triangle defned by 3 verticies
*
* @param v0 first triangle vertex
* @param v1 second triangle vertex
* @param v2 third triangle vertex
* @param loc If return is true, set to the intersection point
* @param dist If return is true, set to distance along the ray (relative to direction)
*/
bool intersectTriangle(const Vector3d &v0, const Vector3d &v1, const Vector3d &v2, Vector3d &loc, float &dist) const;
private:
Vector3d _origin;
Vector3d _direction;
};
} // end of namespace Math
#endif

101
math/rdft.cpp Normal file
View File

@@ -0,0 +1,101 @@
/* 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/>.
*
*/
// Based on eos' (I)RDFT code which is in turn
// Based upon the (I)RDFT code in FFmpeg
// Copyright (c) 2009 Alex Converse <alex dot converse at gmail dot com>
#include "math/rdft.h"
#include "math/fft.h"
#include "math/utils.h"
namespace Math {
RDFT::RDFT(int bits, TransformType trans) : _bits(bits), _sin(1 << bits), _cos(1 << bits), _fft(nullptr) {
assert((_bits >= 4) && (_bits <= 16));
_inverse = trans == IDFT_C2R || trans == DFT_C2R;
_signConvention = trans == IDFT_R2C || trans == DFT_C2R ? 1 : -1;
_fft = new FFT(bits - 1, trans == IDFT_C2R || trans == IDFT_R2C);
int n = 1 << bits;
_tSin = _sin.getTable() + (trans == DFT_R2C || trans == DFT_C2R) * (n >> 2);
_tCos = _cos.getTable();
}
RDFT::~RDFT() {
delete _fft;
}
void RDFT::calc(float *data) {
const int n = 1 << _bits;
const float k1 = 0.5f;
const float k2 = 0.5f - _inverse;
if (!_inverse) {
_fft->permute((Complex *)data);
_fft->calc ((Complex *)data);
}
Complex ev, od;
/* i=0 is a special case because of packing, the DC term is real, so we
are going to throw the N/2 term (also real) in with it. */
ev.re = data[0];
data[0] = ev.re + data[1];
data[1] = ev.re - data[1];
int i;
for (i = 1; i < (n >> 2); i++) {
int i1 = 2 * i;
int i2 = n - i1;
/* Separate even and odd FFTs */
ev.re = k1 * (data[i1 ] + data[i2 ]);
od.im = -k2 * (data[i1 ] - data[i2 ]);
ev.im = k1 * (data[i1 + 1] - data[i2 + 1]);
od.re = k2 * (data[i1 + 1] + data[i2 + 1]);
/* Apply twiddle factors to the odd FFT and add to the even FFT */
data[i1 ] = ev.re + od.re * _tCos[i] - od.im * _tSin[i];
data[i1 + 1] = ev.im + od.im * _tCos[i] + od.re * _tSin[i];
data[i2 ] = ev.re - od.re * _tCos[i] + od.im * _tSin[i];
data[i2 + 1] = -ev.im + od.im * _tCos[i] + od.re * _tSin[i];
}
data[2 * i + 1] = _signConvention * data[2 * i + 1];
if (_inverse) {
data[0] *= k1;
data[1] *= k1;
_fft->permute((Complex *)data);
_fft->calc ((Complex *)data);
}
}
} // End of namespace Math

120
math/rdft.h Normal file
View File

@@ -0,0 +1,120 @@
/* 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/>.
*
*/
// Based on xoreos' (I)RDFT code which is in turn
// Based upon the (I)RDFT code in FFmpeg
// Copyright (c) 2009 Alex Converse <alex dot converse at gmail dot com>
#ifndef MATH_RDFT_H
#define MATH_RDFT_H
#include "math/cosinetables.h"
#include "math/sinetables.h"
namespace Math {
class FFT;
/**
* @defgroup math_rdft RDFT algorithm
* @ingroup math
*
* @brief API for the Real Discrete Fourier Transform (RDFT) algorithm.
*
* @{
*/
/**
* @brief (Inverse) Real Discrete Fourier Transform.
*
* @details Used in audio:
* - QDM2
*
* Used in engines:
* - scumm
*
*
* It has four modes:
*
* Below, n = 1 << bits
*
* (I)DFT_R2C:
* input:
* n real floats
* output:
* n/2 complex floats (stored as real part followed by imag part).
*
* The output represents the first half of the (I)DFT of the input.
* If F is the complex (I)DFT of the input, then
* output[0] = F[0] + i * F[n/2] and
* output[k] = F[k] for k = 1 .. n/2-1.
* Note that F[0] and F[k] are real since the input is real, and
* the remaining values of F can be reconstructed from symmetry if desired.
*
* (I)DFT_C2R:
* input:
* n/2 complex floats
* output:
* n real floats
*
* The input encodes a complex vector x of length n that has the
* required symmetry to have a real (I)DFT:
* x[0] = Re(input[0])
* x[k] = input[k] for k = 1 .. n/2-1
* x[n/2] = Im(input[0])
* x[k] = conj(input[n-k]) for k = n/2+1 .. n-1
* The output is then the real (I)DFT of x, divided by 2.
*
* TODO: Is this division by 2 intentional?
*/
class RDFT {
public:
enum TransformType {
DFT_R2C,
IDFT_C2R,
IDFT_R2C,
DFT_C2R
};
RDFT(int bits, TransformType trans);
~RDFT();
void calc(float *data);
private:
int _bits;
int _inverse;
int _signConvention;
SineTable _sin;
CosineTable _cos;
const float *_tSin;
const float *_tCos;
FFT *_fft;
};
/** @} */
} // End of namespace Math
#endif // MATH_RDFT_H

221
math/rect2d.cpp Normal file
View File

@@ -0,0 +1,221 @@
/* 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/>.
*
*/
#include "common/scummsys.h"
#include "common/textconsole.h"
#include "math/rect2d.h"
namespace Math {
Rect2d::Rect2d() {
}
Rect2d::Rect2d(const Vector2d &topLeft, const Vector2d &bottomRight) {
float left = (topLeft.getX() <= bottomRight.getX() ? topLeft.getX() : bottomRight.getX());
float right = (topLeft.getX() <= bottomRight.getX() ? bottomRight.getX() : topLeft.getX());
float top = (topLeft.getY() <= bottomRight.getY() ? topLeft.getY() : bottomRight.getY());
float bottom = (topLeft.getY() <= bottomRight.getY() ? bottomRight.getY() : topLeft.getY());
_topLeft = Vector2d(left, top);
_topRight = Vector2d(right, top);
_bottomLeft = Vector2d(left, bottom);
_bottomRight = Vector2d(right, bottom);
}
Rect2d::Rect2d(const Vector2d &topLeft, const Vector2d &topRight,
const Vector2d &bottomLeft, const Vector2d &bottomRight) :
_topLeft(topLeft), _topRight(topRight),
_bottomLeft(bottomLeft), _bottomRight(bottomRight) {
}
void Rect2d::rotateAround(const Vector2d &point, const Angle &angle) {
_topLeft.rotateAround(point, angle);
_topRight.rotateAround(point, angle);
_bottomLeft.rotateAround(point, angle);
_bottomRight.rotateAround(point, angle);
}
void Rect2d::rotateAroundCenter(const Angle &angle) {
Vector2d center = getCenter();
rotateAround(center, angle);
}
void Rect2d::moveCenterTo(const Vector2d &pos) {
Vector2d vec(pos - getCenter());
translate(vec);
}
void Rect2d::scale(float amount) {
Vector2d c = getCenter();
moveCenterTo(Vector2d(0, 0));
_topLeft *= amount;
_topRight *= amount;
_bottomLeft *= amount;
_bottomRight *= amount;
moveCenterTo(c);
}
void Rect2d::translate(const Vector2d &vec) {
_topLeft += vec;
_topRight += vec;
_bottomLeft += vec;
_bottomRight += vec;
}
bool Rect2d::intersectsRect(const Rect2d &rect) const {
// TODO: implement this;
error("Rect2d::intersectsRect not implemented");
return false;
}
bool Rect2d::intersectsCircle(const Vector2d &center, float radius) const {
Vector2d c = getCenter();
float w = getWidth();
float h = getHeight();
Math::Angle angle = (_topRight - _topLeft).getAngle();
if (angle == 0) {
Vector2d circleDistance(fabs(center.getX() - c.getX()), fabs(center.getY() - c.getY()));
if (circleDistance.getX() > (w / 2.f + radius)) {
return false;
}
if (circleDistance.getY() > (h / 2.f + radius)) {
return false;
}
if (circleDistance.getX() <= (w / 2.f)) {
return true;
}
if (circleDistance.getY() <= (h / 2.f)) {
return true;
}
float cornerDistance_sq = pow(circleDistance.getX() - w / 2.f, 2.f) +
pow(circleDistance.getY() - h / 2.f, 2.f);
return (cornerDistance_sq <= radius * radius);
} else { //The rectangle was rotated
Rect2d r(_topLeft, _topRight, _bottomLeft, _bottomRight);
r.rotateAroundCenter(-angle);
Vector2d circle(center);
circle.rotateAround(r.getCenter(), -angle);
return r.intersectsCircle(circle, radius);
}
}
inline bool le(float a, float b) {
return (a < b || (fabsf(a - b) < 0.0001f));
}
inline bool ge(float a, float b) {
return (a > b || (fabsf(a - b) < 0.0001f));
}
bool Rect2d::containsPoint(const Vector2d &point) const {
return ge(point.getX(), _topLeft.getX()) && le(point.getX(), _bottomRight.getX()) &&
ge(point.getY(), _topLeft.getY()) && le(point.getY(), _bottomRight.getY());
}
Vector2d Rect2d::getCenter() const {
Vector2d sum = _topLeft + _topRight + _bottomLeft + _bottomRight;
sum /= 4;
return sum;
}
Vector2d Rect2d::getTopLeft() const {
return _topLeft;
}
Vector2d Rect2d::getTopRight() const {
return _topRight;
}
Vector2d Rect2d::getBottomLeft() const {
return _bottomLeft;
}
Vector2d Rect2d::getBottomRight() const {
return _bottomRight;
}
float Rect2d::getWidth() const {
float x = _topRight.getX() - _topLeft.getX();
float y = _topRight.getY() - _topLeft.getY();
return sqrt(x * x + y * y);
}
float Rect2d::getHeight() const {
float x = _bottomLeft.getX() - _topLeft.getX();
float y = _bottomLeft.getY() - _topLeft.getY();
return sqrt(x * x + y * y);
}
Vector2d Rect2d::getIntersection(const Vector2d &start, const Vector2d &dir, Segment2d *edge) const {
float w = getWidth();
float h = getHeight();
float d = sqrt(w * w + h * h);
Segment2d line(start, start + dir.getNormalized() * 2*d);
Vector2d intersection;
Segment2d l(_topLeft, _topRight);
if (line.intersectsSegment(l, &intersection)) {
if (edge) {
*edge = l;
}
return intersection;
}
l = Segment2d(_topRight, _bottomRight);
if (line.intersectsSegment(l, &intersection)) {
if (edge) {
*edge = l;
}
return intersection;
}
l = Segment2d(_bottomRight, _bottomLeft);
if (line.intersectsSegment(l, &intersection)) {
if (edge) {
*edge = l;
}
return intersection;
}
l = Segment2d(_bottomLeft, _topLeft);
if (line.intersectsSegment(l, &intersection)) {
if (edge) {
*edge = l;
}
return intersection;
}
return intersection;
}
}

66
math/rect2d.h Normal file
View File

@@ -0,0 +1,66 @@
/* 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/>.
*
*/
#ifndef MATH_RECT2D_H
#define MATH_RECT2D_H
#include "math/vector2d.h"
#include "math/line2d.h"
namespace Math {
class Segment2d;
class Rect2d {
public:
Rect2d();
Rect2d(const Vector2d &topLeft, const Vector2d &bottomRight);
Rect2d(const Vector2d &topLeft, const Vector2d &topRight,
const Vector2d &bottomLeft, const Vector2d &bottomRight);
void rotateAround(const Vector2d &point, const Angle &angle);
void rotateAroundCenter(const Angle &angle);
void moveCenterTo(const Vector2d &pos);
void scale(float amount);
void translate(const Vector2d &vec);
bool intersectsRect(const Rect2d &rect) const;
bool intersectsCircle(const Vector2d &center, float radius) const;
bool containsPoint(const Vector2d &point) const;
Vector2d getCenter() const;
Vector2d getTopLeft() const;
Vector2d getTopRight() const;
Vector2d getBottomLeft() const;
Vector2d getBottomRight() const;
float getWidth() const;
float getHeight() const;
Vector2d getIntersection(const Vector2d &start, const Vector2d &direction, Segment2d *edge) const;
// private:
Vector2d _topLeft;
Vector2d _topRight;
Vector2d _bottomLeft;
Vector2d _bottomRight;
};
}
#endif

447
math/rotation3d.h Normal file
View File

@@ -0,0 +1,447 @@
/* 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/>.
*
*/
#ifndef MATH_ROTATION3D_H
#define MATH_ROTATION3D_H
#include "common/streamdebug.h"
#include "math/utils.h"
#include "math/transform.h"
#include "math/angle.h"
#include "common/textconsole.h"
namespace Math {
/**
* Euler angle sequence constants
*/
enum EulerOrder {
EO_XYX,
EO_XYZ,
EO_XZX,
EO_XZY,
EO_YXY,
EO_YXZ,
EO_YZX,
EO_YZY,
EO_ZXY, // Original ScummVM implmentation
EO_ZXZ,
EO_ZYX,
EO_ZYZ
};
template<class T>
class Rotation3D : public Transform<T> {
public:
constexpr Rotation3D();
/**
* Constructor and assignment from buildFromEuler
* @param first Rotation on the first Axis, angle in degrees
* @param second Rotation on the second Axis, angle in degrees
* @param third Rotation on the third Axis, angle in degrees
* @param order The Euler Order (specifies axis order)
*/
Rotation3D(const Angle &first, const Angle &second, const Angle &third, EulerOrder order);
/**
* Build a rotation matrix from Euler Angles
* @param first Rotation on the first Axis, angle in degrees
* @param second Rotation on the second Axis, angle in degrees
* @param third Rotation on the third Axis, angle in degrees
* @param order The Euler Order (specifies axis order)
*/
void buildFromEuler(const Angle &first, const Angle &second, const Angle &third, EulerOrder order);
/**
* Build a rotation matrix on the X Axis from an angle
* @param rotX Rotation on the X Axis angle in degrees
*/
void buildAroundX(const Angle &rotX);
/**
* Build a rotation matrix on the Y Axis from an angle
* @param rotY Rotation on the Y Axis angle in degrees
*/
void buildAroundY(const Angle &rotY);
/**
* Build a rotation matrix on the Z Axis from an angle
* @param rotZ Rotation on the Z Axis angle in degrees
*/
void buildAroundZ(const Angle &rotZ);
/**
* Get Euler Angles from a rotation matrix
* @param first Pointer to the storage for the first axis angle
* @param second Pointer to the storage for the second axis angle
* @param third Pointer to the storage for the third axis angle
* @param order The Euler order (specifies axis order)
*/
void getEuler(Angle *first, Angle *second, Angle *third, EulerOrder order) const;
};
template<class T>
constexpr Rotation3D<T>::Rotation3D() : Transform<T>() {}
template<class T>
void Rotation3D<T>::buildFromEuler(const Angle &first, const Angle &second, const Angle &third, EulerOrder order) {
// Build a matrix around each rotation angle
T m2, m3;
// Combine them in the order requested
switch (order) {
case EO_XYX:
this->buildAroundX(first);
m2.buildAroundY(second);
m3.buildAroundX(third);
break;
case EO_XYZ:
this->buildAroundX(first);
m2.buildAroundY(second);
m3.buildAroundZ(third);
break;
case EO_XZX:
this->buildAroundX(first);
m2.buildAroundZ(second);
m3.buildAroundX(third);
break;
case EO_XZY:
this->buildAroundX(first);
m2.buildAroundZ(second);
m3.buildAroundY(third);
break;
case EO_YXY:
this->buildAroundY(first);
m2.buildAroundX(second);
m3.buildAroundY(third);
break;
case EO_YXZ:
this->buildAroundY(first);
m2.buildAroundX(second);
m3.buildAroundZ(third);
break;
case EO_YZX:
this->buildAroundY(first);
m2.buildAroundZ(second);
m3.buildAroundX(third);
break;
case EO_YZY:
this->buildAroundY(first);
m2.buildAroundZ(second);
m3.buildAroundY(third);
break;
// Original ScummVM Implementation
case EO_ZXY:
this->buildAroundZ(first);
m2.buildAroundX(second);
m3.buildAroundY(third);
break;
case EO_ZXZ:
this->buildAroundZ(first);
m2.buildAroundX(second);
m3.buildAroundZ(third);
break;
case EO_ZYX:
this->buildAroundZ(first);
m2.buildAroundY(second);
m3.buildAroundX(third);
break;
case EO_ZYZ:
this->buildAroundZ(first);
m2.buildAroundY(second);
m3.buildAroundZ(third);
break;
default:
error("Invalid Euler Order");
break;
}
// Combine the rotations
this->getMatrix() = this->getMatrix() * m2 * m3;
}
// at. Rotates about the +X axis.
// Left Handed (DirectX) Coordinates
template<class T>
void Rotation3D<T>::buildAroundX(const Angle &rotX) {
float cosa = rotX.getCosine();
float sina = rotX.getSine();
this->getMatrix().getRow(0) << 1.f << 0.f << 0.f;
this->getMatrix().getRow(1) << 0.f << cosa << -sina;
this->getMatrix().getRow(2) << 0.f << sina << cosa;
}
// right. Rotates about the +Y axis.
// Left Handed (DirectX) Coordinates
template<class T>
void Rotation3D<T>::buildAroundY(const Angle &rotY) {
float cosa = rotY.getCosine();
float sina = rotY.getSine();
this->getMatrix().getRow(0) << cosa << 0.f << sina;
this->getMatrix().getRow(1) << 0.f << 1.f << 0.f;
this->getMatrix().getRow(2) << -sina << 0.f << cosa;
}
// up. Rotates about the +Z axis.
// Left Handed (DirectX) Coordinates
template<class T>
void Rotation3D<T>::buildAroundZ(const Angle &rotZ) {
float cosa = rotZ.getCosine();
float sina = rotZ.getSine();
this->getMatrix().getRow(0) << cosa << -sina << 0.f;
this->getMatrix().getRow(1) << sina << cosa << 0.f;
this->getMatrix().getRow(2) << 0.f << 0.f << 1.f;
}
template<class T>
void Rotation3D<T>::getEuler(Angle *first, Angle *second, Angle *third, EulerOrder order) const {
// Cast as the matrix type so we can use getValue
const T *m = &(this->getMatrix());
float f, s, t;
switch (order) {
case EO_XYX:
if (m->getValue(0, 0) < 1.0f) {
if (m->getValue(0, 0) > -1.0f) {
f = atan2(m->getValue(1, 0), -(m->getValue(2, 0)));
s = acos(m->getValue(0, 0));
t = atan2(m->getValue(0, 1), m->getValue(0, 2));
} else {
f = -atan2(-m->getValue(1, 2), m->getValue(1, 1));
s = (float) M_PI;
t = 0.0f;
}
} else {
f = atan2(-m->getValue(1, 2), m->getValue(1, 1));
s = 0.0f;
t = 0.0f;
}
break;
case EO_XYZ:
if (m->getValue(0, 2) < 1.0f) {
if (m->getValue(0, 2) > -1.0f) {
f = atan2(-(m->getValue(1, 2)), m->getValue(2, 2));
s = asin(m->getValue(0, 2));
t = atan2(-(m->getValue(0, 1)), m->getValue(0, 0));
} else {
f = -atan2(m->getValue(1, 0), m->getValue(1, 1));
s = -(float) M_PI / 2.0f;
t = 0.0f;
}
} else {
f = atan2(m->getValue(1, 0), m->getValue(1, 1));
s = (float) M_PI / 2.0f;
t = 0.0f;
}
break;
case EO_XZX:
if (m->getValue(0, 0) < 1.0f) {
if (m->getValue(0, 0) > -1.0f) {
f = atan2(m->getValue(2, 0), m->getValue(1, 0));
s = acos(m->getValue(0, 0));
t = atan2(m->getValue(0, 2), -(m->getValue(0, 1)));
} else {
f = -atan2(m->getValue(2, 1), m->getValue(2, 2));
s = (float) M_PI;
t = 0.0f;
}
} else {
f = atan2(m->getValue(2, 1), m->getValue(2, 2));
s = 0.0f;
t = 0.0f;
}
break;
case EO_XZY:
if (m->getValue(0, 1) < 1.0f) {
if (m->getValue(0, 1) > -1.0f) {
f = atan2(m->getValue(2, 1), m->getValue(1, 1));
s = asin(-(m->getValue(0, 1)));
t = atan2(m->getValue(0, 2), m->getValue(0, 0));
} else {
f = -atan2(-(m->getValue(2, 0)), m->getValue(2, 2));
s = (float) M_PI / 2.0f;
t = 0.0f;
}
} else {
f = atan2(-(m->getValue(2, 0)), m->getValue(2, 2));
s = -(float) M_PI / 2.0f;
t = 0.0f;
}
break;
case EO_YXY:
if (m->getValue(1, 1) < 1.0f) {
if (m->getValue(1, 1) > -1.0f) {
f = atan2(m->getValue(0, 1), m->getValue(2, 1));
s = acos(m->getValue(1, 1));
t = atan2(m->getValue(1, 0), -(m->getValue(1, 2)));
} else {
f = -atan2(m->getValue(0, 2), m->getValue(0, 0));
s = (float) M_PI;
t = 0.0f;
}
} else {
f = atan2(m->getValue(0, 2), m->getValue(0, 0));
s = 0.0f;
t = 0.0f;
}
break;
case EO_YXZ:
if (m->getValue(1, 2) < 1.0f) {
if (m->getValue(1, 2) > -1.0f) {
f = atan2(m->getValue(0, 2), m->getValue(2, 2));
s = asin(-(m->getValue(1, 2)));
t = atan2(m->getValue(1, 0), m->getValue(1, 1));
} else {
f = -atan2(-(m->getValue(0, 1)), m->getValue(0, 0));
s = (float) M_PI / 2.0f;
t = 0.0f;
}
} else {
f = atan2(-(m->getValue(0, 1)), m->getValue(0, 0));
s = -(float) M_PI / 2.0f;
t = 0.0f;
}
break;
case EO_YZX:
if (m->getValue(1, 0) < 1.0f) {
if (m->getValue(1, 0) > -1.0f) {
f = atan2(-(m->getValue(2, 0)), m->getValue(0, 0));
s = asin(m->getValue(1, 0));
t = atan2(-(m->getValue(1, 2)), m->getValue(1, 1));
} else {
f = -atan2(m->getValue(2, 1), m->getValue(2, 2));
s = -(float) M_PI / 2.0f;
t = 0.0f;
}
} else {
f = atan2(m->getValue(2, 1), m->getValue(2, 2));
s = (float) M_PI / 2.0f;
t = 0.0f;
}
break;
case EO_YZY:
if (m->getValue(1, 1) < 1.0f) {
if (m->getValue(1, 1) > -1.0f) {
f = atan2(m->getValue(2, 1), -(m->getValue(0, 1)));
s = acos(m->getValue(1, 1));
t = atan2(m->getValue(1, 2), m->getValue(1, 0));
} else {
f = -atan2(-(m->getValue(2, 0)), m->getValue(2, 2));
s = (float) M_PI;
t = 0.0f;
}
} else {
f = atan2(-(m->getValue(2, 0)), m->getValue(2, 2));
s = 0.0f;
t = 0.0f;
}
break;
case EO_ZXY: // Original ScummVM implmentation
if (m->getValue(2, 1) < 1.0f) {
if (m->getValue(2, 1) > -1.0f) {
f = -atan2(m->getValue(0, 1), m->getValue(1, 1));
s = asin(m->getValue(2, 1));
t = -atan2(m->getValue(2, 0), m->getValue(2, 2));
} else {
f = -atan2(-m->getValue(0, 2), m->getValue(0, 0));
s = -(float) M_PI / 2.0f;
t = 0.0f;
}
} else {
f = atan2(m->getValue(0, 2), m->getValue(0, 0));
s = (float) M_PI / 2.0f;
t = 0.0f;
}
break;
case EO_ZXZ:
if (m->getValue(2, 2) < 1.0f) {
if (m->getValue(2, 2) > -1.0f) {
f = atan2(m->getValue(0, 2), -(m->getValue(1, 2)));
s = acos(m->getValue(2, 2));
t = atan2(m->getValue(2, 0), m->getValue(2, 1));
} else {
f = -atan2(-(m->getValue(0, 1)), m->getValue(0, 0));
s = (float) M_PI;
t = 0.0f;
}
} else {
f = atan2(-(m->getValue(0, 1)), m->getValue(0, 0));
s = 0.0f;
t = 0.0f;
}
break;
case EO_ZYX:
if (m->getValue(2, 0) < 1.0f) {
if (m->getValue(2, 0) > -1.0f) {
f = atan2(m->getValue(1, 0), m->getValue(0, 0));
s = asin(-(m->getValue(2, 0)));
t = atan2(m->getValue(2, 1), m->getValue(2, 2));
} else {
f = -atan2(-m->getValue(1, 2), m->getValue(1, 1));
s = (float) M_PI / 2.0f;
t = 0.0f;
}
} else {
f = atan2(-m->getValue(1, 2), m->getValue(1, 1));
s = -(float) M_PI / 2.0f;
t = 0.0f;
}
break;
case EO_ZYZ:
if (m->getValue(2, 2) < 1.0f) {
if (m->getValue(2, 2) > -1.0f) {
f = atan2(m->getValue(1, 2), m->getValue(0, 2));
s = acos(m->getValue(2, 2));
t = atan2(m->getValue(2, 1), -(m->getValue(2, 0)));
} else {
f = -atan2(m->getValue(1, 0), m->getValue(1, 1));
s = (float) M_PI;
t = 0.0f;
}
} else {
f = atan2(m->getValue(1, 0), m->getValue(1, 1));
s = 0.0f;
t = 0.0f;
}
break;
default:
error("Invalid Euler Order");
break;
}
if (first) {
*first = Math::Angle::fromRadians(f);
}
if (second) {
*second = Math::Angle::fromRadians(s);
}
if (third) {
*third = Math::Angle::fromRadians(t);
}
}
}
#endif

80
math/sinetables.cpp Normal file
View File

@@ -0,0 +1,80 @@
/* 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/>.
*
*/
// Based on eos' sine tables
#include "math/sinetables.h"
namespace Math {
SineTable::SineTable(int nPoints) {
assert((nPoints >= 16) && (nPoints <= 65536)); // log2 space is in [4,16]
assert(nPoints % 4 == 0);
_nPoints = nPoints;
_radResolution = 2.0 * M_PI / _nPoints;
_refSize = _nPoints / 4;
_tableEOS = new float[_nPoints / 2];
_table = new float[_nPoints];
for (int i = 0; i < _nPoints; i++)
_table[i] = sin(i * _radResolution);
// Table contains sin(2*pi*i/_nPoints) for 0<=i<_nPoints/4,
// followed by _nPoints/2<=i<3_nPoints/4
for (int i = 0; i < _nPoints / 4; i++)
_tableEOS[i] = sin(i * _radResolution);
for (int i = 0; i < _nPoints / 4; i++)
_tableEOS[_nPoints / 4 + i] = -_tableEOS[i];
}
float SineTable::at(int index) const {
assert((index >= 0) && (index < _nPoints));
return _table[index];
}
float SineTable::atLegacy(int index) const {
assert((index >= 0) && (index < _nPoints));
if (index < _refSize)
// [0,pi/2)
return _tableEOS[index];
if (index == _refSize)
// pi/2
return 1.0f; // sin(pi/2) = 1.0
if ((index > _refSize) && (index < 2 * _refSize))
// (pi/2,pi)
return _tableEOS[2 * _refSize - index];
if ((index >= 2 * _refSize) && (index < 3 * _refSize))
// [pi,3/2pi)
return -_tableEOS[index - 2 * _refSize];
if ((index > 3 * _refSize) && (index < _nPoints))
// (3/2pi,2pi)
return -_tableEOS[_nPoints - index];
return -1.0f; // sin(3pi/2) = -1.0
}
SineTable::~SineTable() {
delete[] _tableEOS;
delete[] _table;
}
} // End of namespace Math

86
math/sinetables.h Normal file
View File

@@ -0,0 +1,86 @@
/* 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/>.
*
*/
#ifndef MATH_SINETABLES_H
#define MATH_SINETABLES_H
#include "common/scummsys.h"
namespace Math {
/**
* @defgroup math_sinetables Sine tables
* @ingroup math
*
* @brief API for managing sine tables.
*
* @{
*/
class SineTable {
public:
/**
* Construct a sine table given the number of points
*
* @param nPoints Number of distinct radian points, which must be in range [16,65536] and be divisible by 4
*/
SineTable(int nPoints);
~SineTable();
/**
* Get pointer to table
*
* This table contains nPoints/2 entries.
* Prefer to use at()
* The layout of this table is as follows:
* - Entries 0 up to (excluding) nPoints/4:
* sin(0) till (excluding) sin(1/2*pi)
* - Entries 2_nPoints/4 up to nPoints/2:
* sin(pi) till (excluding) sin(3/2*pi)
*/
const float *getTable() { return _tableEOS; }
/**
* Returns sin(2*pi * index / nPoints )
* Index must be in range [0, nPoints - 1]
* Faster than atLegacy
*/
float at(int index) const;
/**
* Returns sin(2*pi * index / nPoints )
* Index must be in range [0, nPoints - 1]
*/
float atLegacy(int index) const;
private:
float *_tableEOS;
float *_table;
double _radResolution; // Smallest radian increment
int _refSize; // _nPoints / 4
int _nPoints; // range of operator[]
};
/** @} */
} // End of namespace Math
#endif // MATH_SINETABLES_H

1082
math/sinewindows.cpp Normal file

File diff suppressed because it is too large Load Diff

35
math/sinewindows.h Normal file
View File

@@ -0,0 +1,35 @@
/* 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/>.
*
*/
// Based on xoreos' SineWindow code
#ifndef MATH_SINEWINDOWS_H
#define MATH_SINEWINDOWS_H
#include "common/scummsys.h"
namespace Math {
const float *getSineWindow(int bits);
} // End of namespace Math
#endif // MATH_SINEWINDOWS_H

64
math/squarematrix.h Normal file
View File

@@ -0,0 +1,64 @@
/* 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/>.
*
*/
#ifndef MATH_SQUAREMATRIX_H
#define MATH_SQUAREMATRIX_H
#include "math/matrix.h"
#include "math/vector.h"
namespace Math {
/**
* \class MatrixType<dim, dim>
* This specialization of MatrixType defines some new methods for square
* matrices.
*/
template<int dim>
class MatrixType<dim, dim> : public MatrixBase<dim, dim> {
public:
inline void setToIdentity() { *this = 1.f; }
inline void transformVector(Vector(dim) *vec) const {
*vec = this->getThis() * *vec;
}
Matrix<dim, dim> &operator=(float i);
protected:
MatrixType() : MatrixBase<dim, dim>() { setToIdentity(); }
MatrixType(float *data) : MatrixBase<dim, dim>(data) { }
MatrixType(const MatrixBase<dim, dim> &m) : MatrixBase<dim, dim>(m) { }
};
template<int dim>
Matrix<dim, dim> &MatrixType<dim, dim>::operator=(float i) {
for (int row = 0; row < dim; ++row) {
for (int col = 0; col < dim; ++col) {
this->setValue(row, col, (row == col ? i : 0.f));
}
}
return this->getThis();
}
}
#endif

40
math/transform.h Normal file
View File

@@ -0,0 +1,40 @@
/* 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/>.
*
*/
#ifndef MATH_TRANSFORM_H
#define MATH_TRANSFORM_H
namespace Math {
template<class T>
class Transform {
public:
constexpr Transform() {}
protected:
inline const T &getMatrix() const { return *static_cast<const T *>(this); }
inline T &getMatrix() { return *static_cast<T *>(this); }
};
}
#endif

118
math/utils.h Normal file
View File

@@ -0,0 +1,118 @@
/* 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/>.
*
*/
#ifndef MATH_UTILS_H
#define MATH_UTILS_H
#include "common/scummsys.h"
#ifndef FLT_MIN
#define FLT_MIN 1E-37f
#endif
#ifndef FLT_MAX
#define FLT_MAX 1E+37f
#endif
namespace Math {
/** A complex number. */
struct Complex {
float re, im;
};
/* Math::epsilon is a constant with a small value which is used for comparing
* floating point numbers.
*
* The value is based on the previous hard-coded numbers in
* Line2d.cpp. Smaller numbers could be used unless they are
* smaller than the float granularity.
*/
static const float epsilon = 0.0001f;
// Round a number towards zero
// Input and Output type can be different
template<class InputT, class OutputT>
inline OutputT trunc(InputT x) {
return (x > 0) ? floor(x) : ceil(x);
}
// Round a number towards zero
// Input and Output type are the same
template<class T>
inline T trunc(T x) {
return trunc<T,T>(x);
}
// Convert radians to degrees
// Input and Output type can be different
// Upconvert everything to floats
template<class InputT, class OutputT>
inline OutputT rad2deg(InputT rad) {
return (OutputT)( (float)rad * (float)57.2957795130823); // 180.0/M_PI = 57.2957795130823
}
// Handle the case differently when the input type is double
template<class OutputT>
inline OutputT rad2deg(double rad) {
return (OutputT)( rad * 57.2957795130823);
}
// Convert radians to degrees
// Input and Output type are the same
template<class T>
inline T rad2deg(T rad) {
return rad2deg<T,T>(rad);
}
// Convert degrees to radians
// Input and Output type can be different
// Upconvert everything to floats
template<class InputT, class OutputT>
inline OutputT deg2rad(InputT deg) {
return (OutputT)( (float)deg * (float)0.0174532925199433); // M_PI/180.0 = 0.0174532925199433
}
// Handle the case differently when the input type is double
template<>
inline double deg2rad<double, double>(double deg) {
return ( deg * 0.0174532925199433);
}
// Convert degrees to radians
// Input and Output type are the same
template<class T>
inline T deg2rad(T deg) {
return deg2rad<T,T>(deg);
}
template<class T>
inline T hypotenuse(T xv, T yv) {
return (T)sqrt((double)(xv * xv + yv * yv));
}
inline float square(float x) {
return x * x;
}
}
#endif

144
math/vector.h Normal file
View File

@@ -0,0 +1,144 @@
/* 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/>.
*
*/
#ifndef MATH_VECTOR_H
#define MATH_VECTOR_H
#include "common/stream.h"
#include "math/matrix.h"
#include "math/utils.h"
namespace Math {
/**
* \class MatrixType<dim, 1>
* This MatrixType specialization defines new methods for the vectors.
*/
template<int dim>
class MatrixType<dim, 1> : public MatrixBase<dim, 1> {
public:
void normalize();
Vector(dim) getNormalized() const;
float getMagnitude() const;
float getSquareMagnitude() const;
float getDistanceTo(const Vector(dim) &point) const;
float dotProduct(const Vector(dim) &v) const;
inline void setValue(int i, float val) { value(i) = val; }
inline float getValue(int i) const { return value(i); }
template<int d>
inline static float dotProduct(const Vector(d) &v1, const Vector(d) &v2) {
return v1.dotProduct(v2);
}
/**
* Reads <i>dim</i> floats from the passed stream, and uses them
* as value 0...dim in chronological order.
*/
void readFromStream(Common::ReadStream *stream);
#if defined(_MSC_VER) && _MSC_VER < 1910 // HACK: C2248 bug in MSVC 2015
public:
#else
protected:
#endif
MatrixType() : MatrixBase<dim, 1>() { }
MatrixType(const float *data) : MatrixBase<dim, 1>(data) { }
MatrixType(const MatrixBase<dim, 1> &m) : MatrixBase<dim, 1>(m) { }
inline float &value(int i) { return this->operator()(i, 0); }
inline float value(int i) const { return this->operator()(i, 0); }
};
template<int dim>
void MatrixType<dim, 1>::normalize() {
float mag = getMagnitude();
if (mag > 0.f) {
for (int i = 0; i < dim; ++i) {
this->operator()(i, 0) /= mag;
}
}
}
template<int dim>
Vector(dim) MatrixType<dim, 1>::getNormalized() const {
Vector(dim) v(*this);
v.normalize();
return v;
}
template<int dim>
float MatrixType<dim, 1>::getMagnitude() const {
return sqrt(getSquareMagnitude());
}
template<int dim>
float MatrixType<dim, 1>::getSquareMagnitude() const {
float mag = 0;
for (int i = 0; i < dim; ++i) {
mag += square(getValue(i));
}
return mag;
}
template<int dim>
float MatrixType<dim, 1>::getDistanceTo(const Vector(dim) &point) const {
float result = 0;
for (int i = 0; i < dim; ++i) {
result += square(getValue(i) - point.getValue(i));
}
return sqrt(result);
}
template<int dim>
float MatrixType<dim, 1>::dotProduct(const Vector(dim) &v) const {
float result = 0;
for (int i = 0; i < dim; ++i) {
result += value(i) * v.value(i);
}
return result;
}
template<int dim>
void MatrixType<dim, 1>::readFromStream(Common::ReadStream *stream) {
for (int i = 0; i < dim; ++i) {
setValue(i, stream->readFloatLE());
}
}
template<int dim>
Common::StreamDebug &operator<<(Common::StreamDebug &dbg, const Math::Matrix<dim, 1> &v) {
dbg.nospace() << "Vector<" << dim << ">(" << v.getValue(0);
for (int i = 1; i < dim; ++i) {
dbg << ", " << v.getValue(i);
}
dbg << ")";
return dbg.space();
}
}
#endif

67
math/vector2d.cpp Normal file
View File

@@ -0,0 +1,67 @@
/* 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/>.
*
*/
#include "math/vector2d.h"
#include "common/streamdebug.h"
namespace Math {
Vector2d::Matrix() :
MatrixType<2, 1>() {
}
Vector2d::Matrix(float x, float y) :
MatrixType<2, 1>() {
setValue(0, x);
setValue(1, y);
}
Vector2d::Matrix(const MatrixBase<2, 1> &vec) :
MatrixType<2, 1>(vec) {
}
Vector2d::Matrix(const float *data) :
MatrixType<2, 1>(data) {
}
void Vector2d::rotateAround(const Vector2d &point, const Angle &angle) {
*this -= point;
float cosa = angle.getCosine();
float sina = angle.getSine();
float x = value(0) * cosa - value(1) * sina;
value(1) = value(0) * sina + value(1) * cosa;
value(0) = x;
*this += point;
}
Angle Vector2d::getAngle() const {
return Angle::arcTangent2(getY(), getX());
}
Vector3d Vector2d::toVector3d() const {
Vector3d v(value(0), value(1), 0);
return v;
}
}

53
math/vector2d.h Normal file
View File

@@ -0,0 +1,53 @@
/* 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/>.
*
*/
#ifndef MATH_VECTOR2D_H
#define MATH_VECTOR2D_H
#include "math/vector.h"
#include "math/vector3d.h"
namespace Math {
typedef Matrix<2, 1> Vector2d;
template<>
class Matrix<2, 1> : public MatrixType<2, 1> {
public:
Matrix();
Matrix(float x, float y);
Matrix(const MatrixBase<2, 1> &vec);
Matrix(const float *data);
inline float getX() const { return getValue(0); }
inline float getY() const { return getValue(1); }
inline void setX(float x) { setValue(0, x); }
inline void setY(float y) { setValue(1, y); }
void rotateAround(const Vector(2) &point, const Angle &angle);
Angle getAngle() const;
Vector3d toVector3d() const;
};
}
#endif

57
math/vector3d.cpp Normal file
View File

@@ -0,0 +1,57 @@
/* 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/>.
*
*/
#include "common/streamdebug.h"
#include "math/vector3d.h"
namespace Math {
Vector3d::Matrix() :
MatrixType<3, 1>() {
}
Vector3d::Matrix(float lx, float ly, float lz) :
MatrixType<3, 1>() {
x() = lx;
y() = ly;
z() = lz;
}
Vector3d::Matrix(const MatrixBase<3, 1> &vec) :
MatrixType<3, 1>(vec) {
}
Vector3d::Matrix(const float *data) :
MatrixType<3, 1>(data) {
}
void Vector3d::set(float lx, float ly, float lz) {
x() = lx; y() = ly; z() = lz;
}
// Get the angle a vector is around the unit circle
// (ignores z-component)
Angle Vector3d::unitCircleAngle() const {
return Angle::arcTangent2(y(), x());
}
} // end of namespace Math

130
math/vector3d.h Normal file
View File

@@ -0,0 +1,130 @@
/* 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/>.
*
*/
#ifndef MATH_VECTOR3D_H
#define MATH_VECTOR3D_H
#include "common/scummsys.h"
#include "common/endian.h"
#include "math/angle.h"
#include "math/squarematrix.h"
#include "math/vector.h"
namespace Math {
typedef Matrix<3, 1> Vector3d;
template<>
class Matrix<3, 1> : public MatrixType<3, 1> {
public:
Matrix();
Matrix(float lx, float ly, float lz);
Matrix(const MatrixBase<3, 1> &m);
Matrix(const float *data);
float& x() { return value(0); }
float x() const { return value(0); }
float& y() { return value(1); }
float y() const { return value(1); }
float& z() { return value(2); }
float z() const { return value(2); }
/**
* Set the value of the vector using three floats
* @param lx X Value
* @param ly Y Value
* @param lz Z Value
*/
void set(float lx, float ly, float lz);
/**
* Get the angle of this vector around the unit circle
* This operation ignores the z-component
* @return The computed angle
*/
Angle unitCircleAngle() const;
/**
* Multiply vector XYZ with Matrix 3x3
*
* @return The result of multiplication
*/
inline Vector3d operator*(const MatrixType<3, 3> &m) const {
const float *d = m.getData();
return Vector3d(x() * d[0] + y() * d[3] + z() * d[6],
x() * d[1] + y() * d[4] + z() * d[7],
x() * d[2] + y() * d[5] + z() * d[8]);
}
/**
* Find the cross product between two vectors
* @param v1 The first vector
* @param v2 The second vector
* @return The resulting cross product
*/
inline static Vector3d crossProduct(const Vector3d& v1, const Vector3d& v2) {
return Vector3d(v1.y() * v2.z() - v1.z() * v2.y(),
v1.z() * v2.x() - v1.x() * v2.z(),
v1.x() * v2.y() - v1.y() * v2.x());
}
/**
* Find the angle between two vectors
* @param v1 The first vector
* @param v2 The second vector
* @return The computed angle
*/
inline static Angle angle(const Vector3d& v1, const Vector3d& v2) {
return Angle::arcCosine(MIN(MAX(dotProduct(v1, v2) / (v1.getMagnitude() * v2.getMagnitude()), -1.0f), 1.0f));
}
/**
* Calculate vector length
* @return The computed length
*/
inline static float length(const Vector3d& v) {
return sqrtf(v.x() * v.x() + v.y() * v.y() + v.z() * v.z());
}
/**
* Calculate vector length
* @return The computed length
*/
float length() const {
return sqrtf(x() * x() + y() * y() + z() * z());
}
/**
* Linearly interpolate between two vectors
* @param v1 The first vector
* @param v2 The second vector
* @param a The value to use to interpolate between v1 and v2
* @return The resulting calculation
*/
inline static Vector3d interpolate(const Vector3d& v1, const Vector3d& v2, const float a) {
return Vector3d(v1 * (1.0f - a) + v2 * a);
}
};
} // end of namespace Math
#endif

58
math/vector4d.cpp Normal file
View File

@@ -0,0 +1,58 @@
/* 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/>.
*
*/
#include "common/streamdebug.h"
#include "math/vector3d.h"
#include "math/vector4d.h"
namespace Math {
Vector4d::Matrix() :
MatrixType<4, 1>() {
}
Vector4d::Matrix(float lx, float ly, float lz, float lw) :
MatrixType<4, 1>() {
x() = lx;
y() = ly;
z() = lz;
w() = lw;
}
Vector4d::Matrix(const MatrixBase<4, 1> &vec) :
MatrixType<4, 1>(vec) {
}
Vector4d::Matrix(const float *data) :
MatrixType<4, 1>(data) {
}
void Vector4d::set(float lx, float ly, float lz, float lw) {
x() = lx; y() = ly; z() = lz; w() = lw;
}
Vector3d Vector4d::getXYZ() const {
Vector3d v(value(0), value(1), value(2));
return v;
}
} // end of namespace Math

59
math/vector4d.h Normal file
View File

@@ -0,0 +1,59 @@
/* 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/>.
*
*/
#ifndef MATH_VECTOR4D_H
#define MATH_VECTOR4D_H
#include "common/scummsys.h"
#include "common/endian.h"
#include "math/vector.h"
#include "math/vector3d.h"
#include "math/angle.h"
namespace Math {
typedef Matrix<4, 1> Vector4d;
template<>
class Matrix<4, 1> : public MatrixType<4, 1> {
public:
float& x() { return value(0); }
float x() const { return value(0); }
float& y() { return value(1); }
float y() const { return value(1); }
float& z() { return value(2); }
float z() const { return value(2); }
float& w() { return value(3); }
float w() const { return value(3); }
Matrix();
Matrix(float lx, float ly, float lz, float lw);
Matrix(const MatrixBase<4, 1> &m);
Matrix(const float *data);
void set(float lx, float ly, float lz, float lw);
Vector3d getXYZ() const;
};
} // end of namespace Math
#endif