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