409 lines
13 KiB
C++
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
|