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