FS2_Open
Open source remastering of the Freespace 2 engine
lighting.cpp
Go to the documentation of this file.
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 the
6  * source.
7  *
8 */
9 
10 
11 
12 #include "cmdline/cmdline.h"
13 #include "debugconsole/console.h"
14 #include "globalincs/systemvars.h"
15 #include "graphics/2d.h"
16 #include "graphics/gropengldraw.h"
17 #include "graphics/gropengllight.h"
18 #include "lighting/lighting.h"
19 #include "math/vecmat.h"
20 #include "model/modelrender.h"
21 #include "render/3d.h"
22 
23 
24 
25 #define MAX_LIGHT_LEVELS 16
26 
27 
29 int Num_lights=0;
30 extern int Cmdline_nohtl;
31 
32 static light *Relevent_lights[MAX_LIGHTS][MAX_LIGHT_LEVELS];
33 static int Num_relevent_lights[MAX_LIGHT_LEVELS];
34 static int Num_light_levels = 0;
35 
37 
38 static int Light_in_shadow = 0; // If true, this means we're in a shadow
39 
40 #define LM_BRIGHTEN 0
41 #define LM_DARKEN 1
42 
43 #define MIN_LIGHT 0.03f // When light drops below this level, ignore it. Must be non-zero! (1/32)
44 
45 
46 static int Lighting_off = 0;
47 
48 // For lighting values, 0.75 is full intensity
49 
50 #if 1 // ADAM'S new stuff
51  static int Lighting_mode = LM_BRIGHTEN;
52  #define AMBIENT_LIGHT_DEFAULT 0.15f //0.10f
53  #define REFLECTIVE_LIGHT_DEFAULT 0.75f //0.90f
54 #else
55  static int Lighting_mode = LM_DARKEN;
56  #define AMBIENT_LIGHT_DEFAULT 0.75f //0.10f
57  #define REFLECTIVE_LIGHT_DEFAULT 0.50f //0.90f
58 #endif
59 
60 static float Ambient_light = AMBIENT_LIGHT_DEFAULT;
61 static float Reflective_light = REFLECTIVE_LIGHT_DEFAULT;
62 
63 int Lighting_flag = 1;
64 
65 static void light_filter_reset();
66 
67 DCF(light,"Changes lighting parameters")
68 {
69  SCP_string arg_str;
70  float val_f;
71  bool val_b;
72 
73  if (dc_optional_string_either("help", "--help")) {
74  dc_printf( "Usage: light keyword\nWhere keyword can be in the following forms:\n" );
75  dc_printf( "light on|off Turns all lighting on/off\n" );
76  dc_printf( "light default Resets lighting to all default values\n" );
77  dc_printf( "light ambient X Where X is the ambient light between 0 and 1.0\n" );
78  dc_printf( "light reflect X Where X is the material reflectiveness between 0 and 1.0\n" );
79  dc_printf( "light dynamic [bool] Toggles dynamic lighting on/off\n" );
80  dc_printf( "light mode [light|darken] Changes the lighting mode.\n" );
81  dc_printf( " Where 'light' means the global light adds light.\n");
82  dc_printf( " and 'darken' means the global light subtracts light.\n");
83  return;
84  }
85 
86  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
87  dc_printf( "Ambient light is set to %.2f\n", Ambient_light );
88  dc_printf( "Reflective light is set to %.2f\n", Reflective_light );
89  dc_printf( "Dynamic lighting is: %s\n", (Lighting_flag?"on":"off") );
90  switch( Lighting_mode ) {
91  case LM_BRIGHTEN:
92  dc_printf( "Lighting mode is: light\n" );
93  break;
94  case LM_DARKEN:
95  dc_printf( "Lighting mode is: darken\n" );
96  break;
97  default:
98  dc_printf( "Lighting mode is: UNKNOWN\n" );
99  }
100  return;
101  }
102 
103  if (dc_optional_string("ambient")) {
104  dc_stuff_float(&val_f);
105  if ((val_f < 0.0f) || (val_f > 1.0f)) {
106  dc_printf(" Error: ambient value must be between 0.0 and 1.0\n");
107  } else {
108  Ambient_light = val_f;
109  }
110 
111  } else if (dc_optional_string("reflect")) {
112  dc_stuff_float(&val_f);
113  if ( (val_f < 0.0f) || (val_f > 1.0f)) {
114  dc_printf(" Error: reflect value mus be between 0.0 and 1.0\n");
115  } else {
116  Reflective_light = val_f;
117  }
118 
119  } else if (dc_optional_string("default")) {
120  Lighting_mode = LM_BRIGHTEN;
121  Ambient_light = AMBIENT_LIGHT_DEFAULT;
122  Reflective_light = REFLECTIVE_LIGHT_DEFAULT;
123  Lighting_flag = 0;
124 
125  } else if (dc_optional_string("mode")) {
126  dc_stuff_string_white(arg_str);
127  if (arg_str == "light") {
128  Lighting_mode = LM_BRIGHTEN;
129 
130  } else if (arg_str == "darken") {
131  Lighting_mode = LM_DARKEN;
132 
133  } else {
134  dc_printf(" Error: unknown light mode: '%s'\n", arg_str.c_str());
135  }
136 
137  } else if (dc_optional_string("dynamic")) {
138  dc_stuff_boolean(&val_b);
139  Lighting_flag = val_b;
140 
141  } else if(dc_maybe_stuff_boolean(&Lighting_off)) {
142  Lighting_off = !Lighting_off;
143 
144  } else {
145  dc_stuff_string_white(arg_str);
146  dc_printf("Error: Unknown argument '%s'\n", arg_str.c_str());
147  }
148 }
149 
151 {
152  Static_light.clear();
153 
154  Num_lights = 0;
155  light_filter_reset();
156 }
157 extern vec3d Object_position;
158 
164 static void light_rotate(light * l)
165 {
166  switch( l->type ) {
167  case LT_DIRECTIONAL:
168  // Rotate the light direction into local coodinates
169 
171  break;
172 
173  case LT_POINT: {
174  vec3d tempv;
175  // Rotate the point into local coordinates
176 
177  vm_vec_sub(&tempv, &l->vec, &Light_base );
178  vm_vec_rotate(&l->local_vec, &tempv, &Light_matrix );
179  }
180  break;
181 
182  case LT_TUBE:{
183  vec3d tempv;
184 
185  // Rotate the point into local coordinates
186  vm_vec_sub(&tempv, &l->vec, &Light_base );
187  vm_vec_rotate(&l->local_vec, &tempv, &Light_matrix );
188 
189  // Rotate the point into local coordinates
190  vm_vec_sub(&tempv, &l->vec2, &Light_base );
191  vm_vec_rotate(&l->local_vec2, &tempv, &Light_matrix );
192  }
193  break;
194 
195  case LT_CONE:
196  break;
197 
198  default:
199  Int3(); // Invalid light type
200  }
201 }
202 
203 // Sets the ambient lighting level.
204 // Ignored for now.
205 void light_set_ambient(float ambient_light)
206 {
207 }
208 
209 void light_add_directional(const vec3d *dir, float intensity, float r, float g, float b, float spec_r, float spec_g, float spec_b, bool specular)
210 {
211  if(!specular){
212  spec_r = r;
213  spec_g = g;
214  spec_b = b;
215  }
216  light * l;
217 
218  if ( Lighting_off ) return;
219 
220  if ( Num_lights >= MAX_LIGHTS ) return;
221 
222  l = &Lights[Num_lights++];
223 
224  l->type = LT_DIRECTIONAL;
225 
226  if ( Lighting_mode == LM_BRIGHTEN ) {
227  vm_vec_copy_scale( &l->vec, dir, -1.0f );
228  } else {
229  vm_vec_copy_scale( &l->vec, dir, 1.0f );
230  }
231 
232  l->r = r;
233  l->g = g;
234  l->b = b;
235  l->spec_r = spec_r;
236  l->spec_g = spec_g;
237  l->spec_b = spec_b;
238  l->intensity = intensity;
239  l->rada = 0.0f;
240  l->radb = 0.0f;
241  l->rada_squared = l->rada*l->rada;
242  l->radb_squared = l->radb*l->radb;
243  l->light_ignore_objnum = -1;
244  l->affected_objnum = -1;
245  l->instance = Num_lights-1;
246 
247  Assert( Num_light_levels <= 1 );
248 
249  Static_light.push_back(l);
250 }
251 
252 
253 void light_add_point(const vec3d *pos, float r1, float r2, float intensity, float r, float g, float b, int light_ignore_objnum, float spec_r, float spec_g, float spec_b, bool specular)
254 {
255  Assertion( r1 > 0.0f, "Invalid radius r1 specified for light: %f. Radius must be > 0.0f. Examine stack trace to determine culprit.\n", r1 );
256  Assertion( r2 > 0.0f, "Invalid radius r2 specified for light: %f. Radius must be > 0.0f. Examine stack trace to determine culprit.\n", r2 );
257 
258  if (r1 < 0.0001f || r2 < 0.0001f)
259  return;
260 
261  if(!specular){
262  spec_r = r;
263  spec_g = g;
264  spec_b = b;
265  }
266 
267  light * l;
268 
269  if ( Lighting_off ) return;
270 
271  if (!Lighting_flag) return;
272 
273  if ( Num_lights >= MAX_LIGHTS ) {
274  mprintf(( "Out of lights!\n" ));
275  return;
276  }
277 
278  l = &Lights[Num_lights++];
279 
280  l->type = LT_POINT;
281  l->vec = *pos;
282  l->r = r;
283  l->g = g;
284  l->b = b;
285  l->spec_r = spec_r;
286  l->spec_g = spec_g;
287  l->spec_b = spec_b;
288  l->intensity = intensity;
289  l->rada = r1;
290  l->radb = r2;
291  l->rada_squared = l->rada*l->rada;
292  l->radb_squared = l->radb*l->radb;
293  l->light_ignore_objnum = light_ignore_objnum;
294  l->affected_objnum = -1;
295  l->instance = Num_lights-1;
296 
297  Assert( Num_light_levels <= 1 );
298 }
299 
300 void light_add_point_unique(const vec3d *pos, float r1, float r2, float intensity, float r, float g, float b, int affected_objnum, float spec_r, float spec_g, float spec_b, bool specular)
301 {
302  Assert(r1 >0);
303  Assert(r2 >0);
304  if(!specular){
305  spec_r = r;
306  spec_g = g;
307  spec_b = b;
308  }
309  light * l;
310 
311  if ( Lighting_off ) return;
312 
313  if (!Lighting_flag) return;
314 
315  if ( Num_lights >= MAX_LIGHTS ) {
316  mprintf(( "Out of lights!\n" ));
317  return;
318  }
319 
320  l = &Lights[Num_lights++];
321 
322  l->type = LT_POINT;
323  l->vec = *pos;
324  l->r = r;
325  l->g = g;
326  l->b = b;
327  l->spec_r = spec_r;
328  l->spec_g = spec_g;
329  l->spec_b = spec_b;
330  l->intensity = intensity;
331  l->rada = r1;
332  l->radb = r2;
333  l->rada_squared = l->rada*l->rada;
334  l->radb_squared = l->radb*l->radb;
335  l->light_ignore_objnum = -1;
336  l->affected_objnum = affected_objnum;
337  l->instance = Num_lights-1;
338 
339  Assert( Num_light_levels <= 1 );
340 }
341 
342 // beams affect every ship except the firing ship
343 void light_add_tube(const vec3d *p0, const vec3d *p1, float r1, float r2, float intensity, float r, float g, float b, int affected_objnum, float spec_r, float spec_g, float spec_b, bool specular)
344 {
345  Assert(r1 >0);
346  Assert(r2 >0);
347  if(!specular){
348  spec_r = r;
349  spec_g = g;
350  spec_b = b;
351  }
352  light * l;
353 
354  if ( Lighting_off ) return;
355 
356  if (!Lighting_flag) return;
357 
358  if ( Num_lights >= MAX_LIGHTS ) {
359  mprintf(( "Out of lights!\n" ));
360  return;
361  }
362 
363  l = &Lights[Num_lights++];
364 
365  l->type = LT_TUBE;
366  l->vec = *p0;
367  l->vec2 = *p1;
368  l->r = r;
369  l->g = g;
370  l->b = b;
371  l->spec_r = spec_r;
372  l->spec_g = spec_g;
373  l->spec_b = spec_b;
374  l->intensity = intensity;
375  l->rada = r1;
376  l->radb = r2;
377  l->rada_squared = l->rada*l->rada;
378  l->radb_squared = l->radb*l->radb;
379  l->light_ignore_objnum = is_minimum_GLSL_version() ? affected_objnum : -1;
380  l->affected_objnum = is_minimum_GLSL_version() ? -1 : affected_objnum;
381  l->instance = Num_lights-1;
382 
383  Assert( Num_light_levels <= 1 );
384 }
385 
389 static void light_filter_reset()
390 {
391  int i;
392  light *l;
393 
394  if ( Lighting_off ) return;
395 
396  Num_light_levels = 1;
397 
398  int n = Num_light_levels-1;
399  Num_relevent_lights[n] = 0;
400 
401  l = Lights;
402  for (i=0; i<Num_lights; i++, l++ ) {
403  Relevent_lights[Num_relevent_lights[n]++][n] = l;
404  }
405 }
406 
407 
416 int light_filter_push( int objnum, const vec3d *pos, float rad )
417 {
418  int i;
419  light *l;
420 
421  if ( Lighting_off ) return 0;
422 
423  light_filter_reset();
424 
425  int n1,n2;
426  n1 = Num_light_levels-1;
427  n2 = Num_light_levels;
428  Num_light_levels++;
429  Assert( Num_light_levels < MAX_LIGHT_LEVELS );
430 
431  Num_relevent_lights[n2] = 0;
432 
433  for (i=0; i<Num_relevent_lights[n1]; i++ ) {
434  l = Relevent_lights[i][n1];
435 
436  switch( l->type ) {
437  case LT_DIRECTIONAL:
438  //Relevent_lights[Num_relevent_lights[n2]++][n2] = l;
439  break;
440 
441  case LT_POINT: {
442  // if this is a "unique" light source, it only affects one guy
443  if(l->affected_objnum >= 0){
444  if(objnum == l->affected_objnum){
445  vec3d to_light;
446  float dist_squared, max_dist_squared;
447  vm_vec_sub( &to_light, &l->vec, pos );
448  dist_squared = vm_vec_mag_squared(&to_light);
449 
450  max_dist_squared = l->radb+rad;
451  max_dist_squared *= max_dist_squared;
452 
453  if ( dist_squared < max_dist_squared ) {
454  Relevent_lights[Num_relevent_lights[n2]++][n2] = l;
455  }
456  }
457  }
458  // otherwise check all relevant objects
459  else {
460  vec3d to_light;
461  float dist_squared, max_dist_squared;
462  vm_vec_sub( &to_light, &l->vec, pos );
463  dist_squared = vm_vec_mag_squared(&to_light);
464 
465  max_dist_squared = l->radb+rad;
466  max_dist_squared *= max_dist_squared;
467 
468  if ( dist_squared < max_dist_squared ) {
469  Relevent_lights[Num_relevent_lights[n2]++][n2] = l;
470  }
471  }
472  }
473  break;
474 
475  // hmm. this could probably be more optimal
476  case LT_TUBE:
478  if(l->light_ignore_objnum != objnum){
479  vec3d nearest;
480  float dist_squared, max_dist_squared;
481  vm_vec_dist_squared_to_line(pos,&l->vec,&l->vec2,&nearest,&dist_squared);
482 
483  max_dist_squared = l->radb+rad;
484  max_dist_squared *= max_dist_squared;
485 
486  if ( dist_squared < max_dist_squared )
487  Relevent_lights[Num_relevent_lights[n2]++][n2] = l;
488  }
489  }
490  else {
491  // all tubes are "unique" light sources for now
492  if((l->affected_objnum >= 0) && (objnum == l->affected_objnum))
493  Relevent_lights[Num_relevent_lights[n2]++][n2] = l;
494  }
495  break;
496 
497  case LT_CONE:
498  break;
499 
500  default:
501  Int3(); // Invalid light type
502  }
503  }
504 
505  return Num_relevent_lights[n2];
506 }
507 
508 static int is_inside(const vec3d *min, const vec3d *max, const vec3d * p0, float rad)
509 {
510  const float *origin = (float *)&p0->xyz.x;
511  const float *minB = (float *)min;
512  const float *maxB = (float *)max;
513  int i;
514 
515  for (i=0; i<3; i++ ) {
516  if ( origin[i] < minB[i] - rad ) {
517  return 0;
518  } else if (origin[i] > maxB[i] + rad ) {
519  return 0;
520  }
521  }
522  return 1;
523 }
524 
525 
526 int light_filter_push_box(const vec3d *min, const vec3d *max)
527 {
528  int i;
529  light *l;
530 
531  if ( Lighting_off ) return 0;
532 
533  int n1,n2;
534  n1 = Num_light_levels-1;
535  n2 = Num_light_levels;
536  Num_light_levels++;
537 
538  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 ( is_inside( min, max, &l->local_vec, l->radb ) ) {
552  Relevent_lights[Num_relevent_lights[n2]++][n2] = l;
553  }
554  }
555  break;
556 
557  case LT_TUBE:
558  if ( is_inside(min, max, &l->local_vec, l->radb) || is_inside(min, max, &l->local_vec2, l->radb) ) {
559  Relevent_lights[Num_relevent_lights[n2]++][n2] = l;
560  }
561  break;
562 
563  case LT_CONE:
564  break;
565 
566  default:
567  Int3(); // Invalid light type
568  }
569  }
570 
571  return Num_relevent_lights[n2];
572 }
573 
575 {
576  if ( Lighting_off ) return;
577 
578  Num_light_levels--;
579  Assert( Num_light_levels > 0 );
580 }
581 
582 static int l_num_points=0, l_num_lights=0;
583 
584 
586 {
587  int i;
588  light *l;
589 
590  if ( Lighting_off ) return;
591 
592  int n = Num_light_levels-1;
593 
594  l = Lights;
595  for (i=0; i<Num_relevent_lights[n]; i++ ) {
596  l = Relevent_lights[i][n];
597  light_rotate(l);
598  }
599 
600  for (i = 0; i < (int)Static_light.size(); i++) {
601  light_rotate(Static_light[i]);
602  }
603 }
604 
609 {
610  return (int)Static_light.size();
611 }
612 
622 {
623  if ( (n < 0) || (n >= (int)Static_light.size()) ) {
624  return 0;
625  }
626 
627  if (pos) {
628  *pos = Static_light[n]->vec;
629 
630  if ( Lighting_mode != LM_DARKEN ) {
631  vm_vec_scale( pos, -1.0f );
632  }
633  }
634  return 1;
635 }
636 
637 
638 void light_set_shadow( int state )
639 {
640  Light_in_shadow = state;
641 }
642 
643 
645 {
646  int idx;
647 
649 
650  for (idx = 0; idx < (int)Static_light.size(); idx++)
651  gr_set_light( Static_light[idx] );
652 
653  extern bool Deferred_lighting;
654  if(Deferred_lighting)
655  return;
656 
657  // for simplicity sake were going to forget about dynamic lights for the moment
658 
659  int n = Num_light_levels-1;
660 
661  for (idx = 0; idx < Num_relevent_lights[n]; idx++ )
662  gr_set_light( Relevent_lights[idx][n] );
663 }
664 
665 
666 ubyte light_apply(const vec3d *pos, const vec3d *norm, float static_light_level)
667 {
668  int i, idx;
669  float lval;
670  light *l;
671 
672  if (Detail.lighting==0) {
673  // No static light
674  return ubyte(fl2i(static_light_level*255.0f));
675  }
676 
677  if ( Lighting_off ) return 191;
678 
679  // Factor in ambient light
680  lval = Ambient_light;
681 
682  // Factor in light from suns if there are any
683  if ( !Light_in_shadow ){
684  // apply all sun lights
685  for (idx = 0; idx < (int)Static_light.size(); idx++) {
686  float ltmp;
687 
688  // calculate light from surface normal
689  ltmp = -vm_vec_dot(&Static_light[idx]->local_vec, norm )*Static_light[idx]->intensity*Reflective_light; // reflective light
690 
691  switch(Lighting_mode) {
692  case LM_BRIGHTEN:
693  if ( ltmp > 0.0f )
694  lval += ltmp;
695  break;
696  case LM_DARKEN:
697  if ( ltmp > 0.0f )
698  lval -= ltmp;
699 
700  if ( lval < 0.0f )
701  lval = 0.0f;
702  break;
703  }
704  }
705  }
706 
707  // At this point, l must be between 0 and 0.75 (0.75-1.0 is for dynamic light only)
708  CLAMP(lval, 0.0f, 0.75f);
709 
710  lval *= static_light_level;
711 
712  int n = Num_light_levels-1;
713 
714  l_num_lights += Num_relevent_lights[n];
715  l_num_points++;
716 
717  for (i=0; i<Num_relevent_lights[n]; i++ ) {
718  l = Relevent_lights[i][n];
719 
720  vec3d to_light;
721  float dot, dist;
722  vm_vec_sub( &to_light, &l->local_vec, pos );
723  dot = vm_vec_dot(&to_light, norm );
724  if ( dot > 0.0f ) {
725  dist = vm_vec_mag_squared(&to_light);
726  if ( dist < l->rada_squared ) {
727  lval += l->intensity*dot;
728  } else if ( dist < l->radb_squared ) {
729  // dist from 0 to
730  float nnum = dist - l->rada_squared;
731  float dden = l->radb_squared - l->rada_squared;
732  float ltmp = (1.0f - nnum / dden )*dot*l->intensity;
733  lval += ltmp;
734  }
735  if ( lval > 1.0f ) {
736  return 255;
737  }
738  }
739  }
740 
741  return ubyte(fl2i(lval*255.0f));
742 }
743 
744 float static_light_factor = 1.0f;
745 float static_tube_factor = 1.0f;
746 float static_point_factor = 1.0f;
748 
749 void light_apply_specular(ubyte *param_r, ubyte *param_g, ubyte *param_b, const vec3d *pos, const vec3d *norm, const vec3d *cam){
750 
751  light *l;
752  float rval = 0, gval = 0, bval = 0;
753  int idx;
754 
755  if ( !Cmdline_spec ) {
756  *param_r = 0;
757  *param_g = 0;
758  *param_b = 0;
759  return;
760  }
761 
762  if (Detail.lighting==0) {
763  *param_r = 0;
764  *param_g = 0;
765  *param_b = 0;
766  return;
767  }
768 
769  if ( Lighting_off ) {
770  *param_r = 0;
771  *param_g = 0;
772  *param_b = 0;
773  return;
774  }
775 
776  vec3d V, N;
777  vm_vec_sub(&V, cam,pos);
778  vm_vec_normalize(&V);
779 
780  N = *norm;
781  vm_vec_normalize(&N);
782 
783  // Factor in light from sun if there is one
784  // apply all sun lights
785  for (idx = 0; idx < (int)Static_light.size(); idx++) {
786  float ltmp;
787 
788  vec3d R;
789  vm_vec_sub(&R,&V, &Static_light[idx]->local_vec);
790  vm_vec_normalize(&R);
791 
792  ltmp = (float)pow((double)vm_vec_dot(&R, &N ), specular_exponent_value) * Static_light[idx]->intensity * static_light_factor; // reflective light
793 
794  switch(Lighting_mode) {
795  case LM_BRIGHTEN:
796  if ( ltmp > 0.0f ) {
797  rval += Static_light[idx]->spec_r * ltmp;
798  gval += Static_light[idx]->spec_g * ltmp;
799  bval += Static_light[idx]->spec_b * ltmp;
800  }
801  break;
802  case LM_DARKEN:
803  if ( ltmp > 0.0f ) {
804  rval -= ltmp; if ( rval < 0.0f ) rval = 0.0f;
805  gval -= ltmp; if ( gval < 0.0f ) gval = 0.0f;
806  bval -= ltmp; if ( bval < 0.0f ) bval = 0.0f;
807  }
808  break;
809  }
810  }
811 
812 
813  CLAMP(rval, 0.0f, 0.75f);
814  CLAMP(gval, 0.0f, 0.75f);
815  CLAMP(bval, 0.0f, 0.75f);
816 
817  //dynamic lights
818 
819  int n = Num_light_levels-1;
820 
821  l_num_lights += Num_relevent_lights[n];
822  l_num_points++;
823 
824  vec3d to_light;
825  float dot, dist;
826  vec3d temp;
827  float factor = 1.0f;
828  for (idx = 0; idx < Num_relevent_lights[n]; idx++) {
829  l = Relevent_lights[idx][n];
830 
831  dist = -1.0f;
832  switch(l->type){
833  // point lights
834  case LT_POINT:
835  vm_vec_sub( &to_light, &l->local_vec, pos );
836  factor = static_point_factor;
837  break;
838 
839  // tube lights
840  case LT_TUBE:
841  if(vm_vec_dist_to_line(pos, &l->local_vec, &l->local_vec2, &temp, &dist) != 0){
842  continue;
843  }
844  factor = static_tube_factor;
845  vm_vec_sub(&to_light, &temp, pos);
846  dist *= dist; // since we use radius squared
847  break;
848 
849  case LT_CONE:
850  continue;
851 
852  // others. BAD
853  default:
854  Int3();
855  }
856 
857  vec3d R;
858  vm_vec_normalize(&to_light);
859  vm_vec_add(&R,&V, &to_light);
860  vm_vec_normalize(&R);
861 
862  dot = (float)pow((double)vm_vec_dot(&R, &N ), specular_exponent_value) * l->intensity * factor; // reflective light
863 
864  if ( dot > 0.0f ) {
865  // indicating that we already calculated the distance (vm_vec_dist_to_line(...) does this for us)
866  if(dist < 0.0f){
867  dist = vm_vec_mag_squared(&to_light);
868  }
869  if ( dist < l->rada_squared ) {
870  float ratio;
871  ratio = l->intensity*dot*factor;
872  ratio *= 0.25f;
873  rval += l->spec_r*ratio;
874  gval += l->spec_g*ratio;
875  bval += l->spec_b*ratio;
876  } else if ( dist < l->radb_squared ) {
877  float ratio;
878  // dist from 0 to
879  float nnum = dist - l->rada_squared;
880  float dden = l->radb_squared - l->rada_squared;
881  ratio = (1.0f - nnum / dden)*dot*l->intensity*factor;
882  ratio *= 0.25f;
883  rval += l->spec_r*ratio;
884  gval += l->spec_g*ratio;
885  bval += l->spec_b*ratio;
886  }
887  }
888  }
889 
890  CLAMP(rval, 0.0f, 1.0f);
891  CLAMP(gval, 0.0f, 1.0f);
892  CLAMP(bval, 0.0f, 1.0f);
893 
894  *param_r = ubyte(fl2i(rval*254.0f));
895  *param_g = ubyte(fl2i(gval*254.0f));
896  *param_b = ubyte(fl2i(bval*254.0f));
897 }
898 
899 void light_apply_rgb( ubyte *param_r, ubyte *param_g, ubyte *param_b, const vec3d *pos, const vec3d *norm, float static_light_level )
900 {
901  int idx;
902  float rval, gval, bval;
903  light *l;
904 
905  if (Detail.lighting==0) {
906  // No static light
907  ubyte lVal = ubyte(fl2i(static_light_level*255.0f));
908  *param_r = lVal;
909  *param_g = lVal;
910  *param_b = lVal;
911  return;
912  }
913 
914  if ( Lighting_off ) {
915  *param_r = 255;
916  *param_g = 255;
917  *param_b = 255;
918  return;
919  }
920 
921  // Factor in ambient light
922  rval = Ambient_light;
923  gval = Ambient_light;
924  bval = Ambient_light;
925 
926  // Factor in light from sun if there is one
927  if ( !Light_in_shadow ){
928  // apply all sun lights
929  for (idx = 0; idx < (int)Static_light.size(); idx++) {
930  float ltmp;
931 
932  // calculate light from surface normal
933  ltmp = -vm_vec_dot(&Static_light[idx]->local_vec, norm )*Static_light[idx]->intensity*Reflective_light; // reflective light
934 
935  switch(Lighting_mode) {
936  case LM_BRIGHTEN:
937  if ( ltmp > 0.0f ) {
938  rval += Static_light[idx]->r * ltmp;
939  gval += Static_light[idx]->g * ltmp;
940  bval += Static_light[idx]->b * ltmp;
941  }
942  break;
943  case LM_DARKEN:
944  if ( ltmp > 0.0f ) {
945  rval -= ltmp; if ( rval < 0.0f ) rval = 0.0f;
946  gval -= ltmp; if ( gval < 0.0f ) gval = 0.0f;
947  bval -= ltmp; if ( bval < 0.0f ) bval = 0.0f;
948  }
949  break;
950  }
951  }
952  }
953 
954  // At this point, l must be between 0 and 0.75 (0.75-1.0 is for dynamic light only)
955  CLAMP(rval, 0.0f, 0.75f);
956  CLAMP(gval, 0.0f, 0.75f);
957  CLAMP(bval, 0.0f, 0.75f);
958 
959  rval *= static_light_level;
960  gval *= static_light_level;
961  bval *= static_light_level;
962 
963  int n = Num_light_levels-1;
964 
965  l_num_lights += Num_relevent_lights[n];
966  l_num_points++;
967 
968  vec3d to_light;
969  float dot, dist;
970  vec3d temp;
971  for (idx = 0; idx < Num_relevent_lights[n]; idx++) {
972  l = Relevent_lights[idx][n];
973 
974  dist = -1.0f;
975  switch(l->type){
976  // point lights
977  case LT_POINT:
978  vm_vec_sub( &to_light, &l->local_vec, pos );
979  break;
980 
981  // tube lights
982  case LT_TUBE:
983  if(vm_vec_dist_to_line(pos, &l->local_vec, &l->local_vec2, &temp, &dist) != 0){
984  continue;
985  }
986  vm_vec_sub(&to_light, &temp, pos);
987  dist *= dist; // since we use radius squared
988  break;
989 
990  case LT_DIRECTIONAL:
991  continue;
992 
993  case LT_CONE:
994  continue;
995 
996  // others. BAD
997  default:
998  Int3();
999  }
1000 
1001  dot = vm_vec_dot(&to_light, norm);
1002  // dot = 1.0f;
1003  if ( dot > 0.0f ) {
1004  // indicating that we already calculated the distance (vm_vec_dist_to_line(...) does this for us)
1005  if(dist < 0.0f){
1006  dist = vm_vec_mag_squared(&to_light);
1007  }
1008  if ( dist < l->rada_squared ) {
1009  float ratio;
1010  ratio = l->intensity*dot;
1011  ratio *= 0.25f;
1012  rval += l->r*ratio;
1013  gval += l->g*ratio;
1014  bval += l->b*ratio;
1015  } else if ( dist < l->radb_squared ) {
1016  float ratio;
1017  // dist from 0 to
1018  float nnum = dist - l->rada_squared;
1019  float dden = l->radb_squared - l->rada_squared;
1020  ratio = (1.0f - nnum / dden)*dot*l->intensity;
1021  ratio *= 0.25f;
1022  rval += l->r*ratio;
1023  gval += l->g*ratio;
1024  bval += l->b*ratio;
1025  }
1026  }
1027  }
1028 
1029  float m = rval;
1030  if ( gval > m ) m = gval;
1031  if ( bval > m ) m = bval;
1032 
1033  if ( m > 1.0f ) {
1034  float im = 1.0f / m;
1035 
1036  rval *= im;
1037  gval *= im;
1038  bval *= im;
1039  }
1040 
1041  CLAMP(rval, 0.0f, 1.0f);
1042  CLAMP(gval, 0.0f, 1.0f);
1043  CLAMP(bval, 0.0f, 1.0f);
1044 
1045  *param_r = ubyte(fl2i(rval*255.0f));
1046  *param_g = ubyte(fl2i(gval*255.0f));
1047  *param_b = ubyte(fl2i(bval*255.0f));
1048 }
1049 
1050 void light_add_cone(const vec3d *pos, const vec3d *dir, float angle, float inner_angle, bool dual_cone, float r1, float r2, float intensity, float r, float g, float b, int light_ignore_objnum, float spec_r, float spec_g, float spec_b, bool specular)
1051 {
1052  Assertion( r1 > 0.0f, "Invalid radius r1 specified for light: %f. Radius must be > 0.0f. Examine stack trace to determine culprit.\n", r1 );
1053  Assertion( r2 > 0.0f, "Invalid radius r2 specified for light: %f. Radius must be > 0.0f. Examine stack trace to determine culprit.\n", r2 );
1054 
1055  if (r1 < 0.0001f || r2 < 0.0001f)
1056  return;
1057 
1058  if(!specular){
1059  spec_r = r;
1060  spec_g = g;
1061  spec_b = b;
1062  }
1063 
1064  light * l;
1065 
1066  if ( Lighting_off ) return;
1067 
1068  if (!Lighting_flag) return;
1069 
1070  if ( Num_lights >= MAX_LIGHTS ) {
1071  mprintf(( "Out of lights!\n" ));
1072  return;
1073  }
1074 
1075  l = &Lights[Num_lights++];
1076 
1077  l->type = LT_CONE;
1078  l->vec = *pos;
1079  l->vec2= *dir;
1080  l->cone_angle = angle;
1081  l->cone_inner_angle = inner_angle;
1082  l->dual_cone = dual_cone;
1083  l->r = r;
1084  l->g = g;
1085  l->b = b;
1086  l->spec_r = spec_r;
1087  l->spec_g = spec_g;
1088  l->spec_b = spec_b;
1089  l->intensity = intensity;
1090  l->rada = r1;
1091  l->radb = r2;
1092  l->rada_squared = l->rada*l->rada;
1093  l->radb_squared = l->radb*l->radb;
1094  l->light_ignore_objnum = light_ignore_objnum;
1095  l->affected_objnum = -1;
1096  l->instance = Num_lights-1;
1097 
1098  Assert( Num_light_levels <= 1 );
1099 }
1100 
1101 bool light_compare_by_type(const light &a, const light &b)
1102 {
1103  return a.type < b.type;
1104 }
1105 
1106 void scene_lights::addLight(const light *light_ptr)
1107 {
1108  Assert(light_ptr != NULL);
1109 
1110  AllLights.push_back(*light_ptr);
1111 
1112  if ( light_ptr->type == LT_DIRECTIONAL ) {
1113  StaticLightIndices.push_back(AllLights.size() - 1);
1114  }
1115 }
1116 
1117 void scene_lights::setLightFilter(int objnum, const vec3d *pos, float rad)
1118 {
1119  size_t i;
1120 
1121  // clear out current filtered lights
1122  FilteredLights.clear();
1123 
1124  for ( i = 0; i < AllLights.size(); ++i ) {
1125  light& l = AllLights[i];
1126 
1127  switch ( l.type ) {
1128  case LT_DIRECTIONAL:
1129  break;
1130  case LT_POINT: {
1131  // if this is a "unique" light source, it only affects one guy
1132  if ( l.affected_objnum >= 0 ) {
1133  if ( objnum == l.affected_objnum ) {
1134  vec3d to_light;
1135  float dist_squared, max_dist_squared;
1136  vm_vec_sub( &to_light, &l.vec, pos );
1137  dist_squared = vm_vec_mag_squared(&to_light);
1138 
1139  max_dist_squared = l.radb+rad;
1140  max_dist_squared *= max_dist_squared;
1141 
1142  if ( dist_squared < max_dist_squared ) {
1143  FilteredLights.push_back(i);
1144  }
1145  }
1146  } else { // otherwise check all relevant objects
1147  vec3d to_light;
1148  float dist_squared, max_dist_squared;
1149  vm_vec_sub( &to_light, &l.vec, pos );
1150  dist_squared = vm_vec_mag_squared(&to_light);
1151 
1152  max_dist_squared = l.radb+rad;
1153  max_dist_squared *= max_dist_squared;
1154 
1155  if ( dist_squared < max_dist_squared ) {
1156  FilteredLights.push_back(i);
1157  }
1158  }
1159  }
1160  break;
1161  case LT_TUBE: {
1162  if ( is_minimum_GLSL_version() ) {
1163  if ( l.light_ignore_objnum != objnum ) {
1164  vec3d nearest;
1165  float dist_squared, max_dist_squared;
1166  vm_vec_dist_squared_to_line(pos,&l.vec,&l.vec2,&nearest,&dist_squared);
1167 
1168  max_dist_squared = l.radb+rad;
1169  max_dist_squared *= max_dist_squared;
1170 
1171  if ( dist_squared < max_dist_squared ) {
1172  FilteredLights.push_back(i);
1173  }
1174  }
1175  } else {
1176  // all tubes are "unique" light sources for now
1177  if ( ( l.affected_objnum >= 0 ) && ( objnum == l.affected_objnum ) ) {
1178  FilteredLights.push_back(i);
1179  }
1180  }
1181  }
1182  break;
1183 
1184  case LT_CONE:
1185  break;
1186 
1187  default:
1188  break;
1189  }
1190  }
1191 }
1192 
1194 {
1195  size_t i;
1196 
1197  light_indexing_info light_info;
1198 
1199  light_info.index_start = 0;
1200  light_info.num_lights = 0;
1201 
1202  // make sure that there are lights to bind?
1203  if ( FilteredLights.size() <= 0 ) {
1204  return light_info;
1205  }
1206 
1207  light_info.index_start = BufferedLights.size();
1208 
1209  for ( i = 0; i < FilteredLights.size(); ++i ) {
1210  BufferedLights.push_back(FilteredLights[i]);
1211  }
1212 
1213  light_info.num_lights = FilteredLights.size();
1214 
1215  return light_info;
1216 }
1217 
1219 {
1220  return StaticLightIndices.size();
1221 }
1222 
1224 {
1225  current_light_index = -1;
1226  current_num_lights = -1;
1227 }
1228 
1230 {
1231  if ( info->index_start == current_light_index && info->num_lights == current_num_lights ) {
1232  // don't need to set new lights since the ones requested to be set are currently set
1233  return false;
1234  }
1235 
1236  current_light_index = info->index_start;
1237  current_num_lights = info->num_lights;
1238 
1240 
1241  gr_set_lighting(true, true);
1242 
1243  for ( size_t i = 0; i < StaticLightIndices.size(); ++i) {
1244  int light_index = StaticLightIndices[i];
1245 
1246  gr_set_light( &AllLights[light_index] );
1247  }
1248 
1249  extern bool Deferred_lighting;
1250  if ( Deferred_lighting ) {
1252  return false;
1253  }
1254 
1255  int index_start = info->index_start;
1256  int num_lights = info->num_lights;
1257 
1258  // check if there are any lights to actually set
1259  if ( num_lights <= 0 || index_start < 0 ) {
1261  return false;
1262  }
1263 
1264  // we definitely shouldn't be exceeding the number of buffered lights
1265  Assert(index_start + num_lights <= (int)BufferedLights.size());
1266 
1267  for ( int i = 0; i < num_lights; ++i ) {
1268  int buffered_light_index = index_start + i;
1269  int light_index = BufferedLights[buffered_light_index];
1270 
1271  gr_set_light(&AllLights[light_index]);
1272  }
1273 
1275 
1276  return true;
1277 }
void light_add_directional(const vec3d *dir, float intensity, float r, float g, float b, float spec_r, float spec_g, float spec_b, bool specular)
Definition: lighting.cpp:209
bool light_compare_by_type(const light &a, const light &b)
Definition: lighting.cpp:1101
int i
Definition: multi_pxo.cpp:466
#define REFLECTIVE_LIGHT_DEFAULT
Definition: lighting.cpp:53
float static_light_factor
Definition: lighting.cpp:744
#define MAX_LIGHTS
Definition: globals.h:86
vec3d local_vec
Definition: lighting.h:36
Assert(pm!=NULL)
int light_filter_push(int objnum, const vec3d *pos, float rad)
Definition: lighting.cpp:416
Definition: pstypes.h:88
#define mprintf(args)
Definition: pstypes.h:238
void light_add_point(const vec3d *pos, float r1, float r2, float intensity, float r, float g, float b, int light_ignore_objnum, float spec_r, float spec_g, float spec_b, bool specular)
Definition: lighting.cpp:253
hull_check p0
Definition: lua.cpp:5051
bool dual_cone
Definition: lighting.h:47
int Cmdline_spec
Definition: cmdline.cpp:329
vec3d local_vec2
Definition: lighting.h:37
int light_get_global_dir(vec3d *pos, int n)
Definition: lighting.cpp:621
struct vec3d::@225::@227 xyz
void setLightFilter(int objnum, const vec3d *pos, float rad)
Definition: lighting.cpp:1117
bool Deferred_lighting
GLclampf f
Definition: Glext.h:7097
light Lights[MAX_LIGHTS]
Definition: lighting.cpp:28
vec3d * vm_vec_rotate(vec3d *dest, const vec3d *src, const matrix *m)
Definition: vecmat.cpp:933
#define Assertion(expr, msg,...)
Definition: clang.h:41
float factor
Definition: lua.cpp:440
void resetLightState()
Definition: lighting.cpp:1223
float rada_squared
Definition: lighting.h:39
std::basic_string< char, std::char_traits< char >, std::allocator< char > > SCP_string
Definition: vmallocator.h:21
#define gr_set_light
Definition: 2d.h:906
float static_point_factor
Definition: lighting.cpp:746
void vm_vec_dist_squared_to_line(const vec3d *p, const vec3d *l0, const vec3d *l1, vec3d *nearest, float *dist_squared)
Definition: vecmat.cpp:2543
#define Int3()
Definition: pstypes.h:292
#define LM_BRIGHTEN
Definition: lighting.cpp:40
float vm_vec_mag_squared(const vec3d *v)
Definition: vecmat.cpp:339
#define CLAMP(x, min, max)
Definition: pstypes.h:488
#define AMBIENT_LIGHT_DEFAULT
Definition: lighting.cpp:52
vec3d Object_position
Definition: 3dsetup.cpp:42
SCP_vector< light * > Static_light
Definition: lighting.cpp:36
float spec_b
Definition: lighting.h:42
#define gr_set_lighting
Definition: 2d.h:924
GLfloat angle
Definition: Glext.h:10324
light_indexing_info bufferLights()
Definition: lighting.cpp:1193
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
vec3d vec2
Definition: lighting.h:35
GLdouble GLdouble GLdouble r
Definition: Glext.h:5337
float b
Definition: lighting.h:41
GLboolean GLboolean g
Definition: Glext.h:5781
void vm_vec_scale(vec3d *dest, float s)
Definition: vecmat.cpp:248
detail_levels Detail
Definition: systemvars.cpp:478
float g
Definition: lighting.h:41
GLboolean GLboolean GLboolean GLboolean a
Definition: Glext.h:5781
int Cmdline_nohtl
Definition: cmdline.cpp:438
int light_filter_push_box(const vec3d *min, const vec3d *max)
Definition: lighting.cpp:526
int vm_vec_dist_to_line(const vec3d *p, const vec3d *l0, const vec3d *l1, vec3d *nearest, float *dist)
Definition: vecmat.cpp:2503
float rada
Definition: lighting.h:39
float spec_r
Definition: lighting.h:42
int getNumStaticLights()
Definition: lighting.cpp:1218
hull_check p1
Definition: lua.cpp:5052
#define LT_TUBE
Definition: lighting.h:27
vec3d Light_base
Definition: 3dsetup.cpp:24
bool dc_maybe_stuff_boolean(bool *b)
Tries to stuff a bool from the Command_string.
float cone_angle
Definition: lighting.h:45
float static_tube_factor
Definition: lighting.cpp:745
bool dc_optional_string_either(const char *str1, const char *str2)
Searches for an optional string and it's alias.
bool setLights(const light_indexing_info *info)
Definition: lighting.cpp:1229
void light_filter_pop()
Definition: lighting.cpp:574
int instance
Definition: lighting.h:48
int idx
Definition: multiui.cpp:761
DCF(light,"Changes lighting parameters")
Definition: lighting.cpp:67
GLclampd n
Definition: Glext.h:7286
unsigned char ubyte
Definition: pstypes.h:62
void light_set_ambient(float ambient_light)
Definition: lighting.cpp:205
void vm_vec_copy_scale(vec3d *dest, const vec3d *src, float s)
Definition: vecmat.cpp:257
void dc_stuff_float(float *f)
Stuffs a float to the given variable.
int type
Definition: lighting.h:33
Definition: lighting.h:32
ubyte light_apply(const vec3d *pos, const vec3d *norm, float static_light_level)
Definition: lighting.cpp:666
int light_get_global_count()
Definition: lighting.cpp:608
float radb_squared
Definition: lighting.h:40
#define LT_POINT
Definition: lighting.h:26
void vm_vec_sub(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:168
void dc_stuff_string_white(char *out_str, size_t maxlen)
Stuffs a whitespace delimited string to out_str from the command line, stopping at the end of the com...
GLboolean GLboolean GLboolean b
Definition: Glext.h:5781
void dc_stuff_boolean(bool *b)
stuffs a boolean evaluated integer or string into the given variable.
#define LT_CONE
Definition: lighting.h:28
void light_add_tube(const vec3d *p0, const vec3d *p1, float r1, float r2, float intensity, float r, float g, float b, int affected_objnum, float spec_r, float spec_g, float spec_b, bool specular)
Definition: lighting.cpp:343
if(aifft_max_checks<=0)
Definition: aiturret.cpp:1581
typedef float(SCP_EXT_CALLCONV *SCPTRACKIR_PFFLOATVOID)()
float spec_g
Definition: lighting.h:42
#define fl2i(fl)
Definition: floating.h:33
#define MAX_LIGHT_LEVELS
Definition: lighting.cpp:25
void light_set_all_relevent()
Definition: lighting.cpp:644
void light_add_cone(const vec3d *pos, const vec3d *dir, float angle, float inner_angle, bool dual_cone, float r1, float r2, float intensity, float r, float g, float b, int light_ignore_objnum, float spec_r, float spec_g, float spec_b, bool specular)
Definition: lighting.cpp:1050
void light_reset()
Definition: lighting.cpp:150
An overhauled/updated debug console to allow monitoring, testing, and general debugging of new featur...
vec3d vec
Definition: lighting.h:34
float radb
Definition: lighting.h:40
hull_check pos
Definition: lua.cpp:5050
const GLfloat * m
Definition: Glext.h:10319
float vm_vec_dot(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:312
#define gr_reset_lighting
Definition: 2d.h:907
int Lighting_flag
Definition: lighting.cpp:63
void light_apply_rgb(ubyte *param_r, ubyte *param_g, ubyte *param_b, const vec3d *pos, const vec3d *norm, float static_light_level)
Definition: lighting.cpp:899
void light_apply_specular(ubyte *param_r, ubyte *param_g, ubyte *param_b, const vec3d *pos, const vec3d *norm, const vec3d *cam)
Definition: lighting.cpp:749
bool dc_optional_string(const char *pstr)
Searches for an optional string.
float intensity
Definition: lighting.h:38
double specular_exponent_value
Definition: lighting.cpp:747
void opengl_change_active_lights(int pos, int d_offset)
int Num_lights
Definition: lighting.cpp:29
int temp
Definition: lua.cpp:4996
float val_f
Definition: multilag.cpp:561
void dc_printf(const char *format,...)
Prints the given char string to the debug console.
Definition: console.cpp:358
bool is_minimum_GLSL_version()
Definition: gropengl.cpp:2064
float cone_inner_angle
Definition: lighting.h:46
void light_add_point_unique(const vec3d *pos, float r1, float r2, float intensity, float r, float g, float b, int affected_objnum, float spec_r, float spec_g, float spec_b, bool specular)
Definition: lighting.cpp:300
void light_set_shadow(int state)
Definition: lighting.cpp:638
float r
Definition: lighting.h:41
#define LM_DARKEN
Definition: lighting.cpp:41
int light_ignore_objnum
Definition: lighting.h:43
matrix Light_matrix
Definition: 3dsetup.cpp:23
#define LT_DIRECTIONAL
Definition: lighting.h:25
void vm_vec_add(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:159
void light_rotate_all()
Definition: lighting.cpp:585
void addLight(const light *light_ptr)
Definition: lighting.cpp:1106
int affected_objnum
Definition: lighting.h:44
float vm_vec_normalize(vec3d *v)
Definition: vecmat.cpp:460