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/common/px_common.h"
29 #include "engines/icb/p4.h"
30 #include "engines/icb/p4_generic.h"
31 #include "engines/icb/global_objects_psx.h"
32 #include "engines/icb/gfx/psx_pcdefines.h"
33 #include "engines/icb/common/px_capri_maths.h"
34 #include "engines/icb/drawpoly_pc.h"
35 #include "engines/icb/light_pc.h"
36 #include "engines/icb/shade_pc.h"
37 
38 namespace ICB {
39 
40 #if _PSX_ON_PC == 1
41 
42 // Globals telling you "extra" parameters about the lights
43 extern uint32 useLampWidth;
44 extern uint32 useLampBounce;
45 extern int32 lampWidth[3];
46 extern int32 lampBounce[3];
47 
48 #else // #if _PSX_ON_PC == 1
49 
50 // Globals telling you "extra" parameters about the lights
51 uint32 useLampWidth;
52 uint32 useLampBounce;
53 int32 lampWidth[3];
54 int32 lampBounce[3];
55 
56 #endif // #if _PSX_ON_PC == 1
57 
58 //------------------------------------------------------------------------
59 // Set the GTE constant light variables
60 // Sets the direciton lights colour matrix
61 // Sets the ambient colour
62 // Fills in the lightDirects matrix
63 
64 // Selects the 3 brightest lamps from the lamplist
65 // at the actors position and puts them into the
66 // GTE light matrix and the lightDirects matrix
67 //
68 
prepareLightsPC(VECTOR * pos,PSXrgb * ambient,PSXLampList * lamplist,PSXShadeList * shadelist,MATRIXPC * lDirects,LampInfo * linfo)69 int32 prepareLightsPC(VECTOR *pos, PSXrgb *ambient, PSXLampList *lamplist, PSXShadeList *shadelist, MATRIXPC *lDirects, LampInfo *linfo) {
70 	// Disable the slow features as default
71 	useLampBounce = 0;
72 	useLampWidth = 0;
73 	// Zero out the "extra" parameters
74 	lampWidth[0] = 0;
75 	lampWidth[1] = 0;
76 	lampWidth[2] = 0;
77 	lampBounce[0] = 0;
78 	lampBounce[1] = 0;
79 	lampBounce[2] = 0;
80 
81 	if (lamplist == NULL) {
82 		return prepareLightsGlobalPC(lDirects);
83 	}
84 
85 	LampInfo lampInfo[MAX_NUMBER_LIGHTS + 1];
86 
87 	// Turn them off
88 	linfo[0].intens = 0;
89 	linfo[1].intens = 0;
90 	linfo[2].intens = 0;
91 
92 	uint32 brightest = MAX_NUMBER_LIGHTS;
93 	uint32 middle = MAX_NUMBER_LIGHTS;
94 	uint32 darkest = MAX_NUMBER_LIGHTS;
95 	lampInfo[brightest].intens = 0;
96 	lampInfo[brightest].index = MAX_NUMBER_LIGHTS;
97 
98 	MATRIXPC lColours;
99 
100 	// Zero out the matrix first off
101 	lDirects->m[0][0] = 0;
102 	lDirects->m[0][1] = 0;
103 	lDirects->m[0][2] = 0;
104 	lDirects->m[1][0] = 0;
105 	lDirects->m[1][1] = 0;
106 	lDirects->m[1][2] = 0;
107 	lDirects->m[2][0] = 0;
108 	lDirects->m[2][1] = 0;
109 	lDirects->m[2][2] = 0;
110 
111 	lColours.m[0][0] = 0;
112 	lColours.m[0][1] = 0;
113 	lColours.m[0][2] = 0;
114 	lColours.m[1][0] = 0;
115 	lColours.m[1][1] = 0;
116 	lColours.m[1][2] = 0;
117 	lColours.m[2][0] = 0;
118 	lColours.m[2][1] = 0;
119 	lColours.m[2][2] = 0;
120 
121 	uint32 num = lamplist->n;
122 
123 	PSXLamp *plamp = NULL;
124 	PSXLampState *plampstate;
125 
126 	uint32 state;
127 	uint32 sstate;
128 	VECTOR dir;
129 	VECTOR normdir;
130 	uint32 i, s;
131 
132 	uint32 *pstate = lamplist->states;
133 	PSXLamp **pplamp = lamplist->lamps;
134 
135 	uint32 ns = shadelist->n;
136 
137 	PSXShade *pshade;
138 	ShadeQuad *pshadestate;
139 
140 	uint32 *psstate;
141 	PSXShade **ppshade;
142 
143 	uint32 inten, m;
144 	for (i = 0; i < num; pplamp++, pstate++, i++) {
145 		// Make the direction vector
146 		plamp = *pplamp;
147 		state = *pstate;
148 
149 		plampstate = plamp->states + state;
150 
151 		// Ignore the lamp if it is switched off
152 		m = plampstate->m;
153 
154 		// For animating lights which are turned off - turn them off
155 		// after the 3 brightest lights have been selected !
156 		if (plamp->nStates > 1)
157 			m = 128;
158 
159 		if (m == 0)
160 			continue;
161 
162 		// Squared distance to the lamp
163 		dir.vx = pos->vx - plampstate->pos.vx;
164 		dir.vy = pos->vy - plampstate->pos.vy;
165 		dir.vz = pos->vz - plampstate->pos.vz;
166 		// VectorNoraml returns the sum of the squares
167 		// i.e. the squared distance
168 		// Normalize the lamp_actor vector to 1.0
169 		uint32 rr = VectorNormal(&dir, &normdir);
170 
171 #define DEBUG_PREPARE_LIGHTS 0
172 #if DEBUG_PREPARE_LIGHTS
173 		printf("Lamp %d rr %d actor %d %d %d lamp %d %d %d\nafs2 %d afe2 %d ans2 %d ane2 %d", i, rr, pos->vx, pos->vy, pos->vz, plampstate->pos.vx, plampstate->pos.vy,
174 		       plampstate->pos.vz, plampstate->ans2, plampstate->ane2, plampstate->afs2, plampstate->afe2);
175 #endif // #if DEBUG_PREPARE_LIGHTS
176 
177 		// Get the light direction
178 		// non-directional lamps e.g. bulbs, OMNI's
179 		// then the direction is vector from lamp to actor i.e. dir
180 		// For directional lamps, the -ve 3rd column of the matrix
181 		// is what we want because MAX definition is the lamp direction
182 		// is 0,0,-1 in the light frame
183 
184 		// The attenuation law is
185 		//
186 		// Intensity
187 		// multiplier
188 		//   |
189 		//   v         near_end             far_start
190 		//                 |                   |
191 		// 1.0 |           *********************
192 		//     |          *                     *
193 		//     |         *                       *
194 		//     |        *                         *
195 		//     |       *                           *
196 		//     |      *                             *
197 		//     |     *                               *
198 		//     |    *                                 *
199 		// 0.0 *****                                   *************
200 		//         |                                   |
201 		//       near_start                         far_end
202 		//
203 		//                   increasing distance --->
204 
205 		// Ignore the lamp if rr > atten_far_end^2
206 		// In pre-process of lights if atten_far_use = 0
207 		// then it sets atten_far_end to a very big number
208 
209 		// RLP schema >= 4 squared distances are stored in the light file
210 		uint32 afe2 = plampstate->afe2;
211 		// if ( ( afe2 < ATTEN_MAX_DISTANCE*ATTEN_MAX_DISTANCE ) && ( rr > afe2 ) ) continue;
212 		if (rr > afe2)
213 			continue;
214 
215 		// RLP schema >= 4 squared distances are stored in the light file
216 		uint32 ans2 = plampstate->ans2;
217 
218 		// Ignore the lamp if rr < atten_near_start^2
219 		// if ( ( ans2 < ATTEN_MAX_DISTANCE*ATTEN_MAX_DISTANCE ) && ( rr < ans2 ) ) continue;
220 		if (rr < ans2)
221 			continue;
222 
223 		// RLP schema >= 4 squared distances are stored in the light file
224 		uint32 ane2 = plampstate->ane2;
225 		uint32 afs2 = plampstate->afs2;
226 
227 		// Are we in the increasing portion ?
228 		if (rr < ane2) {
229 			m = ((rr - ans2) * m) / (ane2 - ans2);
230 		}
231 		// else are we in the decreasing portion ?
232 		else if ((afs2 < ATTEN_MAX_DISTANCE * ATTEN_MAX_DISTANCE) && (rr > afs2)) {
233 			m = ((afe2 - rr) * m) / (afe2 - afs2);
234 		}
235 // else we are in the constant portion : i.e. do nothing
236 
237 #if DEBUG_PREPARE_LIGHTS
238 		printf("Lamp %d rr %d m %d afe2-rr %d afe2-afs2 %d", i, rr, m, (afe2 - rr), (afe2 - afs2));
239 #endif // #if DEBUG_PREPARE_LIGHTS
240 
241 		// Ignore black lamps caused by the attenuation laws
242 		if (m == 0)
243 			continue;
244 
245 		// For conical beams i.e. spot lights
246 		//
247 		// If the light has a beam then take into account the effect on m due
248 		// to angle between the light->actor vector and the light's direction
249 		//
250 		// The attenuation law is
251 		//
252 		// At angles less than beam_angle/2 then multiplier = 1.0
253 		// At angles beyond beam_softness/2 then multiplier = 0.0
254 		// Between these angles have straight line law
255 		//
256 		// Intensity
257 		// multiplier
258 		//   |
259 		//   v         beam_angle/2
260 		//                 |
261 		// 1.0 |************
262 		//     |            *
263 		//     |             *
264 		//     |              *
265 		//     |               *
266 		//     |                *
267 		//     |                 *
268 		// 0.0 |                  *************
269 		//                        |
270 		//                 beam_softness/2
271 		//
272 		//     -----------------> angle between actor and the light direction
273 		//
274 
275 		if (plamp->type == SPOT_LIGHT) {
276 			// ba stored in the file is cos(beam_angle/2), so it can be
277 			// compared directly against the cos term we compute from the
278 			// dot product of light direction & light-actor direction
279 			int32 ba = plamp->ba;
280 			int32 bs = plamp->bs;
281 			// Get cos of the angle between light direciton & light-actor direction
282 			// These are both normalised to 4096, so end result has 1.0 = 4096*4096
283 			// Light direction is -ve z column of matrix (but normdir = -(light to actor vector))
284 			int32 cosa = normdir.vx * plampstate->vx + normdir.vy * plampstate->vy + normdir.vz * plampstate->vz;
285 
286 #if DEBUG_PREPARE_LIGHTS
287 			printf("actor %d %d %d lamp %d %d %d dir %d %d %d cosa %d bs %d ba %d", pos->vx, pos->vy, pos->vz, plampstate->pos.vx, plampstate->pos.vy,
288 			       plampstate->pos.vz, plampstate->vx, plampstate->vy, plampstate->vz, (cosa >> 12), bs, ba);
289 #endif // #if DEBUG_PREPARE_LIGHTS
290 
291 			// is the man more than 90 deg away from the beam direction
292 			if (cosa <= 0)
293 				continue;
294 
295 			// reduce its range so that 1.0=4096
296 			cosa = cosa >> 12;
297 
298 			// is the man outside the beam ?
299 			if (cosa < bs)
300 				continue;
301 
302 			// is the man inside the decreasing portion
303 			if (cosa < ba) {
304 				m = ((cosa - bs) * m) / (ba - bs);
305 			}
306 // else the man is inside the constant portion
307 // and no need to change m
308 #if DEBUG_PREPARE_LIGHTS
309 			printf("m %d", m);
310 #endif // #if DEBUG_PREPARE_LIGHTS
311 		}
312 
313 		// For cylindrical beams i.e. direct lights
314 		//
315 		// If the light has a beam then take into account the effect on m due
316 		// to the perpendicular distance between the light->actor vector and the light's direction vector
317 		//
318 		// The attenuation law is
319 		//
320 		// At distances less than beam_angle then multiplier = 1.0
321 		// At distance beyond beam_softness then multiplier = 0.0
322 		// Between these distance have straight line law
323 		//
324 		// Intensity
325 		// multiplier
326 		//   |
327 		//   v         beam_angle
328 		//                 |
329 		// 1.0 |************
330 		//     |            *
331 		//     |             *
332 		//     |              *
333 		//     |               *
334 		//     |                *
335 		//     |                 *
336 		// 0.0 |                  *************
337 		//                        |
338 		//                 beam_softness
339 		//
340 		//     -----------------> perpendicular distance between actor and the light direction
341 		//
342 		//    *  l - light position
343 		//    |+ -
344 		//    | + B
345 		//    |  +
346 		// A  |   +
347 		//    |    +
348 		//    |  /  +
349 		//    | / P  +
350 		//    |/      +|
351 		//    *       -  n - Light direction (normalised to unit vector)
352 		//    r          -
353 		//    -
354 		//
355 		// Actor position
356 		//
357 		// By pythagorous
358 		//
359 		// perpendicular distance = P = SQRT( A*A - B*B )
360 		//
361 		// B = ( r - l ) . n
362 		//       -   -     -
363 		//
364 		// A = ( r - l )
365 		//       -   -
366 		//
367 		// => P = SQRT( h*h - ( h . n )^2 )
368 		//
369 		// => P = SQRT( h*h - ( h . n )^2 )
370 		//
371 		// => P = SQRT( rr * ( 1 -  ( normdir . n )^2 ) )
372 
373 		if (plamp->type == DIRECT_LIGHT) {
374 			// Light direction is -ve z column of matrix (but normdir = -(light to actor vector))
375 			// These are both normalised to 4096, so end result has 1.0 = 4096*4096
376 			int32 cosa = normdir.vx * plampstate->vx + normdir.vy * plampstate->vy + normdir.vz * plampstate->vz;
377 
378 			// reduce its range so that 1.0=4096
379 			cosa = cosa >> 12;
380 
381 			if (cosa < -4096)
382 				cosa = -4096;
383 			if (cosa > 4096)
384 				cosa = 4096;
385 
386 			// to prevent overflows but make for slower code !
387 			int32 r = (int32)PXsqrt((PXfloat)rr);
388 			int32 P = (r * (int32)PXsqrt((PXfloat)(4096 * 4096 - cosa * cosa))) >> 12;
389 
390 			int32 ba = plamp->ba;
391 			int32 bs = plamp->bs;
392 
393 #if 0
394 			Message("xyz %d %d %d normdir %d %d %d",
395 			        pos->vx, pos->vy, pos->vz, normdir.vx, normdir.vy, normdir.vz) ;
396 			Message("r %d P %d cosa %d m = %d", r, P, cosa, m);
397 #endif
398 			// is the man outside the beam ?
399 			if (P > bs) {
400 				continue;
401 			}
402 
403 			// is the man inside the decreasing portion
404 			if (P > ba) {
405 				m = ((bs - P) * m) / (bs - ba);
406 			} else {
407 			}
408 			// else the man is inside the constant portion
409 			// and no need to change m
410 
411 			// The light direction is fixed
412 			normdir.vx = plampstate->vx;
413 			normdir.vy = plampstate->vy;
414 			normdir.vz = plampstate->vz;
415 		}
416 
417 		// Account for decay
418 		int32 decaym = 4096;
419 
420 		if (plamp->decay == DECAY_INV_SQR) {
421 			decaym = ((4096 * RLP_DECAY_CONSTANT * RLP_DECAY_CONSTANT) / rr);
422 		} else if (plamp->decay == DECAY_INV) {
423 			int32 r = (int32)PXsqrt((PXfloat)rr);
424 			decaym = ((4096 * RLP_DECAY_CONSTANT) / r);
425 		}
426 
427 		if (plamp->decay != DECAY_NONE) {
428 			if (decaym > 4096)
429 				decaym = 4096;
430 			m = (m * decaym) >> 12;
431 		}
432 
433 		// Ignore black lamps caused by the attenuation laws
434 		if (m == 0)
435 			continue;
436 
437 		// Change the multiplier to account for any shades
438 		psstate = shadelist->states;
439 		ppshade = shadelist->shades;
440 		for (s = 0; s < ns; ppshade++, psstate++, s++) {
441 			pshade = *ppshade;
442 			sstate = *psstate;
443 
444 			// Only do static shades in this loop - so we don't
445 			// get sudden light selection change due to animating shades
446 			// turning on/off
447 			if (pshade->nStates > 1)
448 				continue;
449 
450 			pshadestate = pshade->states + sstate;
451 			m = computeShadeMultiplierPC(pshadestate, pos, &plampstate->pos, m);
452 		}
453 
454 		// make the intensity = the multiplier * "value" (as in HSV)
455 		//   of the lights colour
456 		// RLP schema >= 4 v is stored in the lamps colour
457 		inten = m * plampstate->c.v;
458 
459 #if DEBUG_PREPARE_LIGHTS
460 		printf("%HLamp %d m %d rr %d v %d inten %d ans %d ane %d afs %d afe %d", i, m, rr, plampstate->c.v, inten, ans2, ane2, afs2, afe2);
461 #endif // #if DEBUG_PREPARE_LIGHTS
462 
463 		// Ignore lamps which are too dim
464 		if (inten < lampInfo[darkest].intens)
465 			continue;
466 
467 		lampInfo[i].direct.vx = normdir.vx;
468 		lampInfo[i].direct.vy = normdir.vy;
469 		lampInfo[i].direct.vz = normdir.vz;
470 
471 		lampInfo[i].index = i;
472 		lampInfo[i].intens = inten;
473 		lampInfo[i].mult = m;
474 		lampInfo[i].bounce = plamp->b;
475 		lampInfo[i].width = plamp->w;
476 		lampInfo[i].rr = rr;
477 
478 		// compare against the 3 existing intensities
479 		// convention is that 0 = brightest, 1 = middle, 2 = dimmest
480 		if (inten > lampInfo[brightest].intens) {
481 			// Shift the lamps down in intensity
482 			darkest = middle;
483 			middle = brightest;
484 			brightest = i;
485 		} else if (inten > lampInfo[middle].intens) {
486 			// Shift the lamps down in intensity
487 			darkest = middle;
488 			middle = i;
489 		} else { // inten must be > lampInfo[darkest].intens
490 			darkest = i;
491 		}
492 	}
493 
494 	pstate = lamplist->states;
495 
496 	// Do just the brightest lamp
497 	// for ( i = 0; i < 1; pintens++, pindex++, i++ )
498 
499 	// Put the 3 (at most) brightest lamps
500 	uint32 lamp_index[3];
501 	uint32 *pindex = lamp_index;
502 	lamp_index[0] = lampInfo[brightest].index;
503 	lamp_index[1] = lampInfo[middle].index;
504 	lamp_index[2] = lampInfo[darkest].index;
505 
506 	// The brightness of the light at the actor
507 
508 	// Ambient is 0-255, other lights are 0-4095
509 	int32 br = (ambient->r + ambient->g + ambient->g) << 4;
510 
511 	int32 nlights = 0;
512 	// If we have an ambient
513 	if (br != 0)
514 		nlights = 1;
515 
516 #if 0
517 	Message("Lamps %d %d %d", lamp_index[0], lamp_index[1], lamp_index[2]);
518 #endif
519 
520 	for (i = 0; i < 3; pindex++, i++) {
521 		uint32 index = *pindex;
522 		// Ignore unset lamps
523 		if (index >= MAX_NUMBER_LIGHTS)
524 			continue;
525 
526 		// Another lamp
527 		nlights++;
528 
529 		// Fill in the lighting direction matrix
530 		// | Lx1 Ly1 Lz1 |
531 		// | Lx2 Ly2 Lz2 |
532 		// | Lx3 Ly3 Lz3 |
533 		// Lxn, Lyn, Lzn is the x/y/z component of directional light n
534 		LampInfo *pLampInfo = &(lampInfo[index]);
535 		linfo[i] = *pLampInfo;
536 		VECTOR *padirs = &(pLampInfo->direct);
537 		lDirects->m[i][0] = (int16)padirs->vx;
538 		lDirects->m[i][1] = (int16)padirs->vy;
539 		lDirects->m[i][2] = (int16)padirs->vz;
540 
541 		// Fill in the lighting colour matrix
542 		// | Lr1 Lr2 Lr3 |
543 		// | Lg1 Lg2 Lg3 |
544 		// | Lb1 Lb2 Lb3 |
545 		// Lrn, Lgn, Lbn is the red/green/blue of directional light n
546 		// Should do this with GTE vector interpolation
547 		state = pstate[index];
548 		plamp = (lamplist->lamps[index]);
549 		PSXLampState *plampstat = plamp->states + state;
550 		m = pLampInfo->mult;
551 
552 		// For animating lights which are turned off - turn them off
553 		// after the 3 brightest lights have been selected !
554 		if (plamp->nStates > 1) {
555 			m = (m * plampstat->m) >> 7;
556 		}
557 
558 		// Change the multiplier to account for any shades
559 		psstate = shadelist->states;
560 		ppshade = shadelist->shades;
561 		for (s = 0; s < ns; ppshade++, psstate++, s++) {
562 			pshade = *ppshade;
563 			sstate = *psstate;
564 
565 			// Static shades have been done in the previous loop
566 			// so only do animating static shades in this loop
567 			if (pshade->nStates == 1)
568 				continue;
569 
570 			pshadestate = pshade->states + sstate;
571 			m = computeShadeMultiplierPC(pshadestate, pos, &plampstat->pos, m);
572 		}
573 
574 		lColours.m[0][i] = (int16)(((uint32)(plampstat->c.r) * m) >> 7);
575 		lColours.m[1][i] = (int16)(((uint32)(plampstat->c.g) * m) >> 7);
576 		lColours.m[2][i] = (int16)(((uint32)(plampstat->c.b) * m) >> 7);
577 
578 		linfo[i].colour.vx = (int16)lColours.m[0][i];
579 		linfo[i].colour.vy = (int16)lColours.m[1][i];
580 		linfo[i].colour.vz = (int16)lColours.m[2][i];
581 
582 		br = br + (lColours.m[0][i] + lColours.m[1][i] + lColours.m[2][i]);
583 
584 #if 0
585 		Message("Lamp %d %d RGB:%d %d %d dir:%d %d %d",
586 		        i, index,
587 		        lColours.m[0][i], lColours.m[1][i], lColours.m[2][i],
588 		        lDirects->m[i][0], lDirects->m[i][1], lDirects->m[i][2]);
589 #endif
590 
591 		// Only do the square root when we have to
592 		if (pLampInfo->width > 0)
593 			lampWidth[i] = (ONE * pLampInfo->width) / (pLampInfo->width + (int32)PXsqrt((PXfloat)pLampInfo->rr));
594 		else
595 			lampWidth[i] = 0;
596 
597 		lampBounce[i] = pLampInfo->bounce;
598 #if DEBUG_PREPARE_LIGHTS
599 		printf("%HActor %d %d %d Lamp %d %d m %d dir %d %d %d colour %d %d %d", pos->vx, pos->vy, pos->vz, i, index, m, lDirects->m[i][0], lDirects->m[i][1],
600 		       lDirects->m[i][2], lColours.m[0][i], lColours.m[1][i], lColours.m[2][i]);
601 #endif // #if DEBUG_PREPARE_LIGHTS
602 	}
603 	// Non-zero if any non-zero width's
604 	useLampWidth = lampWidth[0] | lampWidth[1] | lampWidth[2];
605 	// Non-zero if any non-zero bounces's
606 	useLampBounce = lampBounce[0] | lampBounce[1] | lampBounce[2];
607 
608 	// Set the GTE lighting colour matrix
609 	gte_SetColorMatrix_pc(&lColours);
610 
611 	// Set the ambient colour
612 	gte_SetBackColor_pc(ambient->r, ambient->g, ambient->b);
613 
614 	// Average out the brightness over the number of lamps
615 	if (nlights > 0) {
616 		br = br / nlights;
617 	}
618 	return br;
619 #undef DEBUG_PREPARE_LIGHTS
620 }
621 
622 //------------------------------------------------------------------------
623 // Set the GTE constant light variables
624 // Sets the direciton lights colour matrix
625 // Sets the ambient colour
626 // Fills in the lightDirects matrix
prepareLightsGlobalPC(MATRIXPC * lightDirects)627 int32 prepareLightsGlobalPC(MATRIXPC *lightDirects) {
628 	// Compute the lighting matrix which is :
629 	// | Lx1 Ly1 Lz1 |
630 	// | Lx2 Ly2 Lz2 |  * local2world_matrix
631 	// | Lx3 Ly3 Lz3 |
632 	// Where : Lxn, Lyn, Lzn is the x/y/z component of directional light n
633 	lightDirects->m[0][0] = (int16)Lights[0].vx;
634 	lightDirects->m[0][1] = (int16)Lights[0].vy;
635 	lightDirects->m[0][2] = (int16)Lights[0].vz;
636 	lightDirects->m[1][0] = (int16)Lights[1].vx;
637 	lightDirects->m[1][1] = (int16)Lights[1].vy;
638 	lightDirects->m[1][2] = (int16)Lights[1].vz;
639 	lightDirects->m[2][0] = (int16)Lights[2].vx;
640 	lightDirects->m[2][1] = (int16)Lights[2].vy;
641 	lightDirects->m[2][2] = (int16)Lights[2].vz;
642 
643 	MATRIXPC lightColours;
644 	// Fill in the lighting colour matrix
645 	// | Lr1 Lr2 Lr3 |
646 	// | Lg1 Lg2 Lg3 |
647 	// | Lb1 Lb2 Lb3 |
648 	lightColours.m[0][0] = (int16)Lights[0].r;
649 	lightColours.m[1][0] = (int16)Lights[0].g;
650 	lightColours.m[2][0] = (int16)Lights[0].b;
651 	lightColours.m[0][1] = (int16)Lights[1].r;
652 	lightColours.m[1][1] = (int16)Lights[1].g;
653 	lightColours.m[2][1] = (int16)Lights[1].b;
654 	lightColours.m[0][2] = (int16)Lights[2].r;
655 	lightColours.m[1][2] = (int16)Lights[2].g;
656 	lightColours.m[2][2] = (int16)Lights[2].b;
657 
658 	// Set the GTE lighting colour matrix
659 	gte_SetColorMatrix_pc(&lightColours);
660 
661 	// Set the ambient colour
662 	gte_SetBackColor_pc(Lights[3].r, Lights[3].g, Lights[3].b);
663 
664 	int32 br;
665 
666 	br = (Lights[3].r + Lights[3].g + Lights[3].b) << 4;
667 	br = br + Lights[0].r + Lights[0].g + Lights[0].b;
668 	br = br + Lights[1].r + Lights[1].g + Lights[1].b;
669 	br = br + Lights[2].r + Lights[2].g + Lights[2].b;
670 
671 	return br;
672 }
673 
674 } // End of namespace ICB
675