1 /* ResidualVM - A 3D game interpreter
2  *
3  * ResidualVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the AUTHORS
5  * file distributed with this source distribution.
6  *
7  * Additional copyright for this file:
8  * Copyright (C) 1999-2000 Revolution Software Ltd.
9  * This code is based on source code created by Revolution Software,
10  * used with permission.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25  *
26  */
27 
28 #ifndef ICB_PC_CAPRI_MATHS_H
29 #define ICB_PC_CAPRI_MATHS_H
30 
31 #include "engines/icb/common/px_capri_maths_pc.h"
32 
33 namespace ICB {
34 
35 #if (_PSX_ON_PC == 0) && !defined ICB_PSX_PCDEFINES_H
36 
37 // make our own equivalents
38 typedef struct MATRIX {
39 	int16 m[3][3]; /* 3x3 rotation matrix */
40 	int16 pad;
41 	int32 t[3]; /* transfer vector */
MATRIXMATRIX42 	MATRIX() { pad = 0; }
43 } MATRIX;
44 
45 /* int32 word type 3D vector */
46 typedef struct VECTOR {
47 	int32 vx, vy;
48 	int32 vz, pad;
VECTORVECTOR49 	VECTOR() { pad = 0; }
50 } VECTOR;
51 
52 /* short word type 3D vector */
53 typedef struct SVECTOR {
54 	int16 vx, vy;
55 	int16 vz, pad;
SVECTORSVECTOR56 	SVECTOR() { pad = 0; }
57 	bool operator==(const SVECTOR &v) { return ((v.vx == vx) && (v.vy == vy) && (v.vz == vz)); }
58 } SVECTOR;
59 
60 /* short word type 3D vector */
61 typedef struct CVECTOR {
62 	uint8 r, g;
63 	int16 b, pad;
CVECTORCVECTOR64 	CVECTOR() { pad = 0; }
65 	bool operator==(const CVECTOR &v) { return ((v.r == r) && (v.g == g) && (v.b == b)); }
66 } CVECTOR;
67 
68 #endif // #if (_PSX_ON_PC==0)
69 
70 #define ONE 4096
71 #define myPI (3.141592654f)
72 
myNINT(float f)73 inline int32 myNINT(float f) {
74 	if (f >= 0.0f)
75 		return int(f + 0.5f);
76 	else
77 		return int(f - 0.5f);
78 }
79 
80 #define VectorNormal myVectorNormal
81 #define ApplyMatrixLV myApplyMatrixLV
82 #define ApplyMatrixSV myApplyMatrixSV
83 #define RotMatrix_gte myRotMatrix_gte
84 #define gte_MulMatrix0 mygte_MulMatrix0
85 #define gte_RotTrans mygte_RotTrans
86 #define gte_RotTransPers mygte_RotTransPers
87 #define gte_RotTransPers3 mygte_RotTransPers3
88 #define gte_SetRotMatrix mygte_SetRotMatrix
89 #define gte_SetTransMatrix mygte_SetTransMatrix
90 #define gte_ApplyRotMatrix mygte_ApplyRotMatrix
91 #define gte_SetGeomScreen mygte_SetGeomScreen
92 #define gte_SetBackColor mygte_SetBackColor
93 #define gte_SetColorMatrix mygte_SetColorMatrix
94 #define gte_SetLightMatrix mygte_SetLightMatrix
95 #define gte_NormalColorCol mygte_NormalColorCol
96 #define gte_NormalColorCol3 mygte_NormalColorCol3
97 #define gte_NormalClip mygte_NormalClip
98 #define gte_AverageZ3 mygte_AverageZ3
99 
100 extern MATRIX *gterot;
101 extern MATRIX *gtetrans;
102 extern MATRIX *gtecolour;
103 extern MATRIX *gtelight;
104 extern int16 gteback[3];
105 extern int32 gtegeomscrn;
106 extern uint8 dcache[1024];
107 
108 #define getScratchAddr(x) ((uint32 *)(dcache + x))
109 
110 inline void myApplyMatrixLV(MATRIX *m, VECTOR *invec, VECTOR *outvec);
111 
112 inline void myApplyMatrixSV(MATRIX *m, SVECTOR *invec, SVECTOR *outvec);
113 
114 inline int32 myVectorNormal(VECTOR *in0, VECTOR *out0);
115 
116 inline void mygte_MulMatrix0(MATRIX *m1, MATRIX *m2, MATRIX *out);
117 
118 inline void mygte_RotTrans(SVECTOR *in0, VECTOR *out0, int32 *flag);
119 
120 inline void mygte_RotTransPers(SVECTOR *in0, int32 *sxy0, int32 *p, int32 *flag, int32 *z);
121 
122 inline void mygte_RotTransPers3(SVECTOR *in0, SVECTOR *in1, SVECTOR *in2, int32 *sxy0, int32 *sxy1, int32 *sxy2, int32 *p, int32 *flag, int32 *z);
123 
124 inline void mygte_SetRotMatrix(MATRIX *m);
125 
126 inline void mygte_SetTransMatrix(MATRIX *m);
127 
128 inline void mygte_ApplyRotMatrix(SVECTOR *invec, VECTOR *outvec);
129 
130 inline void myRotMatrix_gte(SVECTOR *rot, MATRIX *m);
131 
132 inline void mygte_SetColorMatrix(MATRIX *m);
133 
134 inline void mygte_SetLightMatrix(MATRIX *m);
135 
136 inline void mygte_SetGeomScreen(int32 h);
137 
138 inline void mygte_SetBackColor(int32 r, int32 g, int32 b);
139 
140 inline void mygte_NormalColorCol(SVECTOR *v0, CVECTOR *in0, CVECTOR *out0);
141 
142 inline void mygte_NormalColorCol3(SVECTOR *v0, SVECTOR *v1, SVECTOR *v2, CVECTOR *in0, CVECTOR *out0, CVECTOR *out1, CVECTOR *out2);
143 
144 inline void mygte_NormalClip(int32 sxy0, int32 sxy1, int32 sxy2, int32 *flag);
145 
146 inline void mygte_AverageZ3(int32 z0, int32 z1, int32 z2, int32 *sz);
147 
myApplyMatrixLV(MATRIX * m,VECTOR * invec,VECTOR * outvec)148 inline void myApplyMatrixLV(MATRIX *m, VECTOR *invec, VECTOR *outvec) {
149 	outvec->vx = ((int)m->m[0][0] * invec->vx + (int)m->m[0][1] * invec->vy + (int)m->m[0][2] * invec->vz) / 4096;
150 	outvec->vy = ((int)m->m[1][0] * invec->vx + (int)m->m[1][1] * invec->vy + (int)m->m[1][2] * invec->vz) / 4096;
151 	outvec->vz = ((int)m->m[2][0] * invec->vx + (int)m->m[2][1] * invec->vy + (int)m->m[2][2] * invec->vz) / 4096;
152 }
153 
myApplyMatrixSV(MATRIX * m,SVECTOR * invec,SVECTOR * outvec)154 inline void myApplyMatrixSV(MATRIX *m, SVECTOR *invec, SVECTOR *outvec) {
155 	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);
156 	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);
157 	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);
158 }
159 
mygte_MulMatrix0(MATRIX * m1,MATRIX * m2,MATRIX * out)160 inline void mygte_MulMatrix0(MATRIX *m1, MATRIX *m2, MATRIX *out) {
161 	MATRIX local;
162 	MATRIX *work;
163 	if ((out == m1) || (out == m2))
164 		work = &local;
165 	else
166 		work = out;
167 	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);
168 	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);
169 	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);
170 	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);
171 	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);
172 	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);
173 	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);
174 	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);
175 	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);
176 
177 	if (work != out) {
178 		out->m[0][0] = work->m[0][0];
179 		out->m[0][1] = work->m[0][1];
180 		out->m[0][2] = work->m[0][2];
181 
182 		out->m[1][0] = work->m[1][0];
183 		out->m[1][1] = work->m[1][1];
184 		out->m[1][2] = work->m[1][2];
185 
186 		out->m[2][0] = work->m[2][0];
187 		out->m[2][1] = work->m[2][1];
188 		out->m[2][2] = work->m[2][2];
189 	}
190 }
191 
mygte_SetRotMatrix(MATRIX * m)192 inline void mygte_SetRotMatrix(MATRIX *m) { *gterot = *m; }
193 
mygte_SetTransMatrix(MATRIX * m)194 inline void mygte_SetTransMatrix(MATRIX *m) { *gtetrans = *m; }
195 
mygte_ApplyRotMatrix(SVECTOR * invec,VECTOR * outvec)196 inline void mygte_ApplyRotMatrix(SVECTOR *invec, VECTOR *outvec) {
197 	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);
198 	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);
199 	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);
200 }
201 
mygte_RotTrans(SVECTOR * in0,VECTOR * out0,int32 * flag)202 inline void mygte_RotTrans(SVECTOR *in0, VECTOR *out0, int32 *flag) {
203 	mygte_ApplyRotMatrix(in0, out0);
204 	out0->vx += gtetrans->t[0];
205 	out0->vy += gtetrans->t[1];
206 	out0->vz += gtetrans->t[2];
207 
208 	// What GTE flags should we set ?
209 	*flag = 0;
210 }
211 
mygte_RotTransPers(SVECTOR * in0,int32 * sxy0,int32 *,int32 * flag,int32 * z)212 inline void mygte_RotTransPers(SVECTOR *in0, int32 *sxy0, int32 * /* p */, int32 *flag, int32 *z) {
213 	VECTOR cam;
214 	SVECTOR *scrn = (SVECTOR *)sxy0;
215 
216 	gte_RotTrans(in0, &cam, flag);
217 
218 	*flag = 0;
219 
220 	if (cam.vz != 0) {
221 		scrn->vx = (int16)((cam.vx * gtegeomscrn) / cam.vz);
222 		scrn->vy = (int16)((cam.vy * gtegeomscrn) / cam.vz);
223 	} else {
224 		// To force an error and hence an illegal polygon
225 		scrn->vx = 2048;
226 		scrn->vy = 2048;
227 	}
228 
229 	*z = cam.vz / 4;
230 
231 	if (abs(scrn->vx) > 1024)
232 		*flag |= 0x80000000;
233 	if (abs(scrn->vy) > 1024)
234 		*flag |= 0x80000000;
235 
236 	// set the value of flag : closer than h/2
237 	if (cam.vz < 0)
238 		*flag |= 0x80000000;
239 }
240 
mygte_RotTransPers3(SVECTOR * in0,SVECTOR * in1,SVECTOR * in2,int32 * sxy0,int32 * sxy1,int32 * sxy2,int32 * p,int32 * flag,int32 * z)241 inline void mygte_RotTransPers3(SVECTOR *in0, SVECTOR *in1, SVECTOR *in2, int32 *sxy0, int32 *sxy1, int32 *sxy2, int32 *p, int32 *flag, int32 *z) {
242 	int32 z0, z1, z2;
243 	int32 p0, p1, p2;
244 	int32 flag0, flag1, flag2;
245 
246 	mygte_RotTransPers(in0, sxy0, &p0, &flag0, &z0);
247 	mygte_RotTransPers(in1, sxy1, &p1, &flag1, &z1);
248 	mygte_RotTransPers(in2, sxy2, &p2, &flag2, &z2);
249 
250 	// What GTE flags should we set ?
251 	*flag = flag0 | flag1 | flag2;
252 	*p = p2;
253 	*z = z2;
254 }
255 
myRotMatrix_gte(SVECTOR * rot,MATRIX * m)256 inline void myRotMatrix_gte(SVECTOR *rot, MATRIX *m) {
257 	const int32 one = (1 << 12);
258 	float ang0 = (float)rot->vx * 2.0f * myPI / one;
259 	MATRIX m0;
260 	int32 c0 = myNINT(one * (float)cos(ang0));
261 	int32 s0 = myNINT(one * (float)sin(ang0));
262 	m0.m[0][0] = one;
263 	m0.m[0][1] = 0;
264 	m0.m[0][2] = 0;
265 
266 	m0.m[1][0] = 0;
267 	m0.m[1][1] = (int16)c0;
268 	m0.m[1][2] = (int16)-s0;
269 
270 	m0.m[2][0] = 0;
271 	m0.m[2][1] = (int16)s0;
272 	m0.m[2][2] = (int16)c0;
273 
274 	float ang1 = (float)rot->vy * 2.0f * myPI / one;
275 	int32 c1 = myNINT(one * (float)cos(ang1));
276 	int32 s1 = myNINT(one * (float)sin(ang1));
277 	MATRIX m1;
278 	m1.m[0][0] = (int16)c1;
279 	m1.m[0][1] = 0;
280 	m1.m[0][2] = (int16)s1;
281 
282 	m1.m[1][0] = 0;
283 	m1.m[1][1] = one;
284 	m1.m[1][2] = 0;
285 
286 	m1.m[2][0] = (int16)-s1;
287 	m1.m[2][1] = 0;
288 	m1.m[2][2] = (int16)c1;
289 
290 	float ang2 = (float)rot->vz * 2.0f * myPI / one;
291 	int32 c2 = myNINT(one * (float)cos(ang2));
292 	int32 s2 = myNINT(one * (float)sin(ang2));
293 	MATRIX m2;
294 
295 	m2.m[0][0] = (int16)c2;
296 	m2.m[0][1] = (int16)-s2;
297 	m2.m[0][2] = 0;
298 
299 	m2.m[1][0] = (int16)s2;
300 	m2.m[1][1] = (int16)c2;
301 	m2.m[1][2] = 0;
302 
303 	m2.m[2][0] = 0;
304 	m2.m[2][1] = 0;
305 	m2.m[2][2] = one;
306 
307 	mygte_MulMatrix0(&m0, &m1, m);
308 	mygte_MulMatrix0(m, &m2, m);
309 }
310 
mygte_SetBackColor(int32 r,int32 g,int32 b)311 inline void mygte_SetBackColor(int32 r, int32 g, int32 b) {
312 	gteback[0] = (int16)r;
313 	gteback[1] = (int16)g;
314 	gteback[2] = (int16)b;
315 }
316 
mygte_SetColorMatrix(MATRIX * m)317 inline void mygte_SetColorMatrix(MATRIX *m) { *gtecolour = *m; }
318 
mygte_SetLightMatrix(MATRIX * m)319 inline void mygte_SetLightMatrix(MATRIX *m) { *gtelight = *m; }
320 
mygte_SetGeomScreen(int32 h)321 inline void mygte_SetGeomScreen(int32 h) { gtegeomscrn = h; }
322 
mygte_NormalColorCol(SVECTOR * v0,CVECTOR * in0,CVECTOR * out0)323 inline void mygte_NormalColorCol(SVECTOR *v0, CVECTOR *in0, CVECTOR *out0) {
324 	SVECTOR lightEffect;
325 	// Normal line vector(local) -> light source effect
326 	ApplyMatrixSV(gtelight, v0, &lightEffect);
327 	if (lightEffect.vx < 0)
328 		lightEffect.vx = 0;
329 	if (lightEffect.vy < 0)
330 		lightEffect.vy = 0;
331 	if (lightEffect.vz < 0)
332 		lightEffect.vz = 0;
333 
334 	// Light source effect -> Colour effect(local colour matrix+back colour)
335 	SVECTOR colourEffect;
336 	ApplyMatrixSV(gtecolour, &lightEffect, &colourEffect);
337 	if (colourEffect.vx < 0)
338 		colourEffect.vx = 0;
339 	if (colourEffect.vy < 0)
340 		colourEffect.vy = 0;
341 	if (colourEffect.vz < 0)
342 		colourEffect.vz = 0;
343 
344 	// colourEffect is 0-4095 (2^12)
345 	// gteback is 0-255 (2^8)
346 	colourEffect.vx = (int16)((colourEffect.vx >> 4) + gteback[0]);
347 	colourEffect.vy = (int16)((colourEffect.vy >> 4) + gteback[1]);
348 	colourEffect.vz = (int16)((colourEffect.vz >> 4) + gteback[2]);
349 
350 	// 256 = 1.0 in colourEffect
351 	// 128 = 1.0 in in0
352 	int32 red = ((in0->r * colourEffect.vx) >> 8);
353 	int32 green = ((in0->g * colourEffect.vy) >> 8);
354 	int32 blue = ((in0->b * colourEffect.vz) >> 8);
355 
356 	if (red > 255)
357 		red = 255;
358 	if (green > 255)
359 		green = 255;
360 	if (blue > 255)
361 		blue = 255;
362 
363 	out0->r = (uint8)(red);
364 	out0->g = (uint8)(green);
365 	out0->b = (uint8)(blue);
366 }
367 
mygte_NormalColorCol3(SVECTOR * v0,SVECTOR * v1,SVECTOR * v2,CVECTOR * in0,CVECTOR * out0,CVECTOR * out1,CVECTOR * out2)368 inline void mygte_NormalColorCol3(SVECTOR *v0, SVECTOR *v1, SVECTOR *v2, CVECTOR *in0, CVECTOR *out0, CVECTOR *out1, CVECTOR *out2) {
369 	gte_NormalColorCol(v0, in0, out0);
370 	gte_NormalColorCol(v1, in0, out1);
371 	gte_NormalColorCol(v2, in0, out2);
372 }
373 
myVectorNormal(VECTOR * in0,VECTOR * out0)374 inline int32 myVectorNormal(VECTOR *in0, VECTOR *out0) {
375 	int32 r2 = (in0->vx * in0->vx + in0->vy * in0->vy + in0->vz * in0->vz);
376 	float r = (float)sqrt((float)r2) / 4096.0f;
377 
378 	if (fabs(r) < 1.0e-6)
379 		return 0;
380 
381 	out0->vx = (int32)((float)in0->vx / r);
382 	out0->vy = (int32)((float)in0->vy / r);
383 	out0->vz = (int32)((float)in0->vz / r);
384 	return r2;
385 }
386 
mygte_NormalClip(int32 sxy0,int32 sxy1,int32 sxy2,int32 * flag)387 inline void mygte_NormalClip(int32 sxy0, int32 sxy1, int32 sxy2, int32 *flag) {
388 	SVECTOR *v0 = (SVECTOR *)&sxy0;
389 	SVECTOR *v1 = (SVECTOR *)&sxy1;
390 	SVECTOR *v2 = (SVECTOR *)&sxy2;
391 
392 	// compute the cross-product of (v1-v0) x (v2-v0)
393 	int32 l0x = v1->vx - v0->vx;
394 	int32 l0y = v1->vy - v0->vy;
395 	int32 l1x = v2->vx - v0->vx;
396 	int32 l1y = v2->vy - v0->vy;
397 
398 	*flag = ((l0x * l1y) - (l0y * l1x));
399 }
400 
mygte_AverageZ3(int32 z0,int32 z1,int32 z2,int32 * sz)401 inline void mygte_AverageZ3(int32 z0, int32 z1, int32 z2, int32 *sz) {
402 	*sz = (z0 + z1 + z2) / 3;
403 	*sz /= 4;
404 }
405 
406 } // End of namespace ICB
407 
408 #endif // #ifndef __PC_CAPRI_MATHS_H
409