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 #include "engines/icb/px_common.h"
29 #include "engines/icb/px_rcutypes.h"
30 #include "engines/icb/psx_pcdefines.h"
31 #include "engines/icb/shade.h"
32 
33 namespace ICB {
34 
35 // Handy maths function
makePlaneEquation(FVECTOR * v0,FVECTOR * v1,FVECTOR * v2,int32 * d,FVECTOR * pn)36 void makePlaneEquation(FVECTOR *v0, FVECTOR *v1, FVECTOR *v2, int32 *d, FVECTOR *pn) {
37 	FVECTOR l01, l02;
38 	// Line from vertex 0 -> vertex 1
39 	VEC_SUB_VECTOR(*v0, *v1, l01);
40 	// Line from vertex 0 -> vertex 2
41 	VEC_SUB_VECTOR(*v0, *v2, l02);
42 
43 	// the cross-product to get the normal : l01 x l02
44 	CROSS_PRODUCT_VECTOR(l01, l02, *pn);
45 	NORMALISE_VECTOR(*pn);
46 
47 	// the planar distance
48 	*d = (int32)DOT_PRODUCT_VECTOR(*pn, *v0);
49 }
50 
51 /*
52 // A triangle
53 typedef struct ShadeTriangle
54 {
55    SVECTOR l01;  // line vertex 0 -> vertex 1
56    SVECTOR l12;  // line vertex 1 -> vertex 2
57    SVECTOR l20;  // line vertex 2 -> vertex 0
58    SVECTOR n01;  // normal to plane & line 01
59    SVECTOR n12;  // normal to plane & line 12
60    SVECTOR n20;  // normal to plane & line 20
61    SVECTOR pn;   // plane normal
62    uint32 d;     // plane distance
63 } ShadeTriangle;
64 */
65 
preprocessShadeData(FVECTOR v[3],ShadeTriangle * s)66 void preprocessShadeData(FVECTOR v[3], ShadeTriangle *s) {
67 	// find the normal for the shade triangle / polygon !
68 	double l01x = v[1].vx - v[0].vx;
69 	double l01y = v[1].vy - v[0].vy;
70 	double l01z = v[1].vz - v[0].vz;
71 
72 	double l20x = v[0].vx - v[2].vx;
73 	double l20y = v[0].vy - v[2].vy;
74 	double l20z = v[0].vz - v[2].vz;
75 
76 	double l12x = v[2].vx - v[1].vx;
77 	double l12y = v[2].vy - v[1].vy;
78 	double l12z = v[2].vz - v[1].vz;
79 
80 	// the cross-product to get the normal : l01 x l02
81 	double nx, ny, nz;
82 	CROSS_PRODUCT(l01x, l01y, l01z, -l20x, -l20y, -l20z, nx, ny, nz);
83 	NORMALISE(nx, ny, nz);
84 
85 	// the planar distance
86 	double d = DOT_PRODUCT(nx, ny, nz, v[0].vx, v[0].vy, v[0].vz);
87 
88 	// n01 is normal in the plane of l01 : n01 = l01 x n
89 	double n01x, n01y, n01z;
90 	CROSS_PRODUCT(l01x, l01y, l01z, nx, ny, nz, n01x, n01y, n01z);
91 	NORMALISE(n01x, n01y, n01z);
92 	// n12 is normal in the plane of l12 : n12 = l12 x n
93 	double n12x, n12y, n12z;
94 	CROSS_PRODUCT(l12x, l12y, l12z, nx, ny, nz, n12x, n12y, n12z);
95 	NORMALISE(n12x, n12y, n12z);
96 	// n20 is normal in the plane of l20 : n20 = l20 x n
97 	double n20x, n20y, n20z;
98 	CROSS_PRODUCT(l20x, l20y, l20z, nx, ny, nz, n20x, n20y, n20z);
99 	NORMALISE(n20x, n20y, n20z);
100 
101 	double n01dots0, n12dots1, n20dots2;
102 	n01dots0 = DOT_PRODUCT(n01x, n01y, n01z, v[0].vx, v[0].vy, v[0].vz);
103 	n12dots1 = DOT_PRODUCT(n12x, n12y, n12z, v[1].vx, v[1].vy, v[1].vz);
104 	n20dots2 = DOT_PRODUCT(n20x, n20y, n20z, v[2].vx, v[2].vy, v[2].vz);
105 
106 	// Store the pre-processed data
107 	s->l01.vx = (int16)l01x;
108 	s->l01.vy = (int16)l01y;
109 	s->l01.vz = (int16)l01z;
110 
111 	s->l12.vx = (int16)l12x;
112 	s->l12.vy = (int16)l12y;
113 	s->l12.vz = (int16)l12z;
114 
115 	s->l20.vx = (int16)l20x;
116 	s->l20.vy = (int16)l20y;
117 	s->l20.vz = (int16)l20z;
118 
119 	s->n01.vx = (int16)(4096.0f * n01x);
120 	s->n01.vy = (int16)(4096.0f * n01y);
121 	s->n01.vz = (int16)(4096.0f * n01z);
122 
123 	s->n12.vx = (int16)(4096.0f * n12x);
124 	s->n12.vy = (int16)(4096.0f * n12y);
125 	s->n12.vz = (int16)(4096.0f * n12z);
126 
127 	s->n20.vx = (int16)(4096.0f * n20x);
128 	s->n20.vy = (int16)(4096.0f * n20y);
129 	s->n20.vz = (int16)(4096.0f * n20z);
130 
131 	s->pn.vx = (int16)(4096.0f * nx);
132 	s->pn.vy = (int16)(4096.0f * ny);
133 	s->pn.vz = (int16)(4096.0f * nz);
134 
135 	s->d = (int32)(4096.0f * d);
136 	s->n01dots0 = (int32)n01dots0;
137 	s->n12dots1 = (int32)n12dots1;
138 	s->n20dots2 = (int32)n20dots2;
139 }
140 
141 /*
142 // A quad
143 typedef struct ShadeQuad
144 {
145    SVECTOR l01;       // line vertex 0 -> vertex 1
146    SVECTOR l12;       // line vertex 1 -> vertex 2
147    SVECTOR l23;       // line vertex 2 -> vertex 3
148    SVECTOR l30;       // line vertex 3 -> vertex 0
149    SVECTOR n01;       // normal to plane & line 01
150    SVECTOR n12;       // normal to plane & line 12
151    SVECTOR n23;       // normal to plane & line 23
152    SVECTOR n30;       // normal to plane & line 30
153    SVECTOR pn;        // plane normal
154    uint32 d;          // plane distance
155    uint32 n01dots0;   // n01 . vertex 0
156    uint32 n12dots1;   // n12 . vertex 1
157    uint32 n20dots2;   // n23 . vertex 2
158    uint32 n20dots3;   // n30 . vertex 3
159 } ShadeQuad;
160 */
161 
preprocessShadeData(FVECTOR v[4],ShadeQuad * s)162 void preprocessShadeData(FVECTOR v[4], ShadeQuad *s) {
163 
164 	// find the normal for the shade quad !
165 	double l01x = v[1].vx - v[0].vx;
166 	double l01y = v[1].vy - v[0].vy;
167 	double l01z = v[1].vz - v[0].vz;
168 
169 	double l12x = v[2].vx - v[1].vx;
170 	double l12y = v[2].vy - v[1].vy;
171 	double l12z = v[2].vz - v[1].vz;
172 
173 	double l23x = v[3].vx - v[2].vx;
174 	double l23y = v[3].vy - v[2].vy;
175 	double l23z = v[3].vz - v[2].vz;
176 
177 	double l30x = v[0].vx - v[3].vx;
178 	double l30y = v[0].vy - v[3].vy;
179 	double l30z = v[0].vz - v[3].vz;
180 
181 	// the cross-product to get the normal : l01 x l03
182 	double nx, ny, nz;
183 	CROSS_PRODUCT(l01x, l01y, l01z, -l30x, -l30y, -l30z, nx, ny, nz);
184 	NORMALISE(nx, ny, nz);
185 
186 	// the planar distance
187 	double d = DOT_PRODUCT(nx, ny, nz, v[0].vx, v[0].vy, v[0].vz);
188 
189 	// n01 is normal in the plane of l01 : n01 = l01 x n
190 	double n01x, n01y, n01z;
191 	CROSS_PRODUCT(l01x, l01y, l01z, nx, ny, nz, n01x, n01y, n01z);
192 	NORMALISE(n01x, n01y, n01z);
193 	// n12 is normal in the plane of l12 : n12 = l12 x n
194 	double n12x, n12y, n12z;
195 	CROSS_PRODUCT(l12x, l12y, l12z, nx, ny, nz, n12x, n12y, n12z);
196 	NORMALISE(n12x, n12y, n12z);
197 	// n23 is normal in the plane of l23 : n23 = l23 x n
198 	double n23x, n23y, n23z;
199 	CROSS_PRODUCT(l23x, l23y, l23z, nx, ny, nz, n23x, n23y, n23z);
200 	NORMALISE(n23x, n23y, n23z);
201 	// n30 is normal in the plane of l30 : n30 = l30 x n
202 	double n30x, n30y, n30z;
203 	CROSS_PRODUCT(l30x, l30y, l30z, nx, ny, nz, n30x, n30y, n30z);
204 	NORMALISE(n30x, n30y, n30z);
205 
206 	double n01dots0, n12dots1, n23dots2, n30dots3;
207 	n01dots0 = DOT_PRODUCT(n01x, n01y, n01z, v[0].vx, v[0].vy, v[0].vz);
208 	n12dots1 = DOT_PRODUCT(n12x, n12y, n12z, v[1].vx, v[1].vy, v[1].vz);
209 	n23dots2 = DOT_PRODUCT(n23x, n23y, n23z, v[2].vx, v[2].vy, v[2].vz);
210 	n30dots3 = DOT_PRODUCT(n30x, n30y, n30z, v[3].vx, v[3].vy, v[3].vz);
211 
212 	// Store the pre-processed data
213 	s->l01.vx = (int16)l01x;
214 	s->l01.vy = (int16)l01y;
215 	s->l01.vz = (int16)l01z;
216 
217 	s->l12.vx = (int16)l12x;
218 	s->l12.vy = (int16)l12y;
219 	s->l12.vz = (int16)l12z;
220 
221 	s->l23.vx = (int16)l23x;
222 	s->l23.vy = (int16)l23y;
223 	s->l23.vz = (int16)l23z;
224 
225 	s->l30.vx = (int16)l30x;
226 	s->l30.vy = (int16)l30y;
227 	s->l30.vz = (int16)l30z;
228 
229 	s->n01.vx = (int16)(4096.0f * n01x);
230 	s->n01.vy = (int16)(4096.0f * n01y);
231 	s->n01.vz = (int16)(4096.0f * n01z);
232 
233 	s->n12.vx = (int16)(4096.0f * n12x);
234 	s->n12.vy = (int16)(4096.0f * n12y);
235 	s->n12.vz = (int16)(4096.0f * n12z);
236 
237 	s->n23.vx = (int16)(4096.0f * n23x);
238 	s->n23.vy = (int16)(4096.0f * n23y);
239 	s->n23.vz = (int16)(4096.0f * n23z);
240 
241 	s->n30.vx = (int16)(4096.0f * n30x);
242 	s->n30.vy = (int16)(4096.0f * n30y);
243 	s->n30.vz = (int16)(4096.0f * n30z);
244 
245 	s->pn.vx = (int16)(4096.0f * nx);
246 	s->pn.vy = (int16)(4096.0f * ny);
247 	s->pn.vz = (int16)(4096.0f * nz);
248 
249 	s->d = (int32)(4096.0f * d);
250 	s->n01dots0 = (int32)n01dots0;
251 	s->n12dots1 = (int32)n12dots1;
252 	s->n23dots2 = (int32)n23dots2;
253 	s->n30dots3 = (int32)n30dots3;
254 }
255 
256 } // End of namespace ICB
257