]> icculus.org git repositories - btb/d2x.git/blob - main/lighting.c
added big pigsize for shareware d1 v1.4
[btb/d2x.git] / main / lighting.c
1 /* $Id: lighting.c,v 1.4 2003-10-04 03:14:47 btb 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  * Old Log:
20  * Revision 1.4  1995/09/20  14:26:12  allender
21  * more optimizations(?) ala MK
22  *
23  * Revision 1.2  1995/07/05  21:27:31  allender
24  * new and improved lighting code by MK!
25  *
26  * Revision 2.1  1995/07/24  13:21:56  john
27  * Added new lighting calculation code to speed things up.
28  *
29  * Revision 2.0  1995/02/27  11:27:33  john
30  * New version 2.0, which has no anonymous unions, builds with
31  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
32  *
33  * Revision 1.43  1995/02/22  13:57:10  allender
34  * remove anonymous union from object structure
35  *
36  * Revision 1.42  1995/02/13  20:35:07  john
37  * Lintized
38  *
39  * Revision 1.41  1995/02/04  21:43:40  matt
40  * Changed an assert() to an int3() and deal with the bad case
41  *
42  * Revision 1.40  1995/01/15  20:48:27  mike
43  * support light field for powerups.
44  *
45  * Revision 1.39  1994/12/15  13:04:19  mike
46  * Replace Players[Player_num].time_total references with GameTime.
47  *
48  * Revision 1.38  1994/11/28  21:50:41  mike
49  * optimizations.
50  *
51  * Revision 1.37  1994/11/28  01:32:33  mike
52  * lighting optimization.
53  *
54  * Revision 1.36  1994/11/15  12:01:00  john
55  * Changed a bunch of code that uses timer_get_milliseconds to
56  * timer_get_fixed_Seconds.
57  *
58  * Revision 1.35  1994/10/31  21:56:07  matt
59  * Fixed bug & added error checking
60  *
61  * Revision 1.34  1994/10/21  11:24:57  mike
62  * Trap divide overflows in lighting.
63  *
64  * Revision 1.33  1994/10/08  14:49:11  matt
65  * If viewer changed, don't do smooth lighting hack
66  *
67  * Revision 1.32  1994/09/25  23:41:07  matt
68  * Changed the object load & save code to read/write the structure fields one
69  * at a time (rather than the whole structure at once).  This mean that the
70  * object structure can be changed without breaking the load/save functions.
71  * As a result of this change, the local_object data can be and has been
72  * incorporated into the object array.  Also, timeleft is now a property
73  * of all objects, and the object structure has been otherwise cleaned up.
74  *
75  * Revision 1.31  1994/09/25  15:45:15  matt
76  * Added OBJ_LIGHT, a type of object that casts light
77  * Added generalized lifeleft, and moved it to local_object
78  *
79  * Revision 1.30  1994/09/11  15:48:27  mike
80  * Use vm_vec_mag_quick in place of vm_vec_mag in point_dist computation.
81  *
82  * Revision 1.29  1994/09/08  21:44:49  matt
83  * Made lighting ramp 4x as fast; made only static (ambient) light ramp
84  * up, but not headlight & dynamic light
85  *
86  * Revision 1.28  1994/09/02  14:00:07  matt
87  * Simplified explode_object() & mutliple-stage explosions
88  *
89  * Revision 1.27  1994/08/29  19:06:44  mike
90  * Make lighting proportional to square of distance, not linear.
91  *
92  * Revision 1.26  1994/08/25  18:08:38  matt
93  * Made muzzle flash cast 3x as much light
94  *
95  * Revision 1.25  1994/08/23  16:38:31  mike
96  * Key weapon light off bitmaps.tbl.
97  *
98  * Revision 1.24  1994/08/13  12:20:44  john
99  * Made the networking uise the Players array.
100  *
101  * Revision 1.23  1994/08/12  22:42:18  john
102  * Took away Player_stats; added Players array.
103  *
104  * Revision 1.22  1994/07/06  10:19:22  matt
105  * Changed include
106  *
107  * Revision 1.21  1994/06/28  13:20:22  mike
108  * Oops, fixed a dumb typo.
109  *
110  * Revision 1.20  1994/06/28  12:53:25  mike
111  * Change lighting function for flares, make brighter and asynchronously flicker.
112  *
113  * Revision 1.19  1994/06/27  18:31:15  mike
114  * Add flares.
115  *
116  * Revision 1.18  1994/06/20  13:41:17  matt
117  * Added time-based gradual lighting hack for objects
118  * Took out strobing robots
119  *
120  * Revision 1.17  1994/06/19  16:25:54  mike
121  * Optimize lighting.
122  *
123  * Revision 1.16  1994/06/17  18:08:08  mike
124  * Make robots cast more and variable light.
125  *
126  * Revision 1.15  1994/06/13  15:15:55  mike
127  * Fix phantom light, every 64K milliseconds, muzzle flash would flash again.
128  *
129  */
130
131 #ifdef HAVE_CONFIG_H
132 #include <conf.h>
133 #endif
134
135 #ifdef RCS
136 static char rcsid[] = "$Id: lighting.c,v 1.4 2003-10-04 03:14:47 btb Exp $";
137 #endif
138
139 #include <stdio.h>
140 #include <string.h>     // for memset()
141
142 #include "fix.h"
143 #include "vecmat.h"
144 #include "gr.h"
145 #include "inferno.h"
146 #include "segment.h"
147 #include "error.h"
148 #include "mono.h"
149 #include "render.h"
150 #include "game.h"
151 #include "vclip.h"
152 #include "lighting.h"
153 #include "3d.h"
154 #include "laser.h"
155 #include "timer.h"
156 #include "player.h"
157 #include "weapon.h"
158 #include "powerup.h"
159 #include "fvi.h"
160 #include "robot.h"
161 #include "multi.h"
162
163 int     Do_dynamic_light=1;
164 //int   Use_fvi_lighting = 0;
165
166 fix     Dynamic_light[MAX_VERTICES];
167
168 #define LIGHTING_CACHE_SIZE     4096    //      Must be power of 2!
169 #define LIGHTING_FRAME_DELTA    256     //      Recompute cache value every 8 frames.
170 #define LIGHTING_CACHE_SHIFT    8
171
172 int     Lighting_frame_delta = 1;
173
174 int     Lighting_cache[LIGHTING_CACHE_SIZE];
175
176 int Cache_hits=0, Cache_lookups=1;
177
178 //      Return true if we think vertex vertnum is visible from segment segnum.
179 //      If some amount of time has gone by, then recompute, else use cached value.
180 int lighting_cache_visible(int vertnum, int segnum, int objnum, vms_vector *obj_pos, int obj_seg, vms_vector *vertpos)
181 {
182         int     cache_val, cache_frame, cache_vis;
183
184         cache_val = Lighting_cache[((segnum << LIGHTING_CACHE_SHIFT) ^ vertnum) & (LIGHTING_CACHE_SIZE-1)];
185
186         cache_frame = cache_val >> 1;
187         cache_vis = cache_val & 1;
188
189 //mprintf((0, "%i %i %5i %i ", vertnum, segnum, cache_frame, cache_vis));
190
191 Cache_lookups++;
192         if ((cache_frame == 0) || (cache_frame + Lighting_frame_delta <= FrameCount)) {
193                 int                     apply_light=0;
194                 fvi_query       fq;
195                 fvi_info                hit_data;
196                 int                     segnum, hit_type;
197
198                 segnum = -1;
199
200                 #ifndef NDEBUG
201                 segnum = find_point_seg(obj_pos, obj_seg);
202                 if (segnum == -1) {
203                         Int3();         //      Obj_pos is not in obj_seg!
204                         return 0;               //      Done processing this object.
205                 }
206                 #endif
207
208                 fq.p0                                           = obj_pos;
209                 fq.startseg                             = obj_seg;
210                 fq.p1                                           = vertpos;
211                 fq.rad                                  = 0;
212                 fq.thisobjnum                   = objnum;
213                 fq.ignore_obj_list      = NULL;
214                 fq.flags                                        = FQ_TRANSWALL;
215
216                 hit_type = find_vector_intersection(&fq, &hit_data);
217
218                 // Hit_pos = Hit_data.hit_pnt;
219                 // Hit_seg = Hit_data.hit_seg;
220
221                 if (hit_type == HIT_OBJECT)
222                         Int3(); //      Hey, we're not supposed to be checking objects!
223
224                 if (hit_type == HIT_NONE)
225                         apply_light = 1;
226                 else if (hit_type == HIT_WALL) {
227                         fix     dist_dist;
228                         dist_dist = vm_vec_dist_quick(&hit_data.hit_pnt, obj_pos);
229                         if (dist_dist < F1_0/4) {
230                                 apply_light = 1;
231                                 // -- Int3();   //      Curious, did fvi detect intersection with wall containing vertex?
232                         }
233                 }
234                 Lighting_cache[((segnum << LIGHTING_CACHE_SHIFT) ^ vertnum) & (LIGHTING_CACHE_SIZE-1)] = apply_light + (FrameCount << 1);
235 //mprintf((0, "%i\n", apply_light));
236                 return apply_light;
237         } else {
238 //mprintf((0, "\n"));
239 Cache_hits++;
240                 return cache_vis;
241         }       
242 }
243
244 #define HEADLIGHT_CONE_DOT      (F1_0*9/10)
245 #define HEADLIGHT_SCALE         (F1_0*10)
246
247 // ----------------------------------------------------------------------------------------------
248 void apply_light(fix obj_intensity, int obj_seg, vms_vector *obj_pos, int n_render_vertices, short *render_vertices, int objnum)
249 {
250         int     vv;
251
252         if (obj_intensity) {
253                 fix     obji_64 = obj_intensity*64;
254
255                 // for pretty dim sources, only process vertices in object's own segment.
256                 //      12/04/95, MK, markers only cast light in own segment.
257                 if ((abs(obji_64) <= F1_0*8) || (Objects[objnum].type == OBJ_MARKER)) {
258                         short *vp = Segments[obj_seg].verts;
259
260                         for (vv=0; vv<MAX_VERTICES_PER_SEGMENT; vv++) {
261                                 int                     vertnum;
262                                 vms_vector      *vertpos;
263                                 fix                     dist;
264
265                                 vertnum = vp[vv];
266                                 if ((vertnum ^ FrameCount) & 1) {
267                                         vertpos = &Vertices[vertnum];
268                                         dist = vm_vec_dist_quick(obj_pos, vertpos);
269                                         dist = fixmul(dist/4, dist/4);
270                                         if (dist < abs(obji_64)) {
271                                                 if (dist < MIN_LIGHT_DIST)
272                                                         dist = MIN_LIGHT_DIST;
273         
274                                                 Dynamic_light[vertnum] += fixdiv(obj_intensity, dist);
275                                         }
276                                 }
277                         }
278                 } else {
279                         int     headlight_shift = 0;
280                         fix     max_headlight_dist = F1_0*200;
281
282                         if (Objects[objnum].type == OBJ_PLAYER)
283                                 if (Players[Objects[objnum].id].flags & PLAYER_FLAGS_HEADLIGHT_ON) {
284                                         headlight_shift = 3;
285                                         if (Objects[objnum].id != Player_num) {
286                                                 vms_vector      tvec;
287                                                 fvi_query       fq;
288                                                 fvi_info                hit_data;
289                                                 int                     fate;
290
291                                                 vm_vec_scale_add(&tvec, &Objects[objnum].pos, &Objects[objnum].orient.fvec, F1_0*200);
292
293                                                 fq.startseg                             = Objects[objnum].segnum;
294                                                 fq.p0                                           = &Objects[objnum].pos;
295                                                 fq.p1                                           = &tvec;
296                                                 fq.rad                                  = 0;
297                                                 fq.thisobjnum                   = objnum;
298                                                 fq.ignore_obj_list      = NULL;
299                                                 fq.flags                                        = FQ_TRANSWALL;
300
301                                                 fate = find_vector_intersection(&fq, &hit_data);
302                                                 if (fate != HIT_NONE)
303                                                         max_headlight_dist = vm_vec_mag_quick(vm_vec_sub(&tvec, &hit_data.hit_pnt, &Objects[objnum].pos)) + F1_0*4;
304                                         }
305                                 }
306                         // -- for (vv=FrameCount&1; vv<n_render_vertices; vv+=2) {
307                         for (vv=0; vv<n_render_vertices; vv++) {
308                                 int                     vertnum;
309                                 vms_vector      *vertpos;
310                                 fix                     dist;
311                                 int                     apply_light;
312
313                                 vertnum = render_vertices[vv];
314                                 if ((vertnum ^ FrameCount) & 1) {
315                                         vertpos = &Vertices[vertnum];
316                                         dist = vm_vec_dist_quick(obj_pos, vertpos);
317                                         apply_light = 0;
318
319                                         if ((dist >> headlight_shift) < abs(obji_64)) {
320
321                                                 if (dist < MIN_LIGHT_DIST)
322                                                         dist = MIN_LIGHT_DIST;
323
324                                                 //if (Use_fvi_lighting) {
325                                                 //      if (lighting_cache_visible(vertnum, obj_seg, objnum, obj_pos, obj_seg, vertpos)) {
326                                                 //              apply_light = 1;
327                                                 //      }
328                                                 //} else
329                                                         apply_light = 1;
330
331                                                 if (apply_light) {
332                                                         if (headlight_shift) {
333                                                                 fix                     dot;
334                                                                 vms_vector      vec_to_point;
335
336                                                                 vm_vec_sub(&vec_to_point, vertpos, obj_pos);
337                                                                 vm_vec_normalize_quick(&vec_to_point);          //      MK, Optimization note: You compute distance about 15 lines up, this is partially redundant
338                                                                 dot = vm_vec_dot(&vec_to_point, &Objects[objnum].orient.fvec);
339                                                                 if (dot < F1_0/2)
340                                                                         Dynamic_light[vertnum] += fixdiv(obj_intensity, fixmul(HEADLIGHT_SCALE, dist)); //      Do the normal thing, but darken around headlight.
341                                                                 else {
342                                                                         if (Game_mode & GM_MULTI) {
343                                                                                 if (dist < max_headlight_dist)
344                                                                                         Dynamic_light[vertnum] += fixmul(fixmul(dot, dot), obj_intensity)/8;
345                                                                         } else
346                                                                                 Dynamic_light[vertnum] += fixmul(fixmul(dot, dot), obj_intensity)/8;
347                                                                 }
348                                                         } else
349                                                                 Dynamic_light[vertnum] += fixdiv(obj_intensity, dist);
350                                                 }
351                                         }
352                                 }
353                         }
354                 }
355         }
356 }
357
358 #define FLASH_LEN_FIXED_SECONDS (F1_0/3)
359 #define FLASH_SCALE                                     (3*F1_0/FLASH_LEN_FIXED_SECONDS)
360
361 // ----------------------------------------------------------------------------------------------
362 void cast_muzzle_flash_light(int n_render_vertices, short *render_vertices)
363 {
364         fix current_time;
365         int     i;
366         short   time_since_flash;
367
368         current_time = timer_get_fixed_seconds();
369
370         for (i=0; i<MUZZLE_QUEUE_MAX; i++) {
371                 if (Muzzle_data[i].create_time) {
372                         time_since_flash = current_time - Muzzle_data[i].create_time;
373                         if (time_since_flash < FLASH_LEN_FIXED_SECONDS)
374                                 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);
375                         else
376                                 Muzzle_data[i].create_time = 0;         // turn off this muzzle flash
377                 }
378         }
379 }
380
381 //      Translation table to make flares flicker at different rates
382 fix     Obj_light_xlate[16] =
383         {0x1234, 0x3321, 0x2468, 0x1735,
384          0x0123, 0x19af, 0x3f03, 0x232a,
385          0x2123, 0x39af, 0x0f03, 0x132a,
386          0x3123, 0x29af, 0x1f03, 0x032a};
387
388 //      Flag array of objects lit last frame.  Guaranteed to process this frame if lit last frame.
389 sbyte   Lighting_objects[MAX_OBJECTS];
390
391 #define MAX_HEADLIGHTS  8
392 object  *Headlights[MAX_HEADLIGHTS];
393 int             Num_headlights;
394
395 // ---------------------------------------------------------
396 fix compute_light_intensity(int objnum)
397 {
398         object          *obj = &Objects[objnum];
399         int                     objtype = obj->type;
400    fix hoardlight,s;
401         
402         switch (objtype) {
403                 case OBJ_PLAYER:
404                          if (Players[obj->id].flags & PLAYER_FLAGS_HEADLIGHT_ON) {
405                                 if (Num_headlights < MAX_HEADLIGHTS)
406                                         Headlights[Num_headlights++] = obj;
407                                 return HEADLIGHT_SCALE;
408                          } else if ((Game_mode & GM_HOARD) && Players[obj->id].secondary_ammo[PROXIMITY_INDEX]) {
409                         
410                    // If hoard game and player, add extra light based on how many orbs you have
411                         // Pulse as well.
412
413                            hoardlight=i2f(Players[obj->id].secondary_ammo[PROXIMITY_INDEX])/2; //i2f(12));
414                                 hoardlight++;
415                       fix_sincos ((GameTime/2) & 0xFFFF,&s,NULL); // probably a bad way to do it
416                            s+=F1_0; 
417                                 s>>=1;
418                            hoardlight=fixmul (s,hoardlight);
419                  //     mprintf ((0,"Hoardlight is %f!\n",f2fl(hoardlight)));
420                       return (hoardlight);
421                           }
422                         else
423                                 return max(vm_vec_mag_quick(&obj->mtype.phys_info.thrust)/4, F1_0*2) + F1_0/2;
424                         break;
425                 case OBJ_FIREBALL:
426                         if (obj->id != 0xff) {
427                                 if (obj->lifeleft < F1_0*4)
428                                         return fixmul(fixdiv(obj->lifeleft, Vclip[obj->id].play_time), Vclip[obj->id].light_value);
429                                 else
430                                         return Vclip[obj->id].light_value;
431                         } else
432                                  return 0;
433                         break;
434                 case OBJ_ROBOT:
435                         return F1_0*Robot_info[obj->id].lightcast;
436                         break;
437                 case OBJ_WEAPON: {
438                         fix tval = Weapon_info[obj->id].light;
439                         if (Game_mode & GM_MULTI)
440                                 if (obj->id == OMEGA_ID)
441                                         if (d_rand() > 8192)
442                                                 return 0;               //      3/4 of time, omega blobs will cast 0 light!
443
444                         if (obj->id == FLARE_ID )
445                                 return 2* (min(tval, obj->lifeleft) + ((GameTime ^ Obj_light_xlate[objnum&0x0f]) & 0x3fff));
446                         else
447                                 return tval;
448                 }
449
450                 case OBJ_MARKER: {
451                         fix     lightval = obj->lifeleft;
452
453                         lightval &= 0xffff;
454
455                         lightval = 8 * abs(F1_0/2 - lightval);
456
457                         if (obj->lifeleft < F1_0*1000)
458                                 obj->lifeleft += F1_0;  //      Make sure this object doesn't go out.
459
460                         return lightval;
461                 }
462
463                 case OBJ_POWERUP:
464                         return Powerup_info[obj->id].light;
465                         break;
466                 case OBJ_DEBRIS:
467                         return F1_0/4;
468                         break;
469                 case OBJ_LIGHT:
470                         return obj->ctype.light_info.intensity;
471                         break;
472                 default:
473                         return 0;
474                         break;
475         }
476 }
477
478 // ----------------------------------------------------------------------------------------------
479 void set_dynamic_light(void)
480 {
481         int     vv;
482         int     objnum;
483         int     n_render_vertices;
484         short   render_vertices[MAX_VERTICES];
485         sbyte   render_vertex_flags[MAX_VERTICES];
486         int     render_seg,segnum, v;
487         sbyte   new_lighting_objects[MAX_OBJECTS];
488
489         Num_headlights = 0;
490
491         if (!Do_dynamic_light)
492                 return;
493
494 //if (Use_fvi_lighting)
495 //      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));
496
497         memset(render_vertex_flags, 0, Highest_vertex_index+1);
498
499         //      Create list of vertices that need to be looked at for setting of ambient light.
500         n_render_vertices = 0;
501         for (render_seg=0; render_seg<N_render_segs; render_seg++) {
502                 segnum = Render_list[render_seg];
503                 if (segnum != -1) {
504                         short   *vp = Segments[segnum].verts;
505                         for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++) {
506                                 int     vnum = vp[v];
507                                 if (vnum<0 || vnum>Highest_vertex_index) {
508                                         Int3();         //invalid vertex number
509                                         continue;       //ignore it, and go on to next one
510                                 }
511                                 if (!render_vertex_flags[vnum]) {
512                                         render_vertex_flags[vnum] = 1;
513                                         render_vertices[n_render_vertices++] = vnum;
514                                 }
515                                 //--old way-- for (s=0; s<n_render_vertices; s++)
516                                 //--old way--   if (render_vertices[s] == vnum)
517                                 //--old way--           break;
518                                 //--old way-- if (s == n_render_vertices)
519                                 //--old way--   render_vertices[n_render_vertices++] = vnum;
520                         }
521                 }
522         }
523
524         // -- for (vertnum=FrameCount&1; vertnum<n_render_vertices; vertnum+=2) {
525         for (vv=0; vv<n_render_vertices; vv++) {
526                 int     vertnum;
527
528                 vertnum = render_vertices[vv];
529                 Assert(vertnum >= 0 && vertnum <= Highest_vertex_index);
530                 if ((vertnum ^ FrameCount) & 1)
531                         Dynamic_light[vertnum] = 0;
532         }
533
534         cast_muzzle_flash_light(n_render_vertices, render_vertices);
535
536         for (objnum=0; objnum<=Highest_object_index; objnum++)
537                 new_lighting_objects[objnum] = 0;
538
539         //      July 5, 1995: New faster dynamic lighting code.  About 5% faster on the PC (un-optimized).
540         //      Only objects which are in rendered segments cast dynamic light.  We might wad6 to extend this
541         //      one or two segments if we notice light changing as objects go offscreen.  I couldn't see any
542         //      serious visual degradation.  In fact, I could see no humorous degradation, either. --MK
543         for (render_seg=0; render_seg<N_render_segs; render_seg++) {
544                 int     segnum = Render_list[render_seg];
545
546                 objnum = Segments[segnum].objects;
547
548                 while (objnum != -1) {
549                         object          *obj = &Objects[objnum];
550                         vms_vector      *objpos = &obj->pos;
551                         fix                     obj_intensity;
552
553                         obj_intensity = compute_light_intensity(objnum);
554
555                         if (obj_intensity) {
556                                 apply_light(obj_intensity, obj->segnum, objpos, n_render_vertices, render_vertices, obj-Objects);
557                                 new_lighting_objects[objnum] = 1;
558                         }
559
560                         objnum = obj->next;
561                 }
562         }
563
564         //      Now, process all lights from last frame which haven't been processed this frame.
565         for (objnum=0; objnum<=Highest_object_index; objnum++) {
566                 //      In multiplayer games, process even unprocessed objects every 4th frame, else don't know about player sneaking up.
567                 if ((Lighting_objects[objnum]) || ((Game_mode & GM_MULTI) && (((objnum ^ FrameCount) & 3) == 0))) {
568                         if (!new_lighting_objects[objnum]) {
569                                 //      Lighted last frame, but not this frame.  Get intensity...
570                                 object          *obj = &Objects[objnum];
571                                 vms_vector      *objpos = &obj->pos;
572                                 fix                     obj_intensity;
573
574                                 obj_intensity = compute_light_intensity(objnum);
575
576                                 if (obj_intensity) {
577                                         apply_light(obj_intensity, obj->segnum, objpos, n_render_vertices, render_vertices, objnum);
578                                         Lighting_objects[objnum] = 1;
579                                 } else
580                                         Lighting_objects[objnum] = 0;
581                         }
582                 } else {
583                         //      Not lighted last frame, so we don't need to light it.  (Already lit if casting light this frame.)
584                         //      But copy value from new_lighting_objects to update Lighting_objects array.
585                         Lighting_objects[objnum] = new_lighting_objects[objnum];
586                 }
587         }
588 }
589
590 // ---------------------------------------------------------
591
592 void toggle_headlight_active()
593 {
594         if (Players[Player_num].flags & PLAYER_FLAGS_HEADLIGHT) {
595                 Players[Player_num].flags ^= PLAYER_FLAGS_HEADLIGHT_ON;                 
596 #ifdef NETWORK
597                 if (Game_mode & GM_MULTI)
598                         multi_send_flags(Player_num);           
599 #endif
600         }
601 }
602
603 #define HEADLIGHT_BOOST_SCALE 8         //how much to scale light when have headlight boost
604
605 fix     Beam_brightness = (F1_0/2);     //global saying how bright the light beam is
606
607 #define MAX_DIST_LOG    6                                                       //log(MAX_DIST-expressed-as-integer)
608 #define MAX_DIST                (f1_0<<MAX_DIST_LOG)    //no light beyond this dist
609
610 fix compute_headlight_light_on_object(object *objp)
611 {
612         int     i;
613         fix     light;
614
615         //      Let's just illuminate players and robots for speed reasons, ok?
616         if ((objp->type != OBJ_ROBOT) && (objp->type    != OBJ_PLAYER))
617                 return 0;
618
619         light = 0;
620
621         for (i=0; i<Num_headlights; i++) {
622                 fix                     dot, dist;
623                 vms_vector      vec_to_obj;
624                 object          *light_objp;
625
626                 light_objp = Headlights[i];
627
628                 vm_vec_sub(&vec_to_obj, &objp->pos, &light_objp->pos);
629                 dist = vm_vec_normalize_quick(&vec_to_obj);
630                 if (dist > 0) {
631                         dot = vm_vec_dot(&light_objp->orient.fvec, &vec_to_obj);
632
633                         if (dot < F1_0/2)
634                                 light += fixdiv(HEADLIGHT_SCALE, fixmul(HEADLIGHT_SCALE, dist));        //      Do the normal thing, but darken around headlight.
635                         else
636                                 light += fixmul(fixmul(dot, dot), HEADLIGHT_SCALE)/8;
637                 }
638         }
639
640         return light;
641 }
642
643
644 // -- Unused -- //Compute the lighting from the headlight for a given vertex on a face.
645 // -- Unused -- //Takes:
646 // -- Unused -- //  point - the 3d coords of the point
647 // -- Unused -- //  face_light - a scale factor derived from the surface normal of the face
648 // -- Unused -- //If no surface normal effect is wanted, pass F1_0 for face_light
649 // -- Unused -- fix compute_headlight_light(vms_vector *point,fix face_light)
650 // -- Unused -- {
651 // -- Unused --         fix light;
652 // -- Unused --         int use_beam = 0;               //flag for beam effect
653 // -- Unused --
654 // -- Unused --         light = Beam_brightness;
655 // -- Unused --
656 // -- 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) {
657 // -- Unused --                 light *= HEADLIGHT_BOOST_SCALE;
658 // -- Unused --                 use_beam = 1;   //give us beam effect
659 // -- Unused --         }
660 // -- Unused --
661 // -- Unused --         if (light) {                            //if no beam, don't bother with the rest of this
662 // -- Unused --                 fix point_dist;
663 // -- Unused --
664 // -- Unused --                 point_dist = vm_vec_mag_quick(point);
665 // -- Unused --
666 // -- Unused --                 if (point_dist >= MAX_DIST)
667 // -- Unused --
668 // -- Unused --                         light = 0;
669 // -- Unused --
670 // -- Unused --                 else {
671 // -- Unused --                         fix dist_scale,face_scale;
672 // -- Unused --
673 // -- Unused --                         dist_scale = (MAX_DIST - point_dist) >> MAX_DIST_LOG;
674 // -- Unused --                         light = fixmul(light,dist_scale);
675 // -- Unused --
676 // -- Unused --                         if (face_light < 0)
677 // -- Unused --                                 face_light = 0;
678 // -- Unused --
679 // -- Unused --                         face_scale = f1_0/4 + face_light/2;
680 // -- Unused --                         light = fixmul(light,face_scale);
681 // -- Unused --
682 // -- Unused --                         if (use_beam) {
683 // -- Unused --                                 fix beam_scale;
684 // -- Unused --
685 // -- Unused --                                 if (face_light > f1_0*3/4 && point->z > i2f(12)) {
686 // -- Unused --                                         beam_scale = fixdiv(point->z,point_dist);
687 // -- Unused --                                         beam_scale = fixmul(beam_scale,beam_scale);     //square it
688 // -- Unused --                                         light = fixmul(light,beam_scale);
689 // -- Unused --                                 }
690 // -- Unused --                         }
691 // -- Unused --                 }
692 // -- Unused --         }
693 // -- Unused --
694 // -- Unused --         return light;
695 // -- Unused -- }
696
697 //compute the average dynamic light in a segment.  Takes the segment number
698 fix compute_seg_dynamic_light(int segnum)
699 {
700         fix sum;
701         segment *seg;
702         short *verts;
703
704         seg = &Segments[segnum];
705
706         verts = seg->verts;
707         sum = 0;
708
709         sum += Dynamic_light[*verts++];
710         sum += Dynamic_light[*verts++];
711         sum += Dynamic_light[*verts++];
712         sum += Dynamic_light[*verts++];
713         sum += Dynamic_light[*verts++];
714         sum += Dynamic_light[*verts++];
715         sum += Dynamic_light[*verts++];
716         sum += Dynamic_light[*verts];
717
718         return sum >> 3;
719
720 }
721
722 fix object_light[MAX_OBJECTS];
723 int object_sig[MAX_OBJECTS];
724 object *old_viewer;
725 int reset_lighting_hack;
726
727 #define LIGHT_RATE i2f(4)               //how fast the light ramps up
728
729 void start_lighting_frame(object *viewer)
730 {
731         reset_lighting_hack = (viewer != old_viewer);
732
733         old_viewer = viewer;
734 }
735
736 //compute the lighting for an object.  Takes a pointer to the object,
737 //and possibly a rotated 3d point.  If the point isn't specified, the
738 //object's center point is rotated.
739 fix compute_object_light(object *obj,vms_vector *rotated_pnt)
740 {
741         fix light;
742         g3s_point objpnt;
743         int objnum = obj-Objects;
744
745         if (!rotated_pnt) {
746                 g3_rotate_point(&objpnt,&obj->pos);
747                 rotated_pnt = &objpnt.p3_vec;
748         }
749
750         //First, get static light for this segment
751
752         light = Segment2s[obj->segnum].static_light;
753
754         //return light;
755
756
757         //Now, maybe return different value to smooth transitions
758
759         if (!reset_lighting_hack && object_sig[objnum] == obj->signature) {
760                 fix delta_light,frame_delta;
761
762                 delta_light = light - object_light[objnum];
763
764                 frame_delta = fixmul(LIGHT_RATE,FrameTime);
765
766                 if (abs(delta_light) <= frame_delta)
767
768                         object_light[objnum] = light;           //we've hit the goal
769
770                 else
771
772                         if (delta_light < 0)
773                                 light = object_light[objnum] -= frame_delta;
774                         else
775                                 light = object_light[objnum] += frame_delta;
776
777         }
778         else {          //new object, initialize
779
780                 object_sig[objnum] = obj->signature;
781                 object_light[objnum] = light;
782         }
783
784
785
786         //Next, add in headlight on this object
787
788         // -- Matt code: light += compute_headlight_light(rotated_pnt,f1_0);
789         light += compute_headlight_light_on_object(obj);
790  
791         //Finally, add in dynamic light for this segment
792
793         light += compute_seg_dynamic_light(obj->segnum);
794
795
796         return light;
797 }
798
799