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