home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / descent / source / main / segment.c < prev    next >
C/C++ Source or Header  |  1998-06-08  |  73KB  |  2,246 lines

  1. /*
  2.  * $Source: f:/miner/source/main/editor/rcs/segment.c $
  3.  * $Revision: 2.0 $
  4.  * $Author: john $
  5.  * $Date: 1995/02/27 11:35:21 $
  6.  *
  7.  * Interrogation functions for segment data structure.
  8.  *
  9.  * $Log: segment.c $
  10.  * Revision 2.0  1995/02/27  11:35:21  john
  11.  * Version 2.0! No anonymous unions, Watcom 10.0, with no need
  12.  * for bitmaps.tbl.
  13.  * 
  14.  * Revision 1.191  1995/02/22  15:28:30  allender
  15.  * remove anonymous unions from object structure
  16.  * 
  17.  * Revision 1.190  1995/02/02  02:59:40  yuan
  18.  * Working on exterminating bogus matcen_nums... (harmless though)
  19.  * 
  20.  * Revision 1.189  1995/02/01  16:29:51  yuan
  21.  * Stabilizing triggers and matcens.
  22.  * 
  23.  * Revision 1.188  1995/02/01  11:31:47  yuan
  24.  * Trigger bug fixed.
  25.  * 
  26.  * Revision 1.187  1994/11/27  23:17:24  matt
  27.  * Made changes for new mprintf calling convention
  28.  * 
  29.  * Revision 1.186  1994/11/17  14:48:12  mike
  30.  * validation functions moved from editor to game.
  31.  * 
  32.  * Revision 1.185  1994/10/30  14:13:17  mike
  33.  * rip out local segment stuff.
  34.  * 
  35.  * Revision 1.184  1994/10/27  10:04:24  matt
  36.  * When triangulating, don't use WID() to see if connected, look at children
  37.  * 
  38.  * Revision 1.183  1994/10/26  13:40:23  mike
  39.  * debug code for matt.
  40.  * 
  41.  * Revision 1.182  1994/10/24  16:34:00  mike
  42.  * Force render after mine compress to prevent bugs in segment selection via clicking in 3d window.
  43.  * 
  44.  * Revision 1.181  1994/10/20  18:16:15  mike
  45.  * Initialize ControlCenterTriggers.num_links in create_new_mine.
  46.  * 
  47.  * Revision 1.180  1994/10/18  16:29:14  mike
  48.  * Write function to automatically fix bogus segnums in segment array.
  49.  * 
  50.  * Revision 1.179  1994/10/08  17:10:41  matt
  51.  * Correctly set current_level_num when loading/creating mine in editor
  52.  * 
  53.  * Revision 1.178  1994/09/25  14:17:51  mike
  54.  * Initialize (to 0) Num_robot_centers and Num_open_doors at mine creation.
  55.  * 
  56.  * Revision 1.177  1994/09/20  14:36:06  mike
  57.  * Write function to find overlapping segments.
  58.  * 
  59.  * Revision 1.176  1994/08/25  21:55:57  mike
  60.  * IS_CHILD stuff.
  61.  * 
  62.  * Revision 1.175  1994/08/23  15:28:03  mike
  63.  * Fix peculiarity in med_combine_duplicate_vertices.
  64.  * 
  65.  * Revision 1.174  1994/08/09  16:06:17  john
  66.  * Added the ability to place players.  Made old
  67.  * Player variable be ConsoleObject.
  68.  * 
  69.  * Revision 1.173  1994/08/05  21:18:10  matt
  70.  * Allow two doors to be linked together
  71.  * 
  72.  * Revision 1.172  1994/08/04  19:13:16  matt
  73.  * Changed a bunch of vecmat calls to use multiple-function routines, and to
  74.  * allow the use of C macros for some functions
  75.  * 
  76.  * Revision 1.171  1994/07/22  12:37:00  matt
  77.  * Cleaned up editor/game interactions some more.
  78.  * 
  79.  * Revision 1.170  1994/07/22  11:20:08  mike
  80.  * Set Lsegments validity.
  81.  * 
  82.  * Revision 1.169  1994/07/21  19:02:49  mike
  83.  * lsegment stuff.
  84.  * 
  85.  * Revision 1.168  1994/07/21  13:27:17  matt
  86.  * Ripped out remants of old demo system, and added demo
  87.  * disables object movement and game options from menu.
  88.  * 
  89.  * Revision 1.167  1994/07/19  20:15:48  matt
  90.  * Name for each level now saved in the .SAV file & stored in Current_level_name
  91.  * 
  92.  * Revision 1.166  1994/07/06  12:42:45  john
  93.  * Made generic messages for hostages.
  94.  * 
  95.  * Revision 1.165  1994/06/24  17:04:29  john
  96.  * *** empty log message ***
  97.  * 
  98.  * Revision 1.164  1994/06/15  15:42:40  mike
  99.  * Initialize static_light field in new segments.
  100.  * 
  101.  * Revision 1.163  1994/06/13  17:49:19  mike
  102.  * Fix bug in med_validate_side which was toasting lighting for removable walls.
  103.  * 
  104.  * Revision 1.162  1994/06/13  10:52:20  mike
  105.  * Fix bug in triangulation of sides between connected segments.
  106.  * Was assigning SIDE_IS_02 regardless of how triangulated, was
  107.  * causing physics bugs.
  108.  * 
  109.  * Revision 1.161  1994/06/08  18:14:16  mike
  110.  * Fix triangulation of sides in hallways (ie, where there is no wall),
  111.  * so they get triangulated the same way, so find_new_seg doesn't get
  112.  * stuck in an infinite recursion.
  113.  * 
  114.  * Revision 1.160  1994/06/08  11:44:31  mike
  115.  * Fix bug in normals not being opposite on opposite sides of a segment.
  116.  * Problem occurred due to difference in handling of remainder in signed divide.
  117.  * 
  118.  * Revision 1.159  1994/05/31  19:00:15  yuan
  119.  * Fixed gamestate restore.
  120.  * 
  121.  * Revision 1.158  1994/05/30  20:22:36  yuan
  122.  * New triggers.
  123.  * 
  124.  * Revision 1.157  1994/05/26  19:32:51  mike
  125.  * Add bfs_parse.
  126.  * 
  127.  * Revision 1.156  1994/05/23  14:56:46  mike
  128.  * make current segment be add segment.,
  129.  * 
  130.  */
  131.  
  132. #pragma off (unreferenced)
  133. static char rcsid[] = "$Id: segment.c 2.0 1995/02/27 11:35:21 john Exp $";
  134. #pragma on (unreferenced)
  135.  
  136. #include <stdio.h>
  137. #include <stdlib.h>
  138. #include <math.h>
  139. #include <string.h>
  140.  
  141. #include "mono.h"
  142. #include "key.h"
  143. #include "gr.h"
  144.  
  145. #include "inferno.h"
  146. #include "segment.h"
  147. // #include "segment2.h"
  148. #include    "editor.h"
  149. #include "error.h"
  150. #include "object.h"
  151.  
  152. #include "gameseg.h"
  153. #include "render.h"
  154. #include "demo.h"
  155. #include "game.h"
  156.  
  157. #include "wall.h"
  158. #include "switch.h"
  159. #include "fuelcen.h"
  160. #include "seguvs.h"
  161. #include "gameseq.h"
  162.  
  163. #include "medwall.h"
  164. #include "hostage.h"
  165.  
  166. int    Do_duplicate_vertex_check = 0;        // Gets set to 1 in med_create_duplicate_vertex, means to check for duplicate vertices in compress_mine
  167.  
  168. #define    BOTTOM_STUFF    0
  169.  
  170. //    Remap all vertices in polygons in a segment through translation table xlate_verts.
  171. #if BOTTOM_STUFF
  172. void remap_vertices(segment *segp, int *xlate_verts)
  173. {
  174.     int    sidenum, facenum, polynum, v;
  175.  
  176.     for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++)
  177.         for (facenum=0; facenum<segp->sides[sidenum].num_faces; facenum++)
  178.             for (polynum=0; polynum<segp->sides[sidenum].faces[facenum].num_polys; polynum++) {
  179.                 poly *pp = &segp->sides[sidenum].faces[facenum].polys[polynum];
  180.                 for (v=0; v<pp->num_vertices; v++)
  181.                     pp->verts[v] = xlate_verts[pp->verts[v]];
  182.             }
  183. }
  184.  
  185. //    Copy everything from sourceside to destside except sourceside->faces[xx].polys[xx].verts
  186. void copy_side_except_vertex_ids(side *destside, side *sourceside)
  187. {
  188.     int    facenum, polynum, v;
  189.  
  190.     destside->num_faces = sourceside->num_faces;
  191.     destside->tri_edge = sourceside->tri_edge;
  192.     destside->wall_num = sourceside->wall_num;
  193.  
  194.     for (facenum=0; facenum<sourceside->num_faces; facenum++) {
  195.         face *destface = &destside->faces[facenum];
  196.         face *sourceface = &sourceside->faces[facenum];
  197.  
  198.         destface->num_polys = sourceface->num_polys;
  199.         destface->normal = sourceface->normal;
  200.  
  201.         for (polynum=0; polynum<sourceface->num_polys; polynum++) {
  202.             poly *destpoly = &destface->polys[polynum];
  203.             poly *sourcepoly = &sourceface->polys[polynum];
  204.  
  205.             destpoly->num_vertices = sourcepoly->num_vertices;
  206.             destpoly->face_type = sourcepoly->face_type;
  207.             destpoly->tmap_num = sourcepoly->tmap_num;
  208.             destpoly->tmap_num2 = sourcepoly->tmap_num2;
  209.  
  210.             for (v=0; v<sourcepoly->num_vertices; v++)
  211.                 destpoly->uvls[v] = sourcepoly->uvls[v];
  212.         }
  213.  
  214.     }
  215. }
  216.  
  217. //    [side] [index] [cur:next]
  218. //    To remap the vertices on a side after a forward rotation
  219. byte xlate_previous[6][4][2] = {
  220. { {7, 3}, {3, 2}, {2, 6}, {6, 7} },        // remapping left to left
  221. { {5, 4}, {4, 0}, {7, 3}, {6, 7} },        // remapping back to top
  222. { {5, 4}, {1, 5}, {0, 1}, {4, 0} },        // remapping right to right
  223. { {0, 1}, {1, 5}, {2, 6}, {3, 2} },        //    remapping front to bottom
  224. { {1, 5}, {5, 4}, {6, 7}, {2, 6} },        // remapping bottom to back
  225. { {4, 0}, {0, 1}, {3, 2}, {7, 3} },        // remapping top to front
  226. };
  227.  
  228. void remap_vertices_previous(segment *segp, int sidenum)
  229. {
  230.     int    v, w, facenum, polynum;
  231.  
  232.     for (facenum=0; facenum<segp->sides[sidenum].num_faces; facenum++) {
  233.         for (polynum=0; polynum<segp->sides[sidenum].faces[facenum].num_polys; polynum++) {
  234.             poly *pp = &segp->sides[sidenum].faces[facenum].polys[polynum];
  235.  
  236.             for (v=0; v<pp->num_vertices; v++) {
  237.                 for (w=0; w<4; w++) {
  238.                     if (pp->verts[v] == xlate_previous[sidenum][w][0]) {
  239.                         pp->verts[v] = xlate_previous[sidenum][w][1];
  240.                         break;
  241.                     }
  242.                 }
  243.                 Assert(w<4);    // If w == 4, then didn't find current vertex in list, which means xlate_previous table is bogus
  244.             }
  245.         }
  246.     }
  247. }
  248.  
  249. byte xlate_previous_right[6][4][2] = {
  250. { {5, 6}, {6, 7}, {2, 3}, {1, 2} },        // bottom to left
  251. { {6, 7}, {7, 4}, {3, 0}, {2, 3} },        // left to top
  252. { {7, 4}, {4, 5}, {0, 1}, {3, 0} },        // top to right
  253. { {4, 5}, {5, 6}, {1, 2}, {0, 1} },        // right to bottom
  254. { {6, 7}, {5, 6}, {4, 5}, {7, 4} },        // back to back
  255. { {3, 2}, {0, 3}, {1, 0}, {2, 1} },        // front to front
  256. };
  257.  
  258. void remap_vertices_previous_right(segment *segp, int sidenum)
  259. {
  260.     int    v, w, facenum, polynum;
  261.  
  262.     for (facenum=0; facenum<segp->sides[sidenum].num_faces; facenum++) {
  263.         for (polynum=0; polynum<segp->sides[sidenum].faces[facenum].num_polys; polynum++) {
  264.             poly *pp = &segp->sides[sidenum].faces[facenum].polys[polynum];
  265.  
  266.             for (v=0; v<pp->num_vertices; v++) {
  267.                 for (w=0; w<4; w++) {
  268.                     if (pp->verts[v] == xlate_previous_right[sidenum][w][0]) {
  269.                         pp->verts[v] = xlate_previous_right[sidenum][w][1];
  270.                         break;
  271.                     }
  272.                 }
  273.                 Assert(w<4);    // If w == 4, then didn't find current vertex in list, which means xlate_previous table is bogus
  274.             }
  275.         }
  276.     }
  277. }
  278.  
  279.  
  280. // -----------------------------------------------------------------------------------
  281. //    Takes top to front
  282. void med_rotate_segment_forward(segment *segp)
  283. {
  284.     segment    seg_copy;
  285.     int        i;
  286.  
  287.     seg_copy = *segp;
  288.  
  289.     seg_copy.verts[0] = segp->verts[4];
  290.     seg_copy.verts[1] = segp->verts[0];
  291.     seg_copy.verts[2] = segp->verts[3];
  292.     seg_copy.verts[3] = segp->verts[7];
  293.     seg_copy.verts[4] = segp->verts[5];
  294.     seg_copy.verts[5] = segp->verts[1];
  295.     seg_copy.verts[6] = segp->verts[2];
  296.     seg_copy.verts[7] = segp->verts[6];
  297.  
  298.     seg_copy.children[WFRONT] = segp->children[WTOP];
  299.     seg_copy.children[WTOP] = segp->children[WBACK];
  300.     seg_copy.children[WBACK] = segp->children[WBOTTOM];
  301.     seg_copy.children[WBOTTOM] = segp->children[WFRONT];
  302.  
  303.     seg_copy.sides[WFRONT] = segp->sides[WTOP];
  304.     seg_copy.sides[WTOP] = segp->sides[WBACK];
  305.     seg_copy.sides[WBACK] = segp->sides[WBOTTOM];
  306.     seg_copy.sides[WBOTTOM] = segp->sides[WFRONT];
  307.  
  308.     for (i=0; i<6; i++)
  309.         remap_vertices_previous(&seg_copy, i);
  310.  
  311.     *segp = seg_copy;
  312. }
  313.  
  314. // -----------------------------------------------------------------------------------
  315. //    Takes top to right
  316. void med_rotate_segment_right(segment *segp)
  317. {
  318.     segment    seg_copy;
  319.     int        i;
  320.  
  321.     seg_copy = *segp;
  322.  
  323.     seg_copy.verts[4] = segp->verts[7];
  324.     seg_copy.verts[5] = segp->verts[4];
  325.     seg_copy.verts[1] = segp->verts[0];
  326.     seg_copy.verts[0] = segp->verts[3];
  327.     seg_copy.verts[3] = segp->verts[2];
  328.     seg_copy.verts[2] = segp->verts[1];
  329.     seg_copy.verts[6] = segp->verts[5];
  330.     seg_copy.verts[7] = segp->verts[6];
  331.  
  332.     seg_copy.children[WRIGHT] = segp->children[WTOP];
  333.     seg_copy.children[WBOTTOM] = segp->children[WRIGHT];
  334.     seg_copy.children[WLEFT] = segp->children[WBOTTOM];
  335.     seg_copy.children[WTOP] = segp->children[WLEFT];
  336.  
  337.     seg_copy.sides[WRIGHT] = segp->sides[WTOP];
  338.     seg_copy.sides[WBOTTOM] = segp->sides[WRIGHT];
  339.     seg_copy.sides[WLEFT] = segp->sides[WBOTTOM];
  340.     seg_copy.sides[WTOP] = segp->sides[WLEFT];
  341.  
  342.     for (i=0; i<6; i++)
  343.         remap_vertices_previous_right(&seg_copy, i);
  344.  
  345.     *segp = seg_copy;
  346. }
  347.  
  348. void make_curside_bottom_side(void)
  349. {
  350.     switch (Curside) {
  351.         case WRIGHT:    med_rotate_segment_right(Cursegp);        break;
  352.         case WTOP:        med_rotate_segment_right(Cursegp);        med_rotate_segment_right(Cursegp);        break;
  353.         case WLEFT:        med_rotate_segment_right(Cursegp);        med_rotate_segment_right(Cursegp);        med_rotate_segment_right(Cursegp);        break;
  354.         case WBOTTOM:    break;
  355.         case WFRONT:    med_rotate_segment_forward(Cursegp);    break;
  356.         case WBACK:        med_rotate_segment_forward(Cursegp);    med_rotate_segment_forward(Cursegp);    med_rotate_segment_forward(Cursegp);    break;
  357.     }
  358.     Update_flags = UF_WORLD_CHANGED;
  359. }
  360. #endif
  361.  
  362. void ToggleBottom(void)
  363. {
  364.     Render_only_bottom = !Render_only_bottom;
  365.     Update_flags = UF_WORLD_CHANGED;
  366. }
  367.         
  368. // ---------------------------------------------------------------------------------------------
  369. //           ---------- Segment interrogation functions ----------
  370. // ----------------------------------------------------------------------------
  371. //    Return a pointer to the list of vertex indices for the current segment in vp and
  372. //    the number of vertices in *nv.
  373. void med_get_vertex_list(segment *s,int *nv,short **vp)
  374. {
  375.     *vp = s->verts;
  376.     *nv = MAX_VERTICES_PER_SEGMENT;
  377. }
  378.  
  379. // -------------------------------------------------------------------------------
  380. //    Return number of times vertex vi appears in all segments.
  381. //    This function can be used to determine whether a vertex is used exactly once in
  382. //    all segments, in which case it can be freely moved because it is not connected
  383. //    to any other segment.
  384. int med_vertex_count(int vi)
  385. {
  386.     int        s,v;
  387.     segment    *sp;
  388.     int        count;
  389.  
  390.     count = 0;
  391.  
  392.     for (s=0; s<MAX_SEGMENTS; s++) {
  393.         sp = &Segments[s];
  394.         if (sp->segnum != -1)
  395.             for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
  396.                 if (sp->verts[v] == vi)
  397.                     count++;
  398.     }
  399.  
  400.     return count;
  401. }
  402.  
  403. // -------------------------------------------------------------------------------
  404. int is_free_vertex(int vi)
  405. {
  406.     return med_vertex_count(vi) == 1;
  407. }
  408.  
  409.  
  410. // -------------------------------------------------------------------------------
  411. // Move a free vertex in the segment by adding the vector *vofs to its coordinates.
  412. //    Error handling:
  413. //     If the point is not free then:
  414. //        If the point is not valid (probably valid = in 0..7) then:
  415. //        If adding *vofs will cause a degenerate segment then:
  416. //    Note, pi is the point index relative to the segment, not an absolute point index.
  417. // For example, 3 is always the front upper left vertex.
  418. void med_move_vertex(segment *sp, int pi, vms_vector *vofs)
  419. {
  420.     int    abspi;
  421.  
  422.     Assert((pi >= 0) && (pi <= 7));        // check valid range of point indices.
  423.  
  424.     abspi = sp->verts[pi];
  425.  
  426.     // Make sure vertex abspi is free.  If it is free, it appears exactly once in Vertices
  427.     Assert(med_vertex_count(abspi) == 1);
  428.  
  429.     Assert(abspi <= MAX_SEGMENT_VERTICES);            // Make sure vertex id is not bogus.
  430.  
  431.     vm_vec_add(&Vertices[abspi],&Vertices[abspi],vofs);
  432.  
  433.     // Here you need to validate the geometry of the segment, which will be quite tricky.
  434.     // You need to make sure:
  435.     //        The segment is not concave.
  436.     //        None of the sides are concave.
  437.     validate_segment(sp);
  438.  
  439. }
  440.  
  441. // -------------------------------------------------------------------------------
  442. //    Move a free wall in the segment by adding the vector *vofs to its coordinates.
  443. //    Wall indices: 0/1/2/3/4/5 = left/top/right/bottom/back/front
  444. void med_move_wall(segment *sp,int wi, vms_vector *vofs)
  445. {
  446.     char *vp;
  447.     int    i;
  448.  
  449.     Assert( (wi >= 0) && (wi <= 5) );
  450.  
  451.     vp = Side_to_verts[wi];
  452.     for (i=0; i<4; i++) {
  453.         med_move_vertex(sp,*vp,vofs);
  454.         vp++;
  455.     }
  456.  
  457.     validate_segment(sp);
  458. }
  459.  
  460. // -------------------------------------------------------------------------------
  461. //    Return true if one fixed point number is very close to another, else return false.
  462. int fnear(fix f1, fix f2)
  463. {
  464.     return (abs(f1 - f2) <= FIX_EPSILON);
  465. }
  466.  
  467. // -------------------------------------------------------------------------------
  468. int vnear(vms_vector *vp1, vms_vector *vp2)
  469. {
  470.     return fnear(vp1->x, vp2->x) && fnear(vp1->y, vp2->y) && fnear(vp1->z, vp2->z);
  471. }
  472.  
  473. // -------------------------------------------------------------------------------
  474. //    Add the vertex *vp to the global list of vertices, return its index.
  475. //    Search until a matching vertex is found (has nearly the same coordinates) or until Num_vertices
  476. // vertices have been looked at without a match.  If no match, add a new vertex.
  477. int med_add_vertex(vms_vector *vp)
  478. {
  479.     int    v,free_index;
  480.     int    count;                    // number of used vertices found, for loops exits when count == Num_vertices
  481.  
  482. //    set_vertex_counts();
  483.  
  484.     Assert(Num_vertices < MAX_SEGMENT_VERTICES);
  485.  
  486.     count = 0;
  487.     free_index = -1;
  488.     for (v=0; (v < MAX_SEGMENT_VERTICES) && (count < Num_vertices); v++)
  489.         if (Vertex_active[v]) {
  490.             count++;
  491.             if (vnear(vp,&Vertices[v])) {
  492.                 // mprintf((0,"[%4i]  ",v));
  493.                 return v;
  494.             }
  495.         } else if (free_index == -1)
  496.             free_index = v;                    // we want free_index to be the first free slot to add a vertex
  497.  
  498.     if (free_index == -1)
  499.         free_index = Num_vertices;
  500.  
  501.     while (Vertex_active[free_index] && (free_index < MAX_VERTICES))
  502.         free_index++;
  503.  
  504.     Assert(free_index < MAX_VERTICES);
  505.  
  506.     Vertices[free_index] = *vp;
  507.     Vertex_active[free_index] = 1;
  508.  
  509.     Num_vertices++;
  510.  
  511.     if (free_index > Highest_vertex_index)
  512.         Highest_vertex_index = free_index;
  513.  
  514.     return free_index;
  515. }
  516.  
  517. // ------------------------------------------------------------------------------------------
  518. //    Returns the index of a free segment.
  519. //    Scans the Segments array.
  520. int get_free_segment_number(void)
  521. {
  522.     int    segnum;
  523.  
  524.     for (segnum=0; segnum<MAX_SEGMENTS; segnum++)
  525.         if (Segments[segnum].segnum == -1) {
  526.             Num_segments++;
  527.             if (segnum > Highest_segment_index)
  528.                 Highest_segment_index = segnum;
  529.             return segnum;
  530.         }
  531.  
  532.     Assert(0);
  533.  
  534.     return 0;
  535. }
  536.  
  537. // -------------------------------------------------------------------------------
  538. //    Create a new segment, duplicating exactly, including vertex ids and children, the passed segment.
  539. int med_create_duplicate_segment(segment *sp)
  540. {
  541.     int    segnum;
  542.  
  543.     segnum = get_free_segment_number();
  544.  
  545.     Segments[segnum] = *sp;    
  546.  
  547.     return segnum;
  548. }
  549.  
  550. // -------------------------------------------------------------------------------
  551. //    Add the vertex *vp to the global list of vertices, return its index.
  552. //    This is the same as med_add_vertex, except that it does not search for the presence of the vertex.
  553. int med_create_duplicate_vertex(vms_vector *vp)
  554. {
  555.     int    free_index;
  556.  
  557.     Assert(Num_vertices < MAX_SEGMENT_VERTICES);
  558.  
  559.     Do_duplicate_vertex_check = 1;
  560.  
  561.     free_index = Num_vertices;
  562.  
  563.     while (Vertex_active[free_index] && (free_index < MAX_VERTICES))
  564.         free_index++;
  565.  
  566.     Assert(free_index < MAX_VERTICES);
  567.  
  568.     Vertices[free_index] = *vp;
  569.     Vertex_active[free_index] = 1;
  570.  
  571.     Num_vertices++;
  572.  
  573.     if (free_index > Highest_vertex_index)
  574.         Highest_vertex_index = free_index;
  575.  
  576.     return free_index;
  577. }
  578.  
  579.  
  580. // -------------------------------------------------------------------------------
  581. //    Set the vertex *vp at index vnum in the global list of vertices, return its index (just for compatibility).
  582. int med_set_vertex(int vnum,vms_vector *vp)
  583. {
  584.     Assert(vnum < MAX_VERTICES);
  585.  
  586.     Vertices[vnum] = *vp;
  587.  
  588.     // Just in case this vertex wasn't active, mark it as active.
  589.     if (!Vertex_active[vnum]) {
  590.         Vertex_active[vnum] = 1;
  591.         Num_vertices++;
  592.         if ((vnum > Highest_vertex_index) && (vnum < NEW_SEGMENT_VERTICES)) {
  593.             mprintf((0,"Warning -- setting a previously unset vertex, index = %i.\n",vnum));
  594.             Highest_vertex_index = vnum;
  595.         }
  596.     }
  597.  
  598.     return vnum;
  599. }
  600.  
  601.  
  602.  
  603. //    ----
  604. //    A side is determined to be degenerate if the cross products of 3 consecutive points does not point outward.
  605. int check_for_degenerate_side(segment *sp, int sidenum)
  606. {
  607.     char            *vp = Side_to_verts[sidenum];
  608.     vms_vector    vec1, vec2, cross, vec_to_center;
  609.     vms_vector    segc, sidec;
  610.     fix            dot;
  611.     int            degeneracy_flag = 0;
  612.  
  613.     compute_segment_center(&segc, sp);
  614.     compute_center_point_on_side(&sidec, sp, sidenum);
  615.     vm_vec_sub(&vec_to_center, &segc, &sidec);
  616.  
  617.     //vm_vec_sub(&vec1, &Vertices[sp->verts[vp[1]]], &Vertices[sp->verts[vp[0]]]);
  618.     //vm_vec_sub(&vec2, &Vertices[sp->verts[vp[2]]], &Vertices[sp->verts[vp[1]]]);
  619.     //vm_vec_normalize(&vec1);
  620.     //vm_vec_normalize(&vec2);
  621.     vm_vec_normalized_dir(&vec1, &Vertices[sp->verts[vp[1]]], &Vertices[sp->verts[vp[0]]]);
  622.     vm_vec_normalized_dir(&vec2, &Vertices[sp->verts[vp[2]]], &Vertices[sp->verts[vp[1]]]);
  623.     vm_vec_cross(&cross, &vec1, &vec2);
  624.  
  625.     dot = vm_vec_dot(&vec_to_center, &cross);
  626.     if (dot <= 0)
  627.         degeneracy_flag |= 1;
  628.  
  629.     //vm_vec_sub(&vec1, &Vertices[sp->verts[vp[2]]], &Vertices[sp->verts[vp[1]]]);
  630.     //vm_vec_sub(&vec2, &Vertices[sp->verts[vp[3]]], &Vertices[sp->verts[vp[2]]]);
  631.     //vm_vec_normalize(&vec1);
  632.     //vm_vec_normalize(&vec2);
  633.     vm_vec_normalized_dir(&vec1, &Vertices[sp->verts[vp[2]]], &Vertices[sp->verts[vp[1]]]);
  634.     vm_vec_normalized_dir(&vec2, &Vertices[sp->verts[vp[3]]], &Vertices[sp->verts[vp[2]]]);
  635.     vm_vec_cross(&cross, &vec1, &vec2);
  636.  
  637.     dot = vm_vec_dot(&vec_to_center, &cross);
  638.     if (dot <= 0)
  639.         degeneracy_flag |= 1;
  640.  
  641.     return degeneracy_flag;
  642.  
  643. }
  644.  
  645. // -------------------------------------------------------------------------------
  646. void create_removable_wall(segment *sp, int sidenum, int tmap_num)
  647. {
  648.     create_walls_on_side(sp, sidenum);
  649.  
  650.     sp->sides[sidenum].tmap_num = tmap_num;
  651.  
  652.     assign_default_uvs_to_side(sp, sidenum);
  653.     assign_light_to_side(sp, sidenum);
  654. }
  655.  
  656. //    ----
  657. //    See if a segment has gotten turned inside out, or something.
  658. //    If so, set global Degenerate_segment_found and return 1, else return 0.
  659. int check_for_degenerate_segment(segment *sp)
  660. {
  661.     vms_vector    fvec, rvec, uvec, cross;
  662.     fix            dot;
  663.     int            i, degeneracy_flag = 0;                // degeneracy flag for current segment
  664.  
  665.     extract_forward_vector_from_segment(sp, &fvec);
  666.     extract_right_vector_from_segment(sp, &rvec);
  667.     extract_up_vector_from_segment(sp, &uvec);
  668.  
  669.     vm_vec_normalize(&fvec);
  670.     vm_vec_normalize(&rvec);
  671.     vm_vec_normalize(&uvec);
  672.  
  673.     vm_vec_cross(&cross, &fvec, &rvec);
  674.     dot = vm_vec_dot(&cross, &uvec);
  675.  
  676.     if (dot > 0)
  677.         degeneracy_flag = 0;
  678.     else {
  679.         mprintf((0, "segment #%i is degenerate due to cross product check.\n", sp-Segments));
  680.         degeneracy_flag = 1;
  681.     }
  682.  
  683.     //    Now, see if degenerate because of any side.
  684.     for (i=0; i<MAX_SIDES_PER_SEGMENT; i++)
  685.         degeneracy_flag |= check_for_degenerate_side(sp, i);
  686.  
  687.     Degenerate_segment_found |= degeneracy_flag;
  688.  
  689.     return degeneracy_flag;
  690.  
  691. }
  692.  
  693. #if 0
  694.  
  695. // ---------------------------------------------------------------------------------------------
  696. //    Orthogonalize matrix smat, returning result in rmat.
  697. //    Does not modify smat.
  698. //    Uses Gram-Schmidt process.
  699. //    See page 172 of Strang, Gilbert, Linear Algebra and its Applications
  700. //    Matt -- This routine should be moved to the vector matrix library.
  701. //    It IS legal for smat == rmat.
  702. //    We should also have the functions:
  703. //        mat_a = mat_b * scalar;                // we now have mat_a = mat_a * scalar;
  704. //        mat_a = mat_b + mat_c * scalar;    // or maybe not, maybe this is not primitive
  705. void make_orthogonal(vms_matrix *rmat,vms_matrix *smat)
  706. {
  707.     vms_matrix        tmat;
  708.     vms_vector        tvec1,tvec2;
  709.     float                dot;
  710.  
  711.     // Copy source matrix to work area.
  712.     tmat = *smat;
  713.  
  714.     // Normalize the three rows of the matrix tmat.
  715.     vm_vec_normalize(&tmat.xrow);
  716.     vm_vec_normalize(&tmat.yrow);
  717.     vm_vec_normalize(&tmat.zrow);
  718.  
  719.     //    Now, compute the first vector.
  720.     // This is very easy -- just copy the (normalized) source vector.
  721.     rmat->zrow = tmat.zrow;
  722.  
  723.     // Now, compute the second vector.
  724.     // From page 172 of Strang, we use the equation:
  725.     //        b' = b - [transpose(q1) * b] * q1
  726.     //    where:    b  = the second row of tmat
  727.     //                q1 = the first row of rmat
  728.     //                b' = the second row of rmat
  729.  
  730.     // Compute: transpose(q1) * b
  731.     dot = vm_vec_dotprod(&rmat->zrow,&tmat.yrow);
  732.  
  733.     // Compute: b - dot * q1
  734.     rmat->yrow.x = tmat.yrow.x - fixmul(dot,rmat->zrow.x);
  735.     rmat->yrow.y = tmat.yrow.y - fixmul(dot,rmat->zrow.y);
  736.     rmat->yrow.z = tmat.yrow.z - fixmul(dot,rmat->zrow.z);
  737.  
  738.     // Now, compute the third vector.
  739.     // From page 173 of Strang, we use the equation:
  740.     //        c' = c - (q1*c)*q1 - (q2*c)*q2
  741.     //    where:    c  = the third row of tmat
  742.     //                q1 = the first row of rmat
  743.     //                q2 = the second row of rmat
  744.     //                c' = the third row of rmat
  745.  
  746.     // Compute: q1*c
  747.     dot = vm_vec_dotprod(&rmat->zrow,&tmat.xrow);
  748.  
  749.     tvec1.x = fixmul(dot,rmat->zrow.x);
  750.     tvec1.y = fixmul(dot,rmat->zrow.y);
  751.     tvec1.z = fixmul(dot,rmat->zrow.z);
  752.  
  753.     // Compute: q2*c
  754.     dot = vm_vec_dotprod(&rmat->yrow,&tmat.xrow);
  755.  
  756.     tvec2.x = fixmul(dot,rmat->yrow.x);
  757.     tvec2.y = fixmul(dot,rmat->yrow.y);
  758.     tvec2.z = fixmul(dot,rmat->yrow.z);
  759.  
  760.     vm_vec_sub(&rmat->xrow,vm_vec_sub(&rmat->xrow,&tmat.xrow,&tvec1),&tvec2);
  761. }
  762.  
  763. #endif
  764.  
  765. // ------------------------------------------------------------------------------------------
  766. // Given a segment, extract the rotation matrix which defines it.
  767. // Do this by extracting the forward, right, up vectors and then making them orthogonal.
  768. // In the process of making the vectors orthogonal, favor them in the order forward, up, right.
  769. // This means that the forward vector will remain unchanged.
  770. void med_extract_matrix_from_segment(segment *sp,vms_matrix *rotmat)
  771. {
  772.     vms_vector    forwardvec,upvec;
  773.  
  774.     extract_forward_vector_from_segment(sp,&forwardvec);
  775.     extract_up_vector_from_segment(sp,&upvec);
  776.  
  777.     if (((forwardvec.x == 0) && (forwardvec.y == 0) && (forwardvec.z == 0)) || ((upvec.x == 0) && (upvec.y == 0) && (upvec.z == 0))) {
  778.         mprintf((0, "Trapped null vector in med_extract_matrix_from_segment, returning identity matrix.\n"));
  779.         *rotmat = vmd_identity_matrix;
  780.         return;
  781.     }
  782.  
  783.  
  784.     vm_vector_2_matrix(rotmat,&forwardvec,&upvec,NULL);
  785.  
  786. #if 0
  787.     vms_matrix    rm;
  788.  
  789.     extract_forward_vector_from_segment(sp,&rm.zrow);
  790.     extract_right_vector_from_segment(sp,&rm.xrow);
  791.     extract_up_vector_from_segment(sp,&rm.yrow);
  792.  
  793.     vm_vec_normalize(&rm.xrow);
  794.     vm_vec_normalize(&rm.yrow);
  795.     vm_vec_normalize(&rm.zrow);
  796.  
  797.     make_orthogonal(rotmat,&rm);
  798.  
  799.     vm_vec_normalize(&rotmat->xrow);
  800.     vm_vec_normalize(&rotmat->yrow);
  801.     vm_vec_normalize(&rotmat->zrow);
  802.  
  803. // *rotmat = rm; // include this line (and remove the call to make_orthogonal) if you don't want the matrix orthogonalized
  804. #endif
  805.  
  806. }
  807.  
  808. // ------------------------------------------------------------------------------------------
  809. //    Given a rotation matrix *rotmat which describes the orientation of a segment
  810. //    and a side destside, return the rotation matrix which describes the orientation for the side.
  811. void    set_matrix_based_on_side(vms_matrix *rotmat,int destside)
  812. {
  813.     vms_angvec    rotvec;
  814.     vms_matrix    r1,rtemp;
  815.  
  816.     switch (destside) {
  817.         case WLEFT:
  818.             vm_angvec_make(&rotvec,0,0,-16384);
  819.             vm_angles_2_matrix(&r1,&rotvec);
  820.             vm_matrix_x_matrix(&rtemp,rotmat,&r1);
  821.             *rotmat = rtemp;
  822.             break;
  823.  
  824.         case WTOP:
  825.             vm_angvec_make(&rotvec,-16384,0,0);
  826.             vm_angles_2_matrix(&r1,&rotvec);
  827.             vm_matrix_x_matrix(&rtemp,rotmat,&r1);
  828.             *rotmat = rtemp;
  829.             break;
  830.  
  831.         case WRIGHT:
  832.             vm_angvec_make(&rotvec,0,0,16384);
  833.             vm_angles_2_matrix(&r1,&rotvec);
  834.             vm_matrix_x_matrix(&rtemp,rotmat,&r1);
  835.             *rotmat = rtemp;
  836.             break;
  837.  
  838.         case WBOTTOM:
  839.             vm_angvec_make(&rotvec,+16384,-32768,0);    // bank was -32768, but I think that was an erroneous compensation
  840.             vm_angles_2_matrix(&r1,&rotvec);
  841.             vm_matrix_x_matrix(&rtemp,rotmat,&r1);
  842.             *rotmat = rtemp;
  843.             break;
  844.  
  845.         case WFRONT:
  846.             vm_angvec_make(&rotvec,0,0,-32768);
  847.             vm_angles_2_matrix(&r1,&rotvec);
  848.             vm_matrix_x_matrix(&rtemp,rotmat,&r1);
  849.             *rotmat = rtemp;
  850.             break;
  851.  
  852.         case WBACK:
  853.             break;
  854.     }
  855.  
  856. }
  857.  
  858. //    -------------------------------------------------------------------------------------
  859. void change_vertex_occurrences(int dest, int src)
  860. {
  861.     int    g,s,v;
  862.  
  863.     // Fix vertices in groups
  864.     for (g=0;g<num_groups;g++) 
  865.         for (v=0; v<GroupList[g].num_vertices; v++)
  866.             if (GroupList[g].vertices[v] == src)
  867.                 GroupList[g].vertices[v] = dest;
  868.  
  869.     // now scan all segments, changing occurrences of src to dest
  870.     for (s=0; s<=Highest_segment_index; s++)
  871.         if (Segments[s].segnum != -1)
  872.             for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
  873.                 if (Segments[s].verts[v] == src)
  874.                     Segments[s].verts[v] = dest;
  875. }
  876.  
  877. // --------------------------------------------------------------------------------------------------
  878. void compress_vertices(void)
  879. {
  880.     int        hole,vert;
  881.  
  882.     if (Highest_vertex_index == Num_vertices - 1)
  883.         return;
  884.  
  885.     vert = Highest_vertex_index;    //MAX_SEGMENT_VERTICES-1;
  886.  
  887.     for (hole=0; hole < vert; hole++)
  888.         if (!Vertex_active[hole]) {
  889.             // found an unused vertex which is a hole if a used vertex follows (not necessarily immediately) it.
  890.             for ( ; (vert>hole) && (!Vertex_active[vert]); vert--)
  891.                 ;
  892.  
  893.             if (vert > hole) {
  894.  
  895.                 // Ok, hole is the index of a hole, vert is the index of a vertex which follows it.
  896.                 // Copy vert into hole, update pointers to it.
  897.                 Vertices[hole] = Vertices[vert];
  898.                 
  899.                 change_vertex_occurrences(hole, vert);
  900.  
  901.                 vert--;
  902.             }
  903.         }
  904.  
  905.     Highest_vertex_index = Num_vertices-1;
  906. }
  907.  
  908. // --------------------------------------------------------------------------------------------------
  909. void compress_segments(void)
  910. {
  911.     int        hole,seg;
  912.  
  913.     if (Highest_segment_index == Num_segments - 1)
  914.         return;
  915.  
  916.     seg = Highest_segment_index;
  917.  
  918.     for (hole=0; hole < seg; hole++)
  919.         if (Segments[hole].segnum == -1) {
  920.             // found an unused segment which is a hole if a used segment follows (not necessarily immediately) it.
  921.             for ( ; (seg>hole) && (Segments[seg].segnum == -1); seg--)
  922.                 ;
  923.  
  924.             if (seg > hole) {
  925.                 int        f,g,l,s,t,w;
  926.                 segment    *sp;
  927.                 int objnum;
  928.  
  929.                 // Ok, hole is the index of a hole, seg is the index of a segment which follows it.
  930.                 // Copy seg into hole, update pointers to it, update Cursegp, Markedsegp if necessary.
  931.                 Segments[hole] = Segments[seg];
  932.                 Segments[seg].segnum = -1;
  933.  
  934.                 if (Cursegp == &Segments[seg])
  935.                     Cursegp = &Segments[hole];
  936.  
  937.                 if (Markedsegp == &Segments[seg])
  938.                     Markedsegp = &Segments[hole];
  939.  
  940.                 // Fix segments in groups
  941.                 for (g=0;g<num_groups;g++) 
  942.                     for (s=0; s<GroupList[g].num_segments; s++)
  943.                         if (GroupList[g].segments[s] == seg)
  944.                             GroupList[g].segments[s] = hole;
  945.  
  946.                 // Fix walls
  947.                 for (w=0;w<Num_walls;w++)
  948.                     if (Walls[w].segnum == seg)
  949.                         Walls[w].segnum = hole;
  950.  
  951.                 // Fix fuelcenters, robotcens, and triggers... added 2/1/95 -Yuan
  952.                 for (f=0;f<Num_fuelcenters;f++)
  953.                     if (Station[f].segnum == seg)
  954.                         Station[f].segnum = hole;
  955.  
  956.                 for (f=0;f<Num_robot_centers;f++)
  957.                     if (RobotCenters[f].segnum == seg)
  958.                         RobotCenters[f].segnum = hole;
  959.  
  960.                 for (t=0;t<Num_triggers;t++)
  961.                     for (l=0;l<Triggers[t].num_links;l++)
  962.                         if (Triggers[t].seg[l] == seg)
  963.                             Triggers[t].seg[l] = hole;
  964.  
  965.                 sp = &Segments[hole];
  966.                 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
  967.                     if (IS_CHILD(sp->children[s])) {
  968.                         segment *csegp;
  969.                         csegp = &Segments[sp->children[s]];
  970.  
  971.                         // Find out on what side the segment connection to the former seg is on in *csegp.
  972.                         for (t=0; t<MAX_SIDES_PER_SEGMENT; t++) {
  973.                             if (csegp->children[t] == seg) {
  974.                                 csegp->children[t] = hole;                    // It used to be connected to seg, so make it connected to hole
  975.                             }
  976.                         }    // end for t
  977.                     }    // end if
  978.                 }    // end for s
  979.  
  980.                 //Update object segment pointers
  981.                 for (objnum = sp->objects; objnum != -1; objnum = Objects[objnum].next) {
  982.                     Assert(Objects[objnum].segnum == seg);
  983.                     Objects[objnum].segnum = hole;
  984.                 }
  985.  
  986.                 seg--;
  987.  
  988.             }    // end if (seg > hole)
  989.         }    // end if
  990.  
  991.     Highest_segment_index = Num_segments-1;
  992.     med_create_new_segment_from_cursegp();
  993.  
  994. }
  995.  
  996.  
  997. // -------------------------------------------------------------------------------
  998. //    Combine duplicate vertices.
  999. //    If two vertices have the same coordinates, within some small tolerance, then assign
  1000. //    the same vertex number to the two vertices, freeing up one of the vertices.
  1001. void med_combine_duplicate_vertices(byte *vlp)
  1002. {
  1003.     int    v,w;
  1004.  
  1005.     for (v=0; v<Highest_vertex_index; v++)        // Note: ok to do to <, rather than <= because w for loop starts at v+1
  1006.         if (vlp[v]) {
  1007.             vms_vector *vvp = &Vertices[v];
  1008.             for (w=v+1; w<=Highest_vertex_index; w++)
  1009.                 if (vlp[w]) {    //    used to be Vertex_active[w]
  1010.                     if (vnear(vvp, &Vertices[w])) {
  1011.                         change_vertex_occurrences(v, w);
  1012.                     }
  1013.                 }
  1014.         }
  1015.  
  1016. }
  1017.  
  1018. // ------------------------------------------------------------------------------
  1019. //    Compress mine at Segments and Vertices by squeezing out all holes.
  1020. //    If no holes (ie, an unused segment followed by a used segment), then no action.
  1021. //    If Cursegp or Markedsegp is a segment which gets moved to fill in a hole, then
  1022. //    they are properly updated.
  1023. void med_compress_mine(void)
  1024. {
  1025.     if (Do_duplicate_vertex_check) {
  1026.         med_combine_duplicate_vertices(Vertex_active);
  1027.         Do_duplicate_vertex_check = 0;
  1028.     }
  1029.  
  1030.     compress_segments();
  1031.     compress_vertices();
  1032.     set_vertex_counts();
  1033.  
  1034.     //--repair-- create_local_segment_data();
  1035.  
  1036.     //    This is necessary becuase a segment search (due to click in 3d window) uses the previous frame's
  1037.     //    segment information, which could get changed by this.
  1038.     Update_flags = UF_WORLD_CHANGED;
  1039. }
  1040.  
  1041.  
  1042. // ------------------------------------------------------------------------------------------
  1043. //    Copy texture map ids for each face in sseg to dseg.
  1044. void copy_tmap_ids(segment *dseg, segment *sseg)
  1045. {
  1046.     int    s;
  1047.  
  1048.     for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
  1049.         dseg->sides[s].tmap_num = sseg->sides[s].tmap_num;
  1050.         dseg->sides[s].tmap_num2 = 0;
  1051.     }
  1052. }
  1053.  
  1054. // ------------------------------------------------------------------------------------------
  1055. //    Attach a segment with a rotated orientation.
  1056. // Return value:
  1057. //  0 = successful attach
  1058. //  1 = No room in Segments[].
  1059. //  2 = No room in Vertices[].
  1060. //  3 = newside != WFRONT -- for now, the new segment must be attached at its (own) front side
  1061. //     4 = already a face attached on destseg:destside
  1062. int med_attach_segment_rotated(segment *destseg, segment *newseg, int destside, int newside,vms_matrix *attmat)
  1063. {
  1064.     char            *dvp;
  1065.     segment        *nsp;
  1066.     int            side,v;
  1067.     vms_matrix    rotmat,rotmat1,rotmat2,rotmat3,rotmat4;
  1068.     vms_vector    vr,vc,tvs[4],xlate_vec;
  1069.     int            segnum;
  1070.     vms_vector    forvec,upvec;
  1071.  
  1072.     // Return if already a face attached on this side.
  1073.     if (IS_CHILD(destseg->children[destside]))
  1074.         return 4;
  1075.  
  1076.     segnum = get_free_segment_number();
  1077.  
  1078.     forvec = attmat->fvec;
  1079.     upvec = attmat->uvec;
  1080.  
  1081.     //    We are pretty confident we can add the segment.
  1082.     nsp = &Segments[segnum];
  1083.  
  1084.     nsp->segnum = segnum;
  1085.     nsp->objects = -1;
  1086.     nsp->matcen_num = -1;
  1087.  
  1088.     // Copy group value.
  1089.     nsp->group = destseg->group;
  1090.  
  1091.     // Add segment to proper group list.
  1092.     if (nsp->group > -1)
  1093.         add_segment_to_group(nsp-Segments, nsp->group);
  1094.  
  1095.     // Copy the texture map ids.
  1096.     copy_tmap_ids(nsp,newseg);
  1097.  
  1098.     // clear all connections
  1099.     for (side=0; side<MAX_SIDES_PER_SEGMENT; side++) {
  1100.         nsp->children[side] = -1;
  1101.         nsp->sides[side].wall_num = -1;    
  1102.     }
  1103.  
  1104.     // Form the connection
  1105.     destseg->children[destside] = segnum;
  1106. //    destseg->sides[destside].render_flag = 0;
  1107.     nsp->children[newside] = destseg-Segments;
  1108.  
  1109.     // Copy vertex indices of the four vertices forming the joint
  1110.     dvp = Side_to_verts[destside];
  1111.  
  1112.     // Set the vertex indices for the four vertices forming the front of the new side
  1113.     for (v=0; v<4; v++)
  1114.         nsp->verts[v] = destseg->verts[dvp[v]];
  1115.  
  1116.     // The other 4 vertices must be created.
  1117.     // Their coordinates are determined by the 4 welded vertices and the vector from front
  1118.     // to back of the original *newseg.
  1119.  
  1120.     // Do lots of hideous matrix stuff, about 3/4 of which could probably be simplified out.
  1121.     med_extract_matrix_from_segment(destseg,&rotmat);        // get orientation matrix for destseg (orthogonal rotation matrix)
  1122.     set_matrix_based_on_side(&rotmat,destside);
  1123.     vm_vector_2_matrix(&rotmat1,&forvec,&upvec,NULL);
  1124.     vm_matrix_x_matrix(&rotmat4,&rotmat,&rotmat1);            // this is the desired orientation of the new segment
  1125.     med_extract_matrix_from_segment(newseg,&rotmat3);        // this is the current orientation of the new segment
  1126.     vm_transpose_matrix(&rotmat3);                                // get the inverse of the current orientation matrix
  1127.     vm_matrix_x_matrix(&rotmat2,&rotmat4,&rotmat3);            // now rotmat2 takes the current segment to the desired orientation
  1128.  
  1129.     // Warning -- look at this line!
  1130.     vm_transpose_matrix(&rotmat2);    // added 12:33 pm, 10/01/93
  1131.  
  1132.     // Compute and rotate the center point of the attaching face.
  1133.     compute_center_point_on_side(&vc,newseg,newside);
  1134.     vm_vec_rotate(&vr,&vc,&rotmat2);
  1135.  
  1136.     // Now rotate the free vertices in the segment
  1137.     for (v=0; v<4; v++)
  1138.         vm_vec_rotate(&tvs[v],&Vertices[newseg->verts[v+4]],&rotmat2);
  1139.  
  1140.     // Now translate the new segment so that the center point of the attaching faces are the same.
  1141.     compute_center_point_on_side(&vc,destseg,destside);
  1142.     vm_vec_sub(&xlate_vec,&vc,&vr);
  1143.  
  1144.     // Create and add the 4 new vertices.
  1145.     for (v=0; v<4; v++) {
  1146.         vm_vec_add2(&tvs[v],&xlate_vec);
  1147.         nsp->verts[v+4] = med_add_vertex(&tvs[v]);
  1148.     }
  1149.  
  1150.     set_vertex_counts();
  1151.  
  1152.     // Now all the vertices are in place.  Create the faces.
  1153.     validate_segment(nsp);
  1154.  
  1155.     //    Say to not render at the joint.
  1156. //    destseg->sides[destside].render_flag = 0;
  1157. //    nsp->sides[newside].render_flag = 0;
  1158.  
  1159.     Cursegp = nsp;
  1160.  
  1161.     return    0;
  1162. }
  1163.  
  1164. // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  1165.  
  1166. // ------------------------------------------------------------------------------------------
  1167. void scale_free_vertices(segment *sp,vms_vector *vp,fix scale_factor,int min_side,int max_side)
  1168. {
  1169.     int    i;
  1170.     char    *verts;
  1171.  
  1172.     verts = Side_to_verts[min_side];
  1173.  
  1174.     for (i=0; i<4; i++)
  1175.         if (is_free_vertex(sp->verts[verts[i]])) {
  1176.             Vertices[sp->verts[verts[i]]].x = fixmul(vp->x,scale_factor)/2;
  1177.             Vertices[sp->verts[verts[i]]].y = fixmul(vp->y,scale_factor)/2;
  1178.             Vertices[sp->verts[verts[i]]].z = fixmul(vp->z,scale_factor)/2;
  1179.         }
  1180.  
  1181.     verts = Side_to_verts[max_side];
  1182.  
  1183.     for (i=0; i<4; i++)
  1184.         if (is_free_vertex(sp->verts[verts[i]])) {
  1185.             Vertices[sp->verts[verts[i]]].x = fixmul(vp->x,scale_factor)/2;
  1186.             Vertices[sp->verts[verts[i]]].y = fixmul(vp->y,scale_factor)/2;
  1187.             Vertices[sp->verts[verts[i]]].z = fixmul(vp->z,scale_factor)/2;
  1188.         }
  1189. }
  1190.  
  1191.  
  1192. // ------------------------------------------------------------------------------------------
  1193. // Attach side newside of newseg to side destside of destseg.
  1194. // Copies *newseg into global array Segments, increments Num_segments.
  1195. // Forms a weld between the two segments by making the new segment fit to the old segment.
  1196. // Updates number of faces per side if necessitated by new vertex coordinates.
  1197. //    Updates Cursegp.
  1198. // Return value:
  1199. //  0 = successful attach
  1200. //  1 = No room in Segments[].
  1201. //  2 = No room in Vertices[].
  1202. //  3 = newside != WFRONT -- for now, the new segment must be attached at its (own) front side
  1203. //     4 = already a face attached on side newside
  1204. int med_attach_segment(segment *destseg, segment *newseg, int destside, int newside)
  1205. {
  1206.     int        rval;
  1207.     segment    *ocursegp = Cursegp;
  1208.  
  1209.     vms_angvec    tang = {0,0,0};
  1210.     vms_matrix    rotmat;
  1211.  
  1212.     vm_angles_2_matrix(&rotmat,&tang);
  1213.     rval = med_attach_segment_rotated(destseg,newseg,destside,newside,&rotmat);
  1214.     med_propagate_tmaps_to_segments(ocursegp,Cursegp,0);
  1215.     med_propagate_tmaps_to_back_side(Cursegp, Side_opposite[newside],0);
  1216.     copy_uvs_seg_to_seg(&New_segment,Cursegp);
  1217.  
  1218.     return rval;
  1219. }
  1220.  
  1221. // -------------------------------------------------------------------------------
  1222. //    Delete a vertex, sort of.
  1223. //    Decrement the vertex count.  If the count goes to 0, then the vertex is free (has been deleted).
  1224. void delete_vertex(short v)
  1225. {
  1226.     Assert(v < MAX_VERTICES);            // abort if vertex is not in array Vertices
  1227.     Assert(Vertex_active[v] >= 1);    // abort if trying to delete a non-existent vertex
  1228.  
  1229.     Vertex_active[v]--;
  1230. }
  1231.  
  1232. // -------------------------------------------------------------------------------
  1233. //    Update Num_vertices.
  1234. //    This routine should be called by anyone who calls delete_vertex.  It could be called in delete_vertex,
  1235. //    but then it would be called much more often than necessary, and it is a slow routine.
  1236. void update_num_vertices(void)
  1237. {
  1238.     int    v;
  1239.  
  1240.     // Now count the number of vertices.
  1241.     Num_vertices = 0;
  1242.     for (v=0; v<=Highest_vertex_index; v++)
  1243.         if (Vertex_active[v])
  1244.             Num_vertices++;
  1245. }
  1246.  
  1247. // -------------------------------------------------------------------------------
  1248. //    Set Vertex_active to number of occurrences of each vertex.
  1249. //    Set Num_vertices.
  1250. void set_vertex_counts(void)
  1251. {
  1252.     int    s,v;
  1253.  
  1254.     Num_vertices = 0;
  1255.  
  1256.     for (v=0; v<=Highest_vertex_index; v++)
  1257.         Vertex_active[v] = 0;
  1258.  
  1259.     // Count number of occurrences of each vertex.
  1260.     for (s=0; s<=Highest_segment_index; s++)
  1261.         if (Segments[s].segnum != -1)
  1262.             for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++) {
  1263.                 if (!Vertex_active[Segments[s].verts[v]])
  1264.                     Num_vertices++;
  1265.                 Vertex_active[Segments[s].verts[v]]++;
  1266.             }
  1267. }
  1268.  
  1269. // -------------------------------------------------------------------------------
  1270. //    Delete all vertices in segment *sp from the vertex list if they are not contained in another segment.
  1271. //    This is kind of a dangerous routine.  It modifies the global array Vertex_active, using the field as
  1272. //    a count.
  1273. void delete_vertices_in_segment(segment *sp)
  1274. {
  1275.     int    v;
  1276.  
  1277. //    init_vertices();
  1278.  
  1279.     set_vertex_counts();
  1280.  
  1281.     // Subtract one count for each appearance of vertex in deleted segment
  1282.     for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
  1283.         delete_vertex(sp->verts[v]);
  1284.  
  1285.     update_num_vertices();
  1286. }
  1287.  
  1288. extern void validate_segment_side(segment *sp, int sidenum);
  1289.  
  1290. // -------------------------------------------------------------------------------
  1291. //    Delete segment *sp in Segments array.
  1292. // Return value:
  1293. //        0    successfully deleted.
  1294. //        1    unable to delete.
  1295. int med_delete_segment(segment *sp)
  1296. {
  1297.     int        s,side,segnum;
  1298.     int         objnum;
  1299.  
  1300.     segnum = sp-Segments;
  1301.  
  1302.     // Cannot delete segment if only segment.
  1303.     if (Num_segments == 1)
  1304.         return 1;
  1305.  
  1306.     // Don't try to delete if segment doesn't exist.
  1307.     if (sp->segnum == -1) {
  1308.         mprintf((0,"Hey -- you tried to delete a non-existent segment (segnum == -1)\n"));
  1309.         return 1;
  1310.     }
  1311.  
  1312.     // Delete its refueling center if it has one
  1313.     fuelcen_delete(sp);
  1314.  
  1315.     delete_vertices_in_segment(sp);
  1316.  
  1317.     Num_segments--;
  1318.  
  1319.     // If deleted segment has walls on any side, wipe out the wall.
  1320.     for (side=0; side < MAX_SIDES_PER_SEGMENT; side++)
  1321.         if (sp->sides[side].wall_num != -1) 
  1322.             wall_remove_side(sp, side);
  1323.  
  1324.     // Find out what this segment was connected to and break those connections at the other end.
  1325.     for (side=0; side < MAX_SIDES_PER_SEGMENT; side++)
  1326.         if (IS_CHILD(sp->children[side])) {
  1327.             segment    *csp;                                    // the connecting segment
  1328.             int        s;
  1329.  
  1330.             csp = &Segments[sp->children[side]];
  1331.             for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
  1332.                 if (csp->children[s] == segnum) {
  1333.                     csp->children[s] = -1;                // this is the side of connection, break it
  1334.                     validate_segment_side(csp,s);                    // we have converted a connection to a side so validate the segment
  1335.                     med_propagate_tmaps_to_back_side(csp,s,0);
  1336.                 }
  1337.             Cursegp = csp;
  1338.             med_create_new_segment_from_cursegp();
  1339.             copy_uvs_seg_to_seg(&New_segment,Cursegp);
  1340.         }
  1341.  
  1342.     sp->segnum = -1;                                        // Mark segment as inactive.
  1343.  
  1344.     // If deleted segment = marked segment, then say there is no marked segment
  1345.     if (sp == Markedsegp)
  1346.         Markedsegp = 0;
  1347.     
  1348.     //    If deleted segment = a Group segment ptr, then wipe it out.
  1349.     for (s=0;s<num_groups;s++) 
  1350.         if (sp == Groupsegp[s]) 
  1351.             Groupsegp[s] = 0;
  1352.  
  1353.     // If deleted segment = group segment, wipe it off the group list.
  1354.     if (sp->group > -1) 
  1355.             delete_segment_from_group(sp-Segments, sp->group);
  1356.  
  1357.     // If we deleted something which was not connected to anything, must now select a new current segment.
  1358.     if (Cursegp == sp)
  1359.         for (s=0; s<MAX_SEGMENTS; s++)
  1360.             if ((Segments[s].segnum != -1) && (s!=segnum) ) {
  1361.                 Cursegp = &Segments[s];
  1362.                 med_create_new_segment_from_cursegp();
  1363.                break;
  1364.             }
  1365.  
  1366.     // If deleted segment contains objects, wipe out all objects
  1367.     if (sp->objects != -1)     {
  1368. //        if (objnum == Objects[objnum].next) {
  1369. //            mprintf((0, "Warning -- object #%i points to itself.  Setting next to -1.\n", objnum));
  1370. //            Objects[objnum].next = -1;
  1371. //        }
  1372.         for (objnum=sp->objects;objnum!=-1;objnum=Objects[objnum].next)     {
  1373.  
  1374.             //if an object is in the seg, delete it
  1375.             //if the object is the player, move to new curseg
  1376.  
  1377.             if (objnum == (ConsoleObject-Objects))    {
  1378.                 compute_segment_center(&ConsoleObject->pos,Cursegp);
  1379.                 obj_relink(objnum,Cursegp-Segments);
  1380.             } else
  1381.                 obj_delete(objnum);
  1382.         }
  1383.     }
  1384.  
  1385.     // Make sure everything deleted ok...
  1386.     Assert( sp->objects==-1 );
  1387.  
  1388.     // If we are leaving many holes in Segments or Vertices, then compress mine, because it is inefficient to be that way
  1389. //    if ((Highest_segment_index > Num_segments+4) || (Highest_vertex_index > Num_vertices+4*8))
  1390. //        med_compress_mine();
  1391.  
  1392.     return 0;
  1393. }
  1394.  
  1395. // ------------------------------------------------------------------------------------------
  1396. //    Copy texture maps from sseg to dseg
  1397. void copy_tmaps_to_segment(segment *dseg, segment *sseg)
  1398. {
  1399.     int    s;
  1400.  
  1401.     for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
  1402.         dseg->sides[s].type = sseg->sides[s].type;
  1403.         dseg->sides[s].tmap_num = sseg->sides[s].tmap_num;
  1404.         dseg->sides[s].tmap_num2 = sseg->sides[s].tmap_num2;
  1405.     }
  1406.  
  1407. }
  1408.  
  1409. // ------------------------------------------------------------------------------------------
  1410. // Rotate the segment *seg by the pitch, bank, heading defined by *rot, destructively
  1411. // modifying its four free vertices in the global array Vertices.
  1412. // It is illegal to rotate a segment which has connectivity != 1.
  1413. // Pitch, bank, heading are about the point which is the average of the four points
  1414. // forming the side of connection.
  1415. // Return value:
  1416. //  0 = successful rotation
  1417. //  1 = Connectivity makes rotation illegal (connected to 0 or 2+ segments)
  1418. //  2 = Rotation causes degeneracy, such as self-intersecting segment.
  1419. //     3 = Unable to rotate because not connected to exactly 1 segment.
  1420. int med_rotate_segment(segment *seg, vms_matrix *rotmat)
  1421. {
  1422.     segment    *destseg;
  1423.     int        newside,destside,s;
  1424.     int        count;
  1425.     int        back_side,side_tmaps[MAX_SIDES_PER_SEGMENT];
  1426.  
  1427.     // Find side of attachment
  1428.     count = 0;
  1429.     for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
  1430.         if (IS_CHILD(seg->children[s])) {
  1431.             count++;
  1432.             newside = s;
  1433.         }
  1434.  
  1435.     // Return if passed in segment is connected to other than 1 segment.
  1436.     if (count != 1)
  1437.         return 3;
  1438.  
  1439.     destseg = &Segments[seg->children[newside]];
  1440.  
  1441.     destside = 0;
  1442.     while ((destseg->children[destside] != seg-Segments) && (destside < MAX_SIDES_PER_SEGMENT))
  1443.         destside++;
  1444.         
  1445.     // Before deleting the segment, copy its texture maps to New_segment
  1446.     copy_tmaps_to_segment(&New_segment,seg);
  1447.  
  1448.     if (med_delete_segment(seg))
  1449.         mprintf((0,"Error in rotation: Unable to delete segment %i\n",seg-Segments));
  1450.  
  1451.     if (Curside == WFRONT)
  1452.         Curside = WBACK;
  1453.  
  1454.     med_attach_segment_rotated(destseg,&New_segment,destside,AttachSide,rotmat);
  1455.  
  1456.     //    Save tmap_num on each side to restore after call to med_propagate_tmaps_to_segments and _back_side
  1457.     //    which will change the tmap nums.
  1458.     for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
  1459.         side_tmaps[s] = seg->sides[s].tmap_num;
  1460.  
  1461.     back_side = Side_opposite[find_connect_side(destseg, seg)];
  1462.  
  1463.     med_propagate_tmaps_to_segments(destseg, seg,0);
  1464.     med_propagate_tmaps_to_back_side(seg, back_side,0);
  1465.  
  1466.     for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
  1467.         if (s != back_side)
  1468.             seg->sides[s].tmap_num = side_tmaps[s];
  1469.  
  1470.     return    0;
  1471. }
  1472.  
  1473. // ----------------------------------------------------------------------------------------
  1474. int med_rotate_segment_ang(segment *seg, vms_angvec *ang)
  1475. {
  1476.     vms_matrix    rotmat;
  1477.  
  1478.     return med_rotate_segment(seg,vm_angles_2_matrix(&rotmat,ang));
  1479. }
  1480.  
  1481. // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  1482.  
  1483. // ----------------------------------------------------------------------------
  1484. //    Compute the sum of the distances between the four pairs of points.
  1485. //    The connections are:
  1486. //        firstv1 : 0        (firstv1+1)%4 : 1        (firstv1+2)%4 : 2        (firstv1+3)%4 : 3
  1487. fix seg_seg_vertex_distsum(segment *seg1, int side1, segment *seg2, int side2, int firstv1)
  1488. {
  1489.     fix    distsum;
  1490.     int    secondv;
  1491.  
  1492.     distsum = 0;
  1493.     for (secondv=0; secondv<4; secondv++) {
  1494.         int            firstv;
  1495.  
  1496.         firstv = (4-secondv + (3 - firstv1)) % 4;
  1497.         distsum += vm_vec_dist(&Vertices[seg1->verts[Side_to_verts[side1][firstv]]],&Vertices[seg2->verts[Side_to_verts[side2][secondv]]]);
  1498.     }
  1499.  
  1500.     return distsum;
  1501.  
  1502. }
  1503.  
  1504. // ----------------------------------------------------------------------------
  1505. //    Determine how to connect two segments together with the least amount of twisting.
  1506. //    Returns vertex index in 0..3 on first segment.  Assumed ordering of vertices
  1507. //    on second segment is 0,1,2,3.
  1508. //    So, if return value is 2, connect 2:0 3:1 0:2 1:3.
  1509. //    Theory:
  1510. //        We select an ordering of vertices for connection.  For the first pair of vertices to be connected,
  1511. //        compute the vector.  For the three remaining pairs of vertices, compute the vectors from one vertex
  1512. //        to the other.  Compute the dot products of these vectors with the original vector.  Add them up.
  1513. //        The close we are to 3, the better fit we have.  Reason:  The largest value for the dot product is
  1514. //        1.0, and this occurs for a parallel set of vectors.
  1515. int get_index_of_best_fit(segment *seg1, int side1, segment *seg2, int side2)
  1516. {
  1517.     int    firstv;
  1518.     fix    min_distance;
  1519.     int    best_index=0;
  1520.  
  1521.     min_distance = F1_0*30000;
  1522.  
  1523.     for (firstv=0; firstv<4; firstv++) {
  1524.         fix t;
  1525.         t = seg_seg_vertex_distsum(seg1, side1, seg2, side2, firstv);
  1526.         if (t <= min_distance) {
  1527.             min_distance = t;
  1528.             best_index = firstv;
  1529.         }
  1530.     }
  1531.  
  1532.     return best_index;
  1533.  
  1534. }
  1535.  
  1536.  
  1537. #define MAX_VALIDATIONS 50
  1538.  
  1539. // ----------------------------------------------------------------------------
  1540. //    Remap uv coordinates in all sides in segment *sp which have a vertex in vp[4].
  1541. //    vp contains absolute vertex indices.
  1542. void remap_side_uvs(segment *sp,int *vp)
  1543. {
  1544.     int    s,i,v;
  1545.  
  1546.     for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
  1547.         for (v=0; v<4; v++)
  1548.             for (i=0; i<4; i++)                                                // scan each vertex in vp[4]
  1549.                 if (Side_to_verts[s][v] == vp[i]) {
  1550.                     assign_default_uvs_to_side(sp,s);                    // Side s needs to be remapped
  1551.                     goto next_side;
  1552.                 }
  1553. next_side: ;
  1554.     }
  1555. }
  1556.  
  1557. // ----------------------------------------------------------------------------
  1558. //    Assign default uv coordinates to Curside.
  1559. void assign_default_uvs_to_curside(void)
  1560. {
  1561.     assign_default_uvs_to_side(Cursegp, Curside);
  1562. }
  1563.  
  1564. // ----------------------------------------------------------------------------
  1565. //    Assign default uv coordinates to all sides in Curside.
  1566. void assign_default_uvs_to_curseg(void)
  1567. {
  1568.     int    s;
  1569.  
  1570.     for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
  1571.         assign_default_uvs_to_side(Cursegp,s);                    // Side s needs to be remapped
  1572. }
  1573.  
  1574. // ----------------------------------------------------------------------------
  1575. //    Modify seg2 to share side2 with seg1:side1.  This forms a connection between
  1576. //    two segments without creating a new segment.  It modifies seg2 by sharing
  1577. //    vertices from seg1.  seg1 is not modified.  Four vertices from seg2 are
  1578. //    deleted.
  1579. //    Return code:
  1580. //        0            joint formed
  1581. //        1            -- no, this is legal! -- unable to form joint because one or more vertices of side2 is not free
  1582. //        2            unable to form joint because side1 is already used
  1583. int med_form_joint(segment *seg1, int side1, segment *seg2, int side2)
  1584. {
  1585.     char        *vp1,*vp2;
  1586.     int        bfi,v,s,sv,s1,nv;
  1587.     int        lost_vertices[4],remap_vertices[4];
  1588.     int        validation_list[MAX_VALIDATIONS];
  1589.  
  1590.     //    Make sure that neither side is connected.
  1591.     if (IS_CHILD(seg1->children[side1]) || IS_CHILD(seg2->children[side2]))
  1592.         return 2;
  1593.  
  1594.     // Make sure there is no wall there 
  1595.     if ((seg1->sides[side1].wall_num != -1) || (seg2->sides[side2].wall_num != -1))
  1596.         return 2;
  1597.  
  1598.     //    We can form the joint.  Find the best orientation of vertices.
  1599.     bfi = get_index_of_best_fit(seg1, side1, seg2, side2);
  1600.  
  1601.     vp1 = Side_to_verts[side1];
  1602.     vp2 = Side_to_verts[side2];
  1603.  
  1604.     //    Make a copy of the list of vertices in seg2 which will be deleted and set the
  1605.     //    associated vertex number, so that all occurrences of the vertices can be replaced.
  1606.     for (v=0; v<4; v++)
  1607.         lost_vertices[v] = seg2->verts[vp2[v]];
  1608.  
  1609.     //    Now, for each vertex in lost_vertices, determine which vertex it maps to.
  1610.     for (v=0; v<4; v++)
  1611.         remap_vertices[3 - ((v + bfi) % 4)] = seg1->verts[vp1[v]];
  1612.  
  1613.     // Now, in all segments, replace all occurrences of vertices in lost_vertices with remap_vertices
  1614.  
  1615.     // Put the one segment we know are being modified into the validation list.
  1616.     // Note: seg1 does not require a full validation, only a validation of the affected side.  Its vertices do not move.
  1617.     nv = 1;
  1618.     validation_list[0] = seg2 - Segments;
  1619.  
  1620.     for (v=0; v<4; v++)
  1621.         for (s=0; s<=Highest_segment_index; s++)
  1622.             if (Segments[s].segnum != -1)
  1623.                 for (sv=0; sv<MAX_VERTICES_PER_SEGMENT; sv++)
  1624.                     if (Segments[s].verts[sv] == lost_vertices[v]) {
  1625.                         Segments[s].verts[sv] = remap_vertices[v];
  1626.                         // Add segment to list of segments to be validated.
  1627.                         for (s1=0; s1<nv; s1++)
  1628.                             if (validation_list[s1] == s)
  1629.                                 break;
  1630.                         if (s1 == nv)
  1631.                             validation_list[nv++] = s;
  1632.                         Assert(nv < MAX_VALIDATIONS);
  1633.                     }
  1634.  
  1635.     //    Form new connections.
  1636.     seg1->children[side1] = seg2 - Segments;
  1637.     seg2->children[side2] = seg1 - Segments;
  1638.  
  1639.     // validate all segments
  1640.     validate_segment_side(seg1,side1);
  1641.     for (s=0; s<nv; s++) {
  1642.         validate_segment(&Segments[validation_list[s]]);
  1643.         remap_side_uvs(&Segments[validation_list[s]],remap_vertices);    // remap uv coordinates on sides which were reshaped (ie, have a vertex in lost_vertices)
  1644.         warn_if_concave_segment(&Segments[validation_list[s]]);
  1645.     }
  1646.  
  1647.     set_vertex_counts();
  1648.  
  1649.     //    Make sure connection is open, ie renderable.
  1650. //    seg1->sides[side1].render_flag = 0;
  1651. //    seg2->sides[side2].render_flag = 0;
  1652.  
  1653. //--// debug -- check all segments, make sure if a children[s] == -1, then side[s].num_faces != 0
  1654. //--{
  1655. //--int seg,side;
  1656. //--for (seg=0; seg<MAX_SEGMENTS; seg++)
  1657. //--    if (Segments[seg].segnum != -1)
  1658. //--        for (side=0; side<MAX_SIDES_PER_SEGMENT; side++)
  1659. //--            if (Segments[seg].children[side] == -1) {
  1660. //--                if (Segments[seg].sides[side].num_faces == 0) {
  1661. //--                    mprintf((0,"Error: Segment %i, side %i is not connected, but has 0 faces.\n",seg,side));
  1662. //--                    Int3();
  1663. //--                }
  1664. //--            } else if (Segments[seg].sides[side].num_faces != 0) {
  1665. //--                mprintf((0,"Error: Segment %i, side %i is connected, but has %i faces.\n",seg,side,Segments[seg].sides[side].num_faces));
  1666. //--                Int3();
  1667. //--            }
  1668. //--}
  1669.  
  1670.     return 0;
  1671. }
  1672.  
  1673. // ----------------------------------------------------------------------------
  1674. //    Create a new segment and use it to form a bridge between two existing segments.
  1675. //    Specify two segment:side pairs.  If either segment:side is not open (ie, segment->children[side] != -1)
  1676. //    then it is not legal to form the brider.
  1677. //    Return:
  1678. //        0    bridge segment formed
  1679. //        1    unable to form bridge because one (or both) of the sides is not open.
  1680. //    Note that no new vertices are created by this process.
  1681. int med_form_bridge_segment(segment *seg1, int side1, segment *seg2, int side2)
  1682. {
  1683.     segment        *bs;
  1684.     char            *sv;
  1685.     int            v,bfi,i;
  1686.  
  1687.     if (IS_CHILD(seg1->children[side1]) || IS_CHILD(seg2->children[side2]))
  1688.         return 1;
  1689.  
  1690.     bs = &Segments[get_free_segment_number()];
  1691. // mprintf((0,"Forming bridge segment %i from %i to %i\n",bs-Segments,seg1-Segments,seg2-Segments));
  1692.  
  1693.     bs->segnum = bs-Segments;
  1694.     bs->objects = -1;
  1695.  
  1696.     // Copy vertices from seg2 into last 4 vertices of bridge segment.
  1697.     sv = Side_to_verts[side2];
  1698.     for (v=0; v<4; v++)
  1699.         bs->verts[(3-v)+4] = seg2->verts[sv[v]];
  1700.  
  1701.     // Copy vertices from seg1 into first 4 vertices of bridge segment.
  1702.     bfi = get_index_of_best_fit(seg1, side1, seg2, side2);
  1703.  
  1704.     sv = Side_to_verts[side1];
  1705.     for (v=0; v<4; v++)
  1706.         bs->verts[(v + bfi) % 4] = seg1->verts[sv[v]];
  1707.  
  1708.     // Form connections to children, first initialize all to unconnected.
  1709.     for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) {
  1710.         bs->children[i] = -1;
  1711.         bs->sides[i].wall_num = -1;
  1712.     }
  1713.  
  1714.     // Now form connections between segments.
  1715.  
  1716.     bs->children[AttachSide] = seg1 - Segments;
  1717.     bs->children[Side_opposite[AttachSide]] = seg2 - Segments;
  1718.  
  1719.     seg1->children[side1] = bs-Segments; //seg2 - Segments;
  1720.     seg2->children[side2] = bs-Segments; //seg1 - Segments;
  1721.  
  1722.     //    Validate bridge segment, and if degenerate, clean up mess.
  1723.     Degenerate_segment_found = 0;
  1724.  
  1725.     validate_segment(bs);
  1726.  
  1727.     if (Degenerate_segment_found) {
  1728.         seg1->children[side1] = -1;
  1729.         seg2->children[side2] = -1;
  1730.         bs->children[AttachSide] = -1;
  1731.         bs->children[Side_opposite[AttachSide]] = -1;
  1732.         if (med_delete_segment(bs)) {
  1733.             mprintf((0, "Oops, tried to delete bridge segment (because it's degenerate), but couldn't.\n"));
  1734.             Int3();
  1735.         }
  1736.         editor_status("Bridge segment would be degenerate, not created.\n");
  1737.         return 1;
  1738.     } else {
  1739.         validate_segment(seg1);    // used to only validate side, but segment does more error checking: ,side1);
  1740.         validate_segment(seg2);    // ,side2);
  1741.         med_propagate_tmaps_to_segments(seg1,bs,0);
  1742.  
  1743.         editor_status("Bridge segment formed.");
  1744.         warn_if_concave_segment(bs);
  1745.         return 0;
  1746.     }
  1747. }
  1748.  
  1749. // -------------------------------------------------------------------------------
  1750. //    Create a segment given center, dimensions, rotation matrix.
  1751. //    Note that the created segment will always have planar sides and rectangular cross sections.
  1752. //    It will be created with walls on all sides, ie not connected to anything.
  1753. void med_create_segment(segment *sp,fix cx, fix cy, fix cz, fix length, fix width, fix height, vms_matrix *mp)
  1754. {
  1755.     int            i,f;
  1756.     vms_vector    v0,v1,cv;
  1757.  
  1758.     Num_segments++;
  1759.  
  1760.     sp->segnum = 1;                        // What to put here?  I don't know.
  1761.  
  1762.     // Form connections to children, of which it has none.
  1763.     for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) {
  1764.         sp->children[i] = -1;
  1765. //        sp->sides[i].render_flag = 0;
  1766.         sp->sides[i].wall_num  = -1;
  1767.     }
  1768.  
  1769.     sp->group = -1;
  1770.     sp->matcen_num = -1;
  1771.  
  1772.     //    Create relative-to-center vertices, which are the rotated points on the box defined by length, width, height
  1773.     sp->verts[0] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,+width/2,+height/2,-length/2),mp));
  1774.     sp->verts[1] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,+width/2,-height/2,-length/2),mp));
  1775.     sp->verts[2] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,-width/2,-height/2,-length/2),mp));
  1776.     sp->verts[3] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,-width/2,+height/2,-length/2),mp));
  1777.     sp->verts[4] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,+width/2,+height/2,+length/2),mp));
  1778.     sp->verts[5] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,+width/2,-height/2,+length/2),mp));
  1779.     sp->verts[6] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,-width/2,-height/2,+length/2),mp));
  1780.     sp->verts[7] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,-width/2,+height/2,+length/2),mp));
  1781.  
  1782.     // Now create the vector which is the center of the segment and add that to all vertices.
  1783.     while (!vm_vec_make(&cv,cx,cy,cz));
  1784.  
  1785.     //    Now, add the center to all vertices, placing the segment in 3 space.
  1786.     for (i=0; i<MAX_VERTICES_PER_SEGMENT; i++)
  1787.         vm_vec_add(&Vertices[sp->verts[i]],&Vertices[sp->verts[i]],&cv);
  1788.  
  1789.     //    Set scale vector.
  1790. //    sp->scale.x = width;
  1791. //    sp->scale.y = height;
  1792. //    sp->scale.z = length;
  1793.  
  1794.     //    Add faces to all sides.
  1795.     for (f=0; f<MAX_SIDES_PER_SEGMENT; f++)
  1796.         create_walls_on_side(sp,f);
  1797.  
  1798.     sp->objects = -1;        //no objects in this segment
  1799.  
  1800.     // Assume nothing special about this segment
  1801.     sp->special = 0;
  1802.     sp->value = 0;
  1803.     sp->static_light = 0;
  1804.     sp->matcen_num = -1;
  1805.  
  1806.     copy_tmaps_to_segment(sp, &New_segment);
  1807.  
  1808.     assign_default_uvs_to_segment(sp);
  1809. }
  1810.  
  1811. // ----------------------------------------------------------------------------------------------
  1812. //    Create New_segment using a specified scale factor.
  1813. void med_create_new_segment(vms_vector *scale)
  1814. {
  1815.     int            s,t;
  1816.     vms_vector    v0;
  1817.     segment        *sp = &New_segment;
  1818.  
  1819.     fix            length,width,height;
  1820.  
  1821.     length = scale->z;
  1822.     width = scale->x;
  1823.     height = scale->y;
  1824.  
  1825.     sp->segnum = 1;                        // What to put here?  I don't know.
  1826.  
  1827.     //    Create relative-to-center vertices, which are the points on the box defined by length, width, height
  1828.     t = Num_vertices;
  1829.     sp->verts[0] = med_set_vertex(NEW_SEGMENT_VERTICES+0,vm_vec_make(&v0,+width/2,+height/2,-length/2));
  1830.     sp->verts[1] = med_set_vertex(NEW_SEGMENT_VERTICES+1,vm_vec_make(&v0,+width/2,-height/2,-length/2));
  1831.     sp->verts[2] = med_set_vertex(NEW_SEGMENT_VERTICES+2,vm_vec_make(&v0,-width/2,-height/2,-length/2));
  1832.     sp->verts[3] = med_set_vertex(NEW_SEGMENT_VERTICES+3,vm_vec_make(&v0,-width/2,+height/2,-length/2));
  1833.     sp->verts[4] = med_set_vertex(NEW_SEGMENT_VERTICES+4,vm_vec_make(&v0,+width/2,+height/2,+length/2));
  1834.     sp->verts[5] = med_set_vertex(NEW_SEGMENT_VERTICES+5,vm_vec_make(&v0,+width/2,-height/2,+length/2));
  1835.     sp->verts[6] = med_set_vertex(NEW_SEGMENT_VERTICES+6,vm_vec_make(&v0,-width/2,-height/2,+length/2));
  1836.     sp->verts[7] = med_set_vertex(NEW_SEGMENT_VERTICES+7,vm_vec_make(&v0,-width/2,+height/2,+length/2));
  1837.     Num_vertices = t;
  1838.  
  1839. //    sp->scale = *scale;
  1840.  
  1841.     // Form connections to children, of which it has none, init faces and tmaps.
  1842.     for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
  1843.         sp->children[s] = -1;
  1844. //        sp->sides[s].render_flag = 0;
  1845.         sp->sides[s].wall_num = -1;
  1846.         create_walls_on_side(sp,s);
  1847.         sp->sides[s].tmap_num = s;                    // assign some stupid old tmap to this side.
  1848.         sp->sides[s].tmap_num2 = 0;
  1849.     }
  1850.  
  1851.     Seg_orientation.p = 0;    Seg_orientation.b = 0;    Seg_orientation.h = 0;
  1852.  
  1853.     sp->objects = -1;        //no objects in this segment
  1854.  
  1855.     assign_default_uvs_to_segment(sp);
  1856.  
  1857.     // Assume nothing special about this segment
  1858.     sp->special = 0;
  1859.     sp->value = 0;
  1860.     sp->static_light = 0;
  1861.     sp->matcen_num = -1;
  1862. }
  1863.  
  1864. // -------------------------------------------------------------------------------
  1865. void med_create_new_segment_from_cursegp(void)
  1866. {
  1867.     vms_vector    scalevec;
  1868.     vms_vector    uvec, rvec, fvec;
  1869.  
  1870.     med_extract_up_vector_from_segment_side(Cursegp, Curside, &uvec);
  1871.     med_extract_right_vector_from_segment_side(Cursegp, Curside, &rvec);
  1872.     extract_forward_vector_from_segment(Cursegp, &fvec);
  1873.  
  1874.     scalevec.x = vm_vec_mag(&rvec);
  1875.     scalevec.y = vm_vec_mag(&uvec);
  1876.     scalevec.z = vm_vec_mag(&fvec);
  1877.  
  1878.     med_create_new_segment(&scalevec);
  1879. }
  1880.  
  1881. // -------------------------------------------------------------------------------
  1882. //    Initialize all vertices to inactive status.
  1883. void init_all_vertices(void)
  1884. {
  1885.     int        v;
  1886.     int    s;
  1887.  
  1888.     for (v=0; v<MAX_SEGMENT_VERTICES; v++)
  1889.         Vertex_active[v] = 0;
  1890.  
  1891.     for (s=0; s<MAX_SEGMENTS; s++)
  1892.         Segments[s].segnum = -1;
  1893.  
  1894. }
  1895.  
  1896. // --------------------------------------------------------------------------------------
  1897. //    Create a new mine, set global variables.
  1898. int create_new_mine(void)
  1899. {
  1900.     int    s;
  1901.     vms_vector    sizevec;
  1902.     vms_matrix    m1 = IDENTITY_MATRIX;
  1903.  
  1904.     // initialize_mine_arrays();
  1905.  
  1906. //    gamestate_not_restored = 1;
  1907.  
  1908.     // Clear refueling center code
  1909.     fuelcen_reset();
  1910.     hostage_init_all();
  1911.  
  1912.     init_all_vertices();
  1913.  
  1914.     Current_level_num = 0;        //0 means not a real level
  1915.     Current_level_name[0] = 0;
  1916.  
  1917.     Cur_object_index = -1;
  1918.     reset_objects(1);        //just one object, the player
  1919.  
  1920.     num_groups = 0;
  1921.     current_group = -1;
  1922.  
  1923.     Num_vertices = 0;        // Number of vertices in global array.
  1924.     Num_segments = 0;        // Number of segments in global array, will get increased in med_create_segment
  1925.     Cursegp = Segments;    // Say current segment is the only segment.
  1926.     Curside = WBACK;        // The active side is the back side
  1927.     Markedsegp = 0;        // Say there is no marked segment.
  1928.     Markedside = WBACK;    //    Shouldn't matter since Markedsegp == 0, but just in case...
  1929.     for (s=0;s<MAX_GROUPS+1;s++) {
  1930.         GroupList[s].num_segments = 0;        
  1931.         GroupList[s].num_vertices = 0;        
  1932.         Groupsegp[s] = NULL;
  1933.         Groupside[s] = 0;
  1934.     }
  1935.  
  1936.     Num_robot_centers = 0;
  1937.     Num_open_doors = 0;
  1938.     wall_init();
  1939.     trigger_init();
  1940.  
  1941.     // Create New_segment, which is the segment we will be adding at each instance.
  1942.     med_create_new_segment(vm_vec_make(&sizevec,DEFAULT_X_SIZE,DEFAULT_Y_SIZE,DEFAULT_Z_SIZE));        // New_segment = Segments[0];
  1943. //    med_create_segment(Segments,0,0,0,DEFAULT_X_SIZE,DEFAULT_Y_SIZE,DEFAULT_Z_SIZE,vm_mat_make(&m1,F1_0,0,0,0,F1_0,0,0,0,F1_0));
  1944.     med_create_segment(Segments,0,0,0,DEFAULT_X_SIZE,DEFAULT_Y_SIZE,DEFAULT_Z_SIZE,&m1);
  1945.  
  1946.     N_found_segs = 0;
  1947.     N_selected_segs = 0;
  1948.     N_warning_segs = 0;
  1949.  
  1950.     //--repair-- create_local_segment_data();
  1951.  
  1952.     ControlCenterTriggers.num_links = 0;
  1953.  
  1954.     //editor_status("New mine created.");
  1955.     return    0;            // say no error
  1956. }
  1957.  
  1958. // --------------------------------------------------------------------------------------------------
  1959. // Copy a segment from *ssp to *dsp.  Do not simply copy the struct.  Use *dsp's vertices, copying in
  1960. //    just the values, not the indices.
  1961. void med_copy_segment(segment *dsp,segment *ssp)
  1962. {
  1963.     int    v;
  1964.     int    verts_copy[MAX_VERTICES_PER_SEGMENT];
  1965.  
  1966.     //    First make a copy of the vertex list.
  1967.     for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
  1968.         verts_copy[v] = dsp->verts[v];
  1969.  
  1970.     // Now copy the whole struct.
  1971.     *dsp = *ssp;
  1972.  
  1973.     // Now restore the vertex indices.
  1974.     for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
  1975.         dsp->verts[v] = verts_copy[v];
  1976.  
  1977.     // Now destructively modify the vertex values for all vertex indices.
  1978.     for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
  1979.         Vertices[dsp->verts[v]] = Vertices[ssp->verts[v]];
  1980. }
  1981.  
  1982. // -----------------------------------------------------------------------------
  1983. //    Create coordinate axes in orientation of specified segment, stores vertices at *vp.
  1984. void create_coordinate_axes_from_segment(segment *sp,short *vertnums)
  1985. {
  1986.     vms_matrix    rotmat;
  1987.     vms_vector t;
  1988.  
  1989.     med_extract_matrix_from_segment(sp,&rotmat);
  1990.  
  1991.     compute_segment_center(&Vertices[vertnums[0]],sp);
  1992.  
  1993.     t = rotmat.rvec;
  1994.     vm_vec_scale(&t,i2f(32));
  1995.     vm_vec_add(&Vertices[vertnums[1]],&Vertices[vertnums[0]],&t);
  1996.  
  1997.     t = rotmat.uvec;
  1998.     vm_vec_scale(&t,i2f(32));
  1999.     vm_vec_add(&Vertices[vertnums[2]],&Vertices[vertnums[0]],&t);
  2000.  
  2001.     t = rotmat.fvec;
  2002.     vm_vec_scale(&t,i2f(32));
  2003.     vm_vec_add(&Vertices[vertnums[3]],&Vertices[vertnums[0]],&t);
  2004. }
  2005.  
  2006. // -----------------------------------------------------------------------------
  2007. //    Determine if a segment is concave. Returns true if concave
  2008. int check_seg_concavity(segment *s)
  2009. {
  2010.     int sn,vn;
  2011.     vms_vector n0,n1;
  2012.  
  2013.     for (sn=0;sn<MAX_SIDES_PER_SEGMENT;sn++)
  2014.         for (vn=0;vn<=4;vn++) {
  2015.  
  2016.             vm_vec_normal(&n1,
  2017.                 &Vertices[s->verts[Side_to_verts[sn][vn%4]]],
  2018.                 &Vertices[s->verts[Side_to_verts[sn][(vn+1)%4]]],
  2019.                 &Vertices[s->verts[Side_to_verts[sn][(vn+2)%4]]]);
  2020.  
  2021.             //vm_vec_normalize(&n1);
  2022.  
  2023.             if (vn>0) if (vm_vec_dotprod(&n0,&n1) < f0_5) return 1;
  2024.  
  2025.             n0 = n1;
  2026.         }
  2027.  
  2028.     return 0;
  2029. }
  2030.  
  2031.  
  2032. // -----------------------------------------------------------------------------
  2033. //    Find all concave segments and add to list
  2034. void find_concave_segs()
  2035. {
  2036.     int i;
  2037.     segment *s;
  2038.  
  2039.     N_warning_segs = 0;
  2040.  
  2041.     for (s=Segments,i=Highest_segment_index;i>=0;s++,i--)
  2042.         if (s->segnum != -1)
  2043.             if (check_seg_concavity(s)) Warning_segs[N_warning_segs++]=SEG_PTR_2_NUM(s);
  2044.  
  2045.  
  2046. }
  2047.  
  2048.  
  2049. // -----------------------------------------------------------------------------
  2050. void warn_if_concave_segments(void)
  2051. {
  2052.     char temp[1];
  2053.  
  2054.     find_concave_segs();
  2055.  
  2056.     if (N_warning_segs) {
  2057.         editor_status("*** WARNING *** %d concave segments in mine! *** WARNING ***",N_warning_segs);
  2058.         sprintf( temp, "%d", N_warning_segs );
  2059.     }
  2060. }
  2061.  
  2062. // -----------------------------------------------------------------------------
  2063. //    Check segment s, if concave, warn
  2064. void warn_if_concave_segment(segment *s)
  2065. {
  2066.     char temp[1];
  2067.     int    result;
  2068.  
  2069.     result = check_seg_concavity(s);
  2070.  
  2071.     if (result) {
  2072.         Warning_segs[N_warning_segs++] = s-Segments;
  2073.  
  2074.         if (N_warning_segs) {
  2075.             editor_status("*** WARNING *** New segment is concave! *** WARNING ***");
  2076.             sprintf( temp, "%d", N_warning_segs );
  2077.         }
  2078.         //else
  2079.            // editor_status("");
  2080.     } //else
  2081.         //editor_status("");
  2082. }
  2083.  
  2084.  
  2085. // -------------------------------------------------------------------------------
  2086. //    Find segment adjacent to sp:side.
  2087. //    Adjacent means a segment which shares all four vertices.
  2088. //    Return true if segment found and fill in segment in adj_sp and side in adj_side.
  2089. //    Return false if unable to find, in which case adj_sp and adj_side are undefined.
  2090. int med_find_adjacent_segment_side(segment *sp, int side, segment **adj_sp, int *adj_side)
  2091. {
  2092.     int            seg,s,v,vv;
  2093.     int            abs_verts[4];
  2094.  
  2095.     //    Stuff abs_verts[4] array with absolute vertex indices
  2096.     for (v=0; v<4; v++)
  2097.         abs_verts[v] = sp->verts[Side_to_verts[side][v]];
  2098.  
  2099.     //    Scan all segments, looking for a segment which contains the four abs_verts
  2100.     for (seg=0; seg<=Highest_segment_index; seg++) {
  2101.         if (seg != sp-Segments) {
  2102.             for (v=0; v<4; v++) {                                                // do for each vertex in abs_verts
  2103.                 for (vv=0; vv<MAX_VERTICES_PER_SEGMENT; vv++)            // do for each vertex in segment
  2104.                     if (abs_verts[v] == Segments[seg].verts[vv])
  2105.                         goto fass_found1;                                            // Current vertex (indexed by v) is present in segment, try next
  2106.                 goto fass_next_seg;                                                // This segment doesn't contain the vertex indexed by v
  2107.             fass_found1: ;
  2108.             }        // end for v
  2109.  
  2110.             //    All four vertices in sp:side are present in segment seg.
  2111.             //    Determine side and return
  2112.             for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
  2113.                 for (v=0; v<4; v++) {
  2114.                     for (vv=0; vv<4; vv++) {
  2115.                         if (Segments[seg].verts[Side_to_verts[s][v]] == abs_verts[vv])
  2116.                             goto fass_found2;
  2117.                     }
  2118.                     goto fass_next_side;                                            // Couldn't find vertex v in current side, so try next side.
  2119.                 fass_found2: ;
  2120.                 }
  2121.                 // Found all four vertices in current side.  We are done!
  2122.                 *adj_sp = &Segments[seg];
  2123.                 *adj_side = s;
  2124.                 return 1;
  2125.             fass_next_side: ;
  2126.             }
  2127.             Assert(0);    // Impossible -- we identified this segment as containing all 4 vertices of side "side", but we couldn't find them.
  2128.             return 0;
  2129.         fass_next_seg: ;
  2130.         }
  2131.     }
  2132.  
  2133.     return 0;
  2134. }
  2135.  
  2136.  
  2137. #define JOINT_THRESHOLD    10000*F1_0         // (Huge threshold)
  2138.  
  2139. // -------------------------------------------------------------------------------
  2140. //    Find segment closest to sp:side.
  2141. //    Return true if segment found and fill in segment in adj_sp and side in adj_side.
  2142. //    Return false if unable to find, in which case adj_sp and adj_side are undefined.
  2143. int med_find_closest_threshold_segment_side(segment *sp, int side, segment **adj_sp, int *adj_side, fix threshold)
  2144. {
  2145.     int            seg,s;
  2146.     vms_vector  vsc, vtc;         // original segment center, test segment center
  2147.     fix            current_dist, closest_seg_dist;
  2148.  
  2149.     if (IS_CHILD(sp->children[side]))
  2150.         return 0;
  2151.  
  2152.     compute_center_point_on_side(&vsc, sp, side); 
  2153.  
  2154.     closest_seg_dist = JOINT_THRESHOLD;
  2155.  
  2156.     //    Scan all segments, looking for a segment which contains the four abs_verts
  2157.     for (seg=0; seg<=Highest_segment_index; seg++) 
  2158.         if (seg != sp-Segments) 
  2159.             for (s=0;s<MAX_SIDES_PER_SEGMENT;s++) {
  2160.                 if (!IS_CHILD(Segments[seg].children[s])) {
  2161.                     compute_center_point_on_side(&vtc, &Segments[seg], s); 
  2162.                     current_dist = vm_vec_dist( &vsc, &vtc );
  2163.                     if (current_dist < closest_seg_dist) {
  2164.                         *adj_sp = &Segments[seg];
  2165.                         *adj_side = s;
  2166.                         closest_seg_dist = current_dist;
  2167.                     }
  2168.                 }
  2169.             }    
  2170.  
  2171.     if (closest_seg_dist < threshold)
  2172.         return 1;
  2173.     else
  2174.         return 0;
  2175. }
  2176.  
  2177.  
  2178.  
  2179. void med_check_all_vertices()
  2180. {
  2181.     int        s,v;
  2182.     segment    *sp;
  2183.     int        count;
  2184.  
  2185.     count = 0;
  2186.  
  2187.     for (s=0; s<Num_segments; s++) {
  2188.         sp = &Segments[s];
  2189.         if (sp->segnum != -1)
  2190.             for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
  2191.                 Assert(sp->verts[v] <= Highest_vertex_index);
  2192.                     
  2193.     }
  2194.  
  2195. }
  2196.  
  2197. //    -----------------------------------------------------------------------------------------------------
  2198. void check_for_overlapping_segment(int segnum)
  2199. {
  2200.     int    i, v;
  2201.     segmasks    masks;
  2202.     vms_vector    segcenter;
  2203.  
  2204.     compute_segment_center(&segcenter, &Segments[segnum]);
  2205.  
  2206.     for (i=0;i<=Highest_segment_index; i++) {
  2207.         if (i != segnum) {
  2208.             masks = get_seg_masks(&segcenter, i, 0);
  2209.             if (masks.centermask == 0) {
  2210.                 mprintf((0, "Segment %i center is contained in segment %i\n", segnum, i));
  2211.                 continue;
  2212.             }
  2213.  
  2214.             for (v=0; v<8; v++) {
  2215.                 vms_vector    pdel, presult;
  2216.  
  2217.                 vm_vec_sub(&pdel, &Vertices[Segments[segnum].verts[v]], &segcenter);
  2218.                 vm_vec_scale_add(&presult, &segcenter, &pdel, (F1_0*15)/16);
  2219.                 masks = get_seg_masks(&presult, i, 0);
  2220.                 if (masks.centermask == 0) {
  2221.                     mprintf((0, "Segment %i near vertex %i is contained in segment %i\n", segnum, v, i));
  2222.                     break;
  2223.                 }
  2224.             }
  2225.         }
  2226.     }
  2227.  
  2228. }
  2229.  
  2230. //    -----------------------------------------------------------------------------------------------------
  2231. //    Check for overlapping segments.
  2232. void check_for_overlapping_segments(void)
  2233. {
  2234.     int    i;
  2235.  
  2236.     med_compress_mine();
  2237.  
  2238.     for (i=0; i<=Highest_segment_index; i++) {
  2239.         mprintf((0, "+"));
  2240.         check_for_overlapping_segment(i);
  2241.     }
  2242.  
  2243.     mprintf((0, "\nDone!\n"));
  2244. }
  2245.  
  2246.