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