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