home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / descent / source / main / lighting.c < prev    next >
Text File  |  1998-06-08  |  14KB  |  489 lines

  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  12. */
  13. /*
  14.  * $Source: f:/miner/source/main/rcs/lighting.c $
  15.  * $Revision: 2.1 $
  16.  * $Author: john $
  17.  * $Date: 1995/07/24 13:21:56 $
  18.  * 
  19.  * Lighting functions.
  20.  * 
  21.  * $Log: lighting.c $
  22.  * Revision 2.1  1995/07/24  13:21:56  john
  23.  * Added new lighting calculation code to speed things up.
  24.  * 
  25.  * Revision 2.0  1995/02/27  11:27:33  john
  26.  * New version 2.0, which has no anonymous unions, builds with
  27.  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
  28.  * 
  29.  * Revision 1.43  1995/02/22  13:57:10  allender
  30.  * remove anonymous union from object structure
  31.  * 
  32.  * Revision 1.42  1995/02/13  20:35:07  john
  33.  * Lintized
  34.  * 
  35.  * Revision 1.41  1995/02/04  21:43:40  matt
  36.  * Changed an assert() to an int3() and deal with the bad case
  37.  * 
  38.  * Revision 1.40  1995/01/15  20:48:27  mike
  39.  * support light field for powerups.
  40.  * 
  41.  * Revision 1.39  1994/12/15  13:04:19  mike
  42.  * Replace Players[Player_num].time_total references with GameTime.
  43.  * 
  44.  * Revision 1.38  1994/11/28  21:50:41  mike
  45.  * optimizations.
  46.  * 
  47.  * Revision 1.37  1994/11/28  01:32:33  mike
  48.  * lighting optimization.
  49.  * 
  50.  * Revision 1.36  1994/11/15  12:01:00  john
  51.  * Changed a bunch of code that uses timer_get_milliseconds to 
  52.  * timer_get_fixed_Seconds.  
  53.  * 
  54.  * Revision 1.35  1994/10/31  21:56:07  matt
  55.  * Fixed bug & added error checking
  56.  * 
  57.  * Revision 1.34  1994/10/21  11:24:57  mike
  58.  * Trap divide overflows in lighting.
  59.  * 
  60.  * Revision 1.33  1994/10/08  14:49:11  matt
  61.  * If viewer changed, don't do smooth lighting hack
  62.  * 
  63.  * Revision 1.32  1994/09/25  23:41:07  matt
  64.  * Changed the object load & save code to read/write the structure fields one
  65.  * at a time (rather than the whole structure at once).  This mean that the
  66.  * object structure can be changed without breaking the load/save functions.
  67.  * As a result of this change, the local_object data can be and has been 
  68.  * incorporated into the object array.  Also, timeleft is now a property 
  69.  * of all objects, and the object structure has been otherwise cleaned up.
  70.  * 
  71.  * Revision 1.31  1994/09/25  15:45:15  matt
  72.  * Added OBJ_LIGHT, a type of object that casts light
  73.  * Added generalized lifeleft, and moved it to local_object
  74.  * 
  75.  * Revision 1.30  1994/09/11  15:48:27  mike
  76.  * Use vm_vec_mag_quick in place of vm_vec_mag in point_dist computation.
  77.  * 
  78.  * Revision 1.29  1994/09/08  21:44:49  matt
  79.  * Made lighting ramp 4x as fast; made only static (ambient) light ramp
  80.  * up, but not headlight & dynamic light
  81.  * 
  82.  * Revision 1.28  1994/09/02  14:00:07  matt
  83.  * Simplified explode_object() & mutliple-stage explosions
  84.  * 
  85.  * Revision 1.27  1994/08/29  19:06:44  mike
  86.  * Make lighting proportional to square of distance, not linear.
  87.  * 
  88.  * Revision 1.26  1994/08/25  18:08:38  matt
  89.  * Made muzzle flash cast 3x as much light
  90.  * 
  91.  * Revision 1.25  1994/08/23  16:38:31  mike
  92.  * Key weapon light off bitmaps.tbl.
  93.  * 
  94.  * Revision 1.24  1994/08/13  12:20:44  john
  95.  * Made the networking uise the Players array.
  96.  * 
  97.  * Revision 1.23  1994/08/12  22:42:18  john
  98.  * Took away Player_stats; added Players array.
  99.  * 
  100.  * Revision 1.22  1994/07/06  10:19:22  matt
  101.  * Changed include
  102.  * 
  103.  * Revision 1.21  1994/06/28  13:20:22  mike
  104.  * Oops, fixed a dumb typo.
  105.  * 
  106.  * Revision 1.20  1994/06/28  12:53:25  mike
  107.  * Change lighting function for flares, make brighter and asynchronously flicker.
  108.  * 
  109.  * Revision 1.19  1994/06/27  18:31:15  mike
  110.  * Add flares.
  111.  * 
  112.  * Revision 1.18  1994/06/20  13:41:17  matt
  113.  * Added time-based gradual lighting hack for objects
  114.  * Took out strobing robots
  115.  * 
  116.  * Revision 1.17  1994/06/19  16:25:54  mike
  117.  * Optimize lighting.
  118.  * 
  119.  * Revision 1.16  1994/06/17  18:08:08  mike
  120.  * Make robots cast more and variable light.
  121.  * 
  122.  * Revision 1.15  1994/06/13  15:15:55  mike
  123.  * Fix phantom light, every 64K milliseconds, muzzle flash would flash again.
  124.  * 
  125.  */
  126.  
  127.  
  128. #pragma off (unreferenced)
  129. static char rcsid[] = "$Id: lighting.c 2.1 1995/07/24 13:21:56 john Exp $";
  130. #pragma on (unreferenced)
  131.  
  132. #include <stdlib.h>
  133. #include <string.h>    // for memset()
  134.  
  135. #include "inferno.h"
  136. #include "segment.h"
  137. #include "error.h"
  138. #include "mono.h"
  139. #include "render.h"
  140. #include "game.h"
  141. #include "vclip.h"
  142. #include "lighting.h"
  143. #include "3d.h"
  144. #include "laser.h"
  145. #include "timer.h"
  146. #include "player.h"
  147. #include "weapon.h"
  148. #include "powerup.h"
  149.  
  150. //global saying how bright the light beam is
  151. fix    Beam_brightness = (F1_0/2);
  152. // -- optimized out, mk, 11/28/94 -- fix    Face_light_scale = (F1_0/2);
  153. int    use_beam;        //flag for beam effect
  154.  
  155. int    Do_dynamic_light=1;
  156.  
  157. fix    Dynamic_light[MAX_VERTICES];
  158.  
  159. // ----------------------------------------------------------------------------------------------
  160. void apply_light(fix obj_intensity, int obj_seg, vms_vector *obj_pos, int n_render_vertices, short *render_vertices)
  161. {
  162.     int    vv;
  163.  
  164.     if (obj_intensity) {
  165.         fix    obji_64 = obj_intensity*64;
  166.  
  167.         // for pretty dim sources, only process vertices in object's own segment.
  168.         if (obji_64 <= F1_0*8) {
  169.             short *vp = Segments[obj_seg].verts;
  170.  
  171.             for (vv=0; vv<MAX_VERTICES_PER_SEGMENT; vv++) {
  172.                 int            vertnum;
  173.                 vms_vector    *vertpos;
  174.                 fix            dist;
  175.  
  176.                 vertnum = vp[vv];
  177.                 vertpos = &Vertices[vertnum];
  178.                 dist = vm_vec_dist_quick(obj_pos, vertpos);
  179.                 dist = fixmul(dist/4, dist/4);
  180.                 if (dist < obji_64) {
  181.                     if (dist < MIN_LIGHT_DIST)
  182.                         dist = MIN_LIGHT_DIST;
  183.  
  184.                     Dynamic_light[vertnum] += fixdiv(obj_intensity, dist);
  185.                 }
  186.             }
  187.         } else {
  188.             for (vv=FrameCount&1; vv<n_render_vertices; vv+=2) {
  189.                 int            vertnum;
  190.                 vms_vector    *vertpos;
  191.                 fix            dist;
  192.  
  193.                 vertnum = render_vertices[vv];
  194.                 vertpos = &Vertices[vertnum];
  195.                 dist = vm_vec_dist_quick(obj_pos, vertpos);
  196.  
  197.                 if (dist < obji_64) {
  198.                     if (dist < MIN_LIGHT_DIST)
  199.                         dist = MIN_LIGHT_DIST;
  200.  
  201.                     Dynamic_light[vertnum] += fixdiv(obj_intensity, dist);
  202.                 }
  203.             }
  204.         }
  205.     }
  206. }
  207.  
  208. #define    FLASH_LEN_FIXED_SECONDS    (F1_0/3)
  209. #define    FLASH_SCALE                    (3*F1_0/FLASH_LEN_FIXED_SECONDS)
  210.  
  211. // ----------------------------------------------------------------------------------------------
  212. void cast_muzzle_flash_light(int n_render_vertices, short *render_vertices)
  213. {
  214.     fix current_time;
  215.     int    i;
  216.     short    time_since_flash;
  217.  
  218.     current_time = timer_get_fixed_seconds();
  219.  
  220.     for (i=0; i<MUZZLE_QUEUE_MAX; i++) {
  221.         if (Muzzle_data[i].create_time) {
  222.             time_since_flash = current_time - Muzzle_data[i].create_time;
  223.             if (time_since_flash < FLASH_LEN_FIXED_SECONDS)
  224.                 apply_light((FLASH_LEN_FIXED_SECONDS - time_since_flash) * FLASH_SCALE, Muzzle_data[i].segnum, &Muzzle_data[i].pos, n_render_vertices, render_vertices);
  225.             else
  226.                 Muzzle_data[i].create_time = 0;        // turn off this muzzle flash
  227.         }
  228.     }
  229. }
  230.  
  231. //    Translation table to make flares flicker at different rates
  232. fix    Obj_light_xlate[16] =
  233.     {0x1234, 0x3321, 0x2468, 0x1735,
  234.      0x0123, 0x19af, 0x3f03, 0x232a,
  235.      0x2123, 0x39af, 0x0f03, 0x132a,
  236.      0x3123, 0x29af, 0x1f03, 0x032a};
  237.  
  238. // ----------------------------------------------------------------------------------------------
  239. void set_dynamic_light(void)
  240. {
  241.     int    objnum,vertnum;
  242.     int    n_render_vertices;
  243.     short    render_vertices[MAX_VERTICES];
  244.     byte    render_vertex_flags[MAX_VERTICES];
  245.     int    render_seg,segnum, v;
  246.  
  247.     if (!Do_dynamic_light)
  248.         return;
  249.  
  250.     memset(render_vertex_flags, 0, Highest_vertex_index+1);
  251.  
  252.     //    Create list of vertices that need to be looked at for setting of ambient light.
  253.     n_render_vertices = 0;
  254.     for (render_seg=0; render_seg<N_render_segs; render_seg++) {
  255.         segnum = Render_list[render_seg];
  256.         if (segnum != -1) {
  257.             short    *vp = Segments[segnum].verts;
  258.             for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++) {
  259.                 int    vnum = vp[v];
  260.                 if (vnum<0 || vnum>Highest_vertex_index) {
  261.                     Int3();        //invalid vertex number
  262.                     continue;    //ignore it, and go on to next one
  263.                 }
  264.                 if (!render_vertex_flags[vnum]) {
  265.                     render_vertex_flags[vnum] = 1;
  266.                     render_vertices[n_render_vertices++] = vnum;
  267.                 }
  268.                 //--old way-- for (s=0; s<n_render_vertices; s++)
  269.                 //--old way--     if (render_vertices[s] == vnum)
  270.                 //--old way--         break;
  271.                 //--old way-- if (s == n_render_vertices)
  272.                 //--old way--     render_vertices[n_render_vertices++] = vnum;
  273.             }
  274.         }
  275.     }
  276.  
  277.     for (vertnum=FrameCount&1; vertnum<n_render_vertices; vertnum+=2) {
  278.         Assert(render_vertices[vertnum]>=0 && render_vertices[vertnum]<=Highest_vertex_index);
  279.         Dynamic_light[render_vertices[vertnum]] = 0;
  280.     }
  281.  
  282.     cast_muzzle_flash_light(n_render_vertices, render_vertices);
  283.  
  284.     //    Note, starting at 1 to skip player, whose light is handled by a different system, of course.
  285. //    for (objnum=1; objnum<=Highest_object_index; objnum++) {
  286.  
  287.     for (render_seg=0; render_seg<N_render_segs; render_seg++) {
  288.         int    segnum = Render_list[render_seg];
  289.  
  290.         objnum = Segments[segnum].objects;
  291.  
  292.         while (objnum != -1) {
  293.             object        *obj = &Objects[objnum];
  294.             vms_vector    *objpos = &obj->pos;
  295.             int            objtype = obj->type;
  296.             fix            obj_intensity;
  297.     
  298.             switch (objtype) {
  299.                 case OBJ_FIREBALL:
  300.                     if (obj->id != 0xff) {
  301.                         if (obj->lifeleft < F1_0*4)
  302.                             obj_intensity = fixmul(fixdiv(obj->lifeleft, Vclip[obj->id].play_time), Vclip[obj->id].light_value);
  303.                         else
  304.                             obj_intensity = Vclip[obj->id].light_value;
  305.                     } else
  306.                         obj_intensity = 0;
  307.                     break;
  308.                 case OBJ_ROBOT:
  309.                     obj_intensity = F1_0/2;    // + (FrameCount & 0x1f)*F1_0/16;
  310.                     break;
  311.                 case OBJ_WEAPON:
  312.                     obj_intensity = Weapon_info[obj->id].light;
  313.                     if (obj->id == FLARE_ID )
  314.                         obj_intensity = 2* (min(obj_intensity, obj->lifeleft) + ((GameTime ^ Obj_light_xlate[objnum&0x0f]) & 0x3fff));
  315.                     break;
  316.                 case OBJ_POWERUP:
  317.                     obj_intensity = Powerup_info[obj->id].light;
  318.                     break;
  319.                 case OBJ_DEBRIS:
  320.                     obj_intensity = F1_0/4;
  321.                     break;
  322.                 case OBJ_LIGHT:
  323.                     obj_intensity = obj->ctype.light_info.intensity;
  324.                     break;
  325.                 default:
  326.                     obj_intensity = 0;
  327.                     break;
  328.             }
  329.     
  330.             if (obj_intensity)
  331.                 apply_light(obj_intensity, obj->segnum, objpos, n_render_vertices, render_vertices);
  332.  
  333.             objnum = obj->next;
  334.         }
  335.     }
  336.  
  337. }
  338.  
  339. // ---------------------------------------------------------
  340.  
  341. //Compute the lighting from the headlight for a given vertex on a face.
  342. //Takes:
  343. //  point - the 3d coords of the point
  344. //  face_light - a scale factor derived from the surface normal of the face
  345. //If no surface normal effect is wanted, pass F1_0 for face_light
  346. fix compute_headlight_light(vms_vector *point,fix face_light)
  347. {
  348.     fix light;
  349.  
  350.     light = Beam_brightness;
  351.  
  352.     if (light) {                //if no beam, don't bother with the rest of this
  353.         fix point_dist;
  354.  
  355.         if (face_light < 0)
  356.             face_light = 0;
  357.  
  358.         point_dist = vm_vec_mag_quick(point);
  359.  
  360.         //note: beam scale not used if !use_beam
  361.  
  362.         if (point_dist >= MAX_DIST)
  363.  
  364.             light = 0;
  365.  
  366.         else {
  367.             fix dist_scale,temp_lightval;
  368.  
  369.             dist_scale = (MAX_DIST - point_dist) >> MAX_DIST_LOG;
  370.  
  371.             temp_lightval = f1_0/4 + face_light/2;
  372.  
  373.             light = Beam_brightness;
  374.  
  375.             if (use_beam) {
  376.                 fix beam_scale;
  377.  
  378.                 beam_scale = fixdiv(point->z,point_dist);
  379.                 beam_scale = fixmul(beam_scale,beam_scale);    //square it
  380.                 light = fixmul(light,beam_scale);
  381.             }
  382.  
  383.             light = fixmul(light,fixmul(dist_scale,temp_lightval));
  384.  
  385.         }
  386.  
  387.     }
  388.  
  389.     return light;
  390. }
  391.  
  392. //compute the average dynamic light in a segment.  Takes the segment number
  393. fix compute_seg_dynamic_light(int segnum)
  394. {
  395.     fix sum;
  396.     segment *seg;
  397.     short *verts;
  398.  
  399.     seg = &Segments[segnum];
  400.  
  401.     verts = seg->verts;
  402.     sum = 0;
  403.  
  404.     sum += Dynamic_light[*verts++];
  405.     sum += Dynamic_light[*verts++];
  406.     sum += Dynamic_light[*verts++];
  407.     sum += Dynamic_light[*verts++];
  408.     sum += Dynamic_light[*verts++];
  409.     sum += Dynamic_light[*verts++];
  410.     sum += Dynamic_light[*verts++];
  411.     sum += Dynamic_light[*verts];
  412.  
  413.     return sum >> 3;
  414.  
  415. }
  416.  
  417. fix object_light[MAX_OBJECTS];
  418. int object_id[MAX_OBJECTS];
  419. object *old_viewer;
  420.  
  421. #define LIGHT_RATE i2f(4)        //how fast the light ramps up
  422.  
  423. //compute the lighting for an object.  Takes a pointer to the object,
  424. //and possibly a rotated 3d point.  If the point isn't specified, the
  425. //object's center point is rotated.
  426. fix compute_object_light(object *obj,vms_vector *rotated_pnt)
  427. {
  428.     fix light;
  429.     g3s_point objpnt;
  430.     int objnum = obj-Objects;
  431.  
  432.     if (!rotated_pnt) {
  433.         g3_rotate_point(&objpnt,&obj->pos);
  434.         rotated_pnt = &objpnt.p3_vec;
  435.     }
  436.  
  437.     //First, get static light for this segment
  438.  
  439.     light = Segments[obj->segnum].static_light;
  440.  
  441.     //return light;
  442.  
  443.  
  444.     //Now, maybe return different value to smooth transitions
  445.  
  446.     if (Viewer==old_viewer && object_id[objnum] == obj->id) {
  447.         fix delta_light,frame_delta;
  448.  
  449.         delta_light = light - object_light[objnum];
  450.  
  451.         frame_delta = fixmul(LIGHT_RATE,FrameTime);
  452.  
  453.         if (abs(delta_light) <= frame_delta)
  454.  
  455.             object_light[objnum] = light;        //we've hit the goal
  456.  
  457.         else
  458.  
  459.             if (delta_light < 0)
  460.                 light = object_light[objnum] -= frame_delta;
  461.             else
  462.                 light = object_light[objnum] += frame_delta;
  463.  
  464.     }
  465.     else {        //new object, initialize
  466.  
  467.         object_id[objnum] = obj->id;
  468.         object_light[objnum] = light;
  469.     }
  470.  
  471.  
  472.  
  473.     //Next, add in headlight on this object
  474.  
  475.     light += compute_headlight_light(rotated_pnt,f1_0);
  476.  
  477.     //Finally, add in dynamic light for this segment
  478.  
  479.     light += compute_seg_dynamic_light(obj->segnum);
  480.  
  481.  
  482.     old_viewer = Viewer;
  483.  
  484.     return light;
  485. }
  486.  
  487.  
  488. 
  489.