1 //********************************************************************************************
2 //*
3 //* This file is part of Egoboo.
4 //*
5 //* Egoboo is free software: you can redistribute it and/or modify it
6 //* under the terms of the GNU General Public License as published by
7 //* the Free Software Foundation, either version 3 of the License, or
8 //* (at your option) any later version.
9 //*
10 //* Egoboo is distributed in the hope that it will be useful, but
11 //* WITHOUT ANY WARRANTY; without even the implied warranty of
12 //* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 //* General Public License for more details.
14 //*
15 //* You should have received a copy of the GNU General Public License
16 //* along with Egoboo. If not, see <http://www.gnu.org/licenses/>.
17 //*
18 //********************************************************************************************
19
20 /// @file lighting.c
21 /// @brief Code for controlling the character and mesh lighting
22 /// @details
23
24 #include "lighting.h"
25
26 #include "egoboo_math.inl"
27
28 //--------------------------------------------------------------------------------------------
29 //--------------------------------------------------------------------------------------------
30 float light_a = 0.0f, light_d = 0.0f;
31 float light_nrm[3] = {0.0f, 0.0f, 0.0f};
32
33 //--------------------------------------------------------------------------------------------
34 //--------------------------------------------------------------------------------------------
35 static bool_t lighting_sum_project( lighting_cache_t * dst, lighting_cache_t * src, fvec3_t vec, int dir );
36
37 static float lighting_evaluate_cache_base( lighting_cache_base_t * lvec, fvec3_base_t nrm, float * amb );
38
39 //--------------------------------------------------------------------------------------------
40 //--------------------------------------------------------------------------------------------
lighting_vector_evaluate(lighting_vector_t lvec,fvec3_base_t nrm,float * dir,float * amb)41 void lighting_vector_evaluate( lighting_vector_t lvec, fvec3_base_t nrm, float * dir, float * amb )
42 {
43 float loc_dir, loc_amb;
44
45 if ( NULL == dir ) dir = &loc_dir;
46 if ( NULL == amb ) amb = &loc_amb;
47
48 *dir = 0.0f;
49 *amb = 0.0f;
50
51 if ( NULL == lvec ) return;
52
53 if ( nrm[kX] > 0.0f )
54 {
55 *dir += nrm[kX] * lvec[LVEC_PX];
56 }
57 else if ( nrm[kX] < 0.0f )
58 {
59 *dir -= nrm[kX] * lvec[LVEC_MX];
60 }
61
62 if ( nrm[kY] > 0.0f )
63 {
64 *dir += nrm[kY] * lvec[LVEC_PY];
65 }
66 else if ( nrm[kY] < 0.0f )
67 {
68 *dir -= nrm[kY] * lvec[LVEC_MY];
69 }
70
71 if ( nrm[kZ] > 0.0f )
72 {
73 *dir += nrm[kZ] * lvec[LVEC_PZ];
74 }
75 else if ( nrm[kZ] < 0.0f )
76 {
77 *dir -= nrm[kZ] * lvec[LVEC_MZ];
78 }
79
80 // the ambient is not summed
81 *amb += lvec[LVEC_AMB];
82 }
83
84 //--------------------------------------------------------------------------------------------
lighting_vector_sum(lighting_vector_t lvec,fvec3_base_t nrm,float direct,float ambient)85 void lighting_vector_sum( lighting_vector_t lvec, fvec3_base_t nrm, float direct, float ambient )
86 {
87 if ( nrm[kX] > 0.0f )
88 {
89 lvec[LVEC_PX] += nrm[kX] * direct;
90 }
91 else if ( nrm[kX] < 0.0f )
92 {
93 lvec[LVEC_MX] -= nrm[kX] * direct;
94 }
95
96 if ( nrm[kY] > 0.0f )
97 {
98 lvec[LVEC_PY] += nrm[kY] * direct;
99 }
100 else if ( nrm[kY] < 0.0f )
101 {
102 lvec[LVEC_MY] -= nrm[kY] * direct;
103 }
104
105 if ( nrm[kZ] > 0.0f )
106 {
107 lvec[LVEC_PZ] += nrm[kZ] * direct;
108 }
109 else if ( nrm[kZ] < 0.0f )
110 {
111 lvec[LVEC_MZ] -= nrm[kZ] * direct;
112 }
113
114 // the ambient is not summed
115 lvec[LVEC_AMB] += ambient;
116 }
117
118 //--------------------------------------------------------------------------------------------
119 //--------------------------------------------------------------------------------------------
lighting_cache_base_init(lighting_cache_base_t * cache)120 lighting_cache_base_t * lighting_cache_base_init( lighting_cache_base_t * cache )
121 {
122 if ( NULL == cache ) return NULL;
123
124 memset( cache, 0, sizeof( *cache ) );
125
126 return cache;
127 }
128
129 //--------------------------------------------------------------------------------------------
lighting_cache_base_max_light(lighting_cache_base_t * cache)130 bool_t lighting_cache_base_max_light( lighting_cache_base_t * cache )
131 {
132 int cnt;
133 float max_light;
134
135 // determine the lighting extents
136 max_light = ABS( cache->lighting[0] );
137 for ( cnt = 1; cnt < LIGHTING_VEC_SIZE - 1; cnt++ )
138 {
139 max_light = MAX( max_light, ABS( cache->lighting[cnt] ) );
140 }
141
142 cache->max_light = max_light;
143
144 return btrue;
145 }
146
147 //--------------------------------------------------------------------------------------------
lighting_cache_base_blend(lighting_cache_base_t * cold,lighting_cache_base_t * cnew,float keep)148 bool_t lighting_cache_base_blend( lighting_cache_base_t * cold, lighting_cache_base_t * cnew, float keep )
149 {
150 int tnc;
151 float max_delta;
152
153 if ( NULL == cold || NULL == cnew ) return bfalse;
154
155 // blend this in with the existing lighting
156 if ( 1.0f == keep )
157 {
158 // no change from last time
159 max_delta = 0.0f;
160 }
161 else if ( 0.0f == keep )
162 {
163 max_delta = 0.0f;
164 for ( tnc = 0; tnc < LIGHTING_VEC_SIZE; tnc++ )
165 {
166 float delta = ABS( cnew->lighting[tnc] - cold->lighting[tnc] );
167
168 cold->lighting[tnc] = cnew->lighting[tnc];
169
170 max_delta = MAX( max_delta, delta );
171 }
172 }
173 else
174 {
175 max_delta = 0.0f;
176 for ( tnc = 0; tnc < LIGHTING_VEC_SIZE; tnc++ )
177 {
178 float ftmp;
179
180 ftmp = cold->lighting[tnc];
181 cold->lighting[tnc] = ftmp * keep + cnew->lighting[tnc] * ( 1.0f - keep );
182 max_delta = MAX( max_delta, ABS( cold->lighting[tnc] - ftmp ) );
183 }
184 }
185
186 cold->max_delta = max_delta;
187
188 return btrue;
189 }
190
191 //--------------------------------------------------------------------------------------------
192 //--------------------------------------------------------------------------------------------
lighting_cache_init(lighting_cache_t * cache)193 lighting_cache_t * lighting_cache_init( lighting_cache_t * cache )
194 {
195 if ( NULL == cache ) return cache;
196
197 lighting_cache_base_init( &( cache->low ) );
198 lighting_cache_base_init( &( cache->hgh ) );
199
200 cache->max_delta = 0.0f;
201 cache->max_light = 0.0f;
202
203 return cache;
204 }
205
206 //--------------------------------------------------------------------------------------------
lighting_cache_max_light(lighting_cache_t * cache)207 bool_t lighting_cache_max_light( lighting_cache_t * cache )
208 {
209 if ( NULL == cache ) return bfalse;
210
211 // determine the lighting extents
212 lighting_cache_base_max_light( &( cache->low ) );
213 lighting_cache_base_max_light( &( cache->hgh ) );
214
215 // set the maximum direct light
216 cache->max_light = MAX( cache->low.max_light, cache->hgh.max_light );
217
218 return btrue;
219 }
220
221 //--------------------------------------------------------------------------------------------
lighting_cache_blend(lighting_cache_t * cache,lighting_cache_t * cnew,float keep)222 bool_t lighting_cache_blend( lighting_cache_t * cache, lighting_cache_t * cnew, float keep )
223 {
224 if ( NULL == cache || NULL == cnew ) return bfalse;
225
226 // find deltas
227 lighting_cache_base_blend( &( cache->low ), ( &cnew->low ), keep );
228 lighting_cache_base_blend( &( cache->hgh ), ( &cnew->hgh ), keep );
229
230 // find the absolute maximum delta
231 cache->max_delta = MAX( cache->low.max_delta, cache->hgh.max_delta );
232
233 return btrue;
234 }
235
236 //--------------------------------------------------------------------------------------------
237 //--------------------------------------------------------------------------------------------
lighting_project_cache(lighting_cache_t * dst,lighting_cache_t * src,fmat_4x4_t mat)238 bool_t lighting_project_cache( lighting_cache_t * dst, lighting_cache_t * src, fmat_4x4_t mat )
239 {
240 fvec3_t fwd, right, up;
241
242 if ( NULL == src ) return bfalse;
243
244 // blank the destination lighting
245 if ( NULL == lighting_cache_init( dst ) ) return bfalse;
246
247 // do the ambient
248 dst->low.lighting[LVEC_AMB] = src->low.lighting[LVEC_AMB];
249 dst->hgh.lighting[LVEC_AMB] = src->hgh.lighting[LVEC_AMB];
250
251 if ( src->max_light == 0.0f ) return btrue;
252
253 // grab the character directions
254 mat_getChrForward( mat.v, fwd.v ); // along body-fixed +y-axis
255 mat_getChrRight( mat.v, right.v ); // along body-fixed +x-axis
256 mat_getChrUp( mat.v, up.v ); // along body-fixed +z axis
257
258 fvec3_self_normalize( fwd.v );
259 fvec3_self_normalize( right.v );
260 fvec3_self_normalize( up.v );
261
262 // split the lighting cache up
263 lighting_sum_project( dst, src, right, 0 );
264 lighting_sum_project( dst, src, fwd, 2 );
265 lighting_sum_project( dst, src, up, 4 );
266
267 // determine the lighting extents
268 lighting_cache_max_light( dst );
269
270 return btrue;
271 }
272
273 //--------------------------------------------------------------------------------------------
lighting_cache_interpolate(lighting_cache_t * dst,lighting_cache_t * src[],float u,float v)274 bool_t lighting_cache_interpolate( lighting_cache_t * dst, lighting_cache_t * src[], float u, float v )
275 {
276 int tnc;
277 float wt_sum;
278
279 if ( NULL == src ) return bfalse;
280
281 if ( NULL == lighting_cache_init( dst ) ) return bfalse;
282
283 u = CLIP( u, 0.0f, 1.0f );
284 v = CLIP( v, 0.0f, 1.0f );
285
286 wt_sum = 0.0f;
287
288 if ( NULL != src[0] )
289 {
290 float wt = ( 1.0f - u ) * ( 1.0f - v );
291 for ( tnc = 0; tnc < LIGHTING_VEC_SIZE; tnc++ )
292 {
293 dst->low.lighting[tnc] += src[0]->low.lighting[tnc] * wt;
294 dst->hgh.lighting[tnc] += src[0]->hgh.lighting[tnc] * wt;
295 }
296 wt_sum += wt;
297 }
298
299 if ( NULL != src[1] )
300 {
301 float wt = u * ( 1.0f - v );
302 for ( tnc = 0; tnc < LIGHTING_VEC_SIZE; tnc++ )
303 {
304 dst->low.lighting[tnc] += src[1]->low.lighting[tnc] * wt;
305 dst->hgh.lighting[tnc] += src[1]->hgh.lighting[tnc] * wt;
306 }
307 wt_sum += wt;
308 }
309
310 if ( NULL != src[2] )
311 {
312 float wt = ( 1.0f - u ) * v;
313 for ( tnc = 0; tnc < LIGHTING_VEC_SIZE; tnc++ )
314 {
315 dst->low.lighting[tnc] += src[2]->low.lighting[tnc] * wt;
316 dst->hgh.lighting[tnc] += src[2]->hgh.lighting[tnc] * wt;
317 }
318 wt_sum += wt;
319 }
320
321 if ( NULL != src[3] )
322 {
323 float wt = u * v;
324 for ( tnc = 0; tnc < LIGHTING_VEC_SIZE; tnc++ )
325 {
326 dst->low.lighting[tnc] += src[3]->low.lighting[tnc] * wt;
327 dst->hgh.lighting[tnc] += src[3]->hgh.lighting[tnc] * wt;
328 }
329 wt_sum += wt;
330 }
331
332 if ( wt_sum > 0.0f )
333 {
334 if ( wt_sum != 1.0f )
335 {
336 for ( tnc = 0; tnc < LIGHTING_VEC_SIZE; tnc++ )
337 {
338 dst->low.lighting[tnc] /= wt_sum;
339 dst->hgh.lighting[tnc] /= wt_sum;
340 }
341 }
342
343 // determine the lighting extents
344 lighting_cache_max_light( dst );
345 }
346
347 return wt_sum > 0.0f;
348 }
349
350 //--------------------------------------------------------------------------------------------
lighting_cache_test(lighting_cache_t * src[],float u,float v,float * low_delta,float * hgh_delta)351 float lighting_cache_test( lighting_cache_t * src[], float u, float v, float * low_delta, float * hgh_delta )
352 {
353 /// @details BB@> estimate the maximum change in the lighting at this point from the
354 /// measured delta values
355
356 float delta, wt_sum;
357 float loc_low_delta, loc_hgh_delta;
358
359 delta = 0.0f;
360
361 if ( NULL == src ) return delta;
362
363 // handle the optional parameters
364 if ( NULL == low_delta ) low_delta = &loc_low_delta;
365 if ( NULL == hgh_delta ) hgh_delta = &loc_hgh_delta;
366
367 u = CLIP( u, 0.0f, 1.0f );
368 v = CLIP( v, 0.0f, 1.0f );
369
370 wt_sum = 0.0f;
371
372 if ( NULL != src[0] )
373 {
374 float wt = ( 1.0f - u ) * ( 1.0f - v );
375
376 delta += wt * src[0]->max_delta;
377 *low_delta += wt * src[0]->low.max_delta;
378 *hgh_delta += wt * src[0]->hgh.max_delta;
379
380 wt_sum += wt;
381 }
382
383 if ( NULL != src[1] )
384 {
385 float wt = u * ( 1.0f - v );
386
387 delta += wt * src[1]->max_delta;
388 *low_delta += wt * src[1]->low.max_delta;
389 *hgh_delta += wt * src[1]->hgh.max_delta;
390
391 wt_sum += wt;
392 }
393
394 if ( NULL != src[2] )
395 {
396 float wt = ( 1.0f - u ) * v;
397
398 delta += wt * src[2]->max_delta;
399 *low_delta += wt * src[2]->low.max_delta;
400 *hgh_delta += wt * src[2]->hgh.max_delta;
401
402 wt_sum += wt;
403 }
404
405 if ( NULL != src[3] )
406 {
407 float wt = u * v;
408
409 delta += wt * src[3]->max_delta;
410 *low_delta += wt * src[3]->low.max_delta;
411 *hgh_delta += wt * src[3]->hgh.max_delta;
412
413 wt_sum += wt;
414 }
415
416 if ( wt_sum > 0.0f )
417 {
418 delta /= wt_sum;
419 *low_delta /= wt_sum;
420 *hgh_delta /= wt_sum;
421 }
422
423 return delta;
424 }
425
426 //--------------------------------------------------------------------------------------------
lighting_sum_project(lighting_cache_t * dst,lighting_cache_t * src,fvec3_t vec,int dir)427 bool_t lighting_sum_project( lighting_cache_t * dst, lighting_cache_t * src, fvec3_t vec, int dir )
428 {
429 if ( NULL == src || NULL == dst ) return bfalse;
430
431 if ( dir < 0 || dir > 4 || 0 != ( dir&1 ) )
432 return bfalse;
433
434 if ( vec.x > 0 )
435 {
436 dst->low.lighting[dir+0] += vec.x * src->low.lighting[LVEC_PX];
437 dst->low.lighting[dir+1] += vec.x * src->low.lighting[LVEC_MX];
438
439 dst->hgh.lighting[dir+0] += vec.x * src->hgh.lighting[LVEC_PX];
440 dst->hgh.lighting[dir+1] += vec.x * src->hgh.lighting[LVEC_MX];
441 }
442 else if ( vec.x < 0 )
443 {
444 dst->low.lighting[dir+0] -= vec.x * src->low.lighting[LVEC_MX];
445 dst->low.lighting[dir+1] -= vec.x * src->low.lighting[LVEC_PX];
446
447 dst->hgh.lighting[dir+0] -= vec.x * src->hgh.lighting[LVEC_MX];
448 dst->hgh.lighting[dir+1] -= vec.x * src->hgh.lighting[LVEC_PX];
449 }
450
451 if ( vec.y > 0 )
452 {
453 dst->low.lighting[dir+0] += vec.y * src->low.lighting[LVEC_PY];
454 dst->low.lighting[dir+1] += vec.y * src->low.lighting[LVEC_MY];
455
456 dst->hgh.lighting[dir+0] += vec.y * src->hgh.lighting[LVEC_PY];
457 dst->hgh.lighting[dir+1] += vec.y * src->hgh.lighting[LVEC_MY];
458 }
459 else if ( vec.y < 0 )
460 {
461 dst->low.lighting[dir+0] -= vec.y * src->low.lighting[LVEC_MY];
462 dst->low.lighting[dir+1] -= vec.y * src->low.lighting[LVEC_PY];
463
464 dst->hgh.lighting[dir+0] -= vec.y * src->hgh.lighting[LVEC_MY];
465 dst->hgh.lighting[dir+1] -= vec.y * src->hgh.lighting[LVEC_PY];
466 }
467
468 if ( vec.z > 0 )
469 {
470 dst->low.lighting[dir+0] += vec.z * src->low.lighting[LVEC_PZ];
471 dst->low.lighting[dir+1] += vec.z * src->low.lighting[LVEC_MZ];
472
473 dst->hgh.lighting[dir+0] += vec.z * src->hgh.lighting[LVEC_PZ];
474 dst->hgh.lighting[dir+1] += vec.z * src->hgh.lighting[LVEC_MZ];
475 }
476 else if ( vec.z < 0 )
477 {
478 dst->low.lighting[dir+0] -= vec.z * src->low.lighting[LVEC_MZ];
479 dst->low.lighting[dir+1] -= vec.z * src->low.lighting[LVEC_PZ];
480
481 dst->hgh.lighting[dir+0] -= vec.z * src->hgh.lighting[LVEC_MZ];
482 dst->hgh.lighting[dir+1] -= vec.z * src->hgh.lighting[LVEC_PZ];
483 }
484
485 return btrue;
486 }
487
488 //--------------------------------------------------------------------------------------------
lighting_evaluate_cache_base(lighting_cache_base_t * lcache,fvec3_base_t nrm,float * amb)489 float lighting_evaluate_cache_base( lighting_cache_base_t * lcache, fvec3_base_t nrm, float * amb )
490 {
491 float dir;
492 float local_amb;
493
494 // handle the optional parameter
495 if ( NULL == amb ) amb = &local_amb;
496
497 // check for valid data
498 if ( NULL == lcache )
499 {
500 *amb = 0.0f;
501 return 0.0f;
502 }
503
504 // evaluate the dir vector
505 if ( 0.0f == lcache->max_light )
506 {
507 // only ambient light, or black
508 dir = 0.0f;
509 *amb = lcache->lighting[LVEC_AMB];
510 }
511 else
512 {
513 lighting_vector_evaluate( lcache->lighting, nrm, &dir, amb );
514 }
515
516 return dir + *amb;
517 }
518
519 //--------------------------------------------------------------------------------------------
lighting_evaluate_cache(lighting_cache_t * src,fvec3_base_t nrm,float z,aabb_t bbox,float * light_amb,float * light_dir)520 float lighting_evaluate_cache( lighting_cache_t * src, fvec3_base_t nrm, float z, aabb_t bbox, float * light_amb, float * light_dir )
521 {
522 float loc_light_amb = 0.0f, loc_light_dir = 0.0f;
523 float light_tot;
524 float hgh_wt, low_wt, amb ;
525
526 // check for valid parameters
527 if ( NULL == src || NULL == nrm ) return 0.0f;
528
529 // handle optional arguments
530 if ( NULL == light_amb ) light_amb = &loc_light_amb;
531 if ( NULL == light_dir ) light_dir = &loc_light_dir;
532
533 // determine the weighting
534 hgh_wt = ( z - bbox.mins[kZ] ) / ( bbox.maxs[kZ] - bbox.mins[kZ] );
535 hgh_wt = CLIP( hgh_wt, 0.0f, 1.0f );
536 low_wt = 1.0f - hgh_wt;
537
538 // initialize the output
539 light_tot = 0.0f;
540 *light_amb = 0.0f;
541 *light_dir = 0.0f;
542
543 // optimize the use of the lighting_evaluate_cache_base() function
544 if ( low_wt > 0.0f )
545 {
546 light_tot += low_wt * lighting_evaluate_cache_base( &( src->low ), nrm, &amb );
547 *light_amb += low_wt * amb;
548 }
549
550 // optimize the use of the lighting_evaluate_cache_base() function
551 if ( hgh_wt > 0.0f )
552 {
553 light_tot += hgh_wt * lighting_evaluate_cache_base( &( src->hgh ), nrm, &amb );
554 *light_amb += hgh_wt * amb;
555 }
556
557 *light_dir = light_tot - ( *light_amb );
558
559 return light_tot;
560 }
561
562 //--------------------------------------------------------------------------------------------
563 //--------------------------------------------------------------------------------------------
dyna_lighting_intensity(dynalight_t * pdyna,fvec3_base_t diff)564 float dyna_lighting_intensity( dynalight_t * pdyna, fvec3_base_t diff )
565 {
566 /// @details BB@> In the Aaron's lighting, the falloff function was
567 /// light = (255 - r^2 / falloff) / 255.0f
568 /// this has a definite max radius for the light, rmax = sqrt(falloff*255),
569 /// which was good because we could have a definite range for a given light
570 ///
571 /// This is not ideal because the light cuts off too abruptly. The new form of the
572 /// function is (in semi-maple notation)
573 ///
574 /// f(n,r) = integral( (1+y)^n * y * (1-y)^n, y = -1 .. r )
575 ///
576 /// this has the advantage that it forms a bell-shaped curve that approaches 0 smoothly
577 /// at r = -1 and r = 1. The lowest order term will always be quadratic in r, just like
578 /// Aaron's function. To eliminate terms like r^4 and higher order even terms, you can
579 // various f(n,r) with different n's. But combining terms with larger and larger
580 /// n means that the left-over terms that make the function approach zero smoothly
581 /// will have higher and higher powers of r (more expensive) and the cutoff will
582 /// be sharper and sharper (which is against the whole point of this type of function).
583 ///
584 /// Eliminating just the r^4 term gives the function
585 /// f(y) = 1 - y^2 * ( 3.0f - y^4 ) / 2
586 /// to make it match Aaron's function best, you have to scale the function by
587 /// y^2 = r^2 * 2 / 765 / falloff
588 ///
589 /// I have previously tried rational polynomial functions like
590 /// f(r) = k0 / (1 + k1 * r^2 ) + k2 / (1 + k3 * r^4 )
591 /// where the second term is to cancel make the function behave like Aaron's
592 /// at small r, and to make the function approximate same "size" of lighting area
593 /// as Aarons. An added benefit is that this function automatically has the right
594 /// "physics" behavior at large distances (falls off like 1/r^2). But that is the
595 /// exact problem because the infinite range means that it can potentally affect
596 /// the entire mesh, causing problems with computing a large number of lights
597
598 float rho_sqr;
599 float y2;
600 float level = 0.0f;
601
602 if ( NULL == diff ) return 0.0f;
603
604 if ( NULL == pdyna || 0.0f == pdyna->level ) return 0.0f;
605
606 rho_sqr = diff[kX] * diff[kX] + diff[kY] * diff[kY];
607 y2 = rho_sqr * 2.0f / 765.0f / pdyna->falloff;
608
609 if ( y2 > 1.0f ) return bfalse;
610
611 level = 1.0f - 0.5f * y2 * ( 3.0f - y2 * y2 );
612 level *= pdyna->level;
613
614 return level;
615 }
616
617 //--------------------------------------------------------------------------------------------
sum_dyna_lighting(dynalight_t * pdyna,lighting_vector_t lighting,fvec3_base_t nrm)618 bool_t sum_dyna_lighting( dynalight_t * pdyna, lighting_vector_t lighting, fvec3_base_t nrm )
619 {
620 fvec3_base_t local_nrm;
621
622 float rad_sqr, level;
623
624 if ( NULL == pdyna || NULL == lighting || NULL == nrm ) return bfalse;
625
626 level = 255 * dyna_lighting_intensity( pdyna, nrm );
627 if ( 0.0f == level ) return btrue;
628
629 // allow negative lighting, or blind spots will not work properly
630 rad_sqr = nrm[kX] * nrm[kX] + nrm[kY] * nrm[kY] + nrm[kZ] * nrm[kZ];
631
632 // make a local copy of the normal so we do not normalize the data in the calling function
633 memcpy( local_nrm, nrm, sizeof( local_nrm ) );
634
635 // do the normalization
636 if ( 1.0f != rad_sqr && 0.0f != rad_sqr )
637 {
638 float rad = SQRT( rad_sqr );
639 local_nrm[kX] /= rad;
640 local_nrm[kY] /= rad;
641 local_nrm[kZ] /= rad;
642 }
643
644 // sum the lighting
645 lighting_vector_sum( lighting, local_nrm, level, 0.0f );
646
647 return btrue;
648 }
649
650