scummvm/engines/icb/common/px_capri_maths.h
D G Turner 511a886591 ICB: Fix GCC Undefined Macro Symbols Warnings
These are emitted by GCC when -Wundef is passed.

The _PSX symbol looks to be intended to switch the codebase between
building the PSX and PC version of the game due to differences in the
data structures. The _PSX_ON_PC likely allows building a version of
the engine which will run on PC, but use the PSX game data.

These should be refactored to allow the codebase to use either PC or
PSX game data at runtime in future, but for now, these are hardcoded
to the PC game data version for build stability.
2022-07-16 01:47:41 +01:00

409 lines
13 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 ICB_PC_CAPRI_MATHS_H
#define ICB_PC_CAPRI_MATHS_H
#include "engines/icb/psx_config.h"
#include "engines/icb/common/px_capri_maths_pc.h"
namespace ICB {
#if (_PSX_ON_PC == 0) && !defined ICB_PSX_PCDEFINES_H
// make our own equivalents
typedef struct MATRIX {
int16 m[3][3]; /* 3x3 rotation matrix */
int16 pad;
int32 t[3]; /* transfer vector */
MATRIX() { pad = 0; }
} MATRIX;
/* int32 word type 3D vector */
typedef struct VECTOR {
int32 vx, vy;
int32 vz, pad;
VECTOR() { pad = 0; }
} VECTOR;
/* short word type 3D vector */
typedef struct SVECTOR {
int16 vx, vy;
int16 vz, pad;
SVECTOR() { pad = 0; }
bool operator==(const SVECTOR &v) { return ((v.vx == vx) && (v.vy == vy) && (v.vz == vz)); }
} SVECTOR;
/* short word type 3D vector */
typedef struct CVECTOR {
uint8 r, g;
int16 b, pad;
CVECTOR() { pad = 0; }
bool operator==(const CVECTOR &v) { return ((v.r == r) && (v.g == g) && (v.b == b)); }
} CVECTOR;
#endif // #if (_PSX_ON_PC==0)
#define ONE 4096
#define myPI (3.141592654f)
inline int32 myNINT(float f) {
if (f >= 0.0f)
return int(f + 0.5f);
else
return int(f - 0.5f);
}
#define VectorNormal myVectorNormal
#define ApplyMatrixLV myApplyMatrixLV
#define ApplyMatrixSV myApplyMatrixSV
#define RotMatrix_gte myRotMatrix_gte
#define gte_MulMatrix0 mygte_MulMatrix0
#define gte_RotTrans mygte_RotTrans
#define gte_RotTransPers mygte_RotTransPers
#define gte_RotTransPers3 mygte_RotTransPers3
#define gte_SetRotMatrix mygte_SetRotMatrix
#define gte_SetTransMatrix mygte_SetTransMatrix
#define gte_ApplyRotMatrix mygte_ApplyRotMatrix
#define gte_SetGeomScreen mygte_SetGeomScreen
#define gte_SetBackColor mygte_SetBackColor
#define gte_SetColorMatrix mygte_SetColorMatrix
#define gte_SetLightMatrix mygte_SetLightMatrix
#define gte_NormalColorCol mygte_NormalColorCol
#define gte_NormalColorCol3 mygte_NormalColorCol3
#define gte_NormalClip mygte_NormalClip
#define gte_AverageZ3 mygte_AverageZ3
extern MATRIX *gterot;
extern MATRIX *gtetrans;
extern MATRIX *gtecolour;
extern MATRIX *gtelight;
extern int16 gteback[3];
extern int32 gtegeomscrn;
extern uint8 dcache[1024];
#define getScratchAddr(x) ((uint32 *)(dcache + x))
inline void myApplyMatrixLV(MATRIX *m, VECTOR *invec, VECTOR *outvec);
inline void myApplyMatrixSV(MATRIX *m, SVECTOR *invec, SVECTOR *outvec);
inline int32 myVectorNormal(VECTOR *in0, VECTOR *out0);
inline void mygte_MulMatrix0(MATRIX *m1, MATRIX *m2, MATRIX *out);
inline void mygte_RotTrans(SVECTOR *in0, VECTOR *out0, int32 *flag);
inline void mygte_RotTransPers(SVECTOR *in0, int32 *sxy0, int32 *p, int32 *flag, int32 *z);
inline void mygte_RotTransPers3(SVECTOR *in0, SVECTOR *in1, SVECTOR *in2, int32 *sxy0, int32 *sxy1, int32 *sxy2, int32 *p, int32 *flag, int32 *z);
inline void mygte_SetRotMatrix(MATRIX *m);
inline void mygte_SetTransMatrix(MATRIX *m);
inline void mygte_ApplyRotMatrix(SVECTOR *invec, VECTOR *outvec);
inline void myRotMatrix_gte(SVECTOR *rot, MATRIX *m);
inline void mygte_SetColorMatrix(MATRIX *m);
inline void mygte_SetLightMatrix(MATRIX *m);
inline void mygte_SetGeomScreen(int32 h);
inline void mygte_SetBackColor(int32 r, int32 g, int32 b);
inline void mygte_NormalColorCol(SVECTOR *v0, CVECTOR *in0, CVECTOR *out0);
inline void mygte_NormalColorCol3(SVECTOR *v0, SVECTOR *v1, SVECTOR *v2, CVECTOR *in0, CVECTOR *out0, CVECTOR *out1, CVECTOR *out2);
inline void mygte_NormalClip(int32 sxy0, int32 sxy1, int32 sxy2, int32 *flag);
inline void mygte_AverageZ3(int32 z0, int32 z1, int32 z2, int32 *sz);
inline void myApplyMatrixLV(MATRIX *m, VECTOR *invec, VECTOR *outvec) {
outvec->vx = ((int)m->m[0][0] * invec->vx + (int)m->m[0][1] * invec->vy + (int)m->m[0][2] * invec->vz) / 4096;
outvec->vy = ((int)m->m[1][0] * invec->vx + (int)m->m[1][1] * invec->vy + (int)m->m[1][2] * invec->vz) / 4096;
outvec->vz = ((int)m->m[2][0] * invec->vx + (int)m->m[2][1] * invec->vy + (int)m->m[2][2] * invec->vz) / 4096;
}
inline void myApplyMatrixSV(MATRIX *m, SVECTOR *invec, SVECTOR *outvec) {
outvec->vx = (int16)(((int)m->m[0][0] * invec->vx + (int)m->m[0][1] * invec->vy + (int)m->m[0][2] * invec->vz) / 4096);
outvec->vy = (int16)(((int)m->m[1][0] * invec->vx + (int)m->m[1][1] * invec->vy + (int)m->m[1][2] * invec->vz) / 4096);
outvec->vz = (int16)(((int)m->m[2][0] * invec->vx + (int)m->m[2][1] * invec->vy + (int)m->m[2][2] * invec->vz) / 4096);
}
inline void mygte_MulMatrix0(MATRIX *m1, MATRIX *m2, MATRIX *out) {
MATRIX local;
MATRIX *work;
if ((out == m1) || (out == m2))
work = &local;
else
work = out;
work->m[0][0] = (int16)(((int)m1->m[0][0] * (int)m2->m[0][0] + (int)m1->m[0][1] * (int)m2->m[1][0] + (int)m1->m[0][2] * (int)m2->m[2][0]) / 4096);
work->m[0][1] = (int16)(((int)m1->m[0][0] * (int)m2->m[0][1] + (int)m1->m[0][1] * (int)m2->m[1][1] + (int)m1->m[0][2] * (int)m2->m[2][1]) / 4096);
work->m[0][2] = (int16)(((int)m1->m[0][0] * (int)m2->m[0][2] + (int)m1->m[0][1] * (int)m2->m[1][2] + (int)m1->m[0][2] * (int)m2->m[2][2]) / 4096);
work->m[1][0] = (int16)(((int)m1->m[1][0] * (int)m2->m[0][0] + (int)m1->m[1][1] * (int)m2->m[1][0] + (int)m1->m[1][2] * (int)m2->m[2][0]) / 4096);
work->m[1][1] = (int16)(((int)m1->m[1][0] * (int)m2->m[0][1] + (int)m1->m[1][1] * (int)m2->m[1][1] + (int)m1->m[1][2] * (int)m2->m[2][1]) / 4096);
work->m[1][2] = (int16)(((int)m1->m[1][0] * (int)m2->m[0][2] + (int)m1->m[1][1] * (int)m2->m[1][2] + (int)m1->m[1][2] * (int)m2->m[2][2]) / 4096);
work->m[2][0] = (int16)(((int)m1->m[2][0] * (int)m2->m[0][0] + (int)m1->m[2][1] * (int)m2->m[1][0] + (int)m1->m[2][2] * (int)m2->m[2][0]) / 4096);
work->m[2][1] = (int16)(((int)m1->m[2][0] * (int)m2->m[0][1] + (int)m1->m[2][1] * (int)m2->m[1][1] + (int)m1->m[2][2] * (int)m2->m[2][1]) / 4096);
work->m[2][2] = (int16)(((int)m1->m[2][0] * (int)m2->m[0][2] + (int)m1->m[2][1] * (int)m2->m[1][2] + (int)m1->m[2][2] * (int)m2->m[2][2]) / 4096);
if (work != out) {
out->m[0][0] = work->m[0][0];
out->m[0][1] = work->m[0][1];
out->m[0][2] = work->m[0][2];
out->m[1][0] = work->m[1][0];
out->m[1][1] = work->m[1][1];
out->m[1][2] = work->m[1][2];
out->m[2][0] = work->m[2][0];
out->m[2][1] = work->m[2][1];
out->m[2][2] = work->m[2][2];
}
}
inline void mygte_SetRotMatrix(MATRIX *m) { *gterot = *m; }
inline void mygte_SetTransMatrix(MATRIX *m) { *gtetrans = *m; }
inline void mygte_ApplyRotMatrix(SVECTOR *invec, VECTOR *outvec) {
outvec->vx = (((int)gterot->m[0][0] * (int)invec->vx + (int)gterot->m[0][1] * (int)invec->vy + (int)gterot->m[0][2] * (int)invec->vz) / 4096);
outvec->vy = (((int)gterot->m[1][0] * (int)invec->vx + (int)gterot->m[1][1] * (int)invec->vy + (int)gterot->m[1][2] * (int)invec->vz) / 4096);
outvec->vz = (((int)gterot->m[2][0] * (int)invec->vx + (int)gterot->m[2][1] * (int)invec->vy + (int)gterot->m[2][2] * (int)invec->vz) / 4096);
}
inline void mygte_RotTrans(SVECTOR *in0, VECTOR *out0, int32 *flag) {
mygte_ApplyRotMatrix(in0, out0);
out0->vx += gtetrans->t[0];
out0->vy += gtetrans->t[1];
out0->vz += gtetrans->t[2];
// What GTE flags should we set ?
*flag = 0;
}
inline void mygte_RotTransPers(SVECTOR *in0, int32 *sxy0, int32 * /* p */, int32 *flag, int32 *z) {
VECTOR cam;
SVECTOR *scrn = (SVECTOR *)sxy0;
gte_RotTrans(in0, &cam, flag);
*flag = 0;
if (cam.vz != 0) {
scrn->vx = (int16)((cam.vx * gtegeomscrn) / cam.vz);
scrn->vy = (int16)((cam.vy * gtegeomscrn) / cam.vz);
} else {
// To force an error and hence an illegal polygon
scrn->vx = 2048;
scrn->vy = 2048;
}
*z = cam.vz / 4;
if (abs(scrn->vx) > 1024)
*flag |= 0x80000000;
if (abs(scrn->vy) > 1024)
*flag |= 0x80000000;
// set the value of flag : closer than h/2
if (cam.vz < 0)
*flag |= 0x80000000;
}
inline void mygte_RotTransPers3(SVECTOR *in0, SVECTOR *in1, SVECTOR *in2, int32 *sxy0, int32 *sxy1, int32 *sxy2, int32 *p, int32 *flag, int32 *z) {
int32 z0, z1, z2;
int32 p0, p1, p2;
int32 flag0, flag1, flag2;
mygte_RotTransPers(in0, sxy0, &p0, &flag0, &z0);
mygte_RotTransPers(in1, sxy1, &p1, &flag1, &z1);
mygte_RotTransPers(in2, sxy2, &p2, &flag2, &z2);
// What GTE flags should we set ?
*flag = flag0 | flag1 | flag2;
*p = p2;
*z = z2;
}
inline void myRotMatrix_gte(SVECTOR *rot, MATRIX *m) {
const int32 one = (1 << 12);
float ang0 = (float)rot->vx * 2.0f * myPI / one;
MATRIX m0;
int32 c0 = myNINT(one * (float)cos(ang0));
int32 s0 = myNINT(one * (float)sin(ang0));
m0.m[0][0] = one;
m0.m[0][1] = 0;
m0.m[0][2] = 0;
m0.m[1][0] = 0;
m0.m[1][1] = (int16)c0;
m0.m[1][2] = (int16)-s0;
m0.m[2][0] = 0;
m0.m[2][1] = (int16)s0;
m0.m[2][2] = (int16)c0;
float ang1 = (float)rot->vy * 2.0f * myPI / one;
int32 c1 = myNINT(one * (float)cos(ang1));
int32 s1 = myNINT(one * (float)sin(ang1));
MATRIX m1;
m1.m[0][0] = (int16)c1;
m1.m[0][1] = 0;
m1.m[0][2] = (int16)s1;
m1.m[1][0] = 0;
m1.m[1][1] = one;
m1.m[1][2] = 0;
m1.m[2][0] = (int16)-s1;
m1.m[2][1] = 0;
m1.m[2][2] = (int16)c1;
float ang2 = (float)rot->vz * 2.0f * myPI / one;
int32 c2 = myNINT(one * (float)cos(ang2));
int32 s2 = myNINT(one * (float)sin(ang2));
MATRIX m2;
m2.m[0][0] = (int16)c2;
m2.m[0][1] = (int16)-s2;
m2.m[0][2] = 0;
m2.m[1][0] = (int16)s2;
m2.m[1][1] = (int16)c2;
m2.m[1][2] = 0;
m2.m[2][0] = 0;
m2.m[2][1] = 0;
m2.m[2][2] = one;
mygte_MulMatrix0(&m0, &m1, m);
mygte_MulMatrix0(m, &m2, m);
}
inline void mygte_SetBackColor(int32 r, int32 g, int32 b) {
gteback[0] = (int16)r;
gteback[1] = (int16)g;
gteback[2] = (int16)b;
}
inline void mygte_SetColorMatrix(MATRIX *m) { *gtecolour = *m; }
inline void mygte_SetLightMatrix(MATRIX *m) { *gtelight = *m; }
inline void mygte_SetGeomScreen(int32 h) { gtegeomscrn = h; }
inline void mygte_NormalColorCol(SVECTOR *v0, CVECTOR *in0, CVECTOR *out0) {
SVECTOR lightEffect;
// Normal line vector(local) -> light source effect
ApplyMatrixSV(gtelight, v0, &lightEffect);
if (lightEffect.vx < 0)
lightEffect.vx = 0;
if (lightEffect.vy < 0)
lightEffect.vy = 0;
if (lightEffect.vz < 0)
lightEffect.vz = 0;
// Light source effect -> Colour effect(local colour matrix+back colour)
SVECTOR colourEffect;
ApplyMatrixSV(gtecolour, &lightEffect, &colourEffect);
if (colourEffect.vx < 0)
colourEffect.vx = 0;
if (colourEffect.vy < 0)
colourEffect.vy = 0;
if (colourEffect.vz < 0)
colourEffect.vz = 0;
// colourEffect is 0-4095 (2^12)
// gteback is 0-255 (2^8)
colourEffect.vx = (int16)((colourEffect.vx >> 4) + gteback[0]);
colourEffect.vy = (int16)((colourEffect.vy >> 4) + gteback[1]);
colourEffect.vz = (int16)((colourEffect.vz >> 4) + gteback[2]);
// 256 = 1.0 in colourEffect
// 128 = 1.0 in in0
int32 red = ((in0->r * colourEffect.vx) >> 8);
int32 green = ((in0->g * colourEffect.vy) >> 8);
int32 blue = ((in0->b * colourEffect.vz) >> 8);
if (red > 255)
red = 255;
if (green > 255)
green = 255;
if (blue > 255)
blue = 255;
out0->r = (uint8)(red);
out0->g = (uint8)(green);
out0->b = (uint8)(blue);
}
inline void mygte_NormalColorCol3(SVECTOR *v0, SVECTOR *v1, SVECTOR *v2, CVECTOR *in0, CVECTOR *out0, CVECTOR *out1, CVECTOR *out2) {
gte_NormalColorCol(v0, in0, out0);
gte_NormalColorCol(v1, in0, out1);
gte_NormalColorCol(v2, in0, out2);
}
inline int32 myVectorNormal(VECTOR *in0, VECTOR *out0) {
int32 r2 = (in0->vx * in0->vx + in0->vy * in0->vy + in0->vz * in0->vz);
float r = (float)sqrt((float)r2) / 4096.0f;
if (fabs(r) < 1.0e-6)
return 0;
out0->vx = (int32)((float)in0->vx / r);
out0->vy = (int32)((float)in0->vy / r);
out0->vz = (int32)((float)in0->vz / r);
return r2;
}
inline void mygte_NormalClip(int32 sxy0, int32 sxy1, int32 sxy2, int32 *flag) {
SVECTOR *v0 = (SVECTOR *)&sxy0;
SVECTOR *v1 = (SVECTOR *)&sxy1;
SVECTOR *v2 = (SVECTOR *)&sxy2;
// compute the cross-product of (v1-v0) x (v2-v0)
int32 l0x = v1->vx - v0->vx;
int32 l0y = v1->vy - v0->vy;
int32 l1x = v2->vx - v0->vx;
int32 l1y = v2->vy - v0->vy;
*flag = ((l0x * l1y) - (l0y * l1x));
}
inline void mygte_AverageZ3(int32 z0, int32 z1, int32 z2, int32 *sz) {
*sz = (z0 + z1 + z2) / 3;
*sz /= 4;
}
} // End of namespace ICB
#endif // #ifndef __PC_CAPRI_MATHS_H