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