Fix crash if Num_walls=0
[btb/d2x.git] / main / lighting.c
1 /* $Id: lighting.c,v 1.5 2004-08-28 23:17:45 schaffner Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14
15 /*
16  *
17  * Lighting functions.
18  *
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <conf.h>
23 #endif
24
25 #ifdef RCS
26 static char rcsid[] = "$Id: lighting.c,v 1.5 2004-08-28 23:17:45 schaffner Exp $";
27 #endif
28
29 #include <stdio.h>
30 #include <string.h>     // for memset()
31
32 #include "fix.h"
33 #include "vecmat.h"
34 #include "gr.h"
35 #include "inferno.h"
36 #include "segment.h"
37 #include "error.h"
38 #include "mono.h"
39 #include "render.h"
40 #include "game.h"
41 #include "vclip.h"
42 #include "lighting.h"
43 #include "3d.h"
44 #include "laser.h"
45 #include "timer.h"
46 #include "player.h"
47 #include "weapon.h"
48 #include "powerup.h"
49 #include "fvi.h"
50 #include "robot.h"
51 #include "multi.h"
52
53 int     Do_dynamic_light=1;
54 //int   Use_fvi_lighting = 0;
55
56 fix     Dynamic_light[MAX_VERTICES];
57
58 #define LIGHTING_CACHE_SIZE     4096    //      Must be power of 2!
59 #define LIGHTING_FRAME_DELTA    256     //      Recompute cache value every 8 frames.
60 #define LIGHTING_CACHE_SHIFT    8
61
62 int     Lighting_frame_delta = 1;
63
64 int     Lighting_cache[LIGHTING_CACHE_SIZE];
65
66 int Cache_hits=0, Cache_lookups=1;
67
68 //      Return true if we think vertex vertnum is visible from segment segnum.
69 //      If some amount of time has gone by, then recompute, else use cached value.
70 int lighting_cache_visible(int vertnum, int segnum, int objnum, vms_vector *obj_pos, int obj_seg, vms_vector *vertpos)
71 {
72         int     cache_val, cache_frame, cache_vis;
73
74         cache_val = Lighting_cache[((segnum << LIGHTING_CACHE_SHIFT) ^ vertnum) & (LIGHTING_CACHE_SIZE-1)];
75
76         cache_frame = cache_val >> 1;
77         cache_vis = cache_val & 1;
78
79 //mprintf((0, "%i %i %5i %i ", vertnum, segnum, cache_frame, cache_vis));
80
81 Cache_lookups++;
82         if ((cache_frame == 0) || (cache_frame + Lighting_frame_delta <= FrameCount)) {
83                 int                     apply_light=0;
84                 fvi_query       fq;
85                 fvi_info                hit_data;
86                 int                     segnum, hit_type;
87
88                 segnum = -1;
89
90                 #ifndef NDEBUG
91                 segnum = find_point_seg(obj_pos, obj_seg);
92                 if (segnum == -1) {
93                         Int3();         //      Obj_pos is not in obj_seg!
94                         return 0;               //      Done processing this object.
95                 }
96                 #endif
97
98                 fq.p0                                           = obj_pos;
99                 fq.startseg                             = obj_seg;
100                 fq.p1                                           = vertpos;
101                 fq.rad                                  = 0;
102                 fq.thisobjnum                   = objnum;
103                 fq.ignore_obj_list      = NULL;
104                 fq.flags                                        = FQ_TRANSWALL;
105
106                 hit_type = find_vector_intersection(&fq, &hit_data);
107
108                 // Hit_pos = Hit_data.hit_pnt;
109                 // Hit_seg = Hit_data.hit_seg;
110
111                 if (hit_type == HIT_OBJECT)
112                         Int3(); //      Hey, we're not supposed to be checking objects!
113
114                 if (hit_type == HIT_NONE)
115                         apply_light = 1;
116                 else if (hit_type == HIT_WALL) {
117                         fix     dist_dist;
118                         dist_dist = vm_vec_dist_quick(&hit_data.hit_pnt, obj_pos);
119                         if (dist_dist < F1_0/4) {
120                                 apply_light = 1;
121                                 // -- Int3();   //      Curious, did fvi detect intersection with wall containing vertex?
122                         }
123                 }
124                 Lighting_cache[((segnum << LIGHTING_CACHE_SHIFT) ^ vertnum) & (LIGHTING_CACHE_SIZE-1)] = apply_light + (FrameCount << 1);
125 //mprintf((0, "%i\n", apply_light));
126                 return apply_light;
127         } else {
128 //mprintf((0, "\n"));
129 Cache_hits++;
130                 return cache_vis;
131         }       
132 }
133
134 #define HEADLIGHT_CONE_DOT      (F1_0*9/10)
135 #define HEADLIGHT_SCALE         (F1_0*10)
136
137 // ----------------------------------------------------------------------------------------------
138 void apply_light(fix obj_intensity, int obj_seg, vms_vector *obj_pos, int n_render_vertices, short *render_vertices, int objnum)
139 {
140         int     vv;
141
142         if (obj_intensity) {
143                 fix     obji_64 = obj_intensity*64;
144
145                 // for pretty dim sources, only process vertices in object's own segment.
146                 //      12/04/95, MK, markers only cast light in own segment.
147                 if ((abs(obji_64) <= F1_0*8) || (Objects[objnum].type == OBJ_MARKER)) {
148                         short *vp = Segments[obj_seg].verts;
149
150                         for (vv=0; vv<MAX_VERTICES_PER_SEGMENT; vv++) {
151                                 int                     vertnum;
152                                 vms_vector      *vertpos;
153                                 fix                     dist;
154
155                                 vertnum = vp[vv];
156                                 if ((vertnum ^ FrameCount) & 1) {
157                                         vertpos = &Vertices[vertnum];
158                                         dist = vm_vec_dist_quick(obj_pos, vertpos);
159                                         dist = fixmul(dist/4, dist/4);
160                                         if (dist < abs(obji_64)) {
161                                                 if (dist < MIN_LIGHT_DIST)
162                                                         dist = MIN_LIGHT_DIST;
163         
164                                                 Dynamic_light[vertnum] += fixdiv(obj_intensity, dist);
165                                         }
166                                 }
167                         }
168                 } else {
169                         int     headlight_shift = 0;
170                         fix     max_headlight_dist = F1_0*200;
171
172                         if (Objects[objnum].type == OBJ_PLAYER)
173                                 if (Players[Objects[objnum].id].flags & PLAYER_FLAGS_HEADLIGHT_ON) {
174                                         headlight_shift = 3;
175                                         if (Objects[objnum].id != Player_num) {
176                                                 vms_vector      tvec;
177                                                 fvi_query       fq;
178                                                 fvi_info                hit_data;
179                                                 int                     fate;
180
181                                                 vm_vec_scale_add(&tvec, &Objects[objnum].pos, &Objects[objnum].orient.fvec, F1_0*200);
182
183                                                 fq.startseg                             = Objects[objnum].segnum;
184                                                 fq.p0                                           = &Objects[objnum].pos;
185                                                 fq.p1                                           = &tvec;
186                                                 fq.rad                                  = 0;
187                                                 fq.thisobjnum                   = objnum;
188                                                 fq.ignore_obj_list      = NULL;
189                                                 fq.flags                                        = FQ_TRANSWALL;
190
191                                                 fate = find_vector_intersection(&fq, &hit_data);
192                                                 if (fate != HIT_NONE)
193                                                         max_headlight_dist = vm_vec_mag_quick(vm_vec_sub(&tvec, &hit_data.hit_pnt, &Objects[objnum].pos)) + F1_0*4;
194                                         }
195                                 }
196                         // -- for (vv=FrameCount&1; vv<n_render_vertices; vv+=2) {
197                         for (vv=0; vv<n_render_vertices; vv++) {
198                                 int                     vertnum;
199                                 vms_vector      *vertpos;
200                                 fix                     dist;
201                                 int                     apply_light;
202
203                                 vertnum = render_vertices[vv];
204                                 if ((vertnum ^ FrameCount) & 1) {
205                                         vertpos = &Vertices[vertnum];
206                                         dist = vm_vec_dist_quick(obj_pos, vertpos);
207                                         apply_light = 0;
208
209                                         if ((dist >> headlight_shift) < abs(obji_64)) {
210
211                                                 if (dist < MIN_LIGHT_DIST)
212                                                         dist = MIN_LIGHT_DIST;
213
214                                                 //if (Use_fvi_lighting) {
215                                                 //      if (lighting_cache_visible(vertnum, obj_seg, objnum, obj_pos, obj_seg, vertpos)) {
216                                                 //              apply_light = 1;
217                                                 //      }
218                                                 //} else
219                                                         apply_light = 1;
220
221                                                 if (apply_light) {
222                                                         if (headlight_shift) {
223                                                                 fix                     dot;
224                                                                 vms_vector      vec_to_point;
225
226                                                                 vm_vec_sub(&vec_to_point, vertpos, obj_pos);
227                                                                 vm_vec_normalize_quick(&vec_to_point);          //      MK, Optimization note: You compute distance about 15 lines up, this is partially redundant
228                                                                 dot = vm_vec_dot(&vec_to_point, &Objects[objnum].orient.fvec);
229                                                                 if (dot < F1_0/2)
230                                                                         Dynamic_light[vertnum] += fixdiv(obj_intensity, fixmul(HEADLIGHT_SCALE, dist)); //      Do the normal thing, but darken around headlight.
231                                                                 else {
232                                                                         if (Game_mode & GM_MULTI) {
233                                                                                 if (dist < max_headlight_dist)
234                                                                                         Dynamic_light[vertnum] += fixmul(fixmul(dot, dot), obj_intensity)/8;
235                                                                         } else
236                                                                                 Dynamic_light[vertnum] += fixmul(fixmul(dot, dot), obj_intensity)/8;
237                                                                 }
238                                                         } else
239                                                                 Dynamic_light[vertnum] += fixdiv(obj_intensity, dist);
240                                                 }
241                                         }
242                                 }
243                         }
244                 }
245         }
246 }
247
248 #define FLASH_LEN_FIXED_SECONDS (F1_0/3)
249 #define FLASH_SCALE                                     (3*F1_0/FLASH_LEN_FIXED_SECONDS)
250
251 // ----------------------------------------------------------------------------------------------
252 void cast_muzzle_flash_light(int n_render_vertices, short *render_vertices)
253 {
254         fix current_time;
255         int     i;
256         short   time_since_flash;
257
258         current_time = timer_get_fixed_seconds();
259
260         for (i=0; i<MUZZLE_QUEUE_MAX; i++) {
261                 if (Muzzle_data[i].create_time) {
262                         time_since_flash = current_time - Muzzle_data[i].create_time;
263                         if (time_since_flash < FLASH_LEN_FIXED_SECONDS)
264                                 apply_light((FLASH_LEN_FIXED_SECONDS - time_since_flash) * FLASH_SCALE, Muzzle_data[i].segnum, &Muzzle_data[i].pos, n_render_vertices, render_vertices, -1);
265                         else
266                                 Muzzle_data[i].create_time = 0;         // turn off this muzzle flash
267                 }
268         }
269 }
270
271 //      Translation table to make flares flicker at different rates
272 fix     Obj_light_xlate[16] =
273         {0x1234, 0x3321, 0x2468, 0x1735,
274          0x0123, 0x19af, 0x3f03, 0x232a,
275          0x2123, 0x39af, 0x0f03, 0x132a,
276          0x3123, 0x29af, 0x1f03, 0x032a};
277
278 //      Flag array of objects lit last frame.  Guaranteed to process this frame if lit last frame.
279 sbyte   Lighting_objects[MAX_OBJECTS];
280
281 #define MAX_HEADLIGHTS  8
282 object  *Headlights[MAX_HEADLIGHTS];
283 int             Num_headlights;
284
285 // ---------------------------------------------------------
286 fix compute_light_intensity(int objnum)
287 {
288         object          *obj = &Objects[objnum];
289         int                     objtype = obj->type;
290    fix hoardlight,s;
291         
292         switch (objtype) {
293                 case OBJ_PLAYER:
294                          if (Players[obj->id].flags & PLAYER_FLAGS_HEADLIGHT_ON) {
295                                 if (Num_headlights < MAX_HEADLIGHTS)
296                                         Headlights[Num_headlights++] = obj;
297                                 return HEADLIGHT_SCALE;
298                          } else if ((Game_mode & GM_HOARD) && Players[obj->id].secondary_ammo[PROXIMITY_INDEX]) {
299                         
300                    // If hoard game and player, add extra light based on how many orbs you have
301                         // Pulse as well.
302
303                            hoardlight=i2f(Players[obj->id].secondary_ammo[PROXIMITY_INDEX])/2; //i2f(12));
304                                 hoardlight++;
305                       fix_sincos ((GameTime/2) & 0xFFFF,&s,NULL); // probably a bad way to do it
306                            s+=F1_0; 
307                                 s>>=1;
308                            hoardlight=fixmul (s,hoardlight);
309                  //     mprintf ((0,"Hoardlight is %f!\n",f2fl(hoardlight)));
310                       return (hoardlight);
311                           }
312                         else
313                                 return max(vm_vec_mag_quick(&obj->mtype.phys_info.thrust)/4, F1_0*2) + F1_0/2;
314                         break;
315                 case OBJ_FIREBALL:
316                         if (obj->id != 0xff) {
317                                 if (obj->lifeleft < F1_0*4)
318                                         return fixmul(fixdiv(obj->lifeleft, Vclip[obj->id].play_time), Vclip[obj->id].light_value);
319                                 else
320                                         return Vclip[obj->id].light_value;
321                         } else
322                                  return 0;
323                         break;
324                 case OBJ_ROBOT:
325                         return F1_0*Robot_info[obj->id].lightcast;
326                         break;
327                 case OBJ_WEAPON: {
328                         fix tval = Weapon_info[obj->id].light;
329                         if (Game_mode & GM_MULTI)
330                                 if (obj->id == OMEGA_ID)
331                                         if (d_rand() > 8192)
332                                                 return 0;               //      3/4 of time, omega blobs will cast 0 light!
333
334                         if (obj->id == FLARE_ID )
335                                 return 2* (min(tval, obj->lifeleft) + ((GameTime ^ Obj_light_xlate[objnum&0x0f]) & 0x3fff));
336                         else
337                                 return tval;
338                 }
339
340                 case OBJ_MARKER: {
341                         fix     lightval = obj->lifeleft;
342
343                         lightval &= 0xffff;
344
345                         lightval = 8 * abs(F1_0/2 - lightval);
346
347                         if (obj->lifeleft < F1_0*1000)
348                                 obj->lifeleft += F1_0;  //      Make sure this object doesn't go out.
349
350                         return lightval;
351                 }
352
353                 case OBJ_POWERUP:
354                         return Powerup_info[obj->id].light;
355                         break;
356                 case OBJ_DEBRIS:
357                         return F1_0/4;
358                         break;
359                 case OBJ_LIGHT:
360                         return obj->ctype.light_info.intensity;
361                         break;
362                 default:
363                         return 0;
364                         break;
365         }
366 }
367
368 // ----------------------------------------------------------------------------------------------
369 void set_dynamic_light(void)
370 {
371         int     vv;
372         int     objnum;
373         int     n_render_vertices;
374         short   render_vertices[MAX_VERTICES];
375         sbyte   render_vertex_flags[MAX_VERTICES];
376         int     render_seg,segnum, v;
377         sbyte   new_lighting_objects[MAX_OBJECTS];
378
379         Num_headlights = 0;
380
381         if (!Do_dynamic_light)
382                 return;
383
384 //if (Use_fvi_lighting)
385 //      mprintf((0, "hits = %8i, misses = %8i, lookups = %8i, hit ratio = %7.4f\n", Cache_hits, Cache_lookups - Cache_hits, Cache_lookups, (float) Cache_hits / Cache_lookups));
386
387         memset(render_vertex_flags, 0, Highest_vertex_index+1);
388
389         //      Create list of vertices that need to be looked at for setting of ambient light.
390         n_render_vertices = 0;
391         for (render_seg=0; render_seg<N_render_segs; render_seg++) {
392                 segnum = Render_list[render_seg];
393                 if (segnum != -1) {
394                         short   *vp = Segments[segnum].verts;
395                         for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++) {
396                                 int     vnum = vp[v];
397                                 if (vnum<0 || vnum>Highest_vertex_index) {
398                                         Int3();         //invalid vertex number
399                                         continue;       //ignore it, and go on to next one
400                                 }
401                                 if (!render_vertex_flags[vnum]) {
402                                         render_vertex_flags[vnum] = 1;
403                                         render_vertices[n_render_vertices++] = vnum;
404                                 }
405                                 //--old way-- for (s=0; s<n_render_vertices; s++)
406                                 //--old way--   if (render_vertices[s] == vnum)
407                                 //--old way--           break;
408                                 //--old way-- if (s == n_render_vertices)
409                                 //--old way--   render_vertices[n_render_vertices++] = vnum;
410                         }
411                 }
412         }
413
414         // -- for (vertnum=FrameCount&1; vertnum<n_render_vertices; vertnum+=2) {
415         for (vv=0; vv<n_render_vertices; vv++) {
416                 int     vertnum;
417
418                 vertnum = render_vertices[vv];
419                 Assert(vertnum >= 0 && vertnum <= Highest_vertex_index);
420                 if ((vertnum ^ FrameCount) & 1)
421                         Dynamic_light[vertnum] = 0;
422         }
423
424         cast_muzzle_flash_light(n_render_vertices, render_vertices);
425
426         for (objnum=0; objnum<=Highest_object_index; objnum++)
427                 new_lighting_objects[objnum] = 0;
428
429         //      July 5, 1995: New faster dynamic lighting code.  About 5% faster on the PC (un-optimized).
430         //      Only objects which are in rendered segments cast dynamic light.  We might wad6 to extend this
431         //      one or two segments if we notice light changing as objects go offscreen.  I couldn't see any
432         //      serious visual degradation.  In fact, I could see no humorous degradation, either. --MK
433         for (render_seg=0; render_seg<N_render_segs; render_seg++) {
434                 int     segnum = Render_list[render_seg];
435
436                 objnum = Segments[segnum].objects;
437
438                 while (objnum != -1) {
439                         object          *obj = &Objects[objnum];
440                         vms_vector      *objpos = &obj->pos;
441                         fix                     obj_intensity;
442
443                         obj_intensity = compute_light_intensity(objnum);
444
445                         if (obj_intensity) {
446                                 apply_light(obj_intensity, obj->segnum, objpos, n_render_vertices, render_vertices, obj-Objects);
447                                 new_lighting_objects[objnum] = 1;
448                         }
449
450                         objnum = obj->next;
451                 }
452         }
453
454         //      Now, process all lights from last frame which haven't been processed this frame.
455         for (objnum=0; objnum<=Highest_object_index; objnum++) {
456                 //      In multiplayer games, process even unprocessed objects every 4th frame, else don't know about player sneaking up.
457                 if ((Lighting_objects[objnum]) || ((Game_mode & GM_MULTI) && (((objnum ^ FrameCount) & 3) == 0))) {
458                         if (!new_lighting_objects[objnum]) {
459                                 //      Lighted last frame, but not this frame.  Get intensity...
460                                 object          *obj = &Objects[objnum];
461                                 vms_vector      *objpos = &obj->pos;
462                                 fix                     obj_intensity;
463
464                                 obj_intensity = compute_light_intensity(objnum);
465
466                                 if (obj_intensity) {
467                                         apply_light(obj_intensity, obj->segnum, objpos, n_render_vertices, render_vertices, objnum);
468                                         Lighting_objects[objnum] = 1;
469                                 } else
470                                         Lighting_objects[objnum] = 0;
471                         }
472                 } else {
473                         //      Not lighted last frame, so we don't need to light it.  (Already lit if casting light this frame.)
474                         //      But copy value from new_lighting_objects to update Lighting_objects array.
475                         Lighting_objects[objnum] = new_lighting_objects[objnum];
476                 }
477         }
478 }
479
480 // ---------------------------------------------------------
481
482 void toggle_headlight_active()
483 {
484         if (Players[Player_num].flags & PLAYER_FLAGS_HEADLIGHT) {
485                 Players[Player_num].flags ^= PLAYER_FLAGS_HEADLIGHT_ON;                 
486 #ifdef NETWORK
487                 if (Game_mode & GM_MULTI)
488                         multi_send_flags(Player_num);           
489 #endif
490         }
491 }
492
493 #define HEADLIGHT_BOOST_SCALE 8         //how much to scale light when have headlight boost
494
495 fix     Beam_brightness = (F1_0/2);     //global saying how bright the light beam is
496
497 #define MAX_DIST_LOG    6                                                       //log(MAX_DIST-expressed-as-integer)
498 #define MAX_DIST                (f1_0<<MAX_DIST_LOG)    //no light beyond this dist
499
500 fix compute_headlight_light_on_object(object *objp)
501 {
502         int     i;
503         fix     light;
504
505         //      Let's just illuminate players and robots for speed reasons, ok?
506         if ((objp->type != OBJ_ROBOT) && (objp->type    != OBJ_PLAYER))
507                 return 0;
508
509         light = 0;
510
511         for (i=0; i<Num_headlights; i++) {
512                 fix                     dot, dist;
513                 vms_vector      vec_to_obj;
514                 object          *light_objp;
515
516                 light_objp = Headlights[i];
517
518                 vm_vec_sub(&vec_to_obj, &objp->pos, &light_objp->pos);
519                 dist = vm_vec_normalize_quick(&vec_to_obj);
520                 if (dist > 0) {
521                         dot = vm_vec_dot(&light_objp->orient.fvec, &vec_to_obj);
522
523                         if (dot < F1_0/2)
524                                 light += fixdiv(HEADLIGHT_SCALE, fixmul(HEADLIGHT_SCALE, dist));        //      Do the normal thing, but darken around headlight.
525                         else
526                                 light += fixmul(fixmul(dot, dot), HEADLIGHT_SCALE)/8;
527                 }
528         }
529
530         return light;
531 }
532
533
534 // -- Unused -- //Compute the lighting from the headlight for a given vertex on a face.
535 // -- Unused -- //Takes:
536 // -- Unused -- //  point - the 3d coords of the point
537 // -- Unused -- //  face_light - a scale factor derived from the surface normal of the face
538 // -- Unused -- //If no surface normal effect is wanted, pass F1_0 for face_light
539 // -- Unused -- fix compute_headlight_light(vms_vector *point,fix face_light)
540 // -- Unused -- {
541 // -- Unused --         fix light;
542 // -- Unused --         int use_beam = 0;               //flag for beam effect
543 // -- Unused --
544 // -- Unused --         light = Beam_brightness;
545 // -- Unused --
546 // -- Unused --         if ((Players[Player_num].flags & PLAYER_FLAGS_HEADLIGHT) && (Players[Player_num].flags & PLAYER_FLAGS_HEADLIGHT_ON) && Viewer==&Objects[Players[Player_num].objnum] && Players[Player_num].energy > 0) {
547 // -- Unused --                 light *= HEADLIGHT_BOOST_SCALE;
548 // -- Unused --                 use_beam = 1;   //give us beam effect
549 // -- Unused --         }
550 // -- Unused --
551 // -- Unused --         if (light) {                            //if no beam, don't bother with the rest of this
552 // -- Unused --                 fix point_dist;
553 // -- Unused --
554 // -- Unused --                 point_dist = vm_vec_mag_quick(point);
555 // -- Unused --
556 // -- Unused --                 if (point_dist >= MAX_DIST)
557 // -- Unused --
558 // -- Unused --                         light = 0;
559 // -- Unused --
560 // -- Unused --                 else {
561 // -- Unused --                         fix dist_scale,face_scale;
562 // -- Unused --
563 // -- Unused --                         dist_scale = (MAX_DIST - point_dist) >> MAX_DIST_LOG;
564 // -- Unused --                         light = fixmul(light,dist_scale);
565 // -- Unused --
566 // -- Unused --                         if (face_light < 0)
567 // -- Unused --                                 face_light = 0;
568 // -- Unused --
569 // -- Unused --                         face_scale = f1_0/4 + face_light/2;
570 // -- Unused --                         light = fixmul(light,face_scale);
571 // -- Unused --
572 // -- Unused --                         if (use_beam) {
573 // -- Unused --                                 fix beam_scale;
574 // -- Unused --
575 // -- Unused --                                 if (face_light > f1_0*3/4 && point->z > i2f(12)) {
576 // -- Unused --                                         beam_scale = fixdiv(point->z,point_dist);
577 // -- Unused --                                         beam_scale = fixmul(beam_scale,beam_scale);     //square it
578 // -- Unused --                                         light = fixmul(light,beam_scale);
579 // -- Unused --                                 }
580 // -- Unused --                         }
581 // -- Unused --                 }
582 // -- Unused --         }
583 // -- Unused --
584 // -- Unused --         return light;
585 // -- Unused -- }
586
587 //compute the average dynamic light in a segment.  Takes the segment number
588 fix compute_seg_dynamic_light(int segnum)
589 {
590         fix sum;
591         segment *seg;
592         short *verts;
593
594         seg = &Segments[segnum];
595
596         verts = seg->verts;
597         sum = 0;
598
599         sum += Dynamic_light[*verts++];
600         sum += Dynamic_light[*verts++];
601         sum += Dynamic_light[*verts++];
602         sum += Dynamic_light[*verts++];
603         sum += Dynamic_light[*verts++];
604         sum += Dynamic_light[*verts++];
605         sum += Dynamic_light[*verts++];
606         sum += Dynamic_light[*verts];
607
608         return sum >> 3;
609
610 }
611
612 fix object_light[MAX_OBJECTS];
613 int object_sig[MAX_OBJECTS];
614 object *old_viewer;
615 int reset_lighting_hack;
616
617 #define LIGHT_RATE i2f(4)               //how fast the light ramps up
618
619 void start_lighting_frame(object *viewer)
620 {
621         reset_lighting_hack = (viewer != old_viewer);
622
623         old_viewer = viewer;
624 }
625
626 //compute the lighting for an object.  Takes a pointer to the object,
627 //and possibly a rotated 3d point.  If the point isn't specified, the
628 //object's center point is rotated.
629 fix compute_object_light(object *obj,vms_vector *rotated_pnt)
630 {
631         fix light;
632         g3s_point objpnt;
633         int objnum = obj-Objects;
634
635         if (!rotated_pnt) {
636                 g3_rotate_point(&objpnt,&obj->pos);
637                 rotated_pnt = &objpnt.p3_vec;
638         }
639
640         //First, get static light for this segment
641
642         light = Segment2s[obj->segnum].static_light;
643
644         //return light;
645
646
647         //Now, maybe return different value to smooth transitions
648
649         if (!reset_lighting_hack && object_sig[objnum] == obj->signature) {
650                 fix delta_light,frame_delta;
651
652                 delta_light = light - object_light[objnum];
653
654                 frame_delta = fixmul(LIGHT_RATE,FrameTime);
655
656                 if (abs(delta_light) <= frame_delta)
657
658                         object_light[objnum] = light;           //we've hit the goal
659
660                 else
661
662                         if (delta_light < 0)
663                                 light = object_light[objnum] -= frame_delta;
664                         else
665                                 light = object_light[objnum] += frame_delta;
666
667         }
668         else {          //new object, initialize
669
670                 object_sig[objnum] = obj->signature;
671                 object_light[objnum] = light;
672         }
673
674
675
676         //Next, add in headlight on this object
677
678         // -- Matt code: light += compute_headlight_light(rotated_pnt,f1_0);
679         light += compute_headlight_light_on_object(obj);
680  
681         //Finally, add in dynamic light for this segment
682
683         light += compute_seg_dynamic_light(obj->segnum);
684
685
686         return light;
687 }
688
689