home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / descent / source / main / editor / seguvs.c < prev    next >
C/C++ Source or Header  |  1998-06-08  |  56KB  |  1,633 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/editor/rcs/seguvs.c $
  15.  * $Revision: 2.1 $
  16.  * $Author: mike $
  17.  * $Date: 1995/05/08 10:49:34 $
  18.  * 
  19.  * u,v coordinate computation for segment faces
  20.  * 
  21.  * $Log: seguvs.c $
  22.  * Revision 2.1  1995/05/08  10:49:34  mike
  23.  * fix lighting bug: oblong segments could be very dark.
  24.  * 
  25.  * Revision 2.0  1995/02/27  11:36:37  john
  26.  * Version 2.0. Ansi-fied.
  27.  * 
  28.  * Revision 1.84  1994/11/27  23:17:18  matt
  29.  * Made changes for new mprintf calling convention
  30.  * 
  31.  * Revision 1.83  1994/11/17  14:48:02  mike
  32.  * validation functions moved from editor to game.
  33.  * 
  34.  * Revision 1.82  1994/10/15  19:08:26  mike
  35.  * Disable exhaustive search mprintfs in find_point_seg during lighting.
  36.  * 
  37.  * Revision 1.81  1994/08/25  21:55:50  mike
  38.  * IS_CHILD stuff.
  39.  * 
  40.  * Revision 1.80  1994/08/04  19:13:22  matt
  41.  * Changed a bunch of vecmat calls to use multiple-function routines, and to
  42.  * allow the use of C macros for some functions
  43.  * 
  44.  * Revision 1.79  1994/08/03  10:31:33  mike
  45.  * Texture map propagation without uv assignment.
  46.  * 
  47.  * Revision 1.78  1994/08/01  13:31:12  matt
  48.  * Made fvi() check holes in transparent walls, and changed fvi() calling
  49.  * parms to take all input data in query structure.
  50.  * 
  51.  * Revision 1.77  1994/07/08  14:31:24  matt
  52.  * New parms for FVI
  53.  * 
  54.  * Revision 1.76  1994/06/23  14:01:04  mike
  55.  * Fix cache bug which caused some vertices to not get light, mainly
  56.  * noticeable at joints which had doors.
  57.  * 
  58.  * Revision 1.75  1994/06/22  17:33:11  mike
  59.  * Make position of light (which is always towards center of segment from
  60.  * actual light panel) constant, not dependent on segment size, which fixes
  61.  * bug of dark light panels in very large segments.
  62.  * 
  63.  * Revision 1.74  1994/06/21  18:58:18  mike
  64.  * Fix stupid bug in light propagation, was using wrong vector in fvi caching.
  65.  * 
  66.  * Revision 1.73  1994/06/20  11:20:24  mike
  67.  * Fix stupid lighting bug introduced when I went to cached fvi results.
  68.  * 
  69.  * Revision 1.72  1994/06/19  16:26:37  mike
  70.  * Speed up lighting by storing and hashing fvi results.
  71.  * 
  72.  * Revision 1.71  1994/06/17  16:05:56  mike
  73.  * Support optional quick lighting propagation: no find_vector_intersection.
  74.  * 
  75.  * Revision 1.70  1994/06/15  15:42:30  mike
  76.  * Propagate static_light.
  77.  * 
  78.  * Revision 1.69  1994/06/14  16:59:37  mike
  79.  * Fix references to tmap_num2, must strip off orientation bits.
  80.  * 
  81.  * Revision 1.68  1994/06/09  09:58:58  matt
  82.  * Moved find_vector_intersection() from physics.c to new file fvi.c
  83.  * 
  84.  * 
  85.  * Revision 1.67  1994/06/08  18:14:02  mike
  86.  * mprintf a dot in light casting.
  87.  * 
  88.  * Revision 1.66  1994/06/08  14:37:45  mike
  89.  * double static light value in going from value (a short) to static_light (a fix).
  90.  * 
  91.  * Revision 1.65  1994/06/08  14:29:44  matt
  92.  * Added static_light field to segment structure, and padded side struct
  93.  * to be longword aligned.
  94.  * 
  95.  * Revision 1.64  1994/06/08  11:45:24  mike
  96.  * New, supercool, superslow lighting function.
  97.  * 
  98.  * Revision 1.63  1994/06/07  09:38:11  mike
  99.  * Make lighting function yet better by calling find_vector_intersection.
  100.  * 
  101.  * Revision 1.62  1994/06/06  13:14:33  mike
  102.  * Make illusory walls cast light.
  103.  * 
  104.  * Revision 1.61  1994/06/05  20:39:47  mike
  105.  * Add new distance and dot product based lighting function.
  106.  * 
  107.  * Revision 1.60  1994/05/31  12:31:18  mike
  108.  * fix bugs in lighting, though it's not perfect, will be changing all
  109.  * lighting to be distance based.  Bug had to do with not handling one
  110.  * of the return values from WALL_IS_DOORWAY, so assuming light couldn't
  111.  * be recursively propagated almost all the time.
  112.  * 
  113.  * Revision 1.59  1994/05/19  23:35:26  mike
  114.  * Support uv coordinates in range 0..1.0.
  115.  * 
  116.  * Revision 1.58  1994/05/19  12:10:21  matt
  117.  * Use new vecmat macros and globals
  118.  * 
  119.  * Revision 1.57  1994/05/04  19:15:53  mike
  120.  * Error checking for degenerate segments.
  121.  * 
  122.  * Revision 1.56  1994/05/03  11:02:34  mike
  123.  * Change how default texture map assignment works; now pixels are constant size.
  124.  * 
  125.  * Revision 1.55  1994/04/28  23:25:26  yuan
  126.  * Obliterated warnings.
  127.  * 
  128.  */
  129.  
  130.  
  131. #pragma off (unreferenced)
  132. static char rcsid[] = "$Id: seguvs.c 2.1 1995/05/08 10:49:34 mike Exp $";
  133. #pragma on (unreferenced)
  134.  
  135. #include <stdio.h>
  136. #include <stdlib.h>
  137. #include <stdarg.h>
  138. #include <math.h>
  139. #include <string.h>
  140.  
  141. #include "inferno.h"
  142. #include "segment.h"
  143. #include "editor.h"
  144.  
  145. #include "gameseg.h"
  146.  
  147. #include "fix.h"
  148. #include "mono.h"
  149. #include "error.h"
  150.  
  151. #include "wall.h"
  152. #include "kdefs.h"
  153. #include "bm.h"        //    Needed for TmapInfo
  154. #include    "effects.h"    //    Needed for effects_bm_num
  155. #include "fvi.h"
  156.  
  157. //--rotate_uvs-- vms_vector Rightvec;
  158.  
  159. //    ---------------------------------------------------------------------------------------------
  160. //    Returns approximate area of a side
  161. fix area_on_side(side *sidep)
  162. {
  163.     fix    du,dv,width,height;
  164.  
  165.     du = sidep->uvls[1].u - sidep->uvls[0].u;
  166.     dv = sidep->uvls[1].v - sidep->uvls[0].v;
  167.  
  168.     width = fix_sqrt(fixmul(du,du) + fixmul(dv,dv));
  169.  
  170.     du = sidep->uvls[3].u - sidep->uvls[0].u;
  171.     dv = sidep->uvls[3].v - sidep->uvls[0].v;
  172.  
  173.     height = fix_sqrt(fixmul(du,du) + fixmul(dv,dv));
  174.  
  175.     return fixmul(width, height);
  176. }
  177.  
  178. //    -------------------------------------------------------------------------------------------
  179. //    DEBUG function -- callable from debugger.
  180. //    Returns approximate area of all sides which get mapped (ie, are not a connection).
  181. //    I wrote this because I was curious how much memory would be required to texture map all
  182. //    sides individually with custom artwork.  For demo1.min on 2/18/94, it would be about 5 meg.
  183. int area_on_all_sides(void)
  184. {
  185.     int    i,s;
  186.     int    total_area = 0;
  187.  
  188.     for (i=0; i<=Highest_segment_index; i++) {
  189.         segment *segp = &Segments[i];
  190.  
  191.         for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
  192.             if (!IS_CHILD(segp->children[s]))
  193.                 total_area += f2i(area_on_side(&segp->sides[s]));
  194.     }
  195.  
  196.     return total_area;
  197. }
  198.  
  199. fix average_connectivity(void)
  200. {
  201.     int    i,s;
  202.     int    total_sides = 0, total_mapped_sides = 0;
  203.  
  204.     for (i=0; i<=Highest_segment_index; i++) {
  205.         segment *segp = &Segments[i];
  206.  
  207.         for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
  208.             if (!IS_CHILD(segp->children[s]))
  209.                 total_mapped_sides++;
  210.             total_sides++;
  211.         }
  212.     }
  213.  
  214.     return 6 * fixdiv(total_mapped_sides, total_sides);
  215. }
  216.  
  217. #define    MAX_LIGHT_SEGS 16
  218.  
  219. //    ---------------------------------------------------------------------------------------------
  220. //    Scan all polys in all segments, return average light value for vnum.
  221. //    segs = output array for segments containing vertex, terminated by -1.
  222. fix get_average_light_at_vertex(int vnum, short *segs)
  223. {
  224.     int    segnum, relvnum, sidenum;
  225.     fix    total_light;
  226.     int    num_occurrences;
  227. //    #ifndef NDEBUG //Removed this ifdef because the version of Assert that I used to get it to compile doesn't work without this symbol. -KRB
  228.     short    *original_segs = segs;
  229. //    #endif
  230.  
  231.     num_occurrences = 0;
  232.     total_light = 0;
  233.  
  234.     for (segnum=0; segnum<=Highest_segment_index; segnum++) {
  235.         segment *segp = &Segments[segnum];
  236.         short *vp = segp->verts;
  237.  
  238.         for (relvnum=0; relvnum<MAX_VERTICES_PER_SEGMENT; relvnum++)
  239.             if (*vp++ == vnum)
  240.                 break;
  241.  
  242.         if (relvnum < MAX_VERTICES_PER_SEGMENT) {
  243.  
  244.             *segs++ = segnum;
  245.             Assert(segs - original_segs < MAX_LIGHT_SEGS);
  246.  
  247.             for (sidenum=0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) {
  248.                 if (!IS_CHILD(segp->children[sidenum])) {
  249.                     side    *sidep = &segp->sides[sidenum];
  250.                     byte    *vp = Side_to_verts[sidenum];
  251.                     int    v;
  252.  
  253.                     for (v=0; v<4; v++)
  254.                         if (*vp++ == relvnum) {
  255.                             total_light += sidep->uvls[v].l;
  256.                             num_occurrences++;
  257.                         }
  258.                 }    // end if
  259.             }    // end sidenum
  260.         }
  261.     }    // end segnum
  262.  
  263.     *segs = -1;
  264.  
  265.     if (num_occurrences)
  266.         return total_light/num_occurrences;
  267.     else
  268.         return 0;
  269.  
  270. }
  271.  
  272. void set_average_light_at_vertex(int vnum)
  273. {
  274.     int    relvnum, sidenum;
  275.     short    Segment_indices[MAX_LIGHT_SEGS];
  276.     int    segind;
  277.  
  278.     fix average_light;
  279.  
  280.     average_light = get_average_light_at_vertex(vnum, Segment_indices);
  281.  
  282.     if (!average_light)
  283.         return;
  284.  
  285.     segind = 0;
  286.     while (Segment_indices[segind] != -1) {
  287.         int segnum = Segment_indices[segind++];
  288.  
  289.         segment *segp = &Segments[segnum];
  290.  
  291.         for (relvnum=0; relvnum<MAX_VERTICES_PER_SEGMENT; relvnum++)
  292.             if (segp->verts[relvnum] == vnum)
  293.                 break;
  294.  
  295.         if (relvnum < MAX_VERTICES_PER_SEGMENT) {
  296.             for (sidenum=0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) {
  297.                 if (!IS_CHILD(segp->children[sidenum])) {
  298.                     side *sidep = &segp->sides[sidenum];
  299.                     byte    *vp = Side_to_verts[sidenum];
  300.                     int    v;
  301.  
  302.                     for (v=0; v<4; v++)
  303.                         if (*vp++ == relvnum)
  304.                             sidep->uvls[v].l = average_light;
  305.                 }    // end if
  306.             }    // end sidenum
  307.         }    // end if
  308.     }    // end while
  309.  
  310.     Update_flags |= UF_WORLD_CHANGED;
  311. }
  312.  
  313. void set_average_light_on_side(segment *segp, int sidenum)
  314. {
  315.     int    v;
  316.  
  317.     if (!IS_CHILD(segp->children[sidenum]))
  318.         for (v=0; v<4; v++) {
  319. //            mprintf((0,"Vertex %i\n", segp->verts[Side_to_verts[side][v]]));
  320.             set_average_light_at_vertex(segp->verts[Side_to_verts[sidenum][v]]);
  321.         }
  322.  
  323. }
  324.  
  325. void set_average_light_on_curside(void)
  326. {
  327.     set_average_light_on_side(Cursegp, Curside);
  328. }
  329.  
  330. //    -----------------------------------------------------------------------------------------
  331. void set_average_light_on_all_fast(void)
  332. {
  333.     int    s,v,relvnum;
  334.     fix    al;
  335.     int    alc;
  336.     int    seglist[MAX_LIGHT_SEGS];
  337.     int    *segptr;
  338.  
  339.     set_vertex_counts();
  340.  
  341.     //    Set total light value for all vertices in array average_light.
  342.     for (v=0; v<=Highest_vertex_index; v++) {
  343.         al = 0;
  344.         alc = 0;
  345.  
  346.         if (Vertex_active[v]) {
  347.             segptr = seglist;
  348.  
  349.             for (s=0; s<=Highest_segment_index; s++) {
  350.                 segment *segp = &Segments[s];
  351.                 for (relvnum=0; relvnum<MAX_VERTICES_PER_SEGMENT; relvnum++)
  352.                     if (segp->verts[relvnum] == v)
  353.                         break;
  354.  
  355.                     if (relvnum != MAX_VERTICES_PER_SEGMENT) {
  356.                         int        si;
  357.  
  358.                         *segptr++ = s;            // Note this segment in list, so we can process it below.
  359.                         Assert(segptr - seglist < MAX_LIGHT_SEGS);
  360.  
  361.                         for (si=0; si<MAX_SIDES_PER_SEGMENT; si++) {
  362.                             if (!IS_CHILD(segp->children[si])) {
  363.                                 side    *sidep = &segp->sides[si];
  364.                                 byte    *vp = Side_to_verts[si];
  365.                                 int    vv;
  366.  
  367.                                 for (vv=0; vv<4; vv++)
  368.                                     if (*vp++ == relvnum) {
  369.                                         al += sidep->uvls[vv].l;
  370.                                         alc++;
  371.                                     }
  372.                             }    // if (segp->children[si == -1) {
  373.                         }    // for (si=0...
  374.                     }    // if (relvnum != ...
  375.             }    // for (s=0; ...
  376.  
  377.             *segptr = -1;
  378.  
  379.             //    Now, divide average_light by number of number of occurrences for each vertex
  380.             if (alc)
  381.                 al /= alc;
  382.             else
  383.                 al = 0;
  384.  
  385.             segptr = seglist;
  386.             while (*segptr != -1) {
  387.                 int         segnum = *segptr++;
  388.                 segment    *segp = &Segments[segnum];
  389.                 int        sidenum;
  390.  
  391.                 for (relvnum=0; relvnum<MAX_VERTICES_PER_SEGMENT; relvnum++)
  392.                     if (segp->verts[relvnum] == v)
  393.                         break;
  394.  
  395.                 Assert(relvnum < MAX_VERTICES_PER_SEGMENT);    // IMPOSSIBLE! This segment is in seglist, but vertex v does not occur!
  396.                 for (sidenum=0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) {
  397.                     int    wid_result;
  398.                     wid_result = WALL_IS_DOORWAY(segp, sidenum);
  399.                     if ((wid_result != WID_FLY_FLAG) && (wid_result != WID_NO_WALL)) {
  400.                         side *sidep = &segp->sides[sidenum];
  401.                         byte    *vp = Side_to_verts[sidenum];
  402.                         int    v;
  403.  
  404.                         for (v=0; v<4; v++)
  405.                             if (*vp++ == relvnum)
  406.                                 sidep->uvls[v].l = al;
  407.                     }    // end if
  408.                 }    // end sidenum
  409.             }    // end while
  410.  
  411.         }    // if (Vertex_active[v]...
  412.  
  413.     }    // for (v=0...
  414.  
  415. }
  416.  
  417. extern int Doing_lighting_hack_flag;    //    If set, don't mprintf warning messages in gameseg.c/find_point_seg
  418. void set_average_light_on_all(void)
  419. {
  420. //    set_average_light_on_all_fast();
  421.  
  422.     Doing_lighting_hack_flag = 1;
  423.     cast_all_light_in_mine(0);
  424.     Doing_lighting_hack_flag = 0;
  425.     Update_flags |= UF_WORLD_CHANGED;
  426.  
  427. //    int seg, side;
  428.  
  429. //    for (seg=0; seg<=Highest_segment_index; seg++)
  430. //        for (side=0; side<MAX_SIDES_PER_SEGMENT; side++)
  431. //            if (Segments[seg].segnum != -1)
  432. //                set_average_light_on_side(&Segments[seg], side);
  433. }
  434.  
  435. void set_average_light_on_all_quick(void)
  436. {
  437.     cast_all_light_in_mine(1);
  438.     Update_flags |= UF_WORLD_CHANGED;
  439.  
  440. }
  441.  
  442. //    ---------------------------------------------------------------------------------------------
  443. fix compute_uv_dist(uvl *uv0, uvl *uv1)
  444. {
  445.     vms_vector    v0,v1;
  446.  
  447.     v0.x = uv0->u;
  448.     v0.y = 0;
  449.     v0.z = uv0->v;
  450.  
  451.     v1.x = uv1->u;
  452.     v1.y = 0;
  453.     v1.z = uv1->v;
  454.  
  455.     return vm_vec_dist(&v0,&v1);
  456. }
  457.  
  458. //    ---------------------------------------------------------------------------------------------
  459. //    Given a polygon, compress the uv coordinates so that they are as close to 0 as possible.
  460. //    Do this by adding a constant u and v to each uv pair.
  461. void compress_uv_coordinates(side *sidep)
  462. {
  463.     int    v;
  464.     fix    uc, vc;
  465.  
  466.     uc = 0;
  467.     vc = 0;
  468.  
  469.     for (v=0; v<4; v++) {
  470.         uc += sidep->uvls[v].u;
  471.         vc += sidep->uvls[v].v;
  472.     }
  473.  
  474.     uc /= 4;
  475.     vc /= 4;
  476.     uc = uc & 0xffff0000;
  477.     vc = vc & 0xffff0000;
  478.  
  479.     for (v=0; v<4; v++) {
  480.         sidep->uvls[v].u -= uc;
  481.         sidep->uvls[v].v -= vc;
  482.     }
  483.  
  484. }
  485.  
  486. //    ---------------------------------------------------------------------------------------------
  487. void compress_uv_coordinates_on_side(side *sidep)
  488. {
  489.     compress_uv_coordinates(sidep);
  490. }
  491.  
  492. //    ---------------------------------------------------------------------------------------------
  493. void validate_uv_coordinates_on_side(segment *segp, int sidenum)
  494. {
  495. //    int            v;
  496. //    fix            uv_dist,threed_dist;
  497. //    vms_vector    tvec;
  498. //    fix            dist_ratios[MAX_VERTICES_PER_POLY];
  499.     side            *sidep = &segp->sides[sidenum];
  500. //    byte            *vp = Side_to_verts[sidenum];
  501.  
  502. //    This next hunk doesn't seem to affect anything. @mk, 02/13/94
  503. //    for (v=1; v<4; v++) {
  504. //        uv_dist = compute_uv_dist(&sidep->uvls[v],&sidep->uvls[0]);
  505. //        threed_dist = vm_vec_mag(vm_vec_sub(&tvec,&Vertices[segp->verts[vp[v]],&Vertices[vp[0]]));
  506. //        dist_ratios[v-1] = fixdiv(uv_dist,threed_dist);
  507. //    }
  508.  
  509.     compress_uv_coordinates_on_side(sidep);
  510. }
  511.  
  512. void compress_uv_coordinates_in_segment(segment *segp)
  513. {
  514.     int    side;
  515.  
  516.     for (side=0; side<MAX_SIDES_PER_SEGMENT; side++)
  517.         compress_uv_coordinates_on_side(&segp->sides[side]);
  518. }
  519.  
  520. void compress_uv_coordinates_all(void)
  521. {
  522.     int    seg;
  523.  
  524.     for (seg=0; seg<=Highest_segment_index; seg++)
  525.         if (Segments[seg].segnum != -1)
  526.             compress_uv_coordinates_in_segment(&Segments[seg]);
  527. }
  528.  
  529. void check_lighting_side(segment *sp, int sidenum)
  530. {
  531.     int    v;
  532.     side    *sidep = &sp->sides[sidenum];
  533.  
  534.     for (v=0; v<4; v++)
  535.         if ((sidep->uvls[v].l > F1_0*16) || (sidep->uvls[v].l < 0))
  536.             Int3(); //mprintf(0,"Bogus lighting value in segment %i, side %i, vert %i = %x\n",sp-Segments, side, v, sidep->uvls[v].l);
  537. }
  538.  
  539. void check_lighting_segment(segment *segp)
  540. {
  541.     int    side;
  542.  
  543.     for (side=0; side<MAX_SIDES_PER_SEGMENT; side++)
  544.         check_lighting_side(segp, side);
  545. }
  546.  
  547. //    Flag bogus lighting values.
  548. void check_lighting_all(void)
  549. {
  550.     int    seg;
  551.  
  552.     for (seg=0; seg<=Highest_segment_index; seg++)
  553.         if (Segments[seg].segnum != -1)
  554.             check_lighting_segment(&Segments[seg]);
  555. }
  556.  
  557. void assign_default_lighting_on_side(segment *segp, int sidenum)
  558. {
  559.     int    v;
  560.     side    *sidep = &segp->sides[sidenum];
  561.  
  562.     for (v=0; v<4; v++)
  563.         sidep->uvls[v].l = DEFAULT_LIGHTING;
  564. }
  565.  
  566. void assign_default_lighting(segment *segp)
  567. {
  568.     int    sidenum;
  569.  
  570.     for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++)
  571.         assign_default_lighting_on_side(segp, sidenum);
  572. }
  573.  
  574. void assign_default_lighting_all(void)
  575. {
  576.     int    seg;
  577.  
  578.     for (seg=0; seg<=Highest_segment_index; seg++)
  579.         if (Segments[seg].segnum != -1)
  580.             assign_default_lighting(&Segments[seg]);
  581. }
  582.  
  583. //    ---------------------------------------------------------------------------------------------
  584. void validate_uv_coordinates(segment *segp)
  585. {
  586.     int    s;
  587.  
  588.     for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
  589.         validate_uv_coordinates_on_side(segp,s);
  590.  
  591. }
  592.  
  593. //    ---------------------------------------------------------------------------------------------
  594. //    For all faces in side, copy uv coordinates from uvs array to face.
  595. void copy_uvs_from_side_to_faces(segment *segp, int sidenum, uvl uvls[])
  596. {
  597.     int    v;
  598.     side    *sidep = &segp->sides[sidenum];
  599.  
  600.     for (v=0; v<4; v++)
  601.         sidep->uvls[v] = uvls[v];
  602.  
  603. }
  604.  
  605. fix zhypot(fix a,fix b);
  606. #pragma aux zhypot parm [eax] [ebx] value [eax] modify [eax ebx ecx edx] = \
  607.     "imul    eax" \
  608.     "xchg eax,ebx" \
  609.     "mov    ecx,edx" \
  610.     "imul eax" \
  611.     "add    eax,ebx" \
  612.     "adc    edx,ecx" \
  613.     "call    quad_sqrt";
  614.  
  615. //    ---------------------------------------------------------------------------------------------
  616. //    Assign lighting value to side, a function of the normal vector.
  617. void assign_light_to_side(segment *sp, int sidenum)
  618. {
  619.     int    v;
  620.     side    *sidep = &sp->sides[sidenum];
  621.  
  622.     for (v=0; v<4; v++)
  623.         sidep->uvls[v].l = DEFAULT_LIGHTING;
  624. }
  625.  
  626. fix    Stretch_scale_x = F1_0;
  627. fix    Stretch_scale_y = F1_0;
  628.  
  629. //    ---------------------------------------------------------------------------------------------
  630. //    Given u,v coordinates at two vertices, assign u,v coordinates to other two vertices on a side.
  631. //    (Actually, assign them to the coordinates in the faces.)
  632. //    va, vb = face-relative vertex indices corresponding to uva, uvb.  Ie, they are always in 0..3 and should be looked up in
  633. //    Side_to_verts[side] to get the segment relative index.
  634. void assign_uvs_to_side(segment *segp, int sidenum, uvl *uva, uvl *uvb, int va, int vb)
  635. {
  636.     int            vlo,vhi,v0,v1,v2,v3;
  637.     vms_vector    fvec,rvec,tvec;
  638.     vms_matrix    rotmat;
  639.     uvl            uvls[4],ruvmag,fuvmag,uvlo,uvhi;
  640.     fix            fmag,mag01;
  641.     byte            *vp;
  642.  
  643.     Assert( (va<4) && (vb<4) );
  644.     Assert((abs(va - vb) == 1) || (abs(va - vb) == 3));        // make sure the verticies specify an edge
  645.  
  646.     vp = &Side_to_verts[sidenum];
  647.  
  648.     // We want vlo precedes vhi, ie vlo < vhi, or vlo = 3, vhi = 0
  649.     if (va == ((vb + 1) % 4)) {        // va = vb + 1
  650.         vlo = vb;
  651.         vhi = va;
  652.         uvlo = *uvb;
  653.         uvhi = *uva;
  654.     } else {
  655.         vlo = va;
  656.         vhi = vb;
  657.         uvlo = *uva;
  658.         uvhi = *uvb;
  659.     }
  660.  
  661.     Assert(((vlo+1) % 4) == vhi);    // If we are on an edge, then uvhi is one more than uvlo (mod 4)
  662.     uvls[vlo] = uvlo;
  663.     uvls[vhi] = uvhi;
  664.  
  665.     // Now we have vlo precedes vhi, compute vertices ((vhi+1) % 4) and ((vhi+2) % 4)
  666.  
  667.     // Assign u,v scale to a unit length right vector.
  668.     fmag = zhypot(uvhi.v - uvlo.v,uvhi.u - uvlo.u);
  669.     if (fmag < 64) {        // this is a fix, so 64 = 1/1024
  670.         mprintf((0,"Warning: fmag = %7.3f, using approximate u,v values\n",f2fl(fmag)));
  671.         ruvmag.u = F1_0*256;
  672.         ruvmag.v = F1_0*256;
  673.         fuvmag.u = F1_0*256;
  674.         fuvmag.v = F1_0*256;
  675.     } else {
  676.         ruvmag.u = uvhi.v - uvlo.v;
  677.         ruvmag.v = uvlo.u - uvhi.u;
  678.  
  679.         fuvmag.u = uvhi.u - uvlo.u;
  680.         fuvmag.v = uvhi.v - uvlo.v;
  681.     }
  682.  
  683.     v0 = segp->verts[vp[vlo]];
  684.     v1 = segp->verts[vp[vhi]];
  685.     v2 = segp->verts[vp[(vhi+1)%4]];
  686.     v3 = segp->verts[vp[(vhi+2)%4]];
  687.  
  688.     //    Compute right vector by computing orientation matrix from:
  689.     //        forward vector = vlo:vhi
  690.     //          right vector = vlo:(vhi+2) % 4
  691.     vm_vec_sub(&fvec,&Vertices[v1],&Vertices[v0]);
  692.     vm_vec_sub(&rvec,&Vertices[v3],&Vertices[v0]);
  693.  
  694.     if (((fvec.x == 0) && (fvec.y == 0) && (fvec.z == 0)) || ((rvec.x == 0) && (rvec.y == 0) && (rvec.z == 0))) {
  695.         mprintf((1, "Trapped null vector in assign_uvs_to_side, using identity matrix.\n"));
  696.         rotmat = vmd_identity_matrix;
  697.     } else
  698.         vm_vector_2_matrix(&rotmat,&fvec,0,&rvec);
  699.  
  700.     rvec = rotmat.rvec; vm_vec_negate(&rvec);
  701.     fvec = rotmat.fvec;
  702.  
  703.     // mprintf((0, "va = %i, vb = %i\n", va, vb));
  704.     mag01 = vm_vec_dist(&Vertices[v1],&Vertices[v0]);
  705.     if ((va == 0) || (va == 2))
  706.         mag01 = fixmul(mag01, Stretch_scale_x);
  707.     else
  708.         mag01 = fixmul(mag01, Stretch_scale_y);
  709.  
  710.     if (mag01 < F1_0/1024 )
  711.         editor_status("U, V bogosity in segment #%i, probably on side #%i.  CLEAN UP YOUR MESS!", segp-Segments, sidenum);
  712.     else {
  713.         vm_vec_sub(&tvec,&Vertices[v2],&Vertices[v1]);
  714.         uvls[(vhi+1)%4].u = uvhi.u + 
  715.             fixdiv(fixmul(ruvmag.u,vm_vec_dotprod(&rvec,&tvec)),mag01) +
  716.             fixdiv(fixmul(fuvmag.u,vm_vec_dotprod(&fvec,&tvec)),mag01);
  717.  
  718.         uvls[(vhi+1)%4].v = uvhi.v + 
  719.             fixdiv(fixmul(ruvmag.v,vm_vec_dotprod(&rvec,&tvec)),mag01) +
  720.             fixdiv(fixmul(fuvmag.v,vm_vec_dotprod(&fvec,&tvec)),mag01);
  721.  
  722.  
  723.         vm_vec_sub(&tvec,&Vertices[v3],&Vertices[v0]);
  724.         uvls[(vhi+2)%4].u = uvlo.u + 
  725.             fixdiv(fixmul(ruvmag.u,vm_vec_dotprod(&rvec,&tvec)),mag01) +
  726.             fixdiv(fixmul(fuvmag.u,vm_vec_dotprod(&fvec,&tvec)),mag01);
  727.  
  728.         uvls[(vhi+2)%4].v = uvlo.v + 
  729.             fixdiv(fixmul(ruvmag.v,vm_vec_dotprod(&rvec,&tvec)),mag01) +
  730.             fixdiv(fixmul(fuvmag.v,vm_vec_dotprod(&fvec,&tvec)),mag01);
  731.  
  732.         uvls[(vhi+1)%4].l = uvhi.l;
  733.         uvls[(vhi+2)%4].l = uvlo.l;
  734.  
  735.         copy_uvs_from_side_to_faces(segp, sidenum, uvls);
  736.     }
  737. }
  738.  
  739.  
  740. int Vmag = VMAG;
  741.  
  742. // -----------------------------------------------------------------------------------------------------------
  743. //    Assign default uvs to side.
  744. //    This means:
  745. //        v0 = 0,0
  746. //        v1 = k,0 where k is 3d size dependent
  747. //    v2, v3 assigned by assign_uvs_to_side
  748. void assign_default_uvs_to_side(segment *segp,int side)
  749. {
  750.     uvl            uv0,uv1;
  751.     byte            *vp;
  752.  
  753.     uv0.u = 0;
  754.     uv0.v = 0;
  755.  
  756.     vp = Side_to_verts[side];
  757.  
  758.     uv1.u = 0;
  759.     uv1.v = Num_tilings * fixmul(Vmag, vm_vec_dist(&Vertices[segp->verts[vp[1]]],&Vertices[segp->verts[vp[0]]]));
  760.  
  761.     assign_uvs_to_side(segp, side, &uv0, &uv1, 0, 1);
  762. }
  763.  
  764. // -----------------------------------------------------------------------------------------------------------
  765. //    Assign default uvs to side.
  766. //    This means:
  767. //        v0 = 0,0
  768. //        v1 = k,0 where k is 3d size dependent
  769. //    v2, v3 assigned by assign_uvs_to_side
  770. void stretch_uvs_from_curedge(segment *segp, int side)
  771. {
  772.     uvl            uv0,uv1;
  773.     int            v0, v1;
  774.  
  775.     v0 = Curedge;
  776.     v1 = (v0 + 1) % 4;
  777.  
  778.     uv0.u = segp->sides[side].uvls[v0].u;
  779.     uv0.v = segp->sides[side].uvls[v0].v;
  780.  
  781.     uv1.u = segp->sides[side].uvls[v1].u;
  782.     uv1.v = segp->sides[side].uvls[v1].v;
  783.  
  784.     assign_uvs_to_side(segp, side, &uv0, &uv1, v0, v1);
  785. }
  786.  
  787. // --------------------------------------------------------------------------------------------------------------
  788. //    Assign default uvs to a segment.
  789. void assign_default_uvs_to_segment(segment *segp)
  790. {
  791.     int    s;
  792.  
  793.     for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
  794.         assign_default_uvs_to_side(segp,s);
  795.         assign_light_to_side(segp, s);
  796.     }
  797. }
  798.  
  799.  
  800. // -- mk021394 -- // --------------------------------------------------------------------------------------------------------------
  801. // -- mk021394 -- //    Find the face:poly:vertex index in base_seg:base_common_side which is segment relative vertex v1
  802. // -- mk021394 -- //    This very specific routine is subsidiary to med_assign_uvs_to_side.
  803. // -- mk021394 -- void get_face_and_vert(segment *base_seg, int base_common_side, int v1, int *ff, int *vv, int *pi)
  804. // -- mk021394 -- {
  805. // -- mk021394 --     int    p,f,v;
  806. // -- mk021394 -- 
  807. // -- mk021394 --     for (f=0; f<base_seg->sides[base_common_side].num_faces; f++) {
  808. // -- mk021394 --         face *fp = &base_seg->sides[base_common_side].faces[f];
  809. // -- mk021394 --         for (p=0; p<fp->num_polys; p++) {
  810. // -- mk021394 --             poly *pp = &fp->polys[p];
  811. // -- mk021394 --             for (v=0; v<pp->num_vertices; v++)
  812. // -- mk021394 --                 if (pp->verts[v] == v1) {
  813. // -- mk021394 --                     *ff = f;
  814. // -- mk021394 --                     *vv = v;
  815. // -- mk021394 --                     *pi = p;
  816. // -- mk021394 --                     return;
  817. // -- mk021394 --                 }
  818. // -- mk021394 --         }
  819. // -- mk021394 --     }
  820. // -- mk021394 -- 
  821. // -- mk021394 --     Assert(0);    // Error -- Couldn't find face:vertex which matched vertex v1 on base_seg:base_common_side
  822. // -- mk021394 -- }
  823.  
  824. // -- mk021394 -- // --------------------------------------------------------------------------------------------------------------
  825. // -- mk021394 -- //    Find the vertex index in base_seg:base_common_side which is segment relative vertex v1
  826. // -- mk021394 -- //    This very specific routine is subsidiary to med_assign_uvs_to_side.
  827. // -- mk021394 -- void get_side_vert(segment *base_seg,int base_common_side,int v1,int *vv)
  828. // -- mk021394 -- {
  829. // -- mk021394 --     int    p,f,v;
  830. // -- mk021394 -- 
  831. // -- mk021394 --     Assert((base_seg->sides[base_common_side].tri_edge == 0) || (base_seg->sides[base_common_side].tri_edge == 1));
  832. // -- mk021394 --     Assert(base_seg->sides[base_common_side].num_faces <= 2);
  833. // -- mk021394 -- 
  834. // -- mk021394 --     for (f=0; f<base_seg->sides[base_common_side].num_faces; f++) {
  835. // -- mk021394 --         face *fp = &base_seg->sides[base_common_side].faces[f];
  836. // -- mk021394 --         for (p=0; p<fp->num_polys; p++) {
  837. // -- mk021394 --             poly    *pp = &fp->polys[p];
  838. // -- mk021394 --             for (v=0; v<pp->num_vertices; v++)
  839. // -- mk021394 --                 if (pp->verts[v] == v1) {
  840. // -- mk021394 --                     if (pp->num_vertices == 4) {
  841. // -- mk021394 --                         *vv = v;
  842. // -- mk021394 --                         return;
  843. // -- mk021394 --                     }
  844. // -- mk021394 -- 
  845. // -- mk021394 --                     if (base_seg->sides[base_common_side].tri_edge == 0) {    // triangulated 012, 023, so if f==0, *vv = v, if f==1, *vv = v if v=0, else v+1
  846. // -- mk021394 --                         if ((f == 1) && (v > 0))
  847. // -- mk021394 --                             v++;
  848. // -- mk021394 --                         *vv = v;
  849. // -- mk021394 --                         return;
  850. // -- mk021394 --                     } else {                                // triangulated 013, 123
  851. // -- mk021394 --                         if (f == 0) {
  852. // -- mk021394 --                             if (v == 2)
  853. // -- mk021394 --                                 v++;
  854. // -- mk021394 --                         } else
  855. // -- mk021394 --                             v++;
  856. // -- mk021394 --                         *vv = v;
  857. // -- mk021394 --                         return;
  858. // -- mk021394 --                     }
  859. // -- mk021394 --                 }
  860. // -- mk021394 --         }
  861. // -- mk021394 --     }
  862. // -- mk021394 -- 
  863. // -- mk021394 --     Assert(0);    // Error -- Couldn't find face:vertex which matched vertex v1 on base_seg:base_common_side
  864. // -- mk021394 -- }
  865.  
  866. //--rotate_uvs-- // --------------------------------------------------------------------------------------------------------------
  867. //--rotate_uvs-- //    Rotate uvl coordinates uva, uvb about their center point by heading
  868. //--rotate_uvs-- void rotate_uvs(uvl *uva, uvl *uvb, vms_vector *rvec)
  869. //--rotate_uvs-- {
  870. //--rotate_uvs--     uvl    uvc, uva1, uvb1;
  871. //--rotate_uvs-- 
  872. //--rotate_uvs--     uvc.u = (uva->u + uvb->u)/2;
  873. //--rotate_uvs--     uvc.v = (uva->v + uvb->v)/2;
  874. //--rotate_uvs-- 
  875. //--rotate_uvs--     uva1.u = fixmul(uva->u - uvc.u, rvec->x) - fixmul(uva->v - uvc.v, rvec->z);
  876. //--rotate_uvs--     uva1.v = fixmul(uva->u - uvc.u, rvec->z) + fixmul(uva->v - uvc.v, rvec->x);
  877. //--rotate_uvs-- 
  878. //--rotate_uvs--     uva->u = uva1.u + uvc.u;
  879. //--rotate_uvs--     uva->v = uva1.v + uvc.v;
  880. //--rotate_uvs-- 
  881. //--rotate_uvs--     uvb1.u = fixmul(uvb->u - uvc.u, rvec->x) - fixmul(uvb->v - uvc.v, rvec->z);
  882. //--rotate_uvs--     uvb1.v = fixmul(uvb->u - uvc.u, rvec->z) + fixmul(uvb->v - uvc.v, rvec->x);
  883. //--rotate_uvs-- 
  884. //--rotate_uvs--     uvb->u = uvb1.u + uvc.u;
  885. //--rotate_uvs--     uvb->v = uvb1.v + uvc.v;
  886. //--rotate_uvs-- }
  887.  
  888.  
  889. // --------------------------------------------------------------------------------------------------------------
  890. void med_assign_uvs_to_side(segment *con_seg, int con_common_side, segment *base_seg, int base_common_side, int abs_id1, int abs_id2)
  891. {
  892.     uvl        uv1,uv2;
  893.     int        v,bv1,bv2,cv1,cv2, vv1, vv2;
  894.  
  895.     bv1 = -1;    bv2 = -1;
  896.  
  897.     // Find which vertices in segment match abs_id1, abs_id2
  898.     for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++) {
  899.         if (base_seg->verts[v] == abs_id1)
  900.             bv1 = v;
  901.         if (base_seg->verts[v] == abs_id2)
  902.             bv2 = v;
  903.         if (con_seg->verts[v] == abs_id1)
  904.             cv1 = v;
  905.         if (con_seg->verts[v] == abs_id2)
  906.             cv2 = v;
  907.     }
  908.  
  909.     //    Now, bv1, bv2 are segment relative vertices in base segment which are the same as absolute vertices abs_id1, abs_id2
  910.     //         cv1, cv2 are segment relative vertices in conn segment which are the same as absolute vertices abs_id1, abs_id2
  911.  
  912.     Assert((bv1 != -1) && (bv2 != -1) && (cv1 != -1) && (cv2 != -1));
  913.     Assert((uv1.u != uv2.u) || (uv1.v != uv2.v));
  914.  
  915.     //    Now, scan 4 vertices in base side and 4 vertices in connected side.
  916.     //    Set uv1, uv2 to uv coordinates from base side which correspond to vertices bv1, bv2.
  917.     //    Set vv1, vv2 to relative vertex ids (in 0..3) in connecting side which correspond to cv1, cv2
  918.     vv1 = -1;    vv2 = -1;
  919.     for (v=0; v<4; v++) {
  920.         if (bv1 == Side_to_verts[base_common_side][v])
  921.             uv1 = base_seg->sides[base_common_side].uvls[v];
  922.  
  923.         if (bv2 == Side_to_verts[base_common_side][v])
  924.             uv2 = base_seg->sides[base_common_side].uvls[v];
  925.  
  926.         if (cv1 == Side_to_verts[con_common_side][v])
  927.             vv1 = v;
  928.  
  929.         if (cv2 == Side_to_verts[con_common_side][v])
  930.             vv2 = v;
  931.     }
  932.  
  933.     Assert( (vv1 != -1) && (vv2 != -1) );
  934.     assign_uvs_to_side(con_seg, con_common_side, &uv1, &uv2, vv1, vv2);
  935. }
  936.  
  937.  
  938. // -----------------------------------------------------------------------------
  939. //    Given a base and a connecting segment, a side on each of those segments and two global vertex ids,
  940. //    determine which side in each of the segments shares those two vertices.
  941. //    This is used to propagate a texture map id to a connecting segment in an expected and desired way.
  942. //    Since we can attach any side of a segment to any side of another segment, and do so in each case in
  943. //    four different rotations (for a total of 6*6*4 = 144 ways), not having this nifty function will cause
  944. //    great confusion.
  945. void get_side_ids(segment *base_seg, segment *con_seg, int base_side, int con_side, int abs_id1, int abs_id2, int *base_common_side, int *con_common_side)
  946. {
  947.     char        *base_vp,*con_vp;
  948.     int        v0,side;
  949.  
  950.     *base_common_side = -1;
  951.  
  952.     //    Find side in base segment which contains the two global vertex ids.
  953.     for (side=0; side<MAX_SIDES_PER_SEGMENT; side++) {
  954.         if (side != base_side) {
  955.             base_vp = Side_to_verts[side];
  956.             for (v0=0; v0<4; v0++)
  957.                 if (((base_seg->verts[base_vp[v0]] == abs_id1) && (base_seg->verts[base_vp[ (v0+1) % 4]] == abs_id2)) || ((base_seg->verts[base_vp[v0]] == abs_id2) && (base_seg->verts[base_vp[ (v0+1) % 4]] == abs_id1))) {
  958.                     Assert(*base_common_side == -1);        // This means two different sides shared the same edge with base_side == impossible!
  959.                     *base_common_side = side;
  960.                 }
  961.         }
  962.     }
  963.  
  964.     // Note: For connecting segment, process vertices in reversed order.
  965.     *con_common_side = -1;
  966.  
  967.     //    Find side in connecting segment which contains the two global vertex ids.
  968.     for (side=0; side<MAX_SIDES_PER_SEGMENT; side++) {
  969.         if (side != con_side) {
  970.             con_vp = Side_to_verts[side];
  971.             for (v0=0; v0<4; v0++)
  972.                 if (((con_seg->verts[con_vp[(v0 + 1) % 4]] == abs_id1) && (con_seg->verts[con_vp[v0]] == abs_id2))    || ((con_seg->verts[con_vp[(v0 + 1) % 4]] == abs_id2) && (con_seg->verts[con_vp[v0]] == abs_id1))) {
  973.                     Assert(*con_common_side == -1);        // This means two different sides shared the same edge with con_side == impossible!
  974.                     *con_common_side = side;
  975.                 }
  976.         }
  977.     }
  978.  
  979. // mprintf((0,"side %3i adjacent to side %3i\n",*base_common_side,*con_common_side));
  980.  
  981.     Assert((*base_common_side != -1) && (*con_common_side != -1));
  982. }
  983.  
  984. // -----------------------------------------------------------------------------
  985. //    Propagate texture map u,v coordinates from base_seg:base_side to con_seg:con_side.
  986. //    The two vertices abs_id1 and abs_id2 are the only two vertices common to the two sides.
  987. //    If uv_only_flag is 1, then don't assign texture map ids, only update the uv coordinates
  988. //    If uv_only_flag is -1, then ONLY assign texture map ids, don't update the uv coordinates
  989. void propagate_tmaps_to_segment_side(segment *base_seg, int base_side, segment *con_seg, int con_side, int abs_id1, int abs_id2, int uv_only_flag)
  990. {
  991.     int        base_common_side,con_common_side;
  992.     int        tmap_num;
  993.  
  994.     Assert ((uv_only_flag == -1) || (uv_only_flag == 0) || (uv_only_flag == 1));
  995.  
  996.     // Set base_common_side = side in base_seg which contains edge abs_id1:abs_id2
  997.     // Set con_common_side = side in con_seg which contains edge abs_id1:abs_id2
  998.     if (base_seg != con_seg)
  999.         get_side_ids(base_seg, con_seg, base_side, con_side, abs_id1, abs_id2, &base_common_side, &con_common_side);
  1000.     else {
  1001.         base_common_side = base_side;
  1002.         con_common_side = con_side;
  1003.     }
  1004.  
  1005.     // Now, all faces in con_seg which are on side con_common_side get their tmap_num set to whatever tmap is assigned
  1006.     // to whatever face I find which is on side base_common_side.
  1007.     // First, find tmap_num for base_common_side.  If it doesn't exist (ie, there is a connection there), look at the segment
  1008.     // that is connected through it.
  1009.     if (!IS_CHILD(con_seg->children[con_common_side])) {
  1010.         if (!IS_CHILD(base_seg->children[base_common_side])) {
  1011.             // There is at least one face here, so get the tmap_num from there.
  1012.             tmap_num = base_seg->sides[base_common_side].tmap_num;
  1013.  
  1014.             // Now assign all faces in the connecting segment on side con_common_side to tmap_num.
  1015.             if ((uv_only_flag == -1) || (uv_only_flag == 0))
  1016.                 con_seg->sides[con_common_side].tmap_num = tmap_num;
  1017.  
  1018.             if (uv_only_flag != -1)
  1019.                 med_assign_uvs_to_side(con_seg, con_common_side, base_seg, base_common_side, abs_id1, abs_id2);
  1020.  
  1021.         } else {            // There are no faces here, there is a connection, trace through the connection.
  1022.             int    cside;
  1023.  
  1024.             cside = find_connect_side(base_seg, &Segments[base_seg->children[base_common_side]]);
  1025.             propagate_tmaps_to_segment_side(&Segments[base_seg->children[base_common_side]], cside, con_seg, con_side, abs_id1, abs_id2, uv_only_flag);
  1026.         }
  1027.     }
  1028.  
  1029. }
  1030.  
  1031. byte    Edge_between_sides[MAX_SIDES_PER_SEGMENT][MAX_SIDES_PER_SEGMENT][2] = {
  1032. //        left        top        right        bottom    back        front
  1033.     { {-1,-1}, { 3, 7}, {-1,-1}, { 2, 6}, { 6, 7}, { 2, 3} },    // left
  1034.     { { 3, 7}, {-1,-1}, { 0, 4}, {-1,-1}, { 4, 7}, { 0, 3} },    // top
  1035.     { {-1,-1}, { 0, 4}, {-1,-1}, { 1, 5}, { 4, 5}, { 0, 1} },    // right
  1036.     { { 2, 6}, {-1,-1}, { 1, 5}, {-1,-1}, { 5, 6}, { 1, 2} },    // bottom
  1037.     { { 6, 7}, { 4, 7}, { 4, 5}, { 5, 6}, {-1,-1}, {-1,-1} },    // back
  1038.     { { 2, 3}, { 0, 3}, { 0, 1}, { 1, 2}, {-1,-1}, {-1,-1} }};    // front
  1039.  
  1040. // -----------------------------------------------------------------------------
  1041. //    Propagate texture map u,v coordinates to base_seg:back_side from base_seg:some-other-side
  1042. //    There is no easy way to figure out which side is adjacent to another side along some edge, so we do a bit of searching.
  1043. void med_propagate_tmaps_to_back_side(segment *base_seg, int back_side, int uv_only_flag)
  1044. {
  1045.     int    v1,v2;
  1046.     int    s,ss,tmap_num,back_side_tmap;
  1047.  
  1048.     if (IS_CHILD(base_seg->children[back_side]))
  1049.         return;        // connection, so no sides here.
  1050.  
  1051.     //    Scan all sides, look for an occupied side which is not back_side or Side_opposite[back_side]
  1052.     for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
  1053.         if ((s != back_side) && (s != Side_opposite[back_side])) {
  1054.             v1 = Edge_between_sides[s][back_side][0];
  1055.             v2 = Edge_between_sides[s][back_side][1];
  1056.             goto found1;
  1057.         }
  1058.     Assert(0);        // Error -- couldn't find edge != back_side and Side_opposite[back_side]
  1059. found1: ;
  1060.     Assert( (v1 != -1) && (v2 != -1));        // This means there was no shared edge between the two sides.
  1061.  
  1062.     propagate_tmaps_to_segment_side(base_seg, s, base_seg, back_side, base_seg->verts[v1], base_seg->verts[v2], uv_only_flag);
  1063.  
  1064.     //    Assign an unused tmap id to the back side.
  1065.     //    Note that this can get undone by the caller if this was not part of a new attach, but a rotation or a scale (which
  1066.     //    both do attaches).
  1067.     //    First see if tmap on back side is anywhere else.
  1068.     if (!uv_only_flag) {
  1069.         back_side_tmap = base_seg->sides[back_side].tmap_num;
  1070.         for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
  1071.             if (s != back_side)
  1072.                 if (base_seg->sides[s].tmap_num == back_side_tmap) {
  1073.                     for (tmap_num=0; tmap_num < MAX_SIDES_PER_SEGMENT; tmap_num++) {
  1074.                         for (ss=0; ss<MAX_SIDES_PER_SEGMENT; ss++)
  1075.                             if (ss != back_side)
  1076.                                 if (base_seg->sides[ss].tmap_num == New_segment.sides[tmap_num].tmap_num)
  1077.                                     goto found2;        // current texture map (tmap_num) is used on current (ss) side, so try next one
  1078.                         // Current texture map (tmap_num) has not been used, assign to all faces on back_side.
  1079.                         base_seg->sides[back_side].tmap_num = New_segment.sides[tmap_num].tmap_num;
  1080.                         goto done1;
  1081.                     found2: ;
  1082.                     }
  1083.                 }
  1084.         }
  1085.     done1: ;
  1086.     }
  1087.  
  1088. }
  1089.  
  1090. void fix_bogus_uvs_on_side(void)
  1091. {
  1092.     med_propagate_tmaps_to_back_side(Cursegp, Curside, 1);
  1093. }
  1094.  
  1095. void fix_bogus_uvs_on_side1(segment *sp, int sidenum, int uvonly_flag)
  1096. {
  1097.     side    *sidep = &sp->sides[sidenum];
  1098.  
  1099.     if ((sidep->uvls[0].u == 0) && (sidep->uvls[1].u == 0) && (sidep->uvls[2].u == 0)) {
  1100.         mprintf((0,"Found bogus segment %i, side %i\n", sp-Segments, sidenum));
  1101.         med_propagate_tmaps_to_back_side(sp, sidenum, uvonly_flag);
  1102.     }
  1103. }
  1104.  
  1105. void fix_bogus_uvs_seg(segment *segp)
  1106. {
  1107.     int    s;
  1108.  
  1109.     for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
  1110.         if (!IS_CHILD(segp->children[s]))
  1111.             fix_bogus_uvs_on_side1(segp, s, 1);
  1112.     }
  1113. }
  1114.  
  1115. void fix_bogus_uvs_all(void)
  1116. {
  1117.     int    seg;
  1118.  
  1119.     for (seg=0; seg<=Highest_segment_index; seg++)
  1120.         if (Segments[seg].segnum != -1)
  1121.             fix_bogus_uvs_seg(&Segments[seg]);
  1122. }
  1123.  
  1124. // -----------------------------------------------------------------------------
  1125. //    Propagate texture map u,v coordinates to base_seg:back_side from base_seg:some-other-side
  1126. //    There is no easy way to figure out which side is adjacent to another side along some edge, so we do a bit of searching.
  1127. void med_propagate_tmaps_to_any_side(segment *base_seg, int back_side, int tmap_num, int uv_only_flag)
  1128. {
  1129.     int    v1,v2;
  1130.     int    s;
  1131.  
  1132.     //    Scan all sides, look for an occupied side which is not back_side or Side_opposite[back_side]
  1133.     for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
  1134.         if ((s != back_side) && (s != Side_opposite[back_side])) {
  1135.             v1 = Edge_between_sides[s][back_side][0];
  1136.             v2 = Edge_between_sides[s][back_side][1];
  1137.             goto found1;
  1138.         }
  1139.     Assert(0);        // Error -- couldn't find edge != back_side and Side_opposite[back_side]
  1140. found1: ;
  1141.     Assert( (v1 != -1) && (v2 != -1));        // This means there was no shared edge between the two sides.
  1142.  
  1143.     propagate_tmaps_to_segment_side(base_seg, s, base_seg, back_side, base_seg->verts[v1], base_seg->verts[v2], uv_only_flag);
  1144.  
  1145.     base_seg->sides[back_side].tmap_num = tmap_num;
  1146.  
  1147. }
  1148.  
  1149. // -----------------------------------------------------------------------------
  1150. //    Segment base_seg is connected through side base_side to segment con_seg on con_side.
  1151. //    For all walls in con_seg, find the wall in base_seg which shares an edge.  Copy tmap_num
  1152. //    from that side in base_seg to the wall in con_seg.  If the wall in base_seg is not present
  1153. //    (ie, there is another segment connected through it), follow the connection through that
  1154. //    segment to get the wall in the connected segment which shares the edge, and get tmap_num from there.
  1155. void propagate_tmaps_to_segment_sides(segment *base_seg, int base_side, segment *con_seg, int con_side, int uv_only_flag)
  1156. {
  1157.     char        *base_vp,*con_vp;
  1158.     short        abs_id1,abs_id2;
  1159.     int        v;
  1160.  
  1161.     base_vp = Side_to_verts[base_side];
  1162.     con_vp = Side_to_verts[con_side];
  1163.  
  1164.     // Do for each edge on connecting face.
  1165.     for (v=0; v<4; v++) {
  1166.         abs_id1 = base_seg->verts[base_vp[v]];
  1167.         abs_id2 = base_seg->verts[base_vp[(v+1) % 4]];
  1168.         propagate_tmaps_to_segment_side(base_seg, base_side, con_seg, con_side, abs_id1, abs_id2, uv_only_flag);
  1169.     }
  1170.  
  1171. }
  1172.  
  1173. // -----------------------------------------------------------------------------
  1174. //    Propagate texture maps in base_seg to con_seg.
  1175. //    For each wall in con_seg, find the wall in base_seg which shared an edge.  Copy tmap_num from that
  1176. //    wall in base_seg to the wall in con_seg.  If the wall in base_seg is not present, then look at the
  1177. //    segment connected through base_seg through the wall.  The wall with a common edge is the new wall
  1178. //    of interest.  Continue searching in this way until a wall of interest is present.
  1179. void med_propagate_tmaps_to_segments(segment *base_seg,segment *con_seg, int uv_only_flag)
  1180. {
  1181.     int        s;
  1182.  
  1183. // mprintf((0,"Propagating segments from %i to %i\n",base_seg-Segments,con_seg-Segments));
  1184.     for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
  1185.         if (base_seg->children[s] == con_seg-Segments)
  1186.             propagate_tmaps_to_segment_sides(base_seg, s, con_seg, find_connect_side(base_seg, con_seg), uv_only_flag);
  1187.  
  1188.     con_seg->static_light = base_seg->static_light;
  1189.  
  1190.     validate_uv_coordinates(con_seg);
  1191. }
  1192.  
  1193.  
  1194. // -------------------------------------------------------------------------------
  1195. //    Copy texture map uvs from srcseg to destseg.
  1196. //    If two segments have different face structure (eg, destseg has two faces on side 3, srcseg has only 1)
  1197. //    then assign uvs according to side vertex id, not face vertex id.
  1198. void copy_uvs_seg_to_seg(segment *destseg,segment *srcseg)
  1199. {
  1200.     int    s;
  1201.  
  1202.     for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
  1203.         destseg->sides[s].tmap_num = srcseg->sides[s].tmap_num;
  1204.         destseg->sides[s].tmap_num2 = srcseg->sides[s].tmap_num2;
  1205.     }
  1206.  
  1207.     destseg->static_light = srcseg->static_light;
  1208. }
  1209.  
  1210. //    _________________________________________________________________________________________________________________________
  1211. //    Maximum distance between a segment containing light to a segment to receive light.
  1212. #define    LIGHT_DISTANCE_THRESHOLD    (F1_0*80)
  1213. fix    Magical_light_constant = (F1_0*16);
  1214.  
  1215. // int    Seg0, Seg1;
  1216.  
  1217. //int    Bugseg = 27;
  1218.  
  1219. typedef struct {
  1220.     byte            flag, hit_type;
  1221.     vms_vector    vector;
  1222. } hash_info;
  1223.  
  1224. #define    FVI_HASH_SIZE 8
  1225. #define    FVI_HASH_AND_MASK (FVI_HASH_SIZE - 1)
  1226.  
  1227. //    Note: This should be malloced.
  1228. //            Also, the vector should not be 12 bytes, you should only care about some smaller portion of it.
  1229. hash_info    fvi_cache[FVI_HASH_SIZE];
  1230. int    Hash_hits=0, Hash_retries=0, Hash_calcs=0;
  1231.  
  1232. //    -----------------------------------------------------------------------------------------
  1233. //    Set light from a light source.
  1234. //    Light incident on a surface is defined by the light incident at its points.
  1235. //    Light at a point = K * (V . N) / d
  1236. //    where:
  1237. //        K = some magical constant to make everything look good
  1238. //        V = normalized vector from light source to point
  1239. //        N = surface normal at point
  1240. //        d = distance from light source to point
  1241. //    (Note that the above equation can be simplified to K * (VV . N) / d^2 where VV = non-normalized V)
  1242. //    Light intensity emitted from a light source is defined to be cast from four points.
  1243. //    These four points are 1/64 of the way from the corners of the light source to the center
  1244. //    of its segment.  By assuming light is cast from these points, rather than from on the
  1245. //    light surface itself, light will be properly cast on the light surface.  Otherwise, the
  1246. //    vector V would be the null vector.
  1247. //    If quick_light set, then don't use find_vector_intersection
  1248. void cast_light_from_side(segment *segp, int light_side, fix light_intensity, int quick_light)
  1249. {
  1250.     vms_vector    segment_center;
  1251.     int            segnum,sidenum,vertnum, lightnum;
  1252.  
  1253.     compute_segment_center(&segment_center, segp);
  1254.  
  1255. //mprintf((0, "From [%i %i %7.3f]:  ", segp-Segments, light_side, f2fl(light_intensity)));
  1256.  
  1257.     //    Do for four lights, one just inside each corner of side containing light.
  1258.     for (lightnum=0; lightnum<4; lightnum++) {
  1259.         int            light_vertex_num, i;
  1260.         vms_vector    vector_to_center;
  1261.         vms_vector    light_location;
  1262.         // fix            inverse_segment_magnitude;
  1263.  
  1264.         light_vertex_num = segp->verts[Side_to_verts[light_side][lightnum]];
  1265.         light_location = Vertices[light_vertex_num];
  1266.  
  1267.  
  1268.     //    New way, 5/8/95: Move towards center irrespective of size of segment.
  1269.     vm_vec_sub(&vector_to_center, &segment_center, &light_location);
  1270.     vm_vec_normalize_quick(&vector_to_center);
  1271.     vm_vec_add2(&light_location, &vector_to_center);
  1272.  
  1273. // -- Old way, before 5/8/95 --        // -- This way was kind of dumb.  In larger segments, you move LESS towards the center.
  1274. // -- Old way, before 5/8/95 --        //    Main problem, though, is vertices don't illuminate themselves well in oblong segments because the dot product is small.
  1275. // -- Old way, before 5/8/95 --        vm_vec_sub(&vector_to_center, &segment_center, &light_location);
  1276. // -- Old way, before 5/8/95 --        inverse_segment_magnitude = fixdiv(F1_0/5, vm_vec_mag(&vector_to_center));
  1277. // -- Old way, before 5/8/95 --        vm_vec_scale_add(&light_location, &light_location, &vector_to_center, inverse_segment_magnitude);
  1278.  
  1279.         for (segnum=0; segnum<=Highest_segment_index; segnum++) {
  1280.             segment        *rsegp = &Segments[segnum];
  1281.             vms_vector    r_segment_center;
  1282.             fix            dist_to_rseg;
  1283.  
  1284.             for (i=0; i<FVI_HASH_SIZE; i++)
  1285.                 fvi_cache[i].flag = 0;
  1286.  
  1287.             //    efficiency hack (I hope!), for faraway segments, don't check each point.
  1288.             compute_segment_center(&r_segment_center, rsegp);
  1289.             dist_to_rseg = vm_vec_dist_quick(&r_segment_center, &segment_center);
  1290.  
  1291.             if (dist_to_rseg <= LIGHT_DISTANCE_THRESHOLD) {
  1292.                 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
  1293.                     if (WALL_IS_DOORWAY(rsegp, sidenum) != WID_NO_WALL) {
  1294.                         side            *rsidep = &rsegp->sides[sidenum];
  1295.                         vms_vector    *side_normalp = &rsidep->normals[0];    //    kinda stupid? always use vector 0.
  1296.  
  1297. //mprintf((0, "[%i %i], ", rsegp-Segments, sidenum));
  1298.                         for (vertnum=0; vertnum<4; vertnum++) {
  1299.                             fix            distance_to_point, light_at_point, light_dot;
  1300.                             vms_vector    vert_location, vector_to_light;
  1301.                             int            abs_vertnum;
  1302.  
  1303.                             abs_vertnum = rsegp->verts[Side_to_verts[sidenum][vertnum]];
  1304.                             vert_location = Vertices[abs_vertnum];
  1305.                             distance_to_point = vm_vec_dist_quick(&vert_location, &light_location);
  1306.                             vm_vec_sub(&vector_to_light, &light_location, &vert_location);
  1307.                             vm_vec_normalize(&vector_to_light);
  1308.  
  1309.                             //    Hack: In oblong segments, it's possible to get a very small dot product
  1310.                             //    but the light source is very nearby (eg, illuminating light itself!).
  1311.                             light_dot = vm_vec_dot(&vector_to_light, side_normalp);
  1312.                             if (distance_to_point < F1_0)
  1313.                                 if (light_dot > 0)
  1314.                                     light_dot = (light_dot + F1_0)/2;
  1315.  
  1316.                             if (light_dot > 0) {
  1317.                                 light_at_point = fixdiv(fixmul(light_dot, light_dot), distance_to_point);
  1318.                                 light_at_point = fixmul(light_at_point, Magical_light_constant);
  1319.                                 if (light_at_point >= 0) {
  1320.                                     fvi_info    hit_data;
  1321.                                     int        hit_type;
  1322.                                     vms_vector    vert_location_1, r_vector_to_center;
  1323.                                     fix        inverse_segment_magnitude;
  1324.  
  1325.                                     vm_vec_sub(&r_vector_to_center, &r_segment_center, &vert_location);
  1326.                                     inverse_segment_magnitude = fixdiv(F1_0/3, vm_vec_mag(&r_vector_to_center));
  1327.                                     vm_vec_scale_add(&vert_location_1, &vert_location, &r_vector_to_center, inverse_segment_magnitude);
  1328.                                     vert_location = vert_location_1;
  1329.  
  1330. //if ((segp-Segments == 199) && (rsegp-Segments==199))
  1331. //    Int3();
  1332. // Seg0 = segp-Segments;
  1333. // Seg1 = rsegp-Segments;
  1334.                                     if (!quick_light) {
  1335.                                         int hash_value = Side_to_verts[sidenum][vertnum];
  1336.                                         hash_info    *hashp = &fvi_cache[hash_value];
  1337.                                         while (1) {
  1338.                                             if (hashp->flag) {
  1339.                                                 if ((hashp->vector.x == vector_to_light.x) && (hashp->vector.y == vector_to_light.y) && (hashp->vector.z == vector_to_light.z)) {
  1340. //mprintf((0, "{CACHE %4x} ", hash_value));
  1341.                                                     hit_type = hashp->hit_type;
  1342.                                                     Hash_hits++;
  1343.                                                     break;
  1344.                                                 } else {
  1345.                                                     Int3();    // How is this possible?  Should be no hits!
  1346.                                                     Hash_retries++;
  1347.                                                     hash_value = (hash_value+1) & FVI_HASH_AND_MASK;
  1348.                                                     hashp = &fvi_cache[hash_value];
  1349.                                                 }
  1350.                                             } else {
  1351. //mprintf((0, "\nH:%04x ", hash_value));
  1352.                                                 fvi_query fq;
  1353.  
  1354.                                                 Hash_calcs++;
  1355.                                                 hashp->vector = vector_to_light;
  1356.                                                 hashp->flag = 1;
  1357.  
  1358.                                                 fq.p0                        = &light_location;
  1359.                                                 fq.startseg                = segp-Segments;
  1360.                                                 fq.p1                        = &vert_location;
  1361.                                                 fq.rad                    = 0;
  1362.                                                 fq.thisobjnum            = -1;
  1363.                                                 fq.ignore_obj_list    = NULL;
  1364.                                                 fq.flags                    = 0;
  1365.  
  1366.                                                 hit_type = find_vector_intersection(&fq,&hit_data);
  1367.                                                 hashp->hit_type = hit_type;
  1368.                                                 break;
  1369.                                             }
  1370.                                         }
  1371.                                     } else
  1372.                                         hit_type = HIT_NONE;
  1373. //mprintf((0, "hit=%i ", hit_type));
  1374.                                     switch (hit_type) {
  1375.                                         case HIT_NONE:
  1376.                                             light_at_point = fixmul(light_at_point, light_intensity);
  1377.                                             rsidep->uvls[vertnum].l += light_at_point;
  1378. //mprintf((0, "(%5.2f) ", f2fl(light_at_point)));
  1379.                                             if (rsidep->uvls[vertnum].l > F1_0)
  1380.                                                 rsidep->uvls[vertnum].l = F1_0;
  1381.                                             break;
  1382.                                         case HIT_WALL:
  1383.                                             break;
  1384.                                         case HIT_OBJECT:
  1385.                                             Int3();    // Hit object, should be ignoring objects!
  1386.                                             break;
  1387.                                         case HIT_BAD_P0:
  1388.                                             Int3();    //    Ugh, this thing again, what happened, what does it mean?
  1389.                                             break;
  1390.                                     }
  1391.                                 }    //    end if (light_at_point...
  1392.                             }    // end if (light_dot >...
  1393.                         }    //    end for (vertnum=0...
  1394.                     }    //    end if (rsegp...
  1395.                 }    //    end for (sidenum=0...
  1396.             }    //    end if (dist_to_rseg...
  1397.  
  1398.         }    //    end for (segnum=0...
  1399.  
  1400.     }    //    end for (lightnum=0...
  1401.  
  1402. //mprintf((0, "\n"));
  1403. }
  1404.  
  1405.  
  1406. //    ------------------------------------------------------------------------------------------
  1407. //    Zero all lighting values.
  1408. void calim_zero_light_values(void)
  1409. {
  1410.     int    segnum, sidenum, vertnum;
  1411.  
  1412.     for (segnum=0; segnum<=Highest_segment_index; segnum++) {
  1413.         segment *segp = &Segments[segnum];
  1414.         for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
  1415.             side    *sidep = &segp->sides[sidenum];
  1416.             for (vertnum=0; vertnum<4; vertnum++)
  1417.                 sidep->uvls[vertnum].l = F1_0/64;    // Put a tiny bit of light here.
  1418.         }
  1419.         Segments[segnum].static_light = F1_0/64;
  1420.     }
  1421. }
  1422.  
  1423.  
  1424. //    ------------------------------------------------------------------------------------------
  1425. //    Used in setting average light value in a segment, cast light from a side to the center
  1426. //    of all segments.
  1427. void cast_light_from_side_to_center(segment *segp, int light_side, fix light_intensity, int quick_light)
  1428. {
  1429.     vms_vector    segment_center;
  1430.     int            segnum, lightnum;
  1431.  
  1432.     compute_segment_center(&segment_center, segp);
  1433.  
  1434.     //    Do for four lights, one just inside each corner of side containing light.
  1435.     for (lightnum=0; lightnum<4; lightnum++) {
  1436.         int            light_vertex_num;
  1437.         vms_vector    vector_to_center;
  1438.         vms_vector    light_location;
  1439.  
  1440.         light_vertex_num = segp->verts[Side_to_verts[light_side][lightnum]];
  1441.         light_location = Vertices[light_vertex_num];
  1442.         vm_vec_sub(&vector_to_center, &segment_center, &light_location);
  1443.         vm_vec_scale_add(&light_location, &light_location, &vector_to_center, F1_0/64);
  1444.  
  1445.         for (segnum=0; segnum<=Highest_segment_index; segnum++) {
  1446.             segment        *rsegp = &Segments[segnum];
  1447.             vms_vector    r_segment_center;
  1448.             fix            dist_to_rseg;
  1449. //if ((segp == &Segments[Bugseg]) && (rsegp == &Segments[Bugseg]))
  1450. //    Int3();
  1451.             compute_segment_center(&r_segment_center, rsegp);
  1452.             dist_to_rseg = vm_vec_dist_quick(&r_segment_center, &segment_center);
  1453.  
  1454.             if (dist_to_rseg <= LIGHT_DISTANCE_THRESHOLD) {
  1455.                 fix    light_at_point;
  1456.                 if (dist_to_rseg > F1_0)
  1457.                     light_at_point = fixdiv(Magical_light_constant, dist_to_rseg);
  1458.                 else
  1459.                     light_at_point = Magical_light_constant;
  1460.  
  1461.                 if (light_at_point >= 0) {
  1462.                     int        hit_type;
  1463.  
  1464.                     if (!quick_light) {
  1465.                         fvi_query fq;
  1466.                         fvi_info    hit_data;
  1467.  
  1468.                         fq.p0                        = &light_location;
  1469.                         fq.startseg                = segp-Segments;
  1470.                         fq.p1                        = &r_segment_center;
  1471.                         fq.rad                    = 0;
  1472.                         fq.thisobjnum            = -1;
  1473.                         fq.ignore_obj_list    = NULL;
  1474.                         fq.flags                    = 0;
  1475.  
  1476.                         hit_type = find_vector_intersection(&fq,&hit_data);
  1477.                     }
  1478.                     else
  1479.                         hit_type = HIT_NONE;
  1480.  
  1481.                     switch (hit_type) {
  1482.                         case HIT_NONE:
  1483.                             light_at_point = fixmul(light_at_point, light_intensity);
  1484.                             if (light_at_point >= F1_0)
  1485.                                 light_at_point = F1_0-1;
  1486.                             rsegp->static_light += light_at_point;
  1487.                             if (segp->static_light < 0)    // if it went negative, saturate
  1488.                                 segp->static_light = 0;
  1489.                             break;
  1490.                         case HIT_WALL:
  1491.                             break;
  1492.                         case HIT_OBJECT:
  1493.                             Int3();    // Hit object, should be ignoring objects!
  1494.                             break;
  1495.                         case HIT_BAD_P0:
  1496.                             Int3();    //    Ugh, this thing again, what happened, what does it mean?
  1497.                             break;
  1498.                     }
  1499.                 }    //    end if (light_at_point...
  1500.             }    //    end if (dist_to_rseg...
  1501.  
  1502.         }    //    end for (segnum=0...
  1503.  
  1504.     }    //    end for (lightnum=0...
  1505.  
  1506. }
  1507.  
  1508. //    ------------------------------------------------------------------------------------------
  1509. //    Process all lights.
  1510. void calim_process_all_lights(int quick_light)
  1511. {
  1512.     int    segnum, sidenum;
  1513.  
  1514.     for (segnum=0; segnum<=Highest_segment_index; segnum++) {
  1515.         segment    *segp = &Segments[segnum];
  1516.         mprintf((0, "."));
  1517.         for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
  1518.             // if (!IS_CHILD(segp->children[sidenum])) {
  1519.             if (WALL_IS_DOORWAY(segp, sidenum) != WID_NO_WALL) {
  1520.                 side    *sidep = &segp->sides[sidenum];
  1521.                 fix    light_intensity;
  1522.  
  1523.                 light_intensity = TmapInfo[sidep->tmap_num].lighting + TmapInfo[sidep->tmap_num2 & 0x3fff].lighting;
  1524.  
  1525. //                if (segp->sides[sidenum].wall_num != -1) {
  1526. //                    int    wall_num, bitmap_num, effect_num;
  1527. //                    wall_num = segp->sides[sidenum].wall_num;
  1528. //                    effect_num = Walls[wall_num].type;
  1529. //                    bitmap_num = effects_bm_num[effect_num];
  1530. //
  1531. //                    light_intensity += TmapInfo[bitmap_num].lighting;
  1532. //                }
  1533.  
  1534.                 if (light_intensity) {
  1535.                     light_intensity /= 4;            // casting light from four spots, so divide by 4.
  1536.                     cast_light_from_side(segp, sidenum, light_intensity, quick_light);
  1537.                     cast_light_from_side_to_center(segp, sidenum, light_intensity, quick_light);
  1538.                 }
  1539.             }
  1540.         }
  1541.     }
  1542. }
  1543.  
  1544. //    ------------------------------------------------------------------------------------------
  1545. //    Apply static light in mine.
  1546. //    First, zero all light values.
  1547. //    Then, for all light sources, cast their light.
  1548. void cast_all_light_in_mine(int quick_flag)
  1549. {
  1550.  
  1551.     validate_segment_all();
  1552.  
  1553.     calim_zero_light_values();
  1554.  
  1555.     calim_process_all_lights(quick_flag);
  1556.  
  1557. }
  1558.  
  1559. // int    Fvit_num = 1000;
  1560. // 
  1561. // fix find_vector_intersection_test(void)
  1562. // {
  1563. //     int        i;
  1564. //     fvi_info    hit_data;
  1565. //     int        p0_seg, p1_seg, this_objnum, ignore_obj, check_obj_flag;
  1566. //     fix        rad;
  1567. //     int        start_time = timer_get_milliseconds();;
  1568. //     vms_vector    p0,p1;
  1569. // 
  1570. //     ignore_obj = 1;
  1571. //     check_obj_flag = 0;
  1572. //     this_objnum = -1;
  1573. //     rad = F1_0/4;
  1574. // 
  1575. //     for (i=0; i<Fvit_num; i++) {
  1576. //         p0_seg = rand()*(Highest_segment_index+1)/32768;
  1577. //         compute_segment_center(&p0, &Segments[p0_seg]);
  1578. // 
  1579. //         p1_seg = rand()*(Highest_segment_index+1)/32768;
  1580. //         compute_segment_center(&p1, &Segments[p1_seg]);
  1581. // 
  1582. //         find_vector_intersection(&hit_data, &p0, p0_seg, &p1, rad, this_objnum, ignore_obj, check_obj_flag);
  1583. //     }
  1584. // 
  1585. //     return timer_get_milliseconds() - start_time;
  1586. // }
  1587.  
  1588. vms_vector    Normals[MAX_SEGMENTS*12];
  1589.  
  1590. int    Normal_nearness = 4;
  1591.  
  1592. int normal_near(vms_vector *v1, vms_vector *v2)
  1593. {
  1594.     if (abs(v1->x - v2->x) < Normal_nearness)
  1595.         if (abs(v1->y - v2->y) < Normal_nearness)
  1596.             if (abs(v1->z - v2->z) < Normal_nearness)
  1597.                 return 1;
  1598.     return 0;
  1599. }
  1600.  
  1601. int    Total_normals=0;
  1602. int    Diff_normals=0;
  1603.  
  1604. void print_normals(void)
  1605. {
  1606.     int            i,j,s,n,nn;
  1607.     // vms_vector    *normal;
  1608.     int            num_normals=0;
  1609.  
  1610.     Total_normals = 0;
  1611.     Diff_normals = 0;
  1612.  
  1613.     for (i=0; i<=Highest_segment_index; i++)
  1614.         for (s=0; s<6; s++) {
  1615.             if (Segments[i].sides[s].type == SIDE_IS_QUAD)
  1616.                 nn=1;
  1617.             else
  1618.                 nn=2;
  1619.             for (n=0; n<nn; n++) {
  1620.                 for (j=0; j<num_normals; j++)
  1621.                     if (normal_near(&Segments[i].sides[s].normals[n],&Normals[j]))
  1622.                         break;
  1623.                 if (j == num_normals) {
  1624.                     Normals[num_normals++] = Segments[i].sides[s].normals[n];
  1625.                     Diff_normals++;
  1626.                 }
  1627.                 Total_normals++;
  1628.             }
  1629.         }
  1630.  
  1631. }
  1632.  
  1633.