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