1 /*---------------------------------------------------------------------------*
2 Project: Dolphin GD library
3 File: GDLight.c
4
5 Copyright 2001-2005 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Log: GDLight.c,v $
14 Revision 1.6 2007/11/22 13:13:23 iwai_yuma
15 (none)
16
17 Revision 1.5 2007/11/22 13:12:27 iwai_yuma
18 (none)
19
20 Revision 1.4 2007/11/21 19:23:14 iwai
21 Added #pragma warning(disable: 4005).
22
23 Revision 1.3 2006/02/20 04:24:39 mitu
24 Changed include path from dolphin/ to revolution/.
25
26 Revision 1.2 2005/08/17 10:55:09 hirose
27 Moved definition of sinf/cosf for WIN32 from gd.h
28
29 Revision 1.1.1.1 2005/05/12 02:15:49 yasuh-to
30 Ported from dolphin sheath tree.
31
32
33 4 2002/12/18 9:59 Hirose
34 Changed definition of BIG_NUMBER.
35
36 3 2002/12/18 9:41 Hirose
37 Added singularity check in GDSetSpecularDir( ).
38
39 2 2001/09/17 9:33p Hirose
40 Changes regarding specular light APIs.
41
42 1 2001/09/12 1:52p Carl
43 Initial revision of GD: Graphics Display List Library.
44 $NoKeywords: $
45 *---------------------------------------------------------------------------*/
46
47 #include <revolution/gd.h>
48 #include <revolution/os.h>
49 #include <math.h>
50
51 #pragma warning(disable: 4005)
52
53 /*---------------------------------------------------------------------------*/
54
55 #ifdef WIN32
56 #define cosf (float)cos
57 #define sqrtf (float)sqrt
58 #endif
59
60 /*---------------------------------------------------------------------------*/
61
62 /*---------------------------------------------------------------------------*/
63 // Name: GDSetLightAttn
64 //
65 // Description: Sets light attenuation parameters directly.
66 //
67 // Arguments: light HW light ID.
68 // a0,... Attenuation parameters.
69 //
70 // Returns: None
71 //
72 /*---------------------------------------------------------------------------*/
73
GDSetLightAttn(GXLightID light,f32 a0,f32 a1,f32 a2,f32 k0,f32 k1,f32 k2)74 void GDSetLightAttn ( GXLightID light,
75 f32 a0, f32 a1, f32 a2,
76 f32 k0, f32 k1, f32 k2 )
77 {
78 GDWriteXFCmdHdr( (u16) (XF_LIGHT0A0_ID + __GDLightID2Offset(light)), 6 );
79 GDWrite_f32(a0);
80 GDWrite_f32(a1);
81 GDWrite_f32(a2);
82 GDWrite_f32(k0);
83 GDWrite_f32(k1);
84 GDWrite_f32(k2);
85 }
86
87 /*---------------------------------------------------------------------------*/
88 // Name: GDSetLightSpot
89 //
90 // Description: Convenience function to set spotlight parameters.
91 //
92 // Arguments: light HW light ID.
93 // cutoff Cut off angle.
94 // spot_func Spot function characteristics.
95 // Returns:
96 //
97 /*---------------------------------------------------------------------------*/
98
99 #define PI 3.14159265358979323846F
100
GDSetLightSpot(GXLightID light,f32 cutoff,GXSpotFn spot_func)101 void GDSetLightSpot( GXLightID light, f32 cutoff, GXSpotFn spot_func )
102 {
103 f32 a0, a1, a2, r, d, cr;
104
105 if ( cutoff <= 0.0F || cutoff > 90.0F ) {
106 spot_func = GX_SP_OFF;
107 }
108
109 r = cutoff * PI / 180.0F;
110 cr = cosf(r);
111
112 switch ( spot_func ) {
113 case GX_SP_FLAT :
114 a0 = - 1000.0F * cr;
115 a1 = 1000.0F;
116 a2 = 0.0F;
117 break;
118 case GX_SP_COS :
119 a0 = - cr / ( 1.0F - cr );
120 a1 = 1.0F / ( 1.0F - cr );
121 a2 = 0.0F;
122 break;
123 case GX_SP_COS2 :
124 a0 = 0.0F;
125 a1 = - cr / ( 1.0F - cr );
126 a2 = 1.0F / ( 1.0F - cr );
127 break;
128 case GX_SP_SHARP :
129 d = ( 1.0F - cr ) * ( 1.0F - cr );
130 a0 = cr * ( cr - 2.0F ) / d;
131 a1 = 2.0F / d;
132 a2 = -1.0F / d;
133 break;
134 case GX_SP_RING1 :
135 d = ( 1.0F - cr ) * ( 1.0F - cr );
136 a0 = -4.0F * cr / d;
137 a1 = 4.0F * ( 1.0F + cr ) / d;
138 a2 = -4.0F / d;
139 break;
140 case GX_SP_RING2 :
141 d = ( 1.0F - cr ) * ( 1.0F - cr );
142 a0 = 1.0F - 2.0F * cr * cr / d;
143 a1 = 4.0F * cr / d;
144 a2 = -2.0F / d;
145 break;
146 case GX_SP_OFF :
147 default :
148 a0 = 1.0F;
149 a1 = 0.0F;
150 a2 = 0.0F;
151 break;
152 }
153
154 GDWriteXFCmdHdr( (u16) (XF_LIGHT0A0_ID + __GDLightID2Offset(light)), 3 );
155 GDWrite_f32(a0);
156 GDWrite_f32(a1);
157 GDWrite_f32(a2);
158 }
159
160 /*---------------------------------------------------------------------------*/
161 // Name: GDSetLightDistAttn
162 //
163 // Description: Convenience function for setting distance attenuation.
164 //
165 // Arguments: light HW light ID.
166 // ref_dist Reference distance.
167 // ref_br Reference brightness.
168 // dist_func Attenuation characteristics.
169 // Returns:
170 //
171 /*---------------------------------------------------------------------------*/
172
GDSetLightDistAttn(GXLightID light,f32 ref_dist,f32 ref_br,GXDistAttnFn dist_func)173 void GDSetLightDistAttn( GXLightID light, f32 ref_dist, f32 ref_br,
174 GXDistAttnFn dist_func )
175 {
176 f32 k0, k1, k2;
177
178 if ( ref_dist < 0.0F ||
179 ref_br <= 0.0F || ref_br >= 1.0F ) {
180 dist_func = GX_DA_OFF;
181 }
182
183 switch ( dist_func ) {
184 case GX_DA_GENTLE :
185 k0 = 1.0F;
186 k1 = ( 1.0F - ref_br ) / ( ref_br * ref_dist );
187 k2 = 0.0F;
188 break;
189 case GX_DA_MEDIUM :
190 k0 = 1.0F;
191 k1 = 0.5F * ( 1.0f - ref_br ) / ( ref_br * ref_dist );
192 k2 = 0.5F * ( 1.0f - ref_br ) / ( ref_br * ref_dist * ref_dist );
193 break;
194 case GX_DA_STEEP :
195 k0 = 1.0F;
196 k1 = 0.0F;
197 k2 = ( 1.0F - ref_br ) / ( ref_br * ref_dist * ref_dist );
198 break;
199 case GX_DA_OFF :
200 default :
201 k0 = 1.0F;
202 k1 = 0.0F;
203 k2 = 0.0F;
204 break;
205 }
206
207 GDWriteXFCmdHdr( (u16) (XF_LIGHT0K0_ID + __GDLightID2Offset(light)), 3 );
208 GDWrite_f32(k0);
209 GDWrite_f32(k1);
210 GDWrite_f32(k2);
211 }
212
213 /*---------------------------------------------------------------------------*/
214 // Name: GDSetLightColor
215 //
216 // Desc: Sets the Diffuse Color of the light directly.
217 //
218 // Args: light: HW light ID.
219 // color: Diffuse color.
220 //
221 /*---------------------------------------------------------------------------*/
222
GDSetLightColor(GXLightID light,GXColor color)223 void GDSetLightColor ( GXLightID light, GXColor color )
224 {
225 GDWriteXFCmd( (u16) (XF_LIGHT0COLOR_ID + __GDLightID2Offset(light)),
226 (((u32)color.r << 24) |
227 ((u32)color.g << 16) |
228 ((u32)color.b << 8) |
229 ((u32)color.a)) );
230 }
231
232 /*---------------------------------------------------------------------------*/
233 // Name: GDSetLightPos
234 //
235 // Description: Sets the position of light.
236 //
237 // Arguments: light: HW light ID.
238 // x, y, z: Light position/vector.
239 //
240 // Returns: None
241 //
242 /*---------------------------------------------------------------------------*/
243
GDSetLightPos(GXLightID light,f32 x,f32 y,f32 z)244 void GDSetLightPos ( GXLightID light, f32 x, f32 y, f32 z )
245 {
246 GDWriteXFCmdHdr( (u16) (XF_LIGHT0PX_ID + __GDLightID2Offset(light)), 3 );
247 GDWrite_f32(x);
248 GDWrite_f32(y);
249 GDWrite_f32(z);
250 }
251
252 /*---------------------------------------------------------------------------*/
253 // Name: GDSetLightDir
254 //
255 // Description: Sets the direction of (spot) light.
256 //
257 // Arguments: light: HW light ID.
258 // nx,ny,nz: Light direction vector.
259 //
260 // Returns: None
261 //
262 /*---------------------------------------------------------------------------*/
263
GDSetLightDir(GXLightID light,f32 nx,f32 ny,f32 nz)264 void GDSetLightDir ( GXLightID light, f32 nx, f32 ny, f32 nz )
265 {
266 GDWriteXFCmdHdr( (u16) (XF_LIGHT0DX_ID + __GDLightID2Offset(light)), 3 );
267 GDWrite_f32(nx);
268 GDWrite_f32(ny);
269 GDWrite_f32(nz);
270 }
271
272 /*---------------------------------------------------------------------------*/
273 // Name: GDSetSpecularDirHA
274 //
275 // Description: Sets the direction and half-angle vector of specular light.
276 //
277 // Arguments: light: HW light ID.
278 // nx,ny,nz: Light direction vector.
279 // hx,hy,hz: Half-angle vector.
280 //
281 // Returns: None
282 //
283 /*---------------------------------------------------------------------------*/
284
285 #define BIG_NUMBER 1.0E+18F
286
GDSetSpecularDirHA(GXLightID light,f32 nx,f32 ny,f32 nz,f32 hx,f32 hy,f32 hz)287 void GDSetSpecularDirHA ( GXLightID light, f32 nx, f32 ny, f32 nz, f32 hx, f32 hy, f32 hz )
288 {
289 f32 px, py, pz;
290
291 px = -nx * BIG_NUMBER;
292 py = -ny * BIG_NUMBER;
293 pz = -nz * BIG_NUMBER;
294
295 GDWriteXFCmdHdr( (u16) (XF_LIGHT0PX_ID + __GDLightID2Offset(light)), 6 );
296 GDWrite_f32(px);
297 GDWrite_f32(py);
298 GDWrite_f32(pz);
299 GDWrite_f32(hx);
300 GDWrite_f32(hy);
301 GDWrite_f32(hz);
302 }
303
304 /*---------------------------------------------------------------------------*/
305 // Name: GDSetSpecularDir
306 //
307 // Description: Sets the direction and half-angle vector of specular light.
308 // In this function, half-angle is calculated automatically.
309 //
310 // Arguments: light: HW light ID.
311 // nx,ny,nz: Light direction vector.
312 //
313 // Returns: None
314 //
315 /*---------------------------------------------------------------------------*/
316
GDSetSpecularDir(GXLightID light,f32 nx,f32 ny,f32 nz)317 void GDSetSpecularDir ( GXLightID light, f32 nx, f32 ny, f32 nz )
318 {
319 f32 px, py, pz;
320 f32 hx, hy, hz, mag;
321
322 // Compute half-angle vector
323 hx = -nx;
324 hy = -ny;
325 hz = (-nz + 1.0f);
326 mag = hx * hx + hy * hy + hz * hz;
327
328 if ( mag != 0.0f ) // Singularity check
329 {
330 mag = 1.0f / sqrtf(mag);
331 }
332
333 hx *= mag;
334 hy *= mag;
335 hz *= mag;
336
337 px = -nx * BIG_NUMBER;
338 py = -ny * BIG_NUMBER;
339 pz = -nz * BIG_NUMBER;
340
341 GDWriteXFCmdHdr( (u16) (XF_LIGHT0PX_ID + __GDLightID2Offset(light)), 6 );
342 GDWrite_f32(px);
343 GDWrite_f32(py);
344 GDWrite_f32(pz);
345 GDWrite_f32(hx);
346 GDWrite_f32(hy);
347 GDWrite_f32(hz);
348 }
349
350 #undef BIG_NUMBER
351
352 /*---------------------------------------------------------------------------*/
353 // Name: GDLoadLightObjIndx
354 //
355 // Desc: Loads lighting registers in xf block using array index
356 //
357 // Args: lt_obj_indx Index of light object in object array.
358 // light HW light ID.
359 //
360 /*---------------------------------------------------------------------------*/
361
GDLoadLightObjIndx(u32 lt_obj_indx,GXLightID light)362 void GDLoadLightObjIndx ( u32 lt_obj_indx, GXLightID light )
363 {
364 GDWriteXFIndxDCmd( (u16) (XF_LIGHT_BASE_ID + __GDLightID2Offset(light)),
365 XF_LIGHT_SIZE, (u16) lt_obj_indx );
366 }
367
368 /*---------------------------------------------------------------------------*/
369 //
370 // Name: GDSetChanAmbColor
371 //
372 // Desc: Sets Global Ambient Color in xform block
373 //
374 // Args: chan: Color name
375 // amb_color: Ambient color
376 //
377 /*---------------------------------------------------------------------------*/
378
GDSetChanAmbColor(GXChannelID chan,GXColor color)379 void GDSetChanAmbColor ( GXChannelID chan, GXColor color )
380 {
381 GDWriteXFCmd( (u16) (XF_AMBIENT0_ID + (chan & 1)),
382 (((u32)color.r << 24) |
383 ((u32)color.g << 16) |
384 ((u32)color.b << 8) |
385 ((u32)color.a)) );
386 }
387
388 /*---------------------------------------------------------------------------*/
389 //
390 // Name: GDSetChanMatColor
391 //
392 // Desc: Sets Global Material Color in xform block
393 //
394 // Args: chan: Color name
395 // amb_color: Material color
396 //
397 /*---------------------------------------------------------------------------*/
398
GDSetChanMatColor(GXChannelID chan,GXColor color)399 void GDSetChanMatColor ( GXChannelID chan, GXColor color )
400 {
401 GDWriteXFCmd( (u16) (XF_MATERIAL0_ID + (chan & 1)),
402 (((u32)color.r << 24) |
403 ((u32)color.g << 16) |
404 ((u32)color.b << 8) |
405 ((u32)color.a)) );
406 }
407
408 /*---------------------------------------------------------------------------*/
409 //
410 // Name: GDSetChanCtrl
411 //
412 // Desc: Sets lighting controls for a given lighting channel.
413 //
414 // Args: 1. chan: IN Channel ID.
415 // 2. enable: IN Enable lighting for this channel.
416 // 3. amb_src: IN Source for ambient color.
417 // 4. mat_src: IN Source for material color.
418 // 5. light_mask: IN Lights used in the lighting equation.
419 // 6. diff_fn: IN Diffuse function for lighting.
420 // 7. attn_fn: IN Attenuation function name.
421 //
422 /*---------------------------------------------------------------------------*/
423
GDSetChanCtrl(GXChannelID chan,GXBool enable,GXColorSrc amb_src,GXColorSrc mat_src,u32 light_mask,GXDiffuseFn diff_fn,GXAttnFn attn_fn)424 void GDSetChanCtrl ( GXChannelID chan,
425 GXBool enable,
426 GXColorSrc amb_src,
427 GXColorSrc mat_src,
428 u32 light_mask,
429 GXDiffuseFn diff_fn,
430 GXAttnFn attn_fn )
431 {
432 u32 reg;
433
434 reg = XF_COLOR0CNTRL_F_PS( mat_src, enable, (light_mask & 0x0f), amb_src,
435 ((attn_fn==GX_AF_SPEC) ? GX_DF_NONE : diff_fn),
436 (attn_fn != GX_AF_NONE),
437 (attn_fn != GX_AF_SPEC),
438 ((light_mask >> 4) & 0x0f) );
439 GDWriteXFCmd( (u16) (XF_COLOR0CNTRL_ID + (chan & 3)), reg );
440
441 if (chan == GX_COLOR0A0 || chan == GX_COLOR1A1)
442 {
443 GDWriteXFCmd( (u16) (XF_COLOR0CNTRL_ID + ( chan - 2)), reg );
444 }
445 }
446
447