scummvm/engines/qdengine/qdcore/qd_d3dutils.cpp
2024-08-22 22:09:48 +02:00

575 lines
15 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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