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