]> icculus.org git repositories - taylor/freespace2.git/blob - src/lighting/lighting.cpp
Initial revision
[taylor/freespace2.git] / src / lighting / lighting.cpp
1 /*
2  * $Logfile: /Freespace2/code/Lighting/Lighting.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Code to calculate dynamic lighting on a vertex.
8  *
9  * $Log$
10  * Revision 1.1  2002/05/03 03:28:09  root
11  * Initial revision
12  *
13  * 
14  * 5     6/22/99 2:22p Dave
15  * Doh. Fixed a type bug.
16  * 
17  * 4     6/18/99 5:16p Dave
18  * Added real beam weapon lighting. Fixed beam weapon sounds. Added MOTD
19  * dialog to PXO screen.
20  * 
21  * 3     5/09/99 6:00p Dave
22  * Lots of cool new effects. E3 build tweaks.
23  * 
24  * 2     10/07/98 10:53a Dave
25  * Initial checkin.
26  * 
27  * 1     10/07/98 10:49a Dave
28  * 
29  * 37    4/12/98 9:56a John
30  * Made lighting detail flags work.   Made explosions cast light on
31  * highest.
32  * 
33  * 36    4/10/98 5:20p John
34  * Changed RGB in lighting structure to be ubytes.  Removed old
35  * not-necessary 24 bpp software stuff.
36  * 
37  * 35    4/04/98 5:17p John
38  * Added sun stuff.  Made Glide optionally use 8-bpp textures.  (looks
39  * bad)
40  * 
41  * 34    3/14/98 3:07p Adam
42  * re-added some lighting changes
43  * 
44  * 33    3/13/98 4:10p John
45  * Put back in Adam's old lighting values.
46  * 
47  * 32    3/12/98 8:42a John
48  * Checked in Adam's new lighting values.
49  * Checked in changes to timing models code
50  * 
51  * 31    2/26/98 5:42p John
52  * 
53  * 30    2/26/98 3:25p John
54  * Added code to turn on/off lighting.   Made lighting used dist*dist
55  * instead of dist
56  * 
57  * 29    2/19/98 10:51p John
58  * Enabled colored lighting for hardware (Glide)
59  * 
60  * 28    2/13/98 5:00p John
61  * Made lighting push functions return number of releveent lights.
62  * 
63  * 27    1/29/98 3:36p Johnson
64  * JAS:  Fixed some problems with pre_player_entry.
65  * 
66  * 26    1/29/98 3:16p Allender
67  * fix compiler warnings
68  * 
69  * 25    1/29/98 8:14a John
70  * Added support for RGB lighting
71  * 
72  * 24    1/23/98 5:08p John
73  * Took L out of vertex structure used B (blue) instead.   Took all small
74  * fireballs out of fireball types and used particles instead.  Fixed some
75  * debris explosion things.  Restructured fireball code.   Restructured
76  * some lighting code.   Made dynamic lighting on by default. Made groups
77  * of lasers only cast one light.  Made fireballs not cast light.
78  * 
79  * 23    1/10/98 1:14p John
80  * Added explanation to debug console commands
81  * 
82  * 22    1/02/98 11:53a Adam
83  * Changed lighting mode to darken.  Changed ambient and reflect to .75
84  * and .50 to compensate.
85  * 
86  * 21    1/02/98 11:28a Adam
87  * Changed default ambient to 0.55f from 0.45f.
88  * 
89  * 20    12/21/97 4:33p John
90  * Made debug console functions a class that registers itself
91  * automatically, so you don't need to add the function to
92  * debugfunctions.cpp.  
93  * 
94  * 19    12/17/97 7:53p John
95  * Fixed a bug where gunpoint for flashes were in world coordinates,
96  * should have been object.
97  * 
98  * 18    12/17/97 5:11p John
99  * Added brightening back into fade table.  Added code for doing the fast
100  * dynamic gun flashes and thruster flashes.
101  * 
102  * 17    12/12/97 3:02p John
103  * First Rev of Ship Shadows
104  * 
105  * 16    11/07/97 7:24p John
106  * changed lighting to take two ranges.
107  * In textest, added test code to draw nebulas
108  * 
109  * 15    11/04/97 9:19p John
110  * Optimized dynamic lighting more.
111  * 
112  * 14    10/29/97 5:05p John
113  * Changed dynamic lighting to only rotate and calculate lighting for
114  * point lights that are close to an object.  Changed lower framerate cap
115  * from 4 to .5.
116  * 
117  * 13    9/24/97 12:37p Mike
118  * Crank ambient lighting from 0.2 to 0.6
119  * 
120  * 12    9/17/97 9:44a John
121  * fixed bug with lighting set to default
122  * 
123  * 11    9/11/97 5:36p Jasen
124  * Changed ambient and reflective lighting values to give a bit more
125  * realism to the game.  Yeah, yeah, I know I am not a programmer.
126  * 
127  * 10    4/24/97 2:58p John
128  * 
129  * 9     4/24/97 11:49a John
130  * added new lighting commands to console.
131  * 
132  * 8     4/23/97 5:26p John
133  * First rev of new debug console stuff.
134  * 
135  * 7     4/22/97 3:14p John
136  * upped the ambient light
137  * 
138  * 6     4/17/97 6:06p John
139  * New code/data for v19 of BSPGEN with smoothing and zbuffer
140  * optimizations.
141  * 
142  * 5     4/08/97 5:18p John
143  * First rev of decent (dynamic, correct) lighting in FreeSpace.
144  * 
145  * 4     2/17/97 5:18p John
146  * Added a bunch of RCS headers to a bunch of old files that don't have
147  * them.
148  * 
149  * 3     1/30/97 9:35a Hoffoss
150  * Added header for files.
151  *
152  * $NoKeywords: $
153  */
154
155 #include "pstypes.h"
156 #include "vecmat.h"
157 #include "3d.h"
158 #include "fvi.h"
159 #include "key.h"
160 #include "lighting.h"
161 #include "timer.h"
162 #include "systemvars.h"
163
164 #define MAX_LIGHTS 256
165 #define MAX_LIGHT_LEVELS 16
166
167 #define LT_DIRECTIONAL  0               // A light like a sun
168 #define LT_POINT                        1               // A point light, like an explosion
169 #define LT_TUBE                 2               // A tube light, like a fluorescent light
170
171 typedef struct light {
172         int             type;                                                   // What type of light this is
173         vector  vec;                                                    // location in world space of a point light or the direction of a directional light or the first point on the tube for a tube light
174         vector  vec2;                                                   // second point on a tube light
175         vector  local_vec;                                      // rotated light vector
176         vector  local_vec2;                                     // rotated 2nd light vector for a tube light
177         float           intensity;                                      // How bright the light is.
178         float           rad1, rad1_squared;             // How big of an area a point light affect.  Is equal to l->intensity / MIN_LIGHT;
179         float           rad2, rad2_squared;             // How big of an area a point light affect.  Is equal to l->intensity / MIN_LIGHT;
180         float           r,g,b;                                          // The color components of the light
181         int             ignore_objnum;                          // Don't light this object.  Used to optimize weapons casting light on parents.
182         int             affected_objnum;                        // for "unique lights". ie, lights which only affect one object (trust me, its useful)
183 } light;
184
185 light Lights[MAX_LIGHTS];
186 int Num_lights=0;
187
188 light *Relevent_lights[MAX_LIGHTS][MAX_LIGHT_LEVELS];
189 int Num_relevent_lights[MAX_LIGHT_LEVELS];
190 int Num_light_levels = 0;
191
192 #define MAX_STATIC_LIGHTS                       10
193 light * Static_light[MAX_STATIC_LIGHTS];
194 int Static_light_count = 0;
195
196 static int Light_in_shadow = 0; // If true, this means we're in a shadow
197
198 #define LM_BRIGHTEN  0
199 #define LM_DARKEN    1
200
201 #define MIN_LIGHT 0.03f // When light drops below this level, ignore it.  Must be non-zero! (1/32)
202
203
204 int Lighting_off = 0;
205
206 // For lighting values, 0.75 is full intensity
207
208 #if 1           // ADAM'S new stuff
209         int Lighting_mode = LM_BRIGHTEN;
210         #define AMBIENT_LIGHT_DEFAULT           0.15f           //0.10f
211         #define REFLECTIVE_LIGHT_DEFAULT 0.75f          //0.90f
212 #else
213         int Lighting_mode = LM_DARKEN;
214         #define AMBIENT_LIGHT_DEFAULT           0.75f           //0.10f
215         #define REFLECTIVE_LIGHT_DEFAULT 0.50f          //0.90f
216 #endif
217
218 float Ambient_light = AMBIENT_LIGHT_DEFAULT;
219 float Reflective_light = REFLECTIVE_LIGHT_DEFAULT;
220
221 int Lighting_flag = 1;
222
223 DCF(light,"Changes lighting parameters")
224 {
225         if ( Dc_command )       {
226                 dc_get_arg(ARG_STRING);
227                 if ( !strcmp( Dc_arg, "ambient" ))      {
228                         dc_get_arg(ARG_FLOAT);
229                         if ( (Dc_arg_float < 0.0f) || (Dc_arg_float > 1.0f) )   {
230                                 Dc_help = 1;
231                         } else {
232                                 Ambient_light = Dc_arg_float;
233                         } 
234                 } else if ( !strcmp( Dc_arg, "reflect" ))       {
235                         dc_get_arg(ARG_FLOAT);
236                         if ( (Dc_arg_float < 0.0f) || (Dc_arg_float > 1.0f) )   {
237                                 Dc_help = 1;
238                         } else {
239                                 Reflective_light = Dc_arg_float;
240                         } 
241                 } else if ( !strcmp( Dc_arg, "default" ))       {
242                         Lighting_mode = LM_BRIGHTEN;
243                         Ambient_light = AMBIENT_LIGHT_DEFAULT;
244                         Reflective_light = REFLECTIVE_LIGHT_DEFAULT;
245                         Lighting_flag = 0;
246                 } else if ( !strcmp( Dc_arg, "mode" ))  {
247                         dc_get_arg(ARG_STRING);
248                         if ( !strcmp(Dc_arg, "light") ) {
249                                 Lighting_mode = LM_BRIGHTEN;
250                         } else if ( !strcmp(Dc_arg, "darken"))  { 
251                                 Lighting_mode = LM_DARKEN;
252                         } else {
253                                 Dc_help = 1;
254                         }
255                 } else if ( !strcmp( Dc_arg, "dynamic" ))       {
256                         dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);                
257                         if ( Dc_arg_type & ARG_TRUE )   Lighting_flag = 1;      
258                         else if ( Dc_arg_type & ARG_FALSE ) Lighting_flag = 0;  
259                         else if ( Dc_arg_type & ARG_NONE ) Lighting_flag ^= 1;  
260                 } else if ( !strcmp( Dc_arg, "on" ) )   {
261                         Lighting_off = 0;
262                 } else if ( !strcmp( Dc_arg, "off" ) )  {
263                         Lighting_off = 1;
264                 } else {
265                         // print usage, not stats
266                         Dc_help = 1;
267                 }
268         }
269
270         if ( Dc_help )  {
271                 dc_printf( "Usage: light keyword\nWhere keyword can be in the following forms:\n" );
272                 dc_printf( "light on|off          Turns all lighting on/off\n" );
273                 dc_printf( "light default         Resets lighting to all default values\n" );
274                 dc_printf( "light ambient X       Where X is the ambient light between 0 and 1.0\n" );
275                 dc_printf( "light reflect X       Where X is the material reflectiveness between 0 and 1.0\n" );
276                 dc_printf( "light dynamic [bool]  Toggles dynamic lighting on/off\n" );
277                 dc_printf( "light mode [light|darken]   Changes the lighting mode.\n" );
278                 dc_printf( "   Where 'light' means the global light adds light.\n");
279                 dc_printf( "   and 'darken' means the global light subtracts light.\n");
280                 Dc_status = 0;  // don't print status if help is printed.  Too messy.
281         }
282
283         if ( Dc_status )        {
284                 dc_printf( "Ambient light is set to %.2f\n", Ambient_light );
285                 dc_printf( "Reflective light is set to %.2f\n", Reflective_light );
286                 dc_printf( "Dynamic lighting is: %s\n", (Lighting_flag?"on":"off") );
287                 switch( Lighting_mode ) {
288                 case LM_BRIGHTEN:   dc_printf( "Lighting mode is: light\n" ); break;
289                 case LM_DARKEN:   dc_printf( "Lighting mode is: darken\n" ); break;
290                 default: dc_printf( "Lighting mode is: UNKNOWN\n" ); break;
291                 }
292         }
293 }
294
295 void light_reset()
296 {
297         int idx;
298
299         // reset static (sun) lights
300         for(idx=0; idx<MAX_STATIC_LIGHTS; idx++){
301                 Static_light[idx] = NULL;
302         }
303         Static_light_count = 0;
304
305         Num_lights = 0;
306         light_filter_reset();
307 }
308
309 // Rotates the light into the current frame of reference
310 void light_rotate(light * l)
311 {
312         switch( l->type )       {
313         case LT_DIRECTIONAL:
314                 // Rotate the light direction into local coodinates
315                 vm_vec_rotate(&l->local_vec, &l->vec, &Light_matrix );
316                 break;
317         
318         case LT_POINT:  {
319                         vector tempv;
320                         // Rotate the point into local coordinates
321                         vm_vec_sub(&tempv, &l->vec, &Light_base );
322                         vm_vec_rotate(&l->local_vec, &tempv, &Light_matrix );
323                 }
324                 break;
325         
326         case LT_TUBE:{
327                         vector tempv;
328                         // Rotate the point into local coordinates
329                         vm_vec_sub(&tempv, &l->vec, &Light_base );
330                         vm_vec_rotate(&l->local_vec, &tempv, &Light_matrix );
331                         
332                         // Rotate the point into local coordinates
333                         vm_vec_sub(&tempv, &l->vec2, &Light_base );
334                         vm_vec_rotate(&l->local_vec2, &tempv, &Light_matrix );
335                 }
336                 break;
337
338         default:
339                 Int3(); // Invalid light type
340         }
341 }
342
343 // Sets the ambient lighting level.
344 // Ignored for now.
345 void light_set_ambient(float ambient_light)
346 {
347 }
348
349 void light_add_directional( vector *dir, float intensity, float r, float g, float b )
350 {
351         light * l;
352
353         if ( Lighting_off ) return;
354
355         if ( Num_lights >= MAX_LIGHTS ) return;
356
357         l = &Lights[Num_lights++];
358
359         l->type = LT_DIRECTIONAL;
360
361         if ( Lighting_mode == LM_BRIGHTEN )     {
362                 vm_vec_copy_scale( &l->vec, dir, -1.0f );
363         } else {
364                 vm_vec_copy_scale( &l->vec, dir, 1.0f );
365         }
366
367         l->r = r;
368         l->g = g;
369         l->b = b;
370         l->intensity = intensity;
371         l->rad1 = 0.0f;
372         l->rad2 = 0.0f;
373         l->rad1_squared = l->rad1*l->rad1;
374         l->rad2_squared = l->rad2*l->rad2;
375         l->ignore_objnum = -1;
376         l->affected_objnum = -1;
377                 
378         Assert( Num_light_levels <= 1 );
379 //      Relevent_lights[Num_relevent_lights[Num_light_levels-1]++][Num_light_levels-1] = l;
380
381         if(Static_light_count < MAX_STATIC_LIGHTS){             
382                 Static_light[Static_light_count++] = l;
383         }
384 }
385
386
387 void light_add_point( vector * pos, float rad1, float rad2, float intensity, float r, float g, float b, int ignore_objnum )
388 {
389         light * l;
390
391         if ( Lighting_off ) return;
392
393         if (!Lighting_flag) return;
394
395 //      if ( keyd_pressed[KEY_LSHIFT] ) return;
396
397         if ( Num_lights >= MAX_LIGHTS ) {
398                 mprintf(( "Out of lights!\n" ));
399                 return;
400         }
401
402         l = &Lights[Num_lights++];
403
404         l->type = LT_POINT;
405         l->vec = *pos;
406         l->r = r;
407         l->g = g;
408         l->b = b;
409         l->intensity = intensity;
410         l->rad1 = rad1;
411         l->rad2 = rad2;
412         l->rad1_squared = l->rad1*l->rad1;
413         l->rad2_squared = l->rad2*l->rad2;
414         l->ignore_objnum = ignore_objnum;
415         l->affected_objnum = -1;
416
417         Assert( Num_light_levels <= 1 );
418 //      Relevent_lights[Num_relevent_lights[Num_light_levels-1]++][Num_light_levels-1] = l;
419 }
420
421 void light_add_point_unique( vector * pos, float rad1, float rad2, float intensity, float r, float g, float b, int affected_objnum)
422 {
423         light * l;
424
425         if ( Lighting_off ) return;
426
427         if (!Lighting_flag) return;
428
429 //      if ( keyd_pressed[KEY_LSHIFT] ) return;
430
431         if ( Num_lights >= MAX_LIGHTS ) {
432                 mprintf(( "Out of lights!\n" ));
433                 return;
434         }
435
436         l = &Lights[Num_lights++];
437
438         l->type = LT_POINT;
439         l->vec = *pos;
440         l->r = r;
441         l->g = g;
442         l->b = b;
443         l->intensity = intensity;
444         l->rad1 = rad1;
445         l->rad2 = rad2;
446         l->rad1_squared = l->rad1*l->rad1;
447         l->rad2_squared = l->rad2*l->rad2;
448         l->ignore_objnum = -1;
449         l->affected_objnum = affected_objnum;
450
451         Assert( Num_light_levels <= 1 );
452 }
453
454 // for now, tube lights only affect one ship (to keep the filter stuff simple)
455 void light_add_tube(vector *p0, vector *p1, float r1, float r2, float intensity, float r, float g, float b, int affected_objnum)
456 {
457         light * l;
458
459         if ( Lighting_off ) return;
460
461         if (!Lighting_flag) return;
462
463 //      if ( keyd_pressed[KEY_LSHIFT] ) return;
464
465         if ( Num_lights >= MAX_LIGHTS ) {
466                 mprintf(( "Out of lights!\n" ));
467                 return;
468         }
469
470         l = &Lights[Num_lights++];
471
472         l->type = LT_TUBE;
473         l->vec = *p0;
474         l->vec2 = *p1;
475         l->r = r;
476         l->g = g;
477         l->b = b;
478         l->intensity = intensity;
479         l->rad1 = r1;
480         l->rad2 = r2;
481         l->rad1_squared = l->rad1*l->rad1;
482         l->rad2_squared = l->rad2*l->rad2;
483         l->ignore_objnum = -1;
484         l->affected_objnum = affected_objnum;
485
486         Assert( Num_light_levels <= 1 );
487 }
488
489 // Reset the list of lights to point to all lights.
490 void light_filter_reset()
491 {
492         int i;
493         light *l;
494
495         if ( Lighting_off ) return;
496
497         Num_light_levels = 1;
498
499         int n = Num_light_levels-1;
500         Num_relevent_lights[n] = 0;
501
502         l = Lights;
503         for (i=0; i<Num_lights; i++, l++ )      {
504                 Relevent_lights[Num_relevent_lights[n]++][n] = l;
505         }
506 }
507
508
509 // Makes a list of only the lights that will affect
510 // the sphere specified by 'pos' and 'rad' and 'objnum'
511 int light_filter_push( int objnum, vector *pos, float rad )
512 {
513         int i;
514         light *l;
515
516         if ( Lighting_off ) return 0;
517
518         light_filter_reset();
519
520         int n1,n2;
521         n1 = Num_light_levels-1;
522         n2 = Num_light_levels;
523         Num_light_levels++;
524         Assert( Num_light_levels < MAX_LIGHT_LEVELS );
525
526         Num_relevent_lights[n2] = 0;
527
528         for (i=0; i<Num_relevent_lights[n1]; i++ )      {
529                 l = Relevent_lights[i][n1];
530
531                 switch( l->type )       {
532                 case LT_DIRECTIONAL:
533                         //Relevent_lights[Num_relevent_lights[n2]++][n2] = l;
534                         break;
535
536                 case LT_POINT:  {
537                                 // if this is a "unique" light source, it only affects one guy
538                                 if(l->affected_objnum >= 0){
539                                         if(objnum == l->affected_objnum){
540                                                 vector to_light;
541                                                 float dist_squared, max_dist_squared;
542                                                 vm_vec_sub( &to_light, &l->vec, pos );
543                                                 dist_squared = vm_vec_mag_squared(&to_light);
544
545                                                 max_dist_squared = l->rad2+rad;
546                                                 max_dist_squared *= max_dist_squared;
547                                                 
548                                                 if ( dist_squared < max_dist_squared )  {
549                                                         Relevent_lights[Num_relevent_lights[n2]++][n2] = l;
550                                                 }
551                                         }
552                                 }
553                                 // otherwise check all relevant objects
554                                 else {
555                                         // if ( (l->ignore_objnum<0) || (l->ignore_objnum != objnum) )  {
556                                                 vector to_light;
557                                                 float dist_squared, max_dist_squared;
558                                                 vm_vec_sub( &to_light, &l->vec, pos );
559                                                 dist_squared = vm_vec_mag_squared(&to_light);
560
561                                                 max_dist_squared = l->rad2+rad;
562                                                 max_dist_squared *= max_dist_squared;
563                                                 
564                                                 if ( dist_squared < max_dist_squared )  {
565                                                         Relevent_lights[Num_relevent_lights[n2]++][n2] = l;
566                                                 }
567                                         // }
568                                 }
569                         }
570                         break;
571
572                 // hmm. this could probably be more optimal
573                 case LT_TUBE:
574                         // all tubes are "unique" light sources for now
575                         if((l->affected_objnum >= 0) && (objnum == l->affected_objnum)){
576                                 Relevent_lights[Num_relevent_lights[n2]++][n2] = l;
577                         }
578                         break;
579
580                 default:
581                         Int3(); // Invalid light type
582                 }
583         }
584
585         return Num_relevent_lights[n2];
586 }
587
588 int is_inside( vector *min, vector *max, vector * p0, float rad )
589 {
590         float *origin = (float *)&p0->x;
591         float *minB = (float *)min;
592         float *maxB = (float *)max;
593         int i;
594
595         for (i=0; i<3; i++ )    {
596                 if ( origin[i] < minB[i] - rad )        {
597                         return 0;
598                 } else if (origin[i] > maxB[i] + rad )  {
599                         return 0;
600                 }
601         }
602         return 1;
603 }
604
605
606 int light_filter_push_box( vector *min, vector *max )
607 {
608         int i;
609         light *l;
610
611         if ( Lighting_off ) return 0;
612
613         int n1,n2;
614         n1 = Num_light_levels-1;
615         n2 = Num_light_levels;
616         Num_light_levels++;
617
618 //      static int mll = -1;
619 //      if ( Num_light_levels > mll )   {
620 //              mll = Num_light_levels;
621 //              mprintf(( "Max level = %d\n", mll ));
622 //      }
623
624         Assert( Num_light_levels < MAX_LIGHT_LEVELS );
625
626         Num_relevent_lights[n2] = 0;
627
628         for (i=0; i<Num_relevent_lights[n1]; i++ )      {
629                 l = Relevent_lights[i][n1];
630
631                 switch( l->type )       {
632                 case LT_DIRECTIONAL:
633                         Int3(); //Relevent_lights[Num_relevent_lights[n2]++][n2] = l;
634                         break;
635
636                 case LT_POINT:  {
637                                 // l->local_vec
638                                 if ( is_inside( min, max, &l->local_vec, l->rad2 ) )    {
639                                         Relevent_lights[Num_relevent_lights[n2]++][n2] = l;
640                                 }
641                         }
642                         break;
643
644                 case LT_TUBE:
645                         if ( is_inside(min, max, &l->local_vec, l->rad2) || is_inside(min, max, &l->local_vec2, l->rad2) )      {
646                                 Relevent_lights[Num_relevent_lights[n2]++][n2] = l;
647                         }
648                         break;
649
650                 default:
651                         Int3(); // Invalid light type
652                 }
653         }
654
655         return Num_relevent_lights[n2];
656 }
657
658 void light_filter_pop()
659 {
660         if ( Lighting_off ) return;
661
662         Num_light_levels--;
663         Assert( Num_light_levels > 0 );
664 }
665
666 int l_num_points=0, l_num_lights=0;
667
668
669 void light_rotate_all()
670 {
671         int i;
672         light *l;
673
674         if ( Lighting_off ) return;
675
676         int n = Num_light_levels-1;
677
678         l = Lights;
679         for (i=0; i<Num_relevent_lights[n]; i++ )       {
680                 l = Relevent_lights[i][n];
681                 light_rotate(l);
682         }
683
684         for(i=0; i<Static_light_count; i++){    
685                 light_rotate(Static_light[i]);
686         }
687
688 //      l = Lights;
689 //      for (i=0; i<Num_lights; i++, l++ )      {
690 //              light_rotate(l);
691 //      }
692 }
693
694 // return the # of global light sources
695 int light_get_global_count()
696 {
697         return Static_light_count;
698 }
699
700 int light_get_global_dir(vector *pos, int n)
701 {
702         if((n > MAX_STATIC_LIGHTS) || (n > Static_light_count-1)){
703                 return 0;
704         }
705
706         if ( Static_light[n] == NULL ) {
707                 return 0;
708         }
709
710         if (pos) {
711                 *pos = Static_light[n]->vec;
712
713                 if ( Lighting_mode != LM_DARKEN )       {
714                         vm_vec_scale( pos, -1.0f );
715                 }
716         }
717         return 1;
718 }
719
720
721 void light_set_shadow( int state )
722 {
723         Light_in_shadow = state;
724 }
725
726
727 ubyte light_apply( vector *pos, vector * norm, float static_light_level )
728 {
729         int i, idx;
730         float lval;
731         light *l;
732
733         if (Detail.lighting==0) {
734                 // No static light
735                 ubyte l = ubyte(fl2i(static_light_level*255.0f));
736                 return l;
737         }
738
739         if ( Lighting_off ) return 191;
740
741         // Factor in ambient light
742         lval = Ambient_light;
743         
744         // Factor in light from suns if there are any
745         if ( !Light_in_shadow ){
746                 // apply all sun lights
747                 for(idx=0; idx<Static_light_count; idx++){              
748                         float ltmp;
749
750                         // sanity 
751                         if(Static_light[idx] == NULL){
752                                 continue;
753                         }
754
755                         // calculate light from surface normal
756                         ltmp = -vm_vec_dot(&Static_light[idx]->local_vec, norm )*Static_light[idx]->intensity*Reflective_light;         // reflective light
757
758                         switch(Lighting_mode)   {
759                         case LM_BRIGHTEN:
760                                 if ( ltmp > 0.0f )
761                                         lval += ltmp;
762                                 break;
763                         case LM_DARKEN:
764                                 if ( ltmp > 0.0f )
765                                         lval -= ltmp;
766
767                                 if ( lval < 0.0f ) 
768                                         lval = 0.0f;
769                                 break;
770                         }
771                 }
772         }
773
774         // At this point, l must be between 0 and 0.75 (0.75-1.0 is for dynamic light only)
775         if ( lval < 0.0f ) {
776                 lval = 0.0f;
777         } else if ( lval > 0.75f ) {
778                 lval = 0.75f;
779         }
780
781         lval *= static_light_level;
782
783         int n = Num_light_levels-1;
784
785         l_num_lights += Num_relevent_lights[n];
786         l_num_points++;
787
788         for (i=0; i<Num_relevent_lights[n]; i++ )       {
789                 l = Relevent_lights[i][n];
790
791                 vector to_light;
792                 float dot, dist;
793                 vm_vec_sub( &to_light, &l->local_vec, pos );
794                 dot = vm_vec_dot(&to_light, norm );
795                 if ( dot > 0.0f )       {
796                         dist = vm_vec_mag_squared(&to_light);
797                         if ( dist < l->rad1_squared )   {
798                                 lval += l->intensity*dot;
799                         } else if ( dist < l->rad2_squared )    {
800                                 // dist from 0 to 
801                                 float n = dist - l->rad1_squared;
802                                 float d = l->rad2_squared - l->rad1_squared;
803                                 float ltmp = (1.0f - n / d )*dot*l->intensity;
804                                 lval += ltmp;
805                         }
806                         if ( lval > 1.0f ) {
807                                 return 255;
808                         }
809                 }
810         }
811
812         return ubyte(fl2i(lval*255.0f));
813 }
814
815
816 void light_apply_rgb( ubyte *param_r, ubyte *param_g, ubyte *param_b, vector *pos, vector * norm, float static_light_level )
817 {
818         int i, idx;
819         float rval, gval, bval;
820         light *l;
821
822         if (Detail.lighting==0) {
823                 // No static light
824                 ubyte l = ubyte(fl2i(static_light_level*255.0f));
825                 *param_r = l;
826                 *param_g = l;
827                 *param_b = l;
828                 return;
829         }
830
831         if ( Lighting_off ) {
832                 *param_r = 255;
833                 *param_g = 255;
834                 *param_b = 255;
835                 return;
836         }
837
838         // Factor in ambient light
839         rval = Ambient_light;
840         gval = Ambient_light;
841         bval = Ambient_light;
842
843         // Factor in light from sun if there is one
844         if ( !Light_in_shadow ){
845                 // apply all sun lights
846                 for(idx=0; idx<Static_light_count; idx++){                      
847                         float ltmp;
848
849                         // sanity
850                         if(Static_light[idx] == NULL){
851                                 continue;
852                         }
853
854                         // calculate light from surface normal
855                         ltmp = -vm_vec_dot(&Static_light[idx]->local_vec, norm )*Static_light[idx]->intensity*Reflective_light;         // reflective light
856
857                         switch(Lighting_mode)   {
858                         case LM_BRIGHTEN:
859                                 if ( ltmp > 0.0f )      {
860                                         rval += Static_light[idx]->r * ltmp;
861                                         gval += Static_light[idx]->g * ltmp;
862                                         bval += Static_light[idx]->b * ltmp;
863                                 }
864                                 break;
865                         case LM_DARKEN:
866                                 if ( ltmp > 0.0f )      {
867                                         rval -= ltmp; if ( rval < 0.0f ) rval = 0.0f;
868                                         gval -= ltmp; if ( gval < 0.0f ) gval = 0.0f;
869                                         bval -= ltmp; if ( bval < 0.0f ) bval = 0.0f; 
870                                 }
871                                 break;
872                         }
873                 }
874         }
875
876         // At this point, l must be between 0 and 0.75 (0.75-1.0 is for dynamic light only)
877         if ( rval < 0.0f ) {
878                 rval = 0.0f;
879         } else if ( rval > 0.75f ) {
880                 rval = 0.75f;
881         }
882         if ( gval < 0.0f ) {
883                 gval = 0.0f;
884         } else if ( gval > 0.75f ) {
885                 gval = 0.75f;
886         }
887         if ( bval < 0.0f ) {
888                 bval = 0.0f;
889         } else if ( bval > 0.75f ) {
890                 bval = 0.75f;
891         }
892
893         rval *= static_light_level;
894         gval *= static_light_level;
895         bval *= static_light_level;
896
897         int n = Num_light_levels-1;
898
899         l_num_lights += Num_relevent_lights[n];
900         l_num_points++;
901
902         vector to_light;
903         float dot, dist;
904         vector temp;
905         for (i=0; i<Num_relevent_lights[n]; i++ )       {
906                 l = Relevent_lights[i][n];
907
908                 dist = -1.0f;
909                 switch(l->type){
910                 // point lights
911                 case LT_POINT:                  
912                         vm_vec_sub( &to_light, &l->local_vec, pos );
913                         break;
914
915                 // tube lights
916                 case LT_TUBE:                                           
917                         if(vm_vec_dist_to_line(pos, &l->local_vec, &l->local_vec2, &temp, &dist) != 0){
918                                 continue;
919                         }
920                         vm_vec_sub(&to_light, &temp, pos);
921                         dist *= dist;   // since we use radius squared
922                         break;
923
924                 // others. BAD
925                 default:
926                         Int3();
927                 }
928
929                 dot = vm_vec_dot(&to_light, norm);
930         //              dot = 1.0f;
931                 if ( dot > 0.0f )       {
932                         // indicating that we already calculated the distance (vm_vec_dist_to_line(...) does this for us)
933                         if(dist < 0.0f){
934                                 dist = vm_vec_mag_squared(&to_light);
935                         }
936                         if ( dist < l->rad1_squared )   {
937                                 float ratio;
938                                 ratio = l->intensity*dot;
939                                 ratio *= 0.25f;
940                                 rval += l->r*ratio;
941                                 gval += l->g*ratio;
942                                 bval += l->b*ratio;
943                         } else if ( dist < l->rad2_squared )    {
944                                 float ratio;
945                                 // dist from 0 to 
946                                 float n = dist - l->rad1_squared;
947                                 float d = l->rad2_squared - l->rad1_squared;
948                                 ratio = (1.0f - n / d)*dot*l->intensity;
949                                 ratio *= 0.25f;
950                                 rval += l->r*ratio;
951                                 gval += l->g*ratio;
952                                 bval += l->b*ratio;
953                         }
954                 }
955         }
956
957         float m = rval;
958         if ( gval > m ) m = gval;
959         if ( bval > m ) m = bval;
960
961         if ( m > 1.0f ) {
962                 float im = 1.0f / m;
963
964                 rval *= im;
965                 gval *= im;
966                 bval *= im;
967         }
968         
969         if ( rval < 0.0f ) {
970                 rval = 0.0f;
971         } else if ( rval > 1.0f ) {
972                 rval = 1.0f;
973         }
974         if ( gval < 0.0f ) {
975                 gval = 0.0f;
976         } else if ( gval > 1.0f ) {
977                 gval = 1.0f;
978         }
979         if ( bval < 0.0f ) {
980                 bval = 0.0f;
981         } else if ( bval > 1.0f ) {
982                 bval = 1.0f;
983         }
984
985         *param_r = ubyte(fl2i(rval*255.0f));
986         *param_g = ubyte(fl2i(gval*255.0f));
987         *param_b = ubyte(fl2i(bval*255.0f));
988 }
989
990
991 /*
992 float light_apply( vector *pos, vector * norm )
993 {
994 #if 1
995         float r,g,b;
996         light_apply_rgb( &r, &g, &b, pos, norm );
997         return (r+g+b) / 3.0f;
998 #else
999         return light_apply_ramp( pos, norm );
1000 #endif
1001
1002 }
1003 */
1004
1005
1006