mirror of
https://github.com/scummvm/scummvm.git
synced 2025-04-02 10:52:32 -04:00
575 lines
15 KiB
C++
575 lines
15 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
||
*
|
||
* ScummVM is the legal property of its developers, whose names
|
||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||
* file distributed with this source distribution.
|
||
*
|
||
* This program is free software: you can redistribute it and/or modify
|
||
* it under the terms of the GNU General Public License as published by
|
||
* the Free Software Foundation, either version 3 of the License, or
|
||
* (at your option) any later version.
|
||
*
|
||
* This program is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU General Public License
|
||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
*
|
||
*/
|
||
|
||
// Note: Must Define D3D_OVERLOADS to get C++ version of MATRIX3D
|
||
#include "qdengine/qdcore/qd_d3dutils.h"
|
||
|
||
//набор своих функций, потому что те, что представлены в xMath.h
|
||
//не удовлетворяют потребностям
|
||
//я порой такой требовательный, что самому страшно.
|
||
namespace QDEngine {
|
||
|
||
namespace vector_helpers {
|
||
inline VALUE3D
|
||
SquareMagnitude(const Vect3f &v) {
|
||
return v.x * v.x + v.y * v.y + v.z * v.z;
|
||
}
|
||
|
||
inline VALUE3D
|
||
Magnitude(const Vect3f &v) {
|
||
return (VALUE3D) sqrt(SquareMagnitude(v));
|
||
}
|
||
|
||
|
||
inline Vect3f
|
||
Normalize(const Vect3f &v) {
|
||
return v / Magnitude(v);
|
||
}
|
||
|
||
inline VALUE3D DotProduct(const Vect3f &v1, const Vect3f &v2) {
|
||
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
|
||
}
|
||
|
||
inline Vect3f
|
||
CrossProduct(const Vect3f &v1, const Vect3f &v2) {
|
||
Vect3f result;
|
||
|
||
result[0] = v1[1] * v2[2] - v1[2] * v2[1];
|
||
result[1] = v1[2] * v2[0] - v1[0] * v2[2];
|
||
result[2] = v1[0] * v2[1] - v1[1] * v2[0];
|
||
|
||
return result;
|
||
}
|
||
|
||
//угол между векторами лежащими в плоскости ХОУ
|
||
//иначе ее применять НЕЛЬЗЯ
|
||
float VectorAngle(const Vect3f &v1, const Vect3f &v2) {
|
||
return float(atan2(v2.y, v2.x) - atan2(v1.y, v1.x));
|
||
}
|
||
|
||
}//vector_helpers
|
||
|
||
/*
|
||
**-----------------------------------------------------------------------------
|
||
** Name: ZeroMatrix
|
||
** Purpose: sets D3D matrix to all 0's
|
||
**-----------------------------------------------------------------------------
|
||
*/
|
||
|
||
MATRIX3D
|
||
ZeroMatrix() {
|
||
MATRIX3D ret;
|
||
for (int i = 0; i < 4; i++) {
|
||
for (int j = 0; j < 4; j++) {
|
||
ret(i, j) = 0.0f;
|
||
}
|
||
}
|
||
return ret;
|
||
} // end ZeroMatrix
|
||
|
||
/*
|
||
**-----------------------------------------------------------------------------
|
||
** Name: IdentityMatrix
|
||
** Purpose: sets D3D matrix to Identiy (1's on diagonal, zero's elsewhere)
|
||
**-----------------------------------------------------------------------------
|
||
*/
|
||
|
||
MATRIX3D
|
||
IdentityMatrix() {
|
||
MATRIX3D ret;
|
||
for (int i = 0; i < 4; i++) {
|
||
for (int j = 0; j < 4; j++) {
|
||
ret(i, j) = 0.0f;
|
||
}
|
||
ret(i, i) = 1.0f;
|
||
}
|
||
return ret;
|
||
} // end IdentityMatrix
|
||
|
||
/*
|
||
**-----------------------------------------------------------------------------
|
||
** Name: ProjectionMatrix
|
||
** Purpose: sets Projection matrix from fov, near and far planes
|
||
** Notes:
|
||
** 1. fov is in radians.
|
||
** 2. See Blinn, "A Trip Down the Graphics Pipeline" pg 188 for details.
|
||
**-----------------------------------------------------------------------------
|
||
*/
|
||
|
||
MATRIX3D
|
||
ProjectionMatrix(const float near_plane,
|
||
const float far_plane,
|
||
const float fov) {
|
||
float c = (float) cos(fov * 0.5);
|
||
float s = (float) sin(fov * 0.5);
|
||
float Q = s / (1.0f - near_plane / far_plane);
|
||
|
||
MATRIX3D ret = ZeroMatrix();
|
||
ret(0, 0) = c;
|
||
ret(1, 1) = c;
|
||
ret(2, 2) = Q;
|
||
ret(3, 2) = -Q * near_plane;
|
||
ret(2, 3) = s;
|
||
return ret;
|
||
} // end ProjectionMatrix
|
||
|
||
|
||
/*
|
||
**-----------------------------------------------------------------------------
|
||
** Name: ViewMatrix
|
||
** Purpose: Controls where the camara is.
|
||
** Notes:
|
||
** 1. Note the roll parameter is in radians and rools the viewpoint
|
||
** around the viewing direction
|
||
**-----------------------------------------------------------------------------
|
||
*/
|
||
|
||
MATRIX3D ViewMatrixByDir(const Vect3f &from,
|
||
const Vect3f &view_dir,
|
||
const Vect3f &world_up,
|
||
const Vect3f &cam_up) {
|
||
MATRIX3D view = IdentityMatrix();
|
||
//view_dir - Это ось Z в системе координат камеры
|
||
Vect3f zAxis = view_dir;
|
||
|
||
//ось Х в правой системе координат
|
||
Vect3f xAxis = vector_helpers::CrossProduct(zAxis, world_up);
|
||
xAxis = vector_helpers::Normalize(xAxis);
|
||
|
||
Vect3f yAxis = vector_helpers::CrossProduct(zAxis, xAxis);
|
||
|
||
view(0, 0) = xAxis.x;
|
||
view(1, 0) = xAxis.y;
|
||
view(2, 0) = xAxis.z;
|
||
|
||
view(0, 1) = yAxis.x;
|
||
view(1, 1) = yAxis.y;
|
||
view(2, 1) = yAxis.z;
|
||
|
||
view(0, 2) = zAxis.x;
|
||
view(1, 2) = zAxis.y;
|
||
view(2, 2) = zAxis.z;
|
||
|
||
view(3, 0) = -vector_helpers::DotProduct(xAxis, from);
|
||
view(3, 1) = -vector_helpers::DotProduct(cam_up, from);
|
||
view(3, 2) = -vector_helpers::DotProduct(zAxis, from);
|
||
/*
|
||
* после всех вычислений верх камеры имеет с верхом мира угол небольше 90 градусов,
|
||
* что по сути своей не всегда правильно. Для того, чтобы вычислить правильно поворот
|
||
* вокруг оси Z используем up и cam_up. Где cam_up - это верх камеры, который должен
|
||
* быть у неё после поворота.
|
||
* Перед тем как вычислить угол переводим оба вектора в координаты камеры, тогда они
|
||
* будут лежать в плоскости ХОУ. вычисляем угол и поворачиваем.
|
||
*/
|
||
|
||
|
||
//переводим в координаты камеры, чтобы получить
|
||
//плоскую картинку и пользоваться atan2
|
||
float r = vector_helpers::VectorAngle(TransformVector(cam_up, view),
|
||
TransformVector(yAxis, view));
|
||
|
||
view = MatrixMult(RotateZMatrix(-r), view);
|
||
|
||
return view;
|
||
}
|
||
|
||
MATRIX3D
|
||
ViewMatrix(const Vect3f &from,
|
||
const Vect3f &at,
|
||
const Vect3f &world_up,
|
||
const Vect3f &cam_up) {
|
||
|
||
Vect3f view_dir = vector_helpers::Normalize(at - from);
|
||
return ViewMatrixByDir(from, view_dir, world_up, cam_up);
|
||
} // end ViewMatrix
|
||
|
||
/*
|
||
**-----------------------------------------------------------------------------
|
||
** Name: RotateXMatrix
|
||
** Purpose: Rotate matrix about X axis
|
||
**-----------------------------------------------------------------------------
|
||
*/
|
||
|
||
MATRIX3D
|
||
RotateXMatrix(const float rads) {
|
||
float cosine = (float) cos(rads);
|
||
float sine = (float) sin(rads);
|
||
MATRIX3D ret = IdentityMatrix();
|
||
ret(1, 1) = cosine;
|
||
ret(2, 2) = -cosine;
|
||
ret(1, 2) = sine;
|
||
ret(2, 1) = sine;
|
||
return ret;
|
||
} // end RotateXMatrix
|
||
|
||
/*
|
||
**-----------------------------------------------------------------------------
|
||
** Name: RotateYMatrix
|
||
** Purpose: Rotate matrix about Y axis
|
||
**-----------------------------------------------------------------------------
|
||
*/
|
||
|
||
MATRIX3D
|
||
RotateYMatrix(const float rads) {
|
||
float const cosine = (float) cos(rads);
|
||
float const sine = (float) sin(rads);
|
||
|
||
MATRIX3D ret = IdentityMatrix();
|
||
ret(0, 0) = cosine;
|
||
ret(2, 2) = -cosine;
|
||
|
||
ret(0, 2) = sine;
|
||
ret(2, 0) = sine;
|
||
|
||
return ret;
|
||
} // end RotateY
|
||
|
||
/*
|
||
**-----------------------------------------------------------------------------
|
||
** Name: RotateZMatrix
|
||
** Purpose: Rotate matrix about Z axis
|
||
**-----------------------------------------------------------------------------
|
||
*/
|
||
|
||
MATRIX3D
|
||
RotateZMatrix(const float rads) {
|
||
float const cosine = (float) cos(rads);
|
||
float const sine = (float) sin(rads);
|
||
MATRIX3D ret = IdentityMatrix();
|
||
ret(0, 0) = cosine;
|
||
ret(1, 1) = -cosine;
|
||
|
||
ret(0, 1) = sine;
|
||
ret(1, 0) = sine;
|
||
return ret;
|
||
} // end RotateZMatrix
|
||
|
||
/*
|
||
**-----------------------------------------------------------------------------
|
||
** Name: TranslateMatrix
|
||
** Purpose: Returns matrix to translate by (dx, dy, dz)
|
||
**-----------------------------------------------------------------------------
|
||
*/
|
||
|
||
MATRIX3D
|
||
TranslateMatrix(const float dx, const float dy, const float dz) {
|
||
MATRIX3D ret = IdentityMatrix();
|
||
ret(3, 0) = dx;
|
||
ret(3, 1) = dy;
|
||
ret(3, 2) = dz;
|
||
return ret;
|
||
} // end TranslateMatrix
|
||
|
||
/*
|
||
**-----------------------------------------------------------------------------
|
||
** Name: TranslateMatrix
|
||
** Purpose: Returns matrix to translate by v
|
||
**-----------------------------------------------------------------------------
|
||
*/
|
||
|
||
MATRIX3D
|
||
TranslateMatrix(const Vect3f &v) {
|
||
MATRIX3D ret = IdentityMatrix();
|
||
ret(3, 0) = v[0];
|
||
ret(3, 1) = v[1];
|
||
ret(3, 2) = v[2];
|
||
return ret;
|
||
} // end TranslateMatrix
|
||
|
||
/*
|
||
**-----------------------------------------------------------------------------
|
||
** Name: ScaleMatrix
|
||
** Purpose: scale matrix (uniform)
|
||
**-----------------------------------------------------------------------------
|
||
*/
|
||
|
||
MATRIX3D
|
||
ScaleMatrix(const float size) {
|
||
MATRIX3D ret = IdentityMatrix();
|
||
ret(0, 0) = size;
|
||
ret(1, 1) = size;
|
||
ret(2, 2) = size;
|
||
return ret;
|
||
} // end ScaleMatrix
|
||
|
||
/*
|
||
**-----------------------------------------------------------------------------
|
||
** Name: ScaleMatrix
|
||
** Purpose: scale matrix
|
||
**-----------------------------------------------------------------------------
|
||
*/
|
||
|
||
MATRIX3D
|
||
ScaleMatrix(const float a, const float b, const float c) {
|
||
MATRIX3D ret = IdentityMatrix();
|
||
ret(0, 0) = a;
|
||
ret(1, 1) = b;
|
||
ret(2, 2) = c;
|
||
return ret;
|
||
} // end ScaleMatrix
|
||
|
||
/*
|
||
**-----------------------------------------------------------------------------
|
||
** Name: ScaleMatrix
|
||
** Purpose: scale matrix
|
||
**-----------------------------------------------------------------------------
|
||
*/
|
||
|
||
MATRIX3D
|
||
ScaleMatrix(const Vect3f &v) {
|
||
MATRIX3D ret = IdentityMatrix();
|
||
ret(0, 0) = v.x;
|
||
ret(1, 1) = v.y;
|
||
ret(2, 2) = v.z;
|
||
return ret;
|
||
} // end ScaleMatrix
|
||
|
||
/*
|
||
**-----------------------------------------------------------------------------
|
||
** Name: MatrixMult
|
||
** Purpose: [C] = [A] * [B]
|
||
**-----------------------------------------------------------------------------
|
||
*/
|
||
|
||
MATRIX3D
|
||
MatrixMult(const MATRIX3D &a, const MATRIX3D &b) {
|
||
MATRIX3D ret = ZeroMatrix();
|
||
|
||
for (int i = 0; i < 4; i++) {
|
||
for (int j = 0; j < 4; j++) {
|
||
for (int k = 0; k < 4; k++) {
|
||
ret(i, j) += a(k, j) * b(i, k);
|
||
}
|
||
}
|
||
}
|
||
return ret;
|
||
} // end MatrixMult
|
||
|
||
/*
|
||
**-----------------------------------------------------------------------------
|
||
** Name: TransformVector
|
||
** Purpose: V' = V * [M]
|
||
**-----------------------------------------------------------------------------
|
||
*/
|
||
|
||
Vect3f
|
||
TransformVector(const Vect3f &v, const MATRIX3D &m) {
|
||
float hvec[4] = {0.f};
|
||
for (int i = 0; i < 4; i++) {
|
||
hvec[i] = 0.0f;
|
||
// for (int j=0; j<3; j++) {
|
||
// hvec[i] += v[j] * m(j, i);
|
||
// }
|
||
// hvec[i] += m(3, i);
|
||
hvec[i] = v[0] * m(0, i)
|
||
+ v[1] * m(1, i)
|
||
+ v[2] * m(2, i)
|
||
+ m(3, i);
|
||
}
|
||
return Vect3f(hvec[0] / hvec[3], hvec[1] / hvec[3], hvec[2] / hvec[3]);
|
||
} // end TransformVector
|
||
|
||
/*
|
||
**-----------------------------------------------------------------------------
|
||
** Name: TransformNormal
|
||
** Purpose: N' = N * [M]
|
||
**-----------------------------------------------------------------------------
|
||
*/
|
||
|
||
Vect3f
|
||
TransformNormal(const Vect3f &v, const MATRIX3D &mat) {
|
||
MATRIX3D m;
|
||
|
||
m = MatrixInverse(mat);
|
||
m = MatrixTranspose(m);
|
||
return TransformVector(v, m);
|
||
} // end TransformNormal
|
||
|
||
/*
|
||
**-----------------------------------------------------------------------------
|
||
** Name: MatrixInverse
|
||
** Purpose: Creates the inverse of a 4x4 matrix
|
||
**-----------------------------------------------------------------------------
|
||
*/
|
||
|
||
static void lubksb(MATRIX3D &a, int *indx, float *b);
|
||
static void ludcmp(MATRIX3D &a, int *indx, float *d);
|
||
|
||
MATRIX3D
|
||
MatrixInverse(const MATRIX3D &m) {
|
||
MATRIX3D n, y;
|
||
int i, j, indx[4];
|
||
float d, col[4];
|
||
|
||
n = m;
|
||
ludcmp(n, indx, &d);
|
||
|
||
for (j = 0; j < 4; j++) {
|
||
for (i = 0; i < 4; i++) {
|
||
col[i] = 0.0f;
|
||
}
|
||
col[j] = 1.0f;
|
||
lubksb(n, indx, col);
|
||
for (i = 0; i < 4; i++) {
|
||
y(i, j) = col[i];
|
||
}
|
||
}
|
||
return y;
|
||
} // end MatrixInverse
|
||
|
||
/*
|
||
**-----------------------------------------------------------------------------
|
||
** Name: lubksb
|
||
** Purpose: backward subsitution
|
||
**-----------------------------------------------------------------------------
|
||
*/
|
||
|
||
static void
|
||
lubksb(MATRIX3D &a, int *indx, float *b) {
|
||
int i, j, ii = -1, ip;
|
||
float sum;
|
||
|
||
for (i = 0; i < 4; i++) {
|
||
ip = indx[i];
|
||
sum = b[ip];
|
||
b[ip] = b[i];
|
||
if (ii >= 0) {
|
||
for (j = ii; j <= i - 1; j++) {
|
||
sum -= a(i, j) * b[j];
|
||
}
|
||
} else if (sum != 0.0) {
|
||
ii = i;
|
||
}
|
||
b[i] = sum;
|
||
}
|
||
for (i = 3; i >= 0; i--) {
|
||
sum = b[i];
|
||
for (j = i + 1; j < 4; j++) {
|
||
sum -= a(i, j) * b[j];
|
||
}
|
||
b[i] = sum / a(i, i);
|
||
}
|
||
} // end lubksb
|
||
|
||
/*
|
||
**-----------------------------------------------------------------------------
|
||
** Name: ludcmp
|
||
** Purpose: LU decomposition
|
||
**-----------------------------------------------------------------------------
|
||
*/
|
||
|
||
static void
|
||
ludcmp(MATRIX3D &a, int *indx, float *d) {
|
||
float vv[4]; /* implicit scale for each row */
|
||
float big, dum, sum, tmp;
|
||
int i, imax = 0, j, k;
|
||
|
||
*d = 1.0f;
|
||
for (i = 0; i < 4; i++) {
|
||
big = 0.0f;
|
||
for (j = 0; j < 4; j++) {
|
||
if ((tmp = (float) fabs(a(i, j))) > big) {
|
||
big = tmp;
|
||
}
|
||
}
|
||
/*
|
||
if (big == 0.0f) {
|
||
printf("ludcmp(): singular matrix found...\n");
|
||
exit(1);
|
||
}
|
||
*/
|
||
vv[i] = 1.0f / big;
|
||
}
|
||
for (j = 0; j < 4; j++) {
|
||
for (i = 0; i < j; i++) {
|
||
sum = a(i, j);
|
||
for (k = 0; k < i; k++) {
|
||
sum -= a(i, k) * a(k, j);
|
||
}
|
||
a(i, j) = sum;
|
||
}
|
||
big = 0.0f;
|
||
for (i = j; i < 4; i++) {
|
||
sum = a(i, j);
|
||
for (k = 0; k < j; k++) {
|
||
sum -= a(i, k) * a(k, j);
|
||
}
|
||
a(i, j) = sum;
|
||
if ((dum = vv[i] * (float)fabs(sum)) >= big) {
|
||
big = dum;
|
||
imax = i;
|
||
}
|
||
}
|
||
if (j != imax) {
|
||
for (k = 0; k < 4; k++) {
|
||
dum = a(imax, k);
|
||
a(imax, k) = a(j, k);
|
||
a(j, k) = dum;
|
||
}
|
||
*d = -(*d);
|
||
vv[imax] = vv[j];
|
||
}
|
||
indx[j] = imax;
|
||
if (a(j, j) == 0.0f) {
|
||
a(j, j) = 1.0e-20f; /* can be 0.0 also... */
|
||
}
|
||
if (j != 3) {
|
||
dum = 1.0f / a(j, j);
|
||
for (i = j + 1; i < 4; i++) {
|
||
a(i, j) *= dum;
|
||
}
|
||
}
|
||
}
|
||
} // end ludcmp
|
||
|
||
/*
|
||
**-----------------------------------------------------------------------------
|
||
** Name: Matrix Transpose
|
||
** Purpose: [M] = [M]'
|
||
**-----------------------------------------------------------------------------
|
||
*/
|
||
|
||
MATRIX3D
|
||
MatrixTranspose(const MATRIX3D &m) {
|
||
MATRIX3D ret;
|
||
int i, j;
|
||
|
||
for (i = 0; i < 4; i++) {
|
||
for (j = 0; j < 4; j++) {
|
||
ret(i, j) = m(j, i);
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
} // end MatrixTranspose
|
||
|
||
/*
|
||
Class Methods
|
||
*/
|
||
|
||
/*
|
||
**-----------------------------------------------------------------------------
|
||
** end of File
|
||
**-----------------------------------------------------------------------------
|
||
*/
|
||
|
||
|
||
} // namespace QDEngine
|