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