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.
15 * $Source: /cvs/cvsroot/d2x/main/editor/segment.c,v $
17 * $Author: schaffner $
18 * $Date: 2004-08-29 14:03:51 $
20 * Interrogation functions for segment data structure.
22 * $Log: not supported by cvs2svn $
23 * Revision 1.1 2001/10/25 02:27:17 bradleyb
24 * attempt at support for editor, makefile changes, etc
26 * Revision 1.2 1999/09/02 13:37:06 sekmu
27 * remove warning in editor compile
29 * Revision 1.1.1.1 1999/06/14 22:04:21 donut
30 * Import of d1x 1.37 source.
49 // #include "segment2.h"
68 int Do_duplicate_vertex_check = 0; // Gets set to 1 in med_create_duplicate_vertex, means to check for duplicate vertices in compress_mine
70 #define BOTTOM_STUFF 0
72 // Remap all vertices in polygons in a segment through translation table xlate_verts.
74 void remap_vertices(segment *segp, int *xlate_verts)
76 int sidenum, facenum, polynum, v;
78 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++)
79 for (facenum=0; facenum<segp->sides[sidenum].num_faces; facenum++)
80 for (polynum=0; polynum<segp->sides[sidenum].faces[facenum].num_polys; polynum++) {
81 poly *pp = &segp->sides[sidenum].faces[facenum].polys[polynum];
82 for (v=0; v<pp->num_vertices; v++)
83 pp->verts[v] = xlate_verts[pp->verts[v]];
87 // Copy everything from sourceside to destside except sourceside->faces[xx].polys[xx].verts
88 void copy_side_except_vertex_ids(side *destside, side *sourceside)
90 int facenum, polynum, v;
92 destside->num_faces = sourceside->num_faces;
93 destside->tri_edge = sourceside->tri_edge;
94 destside->wall_num = sourceside->wall_num;
96 for (facenum=0; facenum<sourceside->num_faces; facenum++) {
97 face *destface = &destside->faces[facenum];
98 face *sourceface = &sourceside->faces[facenum];
100 destface->num_polys = sourceface->num_polys;
101 destface->normal = sourceface->normal;
103 for (polynum=0; polynum<sourceface->num_polys; polynum++) {
104 poly *destpoly = &destface->polys[polynum];
105 poly *sourcepoly = &sourceface->polys[polynum];
107 destpoly->num_vertices = sourcepoly->num_vertices;
108 destpoly->face_type = sourcepoly->face_type;
109 destpoly->tmap_num = sourcepoly->tmap_num;
110 destpoly->tmap_num2 = sourcepoly->tmap_num2;
112 for (v=0; v<sourcepoly->num_vertices; v++)
113 destpoly->uvls[v] = sourcepoly->uvls[v];
119 // [side] [index] [cur:next]
120 // To remap the vertices on a side after a forward rotation
121 byte xlate_previous[6][4][2] = {
122 { {7, 3}, {3, 2}, {2, 6}, {6, 7} }, // remapping left to left
123 { {5, 4}, {4, 0}, {7, 3}, {6, 7} }, // remapping back to top
124 { {5, 4}, {1, 5}, {0, 1}, {4, 0} }, // remapping right to right
125 { {0, 1}, {1, 5}, {2, 6}, {3, 2} }, // remapping front to bottom
126 { {1, 5}, {5, 4}, {6, 7}, {2, 6} }, // remapping bottom to back
127 { {4, 0}, {0, 1}, {3, 2}, {7, 3} }, // remapping top to front
130 void remap_vertices_previous(segment *segp, int sidenum)
132 int v, w, facenum, polynum;
134 for (facenum=0; facenum<segp->sides[sidenum].num_faces; facenum++) {
135 for (polynum=0; polynum<segp->sides[sidenum].faces[facenum].num_polys; polynum++) {
136 poly *pp = &segp->sides[sidenum].faces[facenum].polys[polynum];
138 for (v=0; v<pp->num_vertices; v++) {
139 for (w=0; w<4; w++) {
140 if (pp->verts[v] == xlate_previous[sidenum][w][0]) {
141 pp->verts[v] = xlate_previous[sidenum][w][1];
145 Assert(w<4); // If w == 4, then didn't find current vertex in list, which means xlate_previous table is bogus
151 byte xlate_previous_right[6][4][2] = {
152 { {5, 6}, {6, 7}, {2, 3}, {1, 2} }, // bottom to left
153 { {6, 7}, {7, 4}, {3, 0}, {2, 3} }, // left to top
154 { {7, 4}, {4, 5}, {0, 1}, {3, 0} }, // top to right
155 { {4, 5}, {5, 6}, {1, 2}, {0, 1} }, // right to bottom
156 { {6, 7}, {5, 6}, {4, 5}, {7, 4} }, // back to back
157 { {3, 2}, {0, 3}, {1, 0}, {2, 1} }, // front to front
160 void remap_vertices_previous_right(segment *segp, int sidenum)
162 int v, w, facenum, polynum;
164 for (facenum=0; facenum<segp->sides[sidenum].num_faces; facenum++) {
165 for (polynum=0; polynum<segp->sides[sidenum].faces[facenum].num_polys; polynum++) {
166 poly *pp = &segp->sides[sidenum].faces[facenum].polys[polynum];
168 for (v=0; v<pp->num_vertices; v++) {
169 for (w=0; w<4; w++) {
170 if (pp->verts[v] == xlate_previous_right[sidenum][w][0]) {
171 pp->verts[v] = xlate_previous_right[sidenum][w][1];
175 Assert(w<4); // If w == 4, then didn't find current vertex in list, which means xlate_previous table is bogus
182 // -----------------------------------------------------------------------------------
183 // Takes top to front
184 void med_rotate_segment_forward(segment *segp)
191 seg_copy.verts[0] = segp->verts[4];
192 seg_copy.verts[1] = segp->verts[0];
193 seg_copy.verts[2] = segp->verts[3];
194 seg_copy.verts[3] = segp->verts[7];
195 seg_copy.verts[4] = segp->verts[5];
196 seg_copy.verts[5] = segp->verts[1];
197 seg_copy.verts[6] = segp->verts[2];
198 seg_copy.verts[7] = segp->verts[6];
200 seg_copy.children[WFRONT] = segp->children[WTOP];
201 seg_copy.children[WTOP] = segp->children[WBACK];
202 seg_copy.children[WBACK] = segp->children[WBOTTOM];
203 seg_copy.children[WBOTTOM] = segp->children[WFRONT];
205 seg_copy.sides[WFRONT] = segp->sides[WTOP];
206 seg_copy.sides[WTOP] = segp->sides[WBACK];
207 seg_copy.sides[WBACK] = segp->sides[WBOTTOM];
208 seg_copy.sides[WBOTTOM] = segp->sides[WFRONT];
211 remap_vertices_previous(&seg_copy, i);
216 // -----------------------------------------------------------------------------------
217 // Takes top to right
218 void med_rotate_segment_right(segment *segp)
225 seg_copy.verts[4] = segp->verts[7];
226 seg_copy.verts[5] = segp->verts[4];
227 seg_copy.verts[1] = segp->verts[0];
228 seg_copy.verts[0] = segp->verts[3];
229 seg_copy.verts[3] = segp->verts[2];
230 seg_copy.verts[2] = segp->verts[1];
231 seg_copy.verts[6] = segp->verts[5];
232 seg_copy.verts[7] = segp->verts[6];
234 seg_copy.children[WRIGHT] = segp->children[WTOP];
235 seg_copy.children[WBOTTOM] = segp->children[WRIGHT];
236 seg_copy.children[WLEFT] = segp->children[WBOTTOM];
237 seg_copy.children[WTOP] = segp->children[WLEFT];
239 seg_copy.sides[WRIGHT] = segp->sides[WTOP];
240 seg_copy.sides[WBOTTOM] = segp->sides[WRIGHT];
241 seg_copy.sides[WLEFT] = segp->sides[WBOTTOM];
242 seg_copy.sides[WTOP] = segp->sides[WLEFT];
245 remap_vertices_previous_right(&seg_copy, i);
250 void make_curside_bottom_side(void)
253 case WRIGHT: med_rotate_segment_right(Cursegp); break;
254 case WTOP: med_rotate_segment_right(Cursegp); med_rotate_segment_right(Cursegp); break;
255 case WLEFT: med_rotate_segment_right(Cursegp); med_rotate_segment_right(Cursegp); med_rotate_segment_right(Cursegp); break;
257 case WFRONT: med_rotate_segment_forward(Cursegp); break;
258 case WBACK: med_rotate_segment_forward(Cursegp); med_rotate_segment_forward(Cursegp); med_rotate_segment_forward(Cursegp); break;
260 Update_flags = UF_WORLD_CHANGED;
264 int ToggleBottom(void)
266 Render_only_bottom = !Render_only_bottom;
267 Update_flags = UF_WORLD_CHANGED;
271 // ---------------------------------------------------------------------------------------------
272 // ---------- Segment interrogation functions ----------
273 // ----------------------------------------------------------------------------
274 // Return a pointer to the list of vertex indices for the current segment in vp and
275 // the number of vertices in *nv.
276 void med_get_vertex_list(segment *s,int *nv,short **vp)
279 *nv = MAX_VERTICES_PER_SEGMENT;
282 // -------------------------------------------------------------------------------
283 // Return number of times vertex vi appears in all segments.
284 // This function can be used to determine whether a vertex is used exactly once in
285 // all segments, in which case it can be freely moved because it is not connected
286 // to any other segment.
287 int med_vertex_count(int vi)
295 for (s=0; s<MAX_SEGMENTS; s++) {
297 if (sp->segnum != -1)
298 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
299 if (sp->verts[v] == vi)
306 // -------------------------------------------------------------------------------
307 int is_free_vertex(int vi)
309 return med_vertex_count(vi) == 1;
313 // -------------------------------------------------------------------------------
314 // Move a free vertex in the segment by adding the vector *vofs to its coordinates.
316 // If the point is not free then:
317 // If the point is not valid (probably valid = in 0..7) then:
318 // If adding *vofs will cause a degenerate segment then:
319 // Note, pi is the point index relative to the segment, not an absolute point index.
320 // For example, 3 is always the front upper left vertex.
321 void med_move_vertex(segment *sp, int pi, vms_vector *vofs)
325 Assert((pi >= 0) && (pi <= 7)); // check valid range of point indices.
327 abspi = sp->verts[pi];
329 // Make sure vertex abspi is free. If it is free, it appears exactly once in Vertices
330 Assert(med_vertex_count(abspi) == 1);
332 Assert(abspi <= MAX_SEGMENT_VERTICES); // Make sure vertex id is not bogus.
334 vm_vec_add(&Vertices[abspi],&Vertices[abspi],vofs);
336 // Here you need to validate the geometry of the segment, which will be quite tricky.
337 // You need to make sure:
338 // The segment is not concave.
339 // None of the sides are concave.
340 validate_segment(sp);
344 // -------------------------------------------------------------------------------
345 // Move a free wall in the segment by adding the vector *vofs to its coordinates.
346 // Wall indices: 0/1/2/3/4/5 = left/top/right/bottom/back/front
347 void med_move_wall(segment *sp,int wi, vms_vector *vofs)
352 Assert( (wi >= 0) && (wi <= 5) );
354 vp = Side_to_verts[wi];
355 for (i=0; i<4; i++) {
356 med_move_vertex(sp,*vp,vofs);
360 validate_segment(sp);
363 // -------------------------------------------------------------------------------
364 // Return true if one fixed point number is very close to another, else return false.
365 int fnear(fix f1, fix f2)
367 return (abs(f1 - f2) <= FIX_EPSILON);
370 // -------------------------------------------------------------------------------
371 int vnear(vms_vector *vp1, vms_vector *vp2)
373 return fnear(vp1->x, vp2->x) && fnear(vp1->y, vp2->y) && fnear(vp1->z, vp2->z);
376 // -------------------------------------------------------------------------------
377 // Add the vertex *vp to the global list of vertices, return its index.
378 // Search until a matching vertex is found (has nearly the same coordinates) or until Num_vertices
379 // vertices have been looked at without a match. If no match, add a new vertex.
380 int med_add_vertex(vms_vector *vp)
383 int count; // number of used vertices found, for loops exits when count == Num_vertices
385 // set_vertex_counts();
387 Assert(Num_vertices < MAX_SEGMENT_VERTICES);
391 for (v=0; (v < MAX_SEGMENT_VERTICES) && (count < Num_vertices); v++)
392 if (Vertex_active[v]) {
394 if (vnear(vp,&Vertices[v])) {
395 // mprintf((0,"[%4i] ",v));
398 } else if (free_index == -1)
399 free_index = v; // we want free_index to be the first free slot to add a vertex
401 if (free_index == -1)
402 free_index = Num_vertices;
404 while (Vertex_active[free_index] && (free_index < MAX_VERTICES))
407 Assert(free_index < MAX_VERTICES);
409 Vertices[free_index] = *vp;
410 Vertex_active[free_index] = 1;
414 if (free_index > Highest_vertex_index)
415 Highest_vertex_index = free_index;
420 // ------------------------------------------------------------------------------------------
421 // Returns the index of a free segment.
422 // Scans the Segments array.
423 int get_free_segment_number(void)
427 for (segnum=0; segnum<MAX_SEGMENTS; segnum++)
428 if (Segments[segnum].segnum == -1) {
430 if (segnum > Highest_segment_index)
431 Highest_segment_index = segnum;
440 // -------------------------------------------------------------------------------
441 // Create a new segment, duplicating exactly, including vertex ids and children, the passed segment.
442 int med_create_duplicate_segment(segment *sp)
446 segnum = get_free_segment_number();
448 Segments[segnum] = *sp;
453 // -------------------------------------------------------------------------------
454 // Add the vertex *vp to the global list of vertices, return its index.
455 // This is the same as med_add_vertex, except that it does not search for the presence of the vertex.
456 int med_create_duplicate_vertex(vms_vector *vp)
460 Assert(Num_vertices < MAX_SEGMENT_VERTICES);
462 Do_duplicate_vertex_check = 1;
464 free_index = Num_vertices;
466 while (Vertex_active[free_index] && (free_index < MAX_VERTICES))
469 Assert(free_index < MAX_VERTICES);
471 Vertices[free_index] = *vp;
472 Vertex_active[free_index] = 1;
476 if (free_index > Highest_vertex_index)
477 Highest_vertex_index = free_index;
483 // -------------------------------------------------------------------------------
484 // Set the vertex *vp at index vnum in the global list of vertices, return its index (just for compatibility).
485 int med_set_vertex(int vnum,vms_vector *vp)
487 Assert(vnum < MAX_VERTICES);
489 Vertices[vnum] = *vp;
491 // Just in case this vertex wasn't active, mark it as active.
492 if (!Vertex_active[vnum]) {
493 Vertex_active[vnum] = 1;
495 if ((vnum > Highest_vertex_index) && (vnum < NEW_SEGMENT_VERTICES)) {
496 mprintf((0,"Warning -- setting a previously unset vertex, index = %i.\n",vnum));
497 Highest_vertex_index = vnum;
507 // A side is determined to be degenerate if the cross products of 3 consecutive points does not point outward.
508 int check_for_degenerate_side(segment *sp, int sidenum)
510 char *vp = Side_to_verts[sidenum];
511 vms_vector vec1, vec2, cross, vec_to_center;
512 vms_vector segc, sidec;
514 int degeneracy_flag = 0;
516 compute_segment_center(&segc, sp);
517 compute_center_point_on_side(&sidec, sp, sidenum);
518 vm_vec_sub(&vec_to_center, &segc, &sidec);
520 //vm_vec_sub(&vec1, &Vertices[sp->verts[vp[1]]], &Vertices[sp->verts[vp[0]]]);
521 //vm_vec_sub(&vec2, &Vertices[sp->verts[vp[2]]], &Vertices[sp->verts[vp[1]]]);
522 //vm_vec_normalize(&vec1);
523 //vm_vec_normalize(&vec2);
524 vm_vec_normalized_dir(&vec1, &Vertices[sp->verts[(int) vp[1]]], &Vertices[sp->verts[(int) vp[0]]]);
525 vm_vec_normalized_dir(&vec2, &Vertices[sp->verts[(int) vp[2]]], &Vertices[sp->verts[(int) vp[1]]]);
526 vm_vec_cross(&cross, &vec1, &vec2);
528 dot = vm_vec_dot(&vec_to_center, &cross);
530 degeneracy_flag |= 1;
532 //vm_vec_sub(&vec1, &Vertices[sp->verts[vp[2]]], &Vertices[sp->verts[vp[1]]]);
533 //vm_vec_sub(&vec2, &Vertices[sp->verts[vp[3]]], &Vertices[sp->verts[vp[2]]]);
534 //vm_vec_normalize(&vec1);
535 //vm_vec_normalize(&vec2);
536 vm_vec_normalized_dir(&vec1, &Vertices[sp->verts[(int) vp[2]]], &Vertices[sp->verts[(int) vp[1]]]);
537 vm_vec_normalized_dir(&vec2, &Vertices[sp->verts[(int) vp[3]]], &Vertices[sp->verts[(int) vp[2]]]);
538 vm_vec_cross(&cross, &vec1, &vec2);
540 dot = vm_vec_dot(&vec_to_center, &cross);
542 degeneracy_flag |= 1;
544 return degeneracy_flag;
548 // -------------------------------------------------------------------------------
549 void create_removable_wall(segment *sp, int sidenum, int tmap_num)
551 create_walls_on_side(sp, sidenum);
553 sp->sides[sidenum].tmap_num = tmap_num;
555 assign_default_uvs_to_side(sp, sidenum);
556 assign_light_to_side(sp, sidenum);
560 // See if a segment has gotten turned inside out, or something.
561 // If so, set global Degenerate_segment_found and return 1, else return 0.
562 int check_for_degenerate_segment(segment *sp)
564 vms_vector fvec, rvec, uvec, cross;
566 int i, degeneracy_flag = 0; // degeneracy flag for current segment
568 extract_forward_vector_from_segment(sp, &fvec);
569 extract_right_vector_from_segment(sp, &rvec);
570 extract_up_vector_from_segment(sp, &uvec);
572 vm_vec_normalize(&fvec);
573 vm_vec_normalize(&rvec);
574 vm_vec_normalize(&uvec);
576 vm_vec_cross(&cross, &fvec, &rvec);
577 dot = vm_vec_dot(&cross, &uvec);
582 mprintf((0, "segment #%i is degenerate due to cross product check.\n", sp-Segments));
586 // Now, see if degenerate because of any side.
587 for (i=0; i<MAX_SIDES_PER_SEGMENT; i++)
588 degeneracy_flag |= check_for_degenerate_side(sp, i);
590 Degenerate_segment_found |= degeneracy_flag;
592 return degeneracy_flag;
598 // ---------------------------------------------------------------------------------------------
599 // Orthogonalize matrix smat, returning result in rmat.
600 // Does not modify smat.
601 // Uses Gram-Schmidt process.
602 // See page 172 of Strang, Gilbert, Linear Algebra and its Applications
603 // Matt -- This routine should be moved to the vector matrix library.
604 // It IS legal for smat == rmat.
605 // We should also have the functions:
606 // mat_a = mat_b * scalar; // we now have mat_a = mat_a * scalar;
607 // mat_a = mat_b + mat_c * scalar; // or maybe not, maybe this is not primitive
608 void make_orthogonal(vms_matrix *rmat,vms_matrix *smat)
611 vms_vector tvec1,tvec2;
614 // Copy source matrix to work area.
617 // Normalize the three rows of the matrix tmat.
618 vm_vec_normalize(&tmat.xrow);
619 vm_vec_normalize(&tmat.yrow);
620 vm_vec_normalize(&tmat.zrow);
622 // Now, compute the first vector.
623 // This is very easy -- just copy the (normalized) source vector.
624 rmat->zrow = tmat.zrow;
626 // Now, compute the second vector.
627 // From page 172 of Strang, we use the equation:
628 // b' = b - [transpose(q1) * b] * q1
629 // where: b = the second row of tmat
630 // q1 = the first row of rmat
631 // b' = the second row of rmat
633 // Compute: transpose(q1) * b
634 dot = vm_vec_dotprod(&rmat->zrow,&tmat.yrow);
636 // Compute: b - dot * q1
637 rmat->yrow.x = tmat.yrow.x - fixmul(dot,rmat->zrow.x);
638 rmat->yrow.y = tmat.yrow.y - fixmul(dot,rmat->zrow.y);
639 rmat->yrow.z = tmat.yrow.z - fixmul(dot,rmat->zrow.z);
641 // Now, compute the third vector.
642 // From page 173 of Strang, we use the equation:
643 // c' = c - (q1*c)*q1 - (q2*c)*q2
644 // where: c = the third row of tmat
645 // q1 = the first row of rmat
646 // q2 = the second row of rmat
647 // c' = the third row of rmat
650 dot = vm_vec_dotprod(&rmat->zrow,&tmat.xrow);
652 tvec1.x = fixmul(dot,rmat->zrow.x);
653 tvec1.y = fixmul(dot,rmat->zrow.y);
654 tvec1.z = fixmul(dot,rmat->zrow.z);
657 dot = vm_vec_dotprod(&rmat->yrow,&tmat.xrow);
659 tvec2.x = fixmul(dot,rmat->yrow.x);
660 tvec2.y = fixmul(dot,rmat->yrow.y);
661 tvec2.z = fixmul(dot,rmat->yrow.z);
663 vm_vec_sub(&rmat->xrow,vm_vec_sub(&rmat->xrow,&tmat.xrow,&tvec1),&tvec2);
668 // ------------------------------------------------------------------------------------------
669 // Given a segment, extract the rotation matrix which defines it.
670 // Do this by extracting the forward, right, up vectors and then making them orthogonal.
671 // In the process of making the vectors orthogonal, favor them in the order forward, up, right.
672 // This means that the forward vector will remain unchanged.
673 void med_extract_matrix_from_segment(segment *sp,vms_matrix *rotmat)
675 vms_vector forwardvec,upvec;
677 extract_forward_vector_from_segment(sp,&forwardvec);
678 extract_up_vector_from_segment(sp,&upvec);
680 if (((forwardvec.x == 0) && (forwardvec.y == 0) && (forwardvec.z == 0)) || ((upvec.x == 0) && (upvec.y == 0) && (upvec.z == 0))) {
681 mprintf((0, "Trapped null vector in med_extract_matrix_from_segment, returning identity matrix.\n"));
682 *rotmat = vmd_identity_matrix;
687 vm_vector_2_matrix(rotmat,&forwardvec,&upvec,NULL);
692 extract_forward_vector_from_segment(sp,&rm.zrow);
693 extract_right_vector_from_segment(sp,&rm.xrow);
694 extract_up_vector_from_segment(sp,&rm.yrow);
696 vm_vec_normalize(&rm.xrow);
697 vm_vec_normalize(&rm.yrow);
698 vm_vec_normalize(&rm.zrow);
700 make_orthogonal(rotmat,&rm);
702 vm_vec_normalize(&rotmat->xrow);
703 vm_vec_normalize(&rotmat->yrow);
704 vm_vec_normalize(&rotmat->zrow);
706 // *rotmat = rm; // include this line (and remove the call to make_orthogonal) if you don't want the matrix orthogonalized
711 // ------------------------------------------------------------------------------------------
712 // Given a rotation matrix *rotmat which describes the orientation of a segment
713 // and a side destside, return the rotation matrix which describes the orientation for the side.
714 void set_matrix_based_on_side(vms_matrix *rotmat,int destside)
716 vms_angvec rotvec,*tmpvec;
721 tmpvec=vm_angvec_make(&rotvec,0,0,-16384);
722 vm_angles_2_matrix(&r1,&rotvec);
723 vm_matrix_x_matrix(&rtemp,rotmat,&r1);
728 tmpvec=vm_angvec_make(&rotvec,-16384,0,0);
729 vm_angles_2_matrix(&r1,&rotvec);
730 vm_matrix_x_matrix(&rtemp,rotmat,&r1);
735 tmpvec=vm_angvec_make(&rotvec,0,0,16384);
736 vm_angles_2_matrix(&r1,&rotvec);
737 vm_matrix_x_matrix(&rtemp,rotmat,&r1);
742 tmpvec=vm_angvec_make(&rotvec,+16384,-32768,0); // bank was -32768, but I think that was an erroneous compensation
743 vm_angles_2_matrix(&r1,&rotvec);
744 vm_matrix_x_matrix(&rtemp,rotmat,&r1);
749 tmpvec=vm_angvec_make(&rotvec,0,0,-32768);
750 vm_angles_2_matrix(&r1,&rotvec);
751 vm_matrix_x_matrix(&rtemp,rotmat,&r1);
761 // -------------------------------------------------------------------------------------
762 void change_vertex_occurrences(int dest, int src)
766 // Fix vertices in groups
767 for (g=0;g<num_groups;g++)
768 for (v=0; v<GroupList[g].num_vertices; v++)
769 if (GroupList[g].vertices[v] == src)
770 GroupList[g].vertices[v] = dest;
772 // now scan all segments, changing occurrences of src to dest
773 for (s=0; s<=Highest_segment_index; s++)
774 if (Segments[s].segnum != -1)
775 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
776 if (Segments[s].verts[v] == src)
777 Segments[s].verts[v] = dest;
780 // --------------------------------------------------------------------------------------------------
781 void compress_vertices(void)
785 if (Highest_vertex_index == Num_vertices - 1)
788 vert = Highest_vertex_index; //MAX_SEGMENT_VERTICES-1;
790 for (hole=0; hole < vert; hole++)
791 if (!Vertex_active[hole]) {
792 // found an unused vertex which is a hole if a used vertex follows (not necessarily immediately) it.
793 for ( ; (vert>hole) && (!Vertex_active[vert]); vert--)
798 // Ok, hole is the index of a hole, vert is the index of a vertex which follows it.
799 // Copy vert into hole, update pointers to it.
800 Vertices[hole] = Vertices[vert];
802 change_vertex_occurrences(hole, vert);
808 Highest_vertex_index = Num_vertices-1;
811 // --------------------------------------------------------------------------------------------------
812 void compress_segments(void)
816 if (Highest_segment_index == Num_segments - 1)
819 seg = Highest_segment_index;
821 for (hole=0; hole < seg; hole++)
822 if (Segments[hole].segnum == -1) {
823 // found an unused segment which is a hole if a used segment follows (not necessarily immediately) it.
824 for ( ; (seg>hole) && (Segments[seg].segnum == -1); seg--)
832 // Ok, hole is the index of a hole, seg is the index of a segment which follows it.
833 // Copy seg into hole, update pointers to it, update Cursegp, Markedsegp if necessary.
834 Segments[hole] = Segments[seg];
835 Segments[seg].segnum = -1;
837 if (Cursegp == &Segments[seg])
838 Cursegp = &Segments[hole];
840 if (Markedsegp == &Segments[seg])
841 Markedsegp = &Segments[hole];
843 // Fix segments in groups
844 for (g=0;g<num_groups;g++)
845 for (s=0; s<GroupList[g].num_segments; s++)
846 if (GroupList[g].segments[s] == seg)
847 GroupList[g].segments[s] = hole;
850 for (w=0;w<Num_walls;w++)
851 if (Walls[w].segnum == seg)
852 Walls[w].segnum = hole;
854 // Fix fuelcenters, robotcens, and triggers... added 2/1/95 -Yuan
855 for (f=0;f<Num_fuelcenters;f++)
856 if (Station[f].segnum == seg)
857 Station[f].segnum = hole;
859 for (f=0;f<Num_robot_centers;f++)
860 if (RobotCenters[f].segnum == seg)
861 RobotCenters[f].segnum = hole;
863 for (t=0;t<Num_triggers;t++)
864 for (l=0;l<Triggers[t].num_links;l++)
865 if (Triggers[t].seg[l] == seg)
866 Triggers[t].seg[l] = hole;
868 sp = &Segments[hole];
869 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
870 if (IS_CHILD(sp->children[s])) {
872 csegp = &Segments[sp->children[s]];
874 // Find out on what side the segment connection to the former seg is on in *csegp.
875 for (t=0; t<MAX_SIDES_PER_SEGMENT; t++) {
876 if (csegp->children[t] == seg) {
877 csegp->children[t] = hole; // It used to be connected to seg, so make it connected to hole
883 //Update object segment pointers
884 for (objnum = sp->objects; objnum != -1; objnum = Objects[objnum].next) {
885 Assert(Objects[objnum].segnum == seg);
886 Objects[objnum].segnum = hole;
891 } // end if (seg > hole)
894 Highest_segment_index = Num_segments-1;
895 med_create_new_segment_from_cursegp();
900 // -------------------------------------------------------------------------------
901 // Combine duplicate vertices.
902 // If two vertices have the same coordinates, within some small tolerance, then assign
903 // the same vertex number to the two vertices, freeing up one of the vertices.
904 void med_combine_duplicate_vertices(byte *vlp)
908 for (v=0; v<Highest_vertex_index; v++) // Note: ok to do to <, rather than <= because w for loop starts at v+1
910 vms_vector *vvp = &Vertices[v];
911 for (w=v+1; w<=Highest_vertex_index; w++)
912 if (vlp[w]) { // used to be Vertex_active[w]
913 if (vnear(vvp, &Vertices[w])) {
914 change_vertex_occurrences(v, w);
921 // ------------------------------------------------------------------------------
922 // Compress mine at Segments and Vertices by squeezing out all holes.
923 // If no holes (ie, an unused segment followed by a used segment), then no action.
924 // If Cursegp or Markedsegp is a segment which gets moved to fill in a hole, then
925 // they are properly updated.
926 void med_compress_mine(void)
928 if (Do_duplicate_vertex_check) {
929 med_combine_duplicate_vertices(Vertex_active);
930 Do_duplicate_vertex_check = 0;
937 //--repair-- create_local_segment_data();
939 // This is necessary becuase a segment search (due to click in 3d window) uses the previous frame's
940 // segment information, which could get changed by this.
941 Update_flags = UF_WORLD_CHANGED;
945 // ------------------------------------------------------------------------------------------
946 // Copy texture map ids for each face in sseg to dseg.
947 void copy_tmap_ids(segment *dseg, segment *sseg)
951 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
952 dseg->sides[s].tmap_num = sseg->sides[s].tmap_num;
953 dseg->sides[s].tmap_num2 = 0;
957 // ------------------------------------------------------------------------------------------
958 // Attach a segment with a rotated orientation.
960 // 0 = successful attach
961 // 1 = No room in Segments[].
962 // 2 = No room in Vertices[].
963 // 3 = newside != WFRONT -- for now, the new segment must be attached at its (own) front side
964 // 4 = already a face attached on destseg:destside
965 int med_attach_segment_rotated(segment *destseg, segment *newseg, int destside, int newside,vms_matrix *attmat)
971 vms_matrix rotmat,rotmat1,rotmat2,rotmat3,rotmat4;
972 vms_vector vr,vc,tvs[4],xlate_vec;
974 vms_vector forvec,upvec;
976 // Return if already a face attached on this side.
977 if (IS_CHILD(destseg->children[destside]))
980 segnum = get_free_segment_number();
982 forvec = attmat->fvec;
983 upvec = attmat->uvec;
985 // We are pretty confident we can add the segment.
986 nsp = &Segments[segnum];
987 nsp2 = &Segment2s[segnum];
989 nsp->segnum = segnum;
991 nsp2->matcen_num = -1;
994 nsp->group = destseg->group;
996 // Add segment to proper group list.
998 add_segment_to_group(nsp-Segments, nsp->group);
1000 // Copy the texture map ids.
1001 copy_tmap_ids(nsp,newseg);
1003 // clear all connections
1004 for (side=0; side<MAX_SIDES_PER_SEGMENT; side++) {
1005 nsp->children[side] = -1;
1006 nsp->sides[side].wall_num = -1;
1009 // Form the connection
1010 destseg->children[destside] = segnum;
1011 // destseg->sides[destside].render_flag = 0;
1012 nsp->children[newside] = destseg-Segments;
1014 // Copy vertex indices of the four vertices forming the joint
1015 dvp = Side_to_verts[destside];
1017 // Set the vertex indices for the four vertices forming the front of the new side
1019 nsp->verts[v] = destseg->verts[(int) dvp[v]];
1021 // The other 4 vertices must be created.
1022 // Their coordinates are determined by the 4 welded vertices and the vector from front
1023 // to back of the original *newseg.
1025 // Do lots of hideous matrix stuff, about 3/4 of which could probably be simplified out.
1026 med_extract_matrix_from_segment(destseg,&rotmat); // get orientation matrix for destseg (orthogonal rotation matrix)
1027 set_matrix_based_on_side(&rotmat,destside);
1028 vm_vector_2_matrix(&rotmat1,&forvec,&upvec,NULL);
1029 vm_matrix_x_matrix(&rotmat4,&rotmat,&rotmat1); // this is the desired orientation of the new segment
1030 med_extract_matrix_from_segment(newseg,&rotmat3); // this is the current orientation of the new segment
1031 vm_transpose_matrix(&rotmat3); // get the inverse of the current orientation matrix
1032 vm_matrix_x_matrix(&rotmat2,&rotmat4,&rotmat3); // now rotmat2 takes the current segment to the desired orientation
1034 // Warning -- look at this line!
1035 vm_transpose_matrix(&rotmat2); // added 12:33 pm, 10/01/93
1037 // Compute and rotate the center point of the attaching face.
1038 compute_center_point_on_side(&vc,newseg,newside);
1039 vm_vec_rotate(&vr,&vc,&rotmat2);
1041 // Now rotate the free vertices in the segment
1043 vm_vec_rotate(&tvs[v],&Vertices[newseg->verts[v+4]],&rotmat2);
1045 // Now translate the new segment so that the center point of the attaching faces are the same.
1046 compute_center_point_on_side(&vc,destseg,destside);
1047 vm_vec_sub(&xlate_vec,&vc,&vr);
1049 // Create and add the 4 new vertices.
1050 for (v=0; v<4; v++) {
1051 vm_vec_add2(&tvs[v],&xlate_vec);
1052 nsp->verts[v+4] = med_add_vertex(&tvs[v]);
1055 set_vertex_counts();
1057 // Now all the vertices are in place. Create the faces.
1058 validate_segment(nsp);
1060 // Say to not render at the joint.
1061 // destseg->sides[destside].render_flag = 0;
1062 // nsp->sides[newside].render_flag = 0;
1069 // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
1071 // ------------------------------------------------------------------------------------------
1072 void scale_free_vertices(segment *sp,vms_vector *vp,fix scale_factor,int min_side,int max_side)
1077 verts = Side_to_verts[min_side];
1080 if (is_free_vertex(sp->verts[(int) verts[i]])) {
1081 Vertices[sp->verts[(int) verts[i]]].x = fixmul(vp->x,scale_factor)/2;
1082 Vertices[sp->verts[(int) verts[i]]].y = fixmul(vp->y,scale_factor)/2;
1083 Vertices[sp->verts[(int) verts[i]]].z = fixmul(vp->z,scale_factor)/2;
1086 verts = Side_to_verts[max_side];
1089 if (is_free_vertex(sp->verts[(int) verts[i]])) {
1090 Vertices[sp->verts[(int) verts[i]]].x = fixmul(vp->x,scale_factor)/2;
1091 Vertices[sp->verts[(int) verts[i]]].y = fixmul(vp->y,scale_factor)/2;
1092 Vertices[sp->verts[(int) verts[i]]].z = fixmul(vp->z,scale_factor)/2;
1097 // ------------------------------------------------------------------------------------------
1098 // Attach side newside of newseg to side destside of destseg.
1099 // Copies *newseg into global array Segments, increments Num_segments.
1100 // Forms a weld between the two segments by making the new segment fit to the old segment.
1101 // Updates number of faces per side if necessitated by new vertex coordinates.
1104 // 0 = successful attach
1105 // 1 = No room in Segments[].
1106 // 2 = No room in Vertices[].
1107 // 3 = newside != WFRONT -- for now, the new segment must be attached at its (own) front side
1108 // 4 = already a face attached on side newside
1109 int med_attach_segment(segment *destseg, segment *newseg, int destside, int newside)
1112 segment *ocursegp = Cursegp;
1114 vms_angvec tang = {0,0,0};
1117 vm_angles_2_matrix(&rotmat,&tang);
1118 rval = med_attach_segment_rotated(destseg,newseg,destside,newside,&rotmat);
1119 med_propagate_tmaps_to_segments(ocursegp,Cursegp,0);
1120 med_propagate_tmaps_to_back_side(Cursegp, Side_opposite[newside],0);
1121 copy_uvs_seg_to_seg(&New_segment,Cursegp);
1126 // -------------------------------------------------------------------------------
1127 // Delete a vertex, sort of.
1128 // Decrement the vertex count. If the count goes to 0, then the vertex is free (has been deleted).
1129 void delete_vertex(short v)
1131 Assert(v < MAX_VERTICES); // abort if vertex is not in array Vertices
1132 Assert(Vertex_active[v] >= 1); // abort if trying to delete a non-existent vertex
1137 // -------------------------------------------------------------------------------
1138 // Update Num_vertices.
1139 // This routine should be called by anyone who calls delete_vertex. It could be called in delete_vertex,
1140 // but then it would be called much more often than necessary, and it is a slow routine.
1141 void update_num_vertices(void)
1145 // Now count the number of vertices.
1147 for (v=0; v<=Highest_vertex_index; v++)
1148 if (Vertex_active[v])
1152 // -------------------------------------------------------------------------------
1153 // Set Vertex_active to number of occurrences of each vertex.
1154 // Set Num_vertices.
1155 void set_vertex_counts(void)
1161 for (v=0; v<=Highest_vertex_index; v++)
1162 Vertex_active[v] = 0;
1164 // Count number of occurrences of each vertex.
1165 for (s=0; s<=Highest_segment_index; s++)
1166 if (Segments[s].segnum != -1)
1167 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++) {
1168 if (!Vertex_active[Segments[s].verts[v]])
1170 Vertex_active[Segments[s].verts[v]]++;
1174 // -------------------------------------------------------------------------------
1175 // Delete all vertices in segment *sp from the vertex list if they are not contained in another segment.
1176 // This is kind of a dangerous routine. It modifies the global array Vertex_active, using the field as
1178 void delete_vertices_in_segment(segment *sp)
1184 set_vertex_counts();
1186 // Subtract one count for each appearance of vertex in deleted segment
1187 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
1188 delete_vertex(sp->verts[v]);
1190 update_num_vertices();
1193 extern void validate_segment_side(segment *sp, int sidenum);
1195 // -------------------------------------------------------------------------------
1196 // Delete segment *sp in Segments array.
1198 // 0 successfully deleted.
1199 // 1 unable to delete.
1200 int med_delete_segment(segment *sp)
1205 segnum = sp-Segments;
1207 // Cannot delete segment if only segment.
1208 if (Num_segments == 1)
1211 // Don't try to delete if segment doesn't exist.
1212 if (sp->segnum == -1) {
1213 mprintf((0,"Hey -- you tried to delete a non-existent segment (segnum == -1)\n"));
1217 // Delete its refueling center if it has one
1220 delete_vertices_in_segment(sp);
1224 // If deleted segment has walls on any side, wipe out the wall.
1225 for (side=0; side < MAX_SIDES_PER_SEGMENT; side++)
1226 if (sp->sides[side].wall_num != -1)
1227 wall_remove_side(sp, side);
1229 // Find out what this segment was connected to and break those connections at the other end.
1230 for (side=0; side < MAX_SIDES_PER_SEGMENT; side++)
1231 if (IS_CHILD(sp->children[side])) {
1232 segment *csp; // the connecting segment
1235 csp = &Segments[sp->children[side]];
1236 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
1237 if (csp->children[s] == segnum) {
1238 csp->children[s] = -1; // this is the side of connection, break it
1239 validate_segment_side(csp,s); // we have converted a connection to a side so validate the segment
1240 med_propagate_tmaps_to_back_side(csp,s,0);
1243 med_create_new_segment_from_cursegp();
1244 copy_uvs_seg_to_seg(&New_segment,Cursegp);
1247 sp->segnum = -1; // Mark segment as inactive.
1249 // If deleted segment = marked segment, then say there is no marked segment
1250 if (sp == Markedsegp)
1253 // If deleted segment = a Group segment ptr, then wipe it out.
1254 for (s=0;s<num_groups;s++)
1255 if (sp == Groupsegp[s])
1258 // If deleted segment = group segment, wipe it off the group list.
1260 delete_segment_from_group(sp-Segments, sp->group);
1262 // If we deleted something which was not connected to anything, must now select a new current segment.
1264 for (s=0; s<MAX_SEGMENTS; s++)
1265 if ((Segments[s].segnum != -1) && (s!=segnum) ) {
1266 Cursegp = &Segments[s];
1267 med_create_new_segment_from_cursegp();
1271 // If deleted segment contains objects, wipe out all objects
1272 if (sp->objects != -1) {
1273 // if (objnum == Objects[objnum].next) {
1274 // mprintf((0, "Warning -- object #%i points to itself. Setting next to -1.\n", objnum));
1275 // Objects[objnum].next = -1;
1277 for (objnum=sp->objects;objnum!=-1;objnum=Objects[objnum].next) {
1279 //if an object is in the seg, delete it
1280 //if the object is the player, move to new curseg
1282 if (objnum == (ConsoleObject-Objects)) {
1283 compute_segment_center(&ConsoleObject->pos,Cursegp);
1284 obj_relink(objnum,Cursegp-Segments);
1290 // Make sure everything deleted ok...
1291 Assert( sp->objects==-1 );
1293 // If we are leaving many holes in Segments or Vertices, then compress mine, because it is inefficient to be that way
1294 // if ((Highest_segment_index > Num_segments+4) || (Highest_vertex_index > Num_vertices+4*8))
1295 // med_compress_mine();
1300 // ------------------------------------------------------------------------------------------
1301 // Copy texture maps from sseg to dseg
1302 void copy_tmaps_to_segment(segment *dseg, segment *sseg)
1306 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
1307 dseg->sides[s].type = sseg->sides[s].type;
1308 dseg->sides[s].tmap_num = sseg->sides[s].tmap_num;
1309 dseg->sides[s].tmap_num2 = sseg->sides[s].tmap_num2;
1314 // ------------------------------------------------------------------------------------------
1315 // Rotate the segment *seg by the pitch, bank, heading defined by *rot, destructively
1316 // modifying its four free vertices in the global array Vertices.
1317 // It is illegal to rotate a segment which has connectivity != 1.
1318 // Pitch, bank, heading are about the point which is the average of the four points
1319 // forming the side of connection.
1321 // 0 = successful rotation
1322 // 1 = Connectivity makes rotation illegal (connected to 0 or 2+ segments)
1323 // 2 = Rotation causes degeneracy, such as self-intersecting segment.
1324 // 3 = Unable to rotate because not connected to exactly 1 segment.
1325 int med_rotate_segment(segment *seg, vms_matrix *rotmat)
1328 int newside=0,destside,s;
1330 int back_side,side_tmaps[MAX_SIDES_PER_SEGMENT];
1332 // Find side of attachment
1334 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
1335 if (IS_CHILD(seg->children[s])) {
1340 // Return if passed in segment is connected to other than 1 segment.
1344 destseg = &Segments[seg->children[newside]];
1347 while ((destseg->children[destside] != seg-Segments) && (destside < MAX_SIDES_PER_SEGMENT))
1350 // Before deleting the segment, copy its texture maps to New_segment
1351 copy_tmaps_to_segment(&New_segment,seg);
1353 if (med_delete_segment(seg))
1354 mprintf((0,"Error in rotation: Unable to delete segment %i\n",seg-Segments));
1356 if (Curside == WFRONT)
1359 med_attach_segment_rotated(destseg,&New_segment,destside,AttachSide,rotmat);
1361 // Save tmap_num on each side to restore after call to med_propagate_tmaps_to_segments and _back_side
1362 // which will change the tmap nums.
1363 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
1364 side_tmaps[s] = seg->sides[s].tmap_num;
1366 back_side = Side_opposite[find_connect_side(destseg, seg)];
1368 med_propagate_tmaps_to_segments(destseg, seg,0);
1369 med_propagate_tmaps_to_back_side(seg, back_side,0);
1371 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
1373 seg->sides[s].tmap_num = side_tmaps[s];
1378 // ----------------------------------------------------------------------------------------
1379 int med_rotate_segment_ang(segment *seg, vms_angvec *ang)
1383 return med_rotate_segment(seg,vm_angles_2_matrix(&rotmat,ang));
1386 // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
1388 // ----------------------------------------------------------------------------
1389 // Compute the sum of the distances between the four pairs of points.
1390 // The connections are:
1391 // firstv1 : 0 (firstv1+1)%4 : 1 (firstv1+2)%4 : 2 (firstv1+3)%4 : 3
1392 fix seg_seg_vertex_distsum(segment *seg1, int side1, segment *seg2, int side2, int firstv1)
1398 for (secondv=0; secondv<4; secondv++) {
1401 firstv = (4-secondv + (3 - firstv1)) % 4;
1402 distsum += vm_vec_dist(&Vertices[seg1->verts[Side_to_verts[side1][firstv]]],&Vertices[seg2->verts[Side_to_verts[side2][secondv]]]);
1409 // ----------------------------------------------------------------------------
1410 // Determine how to connect two segments together with the least amount of twisting.
1411 // Returns vertex index in 0..3 on first segment. Assumed ordering of vertices
1412 // on second segment is 0,1,2,3.
1413 // So, if return value is 2, connect 2:0 3:1 0:2 1:3.
1415 // We select an ordering of vertices for connection. For the first pair of vertices to be connected,
1416 // compute the vector. For the three remaining pairs of vertices, compute the vectors from one vertex
1417 // to the other. Compute the dot products of these vectors with the original vector. Add them up.
1418 // The close we are to 3, the better fit we have. Reason: The largest value for the dot product is
1419 // 1.0, and this occurs for a parallel set of vectors.
1420 int get_index_of_best_fit(segment *seg1, int side1, segment *seg2, int side2)
1426 min_distance = F1_0*30000;
1428 for (firstv=0; firstv<4; firstv++) {
1430 t = seg_seg_vertex_distsum(seg1, side1, seg2, side2, firstv);
1431 if (t <= min_distance) {
1433 best_index = firstv;
1442 #define MAX_VALIDATIONS 50
1444 // ----------------------------------------------------------------------------
1445 // Remap uv coordinates in all sides in segment *sp which have a vertex in vp[4].
1446 // vp contains absolute vertex indices.
1447 void remap_side_uvs(segment *sp,int *vp)
1451 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
1453 for (i=0; i<4; i++) // scan each vertex in vp[4]
1454 if (Side_to_verts[s][v] == vp[i]) {
1455 assign_default_uvs_to_side(sp,s); // Side s needs to be remapped
1462 // ----------------------------------------------------------------------------
1463 // Assign default uv coordinates to Curside.
1464 void assign_default_uvs_to_curside(void)
1466 assign_default_uvs_to_side(Cursegp, Curside);
1469 // ----------------------------------------------------------------------------
1470 // Assign default uv coordinates to all sides in Curside.
1471 void assign_default_uvs_to_curseg(void)
1475 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
1476 assign_default_uvs_to_side(Cursegp,s); // Side s needs to be remapped
1479 // ----------------------------------------------------------------------------
1480 // Modify seg2 to share side2 with seg1:side1. This forms a connection between
1481 // two segments without creating a new segment. It modifies seg2 by sharing
1482 // vertices from seg1. seg1 is not modified. Four vertices from seg2 are
1486 // 1 -- no, this is legal! -- unable to form joint because one or more vertices of side2 is not free
1487 // 2 unable to form joint because side1 is already used
1488 int med_form_joint(segment *seg1, int side1, segment *seg2, int side2)
1491 int bfi,v,s,sv,s1,nv;
1492 int lost_vertices[4],remap_vertices[4];
1493 int validation_list[MAX_VALIDATIONS];
1495 // Make sure that neither side is connected.
1496 if (IS_CHILD(seg1->children[side1]) || IS_CHILD(seg2->children[side2]))
1499 // Make sure there is no wall there
1500 if ((seg1->sides[side1].wall_num != -1) || (seg2->sides[side2].wall_num != -1))
1503 // We can form the joint. Find the best orientation of vertices.
1504 bfi = get_index_of_best_fit(seg1, side1, seg2, side2);
1506 vp1 = Side_to_verts[side1];
1507 vp2 = Side_to_verts[side2];
1509 // Make a copy of the list of vertices in seg2 which will be deleted and set the
1510 // associated vertex number, so that all occurrences of the vertices can be replaced.
1512 lost_vertices[v] = seg2->verts[(int) vp2[v]];
1514 // Now, for each vertex in lost_vertices, determine which vertex it maps to.
1516 remap_vertices[3 - ((v + bfi) % 4)] = seg1->verts[(int) vp1[v]];
1518 // Now, in all segments, replace all occurrences of vertices in lost_vertices with remap_vertices
1520 // Put the one segment we know are being modified into the validation list.
1521 // Note: seg1 does not require a full validation, only a validation of the affected side. Its vertices do not move.
1523 validation_list[0] = seg2 - Segments;
1526 for (s=0; s<=Highest_segment_index; s++)
1527 if (Segments[s].segnum != -1)
1528 for (sv=0; sv<MAX_VERTICES_PER_SEGMENT; sv++)
1529 if (Segments[s].verts[sv] == lost_vertices[v]) {
1530 Segments[s].verts[sv] = remap_vertices[v];
1531 // Add segment to list of segments to be validated.
1532 for (s1=0; s1<nv; s1++)
1533 if (validation_list[s1] == s)
1536 validation_list[nv++] = s;
1537 Assert(nv < MAX_VALIDATIONS);
1540 // Form new connections.
1541 seg1->children[side1] = seg2 - Segments;
1542 seg2->children[side2] = seg1 - Segments;
1544 // validate all segments
1545 validate_segment_side(seg1,side1);
1546 for (s=0; s<nv; s++) {
1547 validate_segment(&Segments[validation_list[s]]);
1548 remap_side_uvs(&Segments[validation_list[s]],remap_vertices); // remap uv coordinates on sides which were reshaped (ie, have a vertex in lost_vertices)
1549 warn_if_concave_segment(&Segments[validation_list[s]]);
1552 set_vertex_counts();
1554 // Make sure connection is open, ie renderable.
1555 // seg1->sides[side1].render_flag = 0;
1556 // seg2->sides[side2].render_flag = 0;
1558 //--// debug -- check all segments, make sure if a children[s] == -1, then side[s].num_faces != 0
1561 //--for (seg=0; seg<MAX_SEGMENTS; seg++)
1562 //-- if (Segments[seg].segnum != -1)
1563 //-- for (side=0; side<MAX_SIDES_PER_SEGMENT; side++)
1564 //-- if (Segments[seg].children[side] == -1) {
1565 //-- if (Segments[seg].sides[side].num_faces == 0) {
1566 //-- mprintf((0,"Error: Segment %i, side %i is not connected, but has 0 faces.\n",seg,side));
1569 //-- } else if (Segments[seg].sides[side].num_faces != 0) {
1570 //-- mprintf((0,"Error: Segment %i, side %i is connected, but has %i faces.\n",seg,side,Segments[seg].sides[side].num_faces));
1578 // ----------------------------------------------------------------------------
1579 // Create a new segment and use it to form a bridge between two existing segments.
1580 // Specify two segment:side pairs. If either segment:side is not open (ie, segment->children[side] != -1)
1581 // then it is not legal to form the brider.
1583 // 0 bridge segment formed
1584 // 1 unable to form bridge because one (or both) of the sides is not open.
1585 // Note that no new vertices are created by this process.
1586 int med_form_bridge_segment(segment *seg1, int side1, segment *seg2, int side2)
1592 if (IS_CHILD(seg1->children[side1]) || IS_CHILD(seg2->children[side2]))
1595 bs = &Segments[get_free_segment_number()];
1596 // mprintf((0,"Forming bridge segment %i from %i to %i\n",bs-Segments,seg1-Segments,seg2-Segments));
1598 bs->segnum = bs-Segments;
1601 // Copy vertices from seg2 into last 4 vertices of bridge segment.
1602 sv = Side_to_verts[side2];
1604 bs->verts[(3-v)+4] = seg2->verts[(int) sv[v]];
1606 // Copy vertices from seg1 into first 4 vertices of bridge segment.
1607 bfi = get_index_of_best_fit(seg1, side1, seg2, side2);
1609 sv = Side_to_verts[side1];
1611 bs->verts[(v + bfi) % 4] = seg1->verts[(int) sv[v]];
1613 // Form connections to children, first initialize all to unconnected.
1614 for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) {
1615 bs->children[i] = -1;
1616 bs->sides[i].wall_num = -1;
1619 // Now form connections between segments.
1621 bs->children[AttachSide] = seg1 - Segments;
1622 bs->children[(int) Side_opposite[AttachSide]] = seg2 - Segments;
1624 seg1->children[side1] = bs-Segments; //seg2 - Segments;
1625 seg2->children[side2] = bs-Segments; //seg1 - Segments;
1627 // Validate bridge segment, and if degenerate, clean up mess.
1628 Degenerate_segment_found = 0;
1630 validate_segment(bs);
1632 if (Degenerate_segment_found) {
1633 seg1->children[side1] = -1;
1634 seg2->children[side2] = -1;
1635 bs->children[AttachSide] = -1;
1636 bs->children[(int) Side_opposite[AttachSide]] = -1;
1637 if (med_delete_segment(bs)) {
1638 mprintf((0, "Oops, tried to delete bridge segment (because it's degenerate), but couldn't.\n"));
1641 editor_status("Bridge segment would be degenerate, not created.\n");
1644 validate_segment(seg1); // used to only validate side, but segment does more error checking: ,side1);
1645 validate_segment(seg2); // ,side2);
1646 med_propagate_tmaps_to_segments(seg1,bs,0);
1648 editor_status("Bridge segment formed.");
1649 warn_if_concave_segment(bs);
1654 // -------------------------------------------------------------------------------
1655 // Create a segment given center, dimensions, rotation matrix.
1656 // Note that the created segment will always have planar sides and rectangular cross sections.
1657 // It will be created with walls on all sides, ie not connected to anything.
1658 void med_create_segment(segment *sp,fix cx, fix cy, fix cz, fix length, fix width, fix height, vms_matrix *mp)
1661 vms_vector v0,v1,cv;
1666 sp->segnum = 1; // What to put here? I don't know.
1667 sp2 = &Segment2s[sp->segnum];
1669 // Form connections to children, of which it has none.
1670 for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) {
1671 sp->children[i] = -1;
1672 // sp->sides[i].render_flag = 0;
1673 sp->sides[i].wall_num = -1;
1677 sp2->matcen_num = -1;
1679 // Create relative-to-center vertices, which are the rotated points on the box defined by length, width, height
1680 sp->verts[0] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,+width/2,+height/2,-length/2),mp));
1681 sp->verts[1] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,+width/2,-height/2,-length/2),mp));
1682 sp->verts[2] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,-width/2,-height/2,-length/2),mp));
1683 sp->verts[3] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,-width/2,+height/2,-length/2),mp));
1684 sp->verts[4] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,+width/2,+height/2,+length/2),mp));
1685 sp->verts[5] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,+width/2,-height/2,+length/2),mp));
1686 sp->verts[6] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,-width/2,-height/2,+length/2),mp));
1687 sp->verts[7] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,-width/2,+height/2,+length/2),mp));
1689 // Now create the vector which is the center of the segment and add that to all vertices.
1690 while (!vm_vec_make(&cv,cx,cy,cz));
1692 // Now, add the center to all vertices, placing the segment in 3 space.
1693 for (i=0; i<MAX_VERTICES_PER_SEGMENT; i++)
1694 vm_vec_add(&Vertices[sp->verts[i]],&Vertices[sp->verts[i]],&cv);
1696 // Set scale vector.
1697 // sp->scale.x = width;
1698 // sp->scale.y = height;
1699 // sp->scale.z = length;
1701 // Add faces to all sides.
1702 for (f=0; f<MAX_SIDES_PER_SEGMENT; f++)
1703 create_walls_on_side(sp,f);
1705 sp->objects = -1; //no objects in this segment
1707 // Assume nothing special about this segment
1710 sp2->static_light = 0;
1711 sp2->matcen_num = -1;
1713 copy_tmaps_to_segment(sp, &New_segment);
1715 assign_default_uvs_to_segment(sp);
1718 // ----------------------------------------------------------------------------------------------
1719 // Create New_segment using a specified scale factor.
1720 void med_create_new_segment(vms_vector *scale)
1724 segment *sp = &New_segment;
1727 fix length,width,height;
1733 sp->segnum = 1; // What to put here? I don't know.
1734 sp2 = &Segment2s[sp->segnum];
1736 // Create relative-to-center vertices, which are the points on the box defined by length, width, height
1738 sp->verts[0] = med_set_vertex(NEW_SEGMENT_VERTICES+0,vm_vec_make(&v0,+width/2,+height/2,-length/2));
1739 sp->verts[1] = med_set_vertex(NEW_SEGMENT_VERTICES+1,vm_vec_make(&v0,+width/2,-height/2,-length/2));
1740 sp->verts[2] = med_set_vertex(NEW_SEGMENT_VERTICES+2,vm_vec_make(&v0,-width/2,-height/2,-length/2));
1741 sp->verts[3] = med_set_vertex(NEW_SEGMENT_VERTICES+3,vm_vec_make(&v0,-width/2,+height/2,-length/2));
1742 sp->verts[4] = med_set_vertex(NEW_SEGMENT_VERTICES+4,vm_vec_make(&v0,+width/2,+height/2,+length/2));
1743 sp->verts[5] = med_set_vertex(NEW_SEGMENT_VERTICES+5,vm_vec_make(&v0,+width/2,-height/2,+length/2));
1744 sp->verts[6] = med_set_vertex(NEW_SEGMENT_VERTICES+6,vm_vec_make(&v0,-width/2,-height/2,+length/2));
1745 sp->verts[7] = med_set_vertex(NEW_SEGMENT_VERTICES+7,vm_vec_make(&v0,-width/2,+height/2,+length/2));
1748 // sp->scale = *scale;
1750 // Form connections to children, of which it has none, init faces and tmaps.
1751 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
1752 sp->children[s] = -1;
1753 // sp->sides[s].render_flag = 0;
1754 sp->sides[s].wall_num = -1;
1755 create_walls_on_side(sp,s);
1756 sp->sides[s].tmap_num = s; // assign some stupid old tmap to this side.
1757 sp->sides[s].tmap_num2 = 0;
1760 Seg_orientation.p = 0; Seg_orientation.b = 0; Seg_orientation.h = 0;
1762 sp->objects = -1; //no objects in this segment
1764 assign_default_uvs_to_segment(sp);
1766 // Assume nothing special about this segment
1769 sp2->static_light = 0;
1770 sp2->matcen_num = -1;
1773 // -------------------------------------------------------------------------------
1774 void med_create_new_segment_from_cursegp(void)
1776 vms_vector scalevec;
1777 vms_vector uvec, rvec, fvec;
1779 med_extract_up_vector_from_segment_side(Cursegp, Curside, &uvec);
1780 med_extract_right_vector_from_segment_side(Cursegp, Curside, &rvec);
1781 extract_forward_vector_from_segment(Cursegp, &fvec);
1783 scalevec.x = vm_vec_mag(&rvec);
1784 scalevec.y = vm_vec_mag(&uvec);
1785 scalevec.z = vm_vec_mag(&fvec);
1787 med_create_new_segment(&scalevec);
1790 // -------------------------------------------------------------------------------
1791 // Initialize all vertices to inactive status.
1792 void init_all_vertices(void)
1797 for (v=0; v<MAX_SEGMENT_VERTICES; v++)
1798 Vertex_active[v] = 0;
1800 for (s=0; s<MAX_SEGMENTS; s++)
1801 Segments[s].segnum = -1;
1805 // --------------------------------------------------------------------------------------
1806 // Create a new mine, set global variables.
1807 int create_new_mine(void)
1811 vms_matrix m1 = IDENTITY_MATRIX;
1813 // initialize_mine_arrays();
1815 // gamestate_not_restored = 1;
1817 // Clear refueling center code
1821 init_all_vertices();
1823 Current_level_num = 0; //0 means not a real level
1824 Current_level_name[0] = 0;
1826 Cur_object_index = -1;
1827 reset_objects(1); //just one object, the player
1832 Num_vertices = 0; // Number of vertices in global array.
1833 Num_segments = 0; // Number of segments in global array, will get increased in med_create_segment
1834 Cursegp = Segments; // Say current segment is the only segment.
1835 Curside = WBACK; // The active side is the back side
1836 Markedsegp = 0; // Say there is no marked segment.
1837 Markedside = WBACK; // Shouldn't matter since Markedsegp == 0, but just in case...
1838 for (s=0;s<MAX_GROUPS+1;s++) {
1839 GroupList[s].num_segments = 0;
1840 GroupList[s].num_vertices = 0;
1841 Groupsegp[s] = NULL;
1845 Num_robot_centers = 0;
1850 // Create New_segment, which is the segment we will be adding at each instance.
1851 med_create_new_segment(vm_vec_make(&sizevec,DEFAULT_X_SIZE,DEFAULT_Y_SIZE,DEFAULT_Z_SIZE)); // New_segment = Segments[0];
1852 // 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));
1853 med_create_segment(Segments,0,0,0,DEFAULT_X_SIZE,DEFAULT_Y_SIZE,DEFAULT_Z_SIZE,&m1);
1856 N_selected_segs = 0;
1859 //--repair-- create_local_segment_data();
1861 ControlCenterTriggers.num_links = 0;
1863 //editor_status("New mine created.");
1864 return 0; // say no error
1867 // --------------------------------------------------------------------------------------------------
1868 // Copy a segment from *ssp to *dsp. Do not simply copy the struct. Use *dsp's vertices, copying in
1869 // just the values, not the indices.
1870 void med_copy_segment(segment *dsp,segment *ssp)
1873 int verts_copy[MAX_VERTICES_PER_SEGMENT];
1875 // First make a copy of the vertex list.
1876 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
1877 verts_copy[v] = dsp->verts[v];
1879 // Now copy the whole struct.
1882 // Now restore the vertex indices.
1883 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
1884 dsp->verts[v] = verts_copy[v];
1886 // Now destructively modify the vertex values for all vertex indices.
1887 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
1888 Vertices[dsp->verts[v]] = Vertices[ssp->verts[v]];
1891 // -----------------------------------------------------------------------------
1892 // Create coordinate axes in orientation of specified segment, stores vertices at *vp.
1893 void create_coordinate_axes_from_segment(segment *sp,short *vertnums)
1898 med_extract_matrix_from_segment(sp,&rotmat);
1900 compute_segment_center(&Vertices[vertnums[0]],sp);
1903 vm_vec_scale(&t,i2f(32));
1904 vm_vec_add(&Vertices[vertnums[1]],&Vertices[vertnums[0]],&t);
1907 vm_vec_scale(&t,i2f(32));
1908 vm_vec_add(&Vertices[vertnums[2]],&Vertices[vertnums[0]],&t);
1911 vm_vec_scale(&t,i2f(32));
1912 vm_vec_add(&Vertices[vertnums[3]],&Vertices[vertnums[0]],&t);
1915 // -----------------------------------------------------------------------------
1916 // Determine if a segment is concave. Returns true if concave
1917 int check_seg_concavity(segment *s)
1922 for (sn=0;sn<MAX_SIDES_PER_SEGMENT;sn++)
1923 for (vn=0;vn<=4;vn++) {
1926 &Vertices[s->verts[Side_to_verts[sn][vn%4]]],
1927 &Vertices[s->verts[Side_to_verts[sn][(vn+1)%4]]],
1928 &Vertices[s->verts[Side_to_verts[sn][(vn+2)%4]]]);
1930 //vm_vec_normalize(&n1);
1932 if (vn>0) if (vm_vec_dotprod(&n0,&n1) < f0_5) return 1;
1941 // -----------------------------------------------------------------------------
1942 // Find all concave segments and add to list
1943 void find_concave_segs()
1950 for (s=Segments,i=Highest_segment_index;i>=0;s++,i--)
1951 if (s->segnum != -1)
1952 if (check_seg_concavity(s)) Warning_segs[N_warning_segs++]=SEG_PTR_2_NUM(s);
1958 // -----------------------------------------------------------------------------
1959 void warn_if_concave_segments(void)
1963 find_concave_segs();
1965 if (N_warning_segs) {
1966 editor_status("*** WARNING *** %d concave segments in mine! *** WARNING ***",N_warning_segs);
1967 sprintf( temp, "%d", N_warning_segs );
1971 // -----------------------------------------------------------------------------
1972 // Check segment s, if concave, warn
1973 void warn_if_concave_segment(segment *s)
1978 result = check_seg_concavity(s);
1981 Warning_segs[N_warning_segs++] = s-Segments;
1983 if (N_warning_segs) {
1984 editor_status("*** WARNING *** New segment is concave! *** WARNING ***");
1985 sprintf( temp, "%d", N_warning_segs );
1988 // editor_status("");
1990 //editor_status("");
1994 // -------------------------------------------------------------------------------
1995 // Find segment adjacent to sp:side.
1996 // Adjacent means a segment which shares all four vertices.
1997 // Return true if segment found and fill in segment in adj_sp and side in adj_side.
1998 // Return false if unable to find, in which case adj_sp and adj_side are undefined.
1999 int med_find_adjacent_segment_side(segment *sp, int side, segment **adj_sp, int *adj_side)
2004 // Stuff abs_verts[4] array with absolute vertex indices
2006 abs_verts[v] = sp->verts[Side_to_verts[side][v]];
2008 // Scan all segments, looking for a segment which contains the four abs_verts
2009 for (seg=0; seg<=Highest_segment_index; seg++) {
2010 if (seg != sp-Segments) {
2011 for (v=0; v<4; v++) { // do for each vertex in abs_verts
2012 for (vv=0; vv<MAX_VERTICES_PER_SEGMENT; vv++) // do for each vertex in segment
2013 if (abs_verts[v] == Segments[seg].verts[vv])
2014 goto fass_found1; // Current vertex (indexed by v) is present in segment, try next
2015 goto fass_next_seg; // This segment doesn't contain the vertex indexed by v
2019 // All four vertices in sp:side are present in segment seg.
2020 // Determine side and return
2021 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
2022 for (v=0; v<4; v++) {
2023 for (vv=0; vv<4; vv++) {
2024 if (Segments[seg].verts[Side_to_verts[s][v]] == abs_verts[vv])
2027 goto fass_next_side; // Couldn't find vertex v in current side, so try next side.
2030 // Found all four vertices in current side. We are done!
2031 *adj_sp = &Segments[seg];
2036 Assert(0); // Impossible -- we identified this segment as containing all 4 vertices of side "side", but we couldn't find them.
2046 #define JOINT_THRESHOLD 10000*F1_0 // (Huge threshold)
2048 // -------------------------------------------------------------------------------
2049 // Find segment closest to sp:side.
2050 // Return true if segment found and fill in segment in adj_sp and side in adj_side.
2051 // Return false if unable to find, in which case adj_sp and adj_side are undefined.
2052 int med_find_closest_threshold_segment_side(segment *sp, int side, segment **adj_sp, int *adj_side, fix threshold)
2055 vms_vector vsc, vtc; // original segment center, test segment center
2056 fix current_dist, closest_seg_dist;
2058 if (IS_CHILD(sp->children[side]))
2061 compute_center_point_on_side(&vsc, sp, side);
2063 closest_seg_dist = JOINT_THRESHOLD;
2065 // Scan all segments, looking for a segment which contains the four abs_verts
2066 for (seg=0; seg<=Highest_segment_index; seg++)
2067 if (seg != sp-Segments)
2068 for (s=0;s<MAX_SIDES_PER_SEGMENT;s++) {
2069 if (!IS_CHILD(Segments[seg].children[s])) {
2070 compute_center_point_on_side(&vtc, &Segments[seg], s);
2071 current_dist = vm_vec_dist( &vsc, &vtc );
2072 if (current_dist < closest_seg_dist) {
2073 *adj_sp = &Segments[seg];
2075 closest_seg_dist = current_dist;
2080 if (closest_seg_dist < threshold)
2088 void med_check_all_vertices()
2096 for (s=0; s<Num_segments; s++) {
2098 if (sp->segnum != -1)
2099 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
2100 Assert(sp->verts[v] <= Highest_vertex_index);
2106 // -----------------------------------------------------------------------------------------------------
2107 void check_for_overlapping_segment(int segnum)
2111 vms_vector segcenter;
2113 compute_segment_center(&segcenter, &Segments[segnum]);
2115 for (i=0;i<=Highest_segment_index; i++) {
2117 masks = get_seg_masks(&segcenter, i, 0);
2118 if (masks.centermask == 0) {
2119 mprintf((0, "Segment %i center is contained in segment %i\n", segnum, i));
2123 for (v=0; v<8; v++) {
2124 vms_vector pdel, presult;
2126 vm_vec_sub(&pdel, &Vertices[Segments[segnum].verts[v]], &segcenter);
2127 vm_vec_scale_add(&presult, &segcenter, &pdel, (F1_0*15)/16);
2128 masks = get_seg_masks(&presult, i, 0);
2129 if (masks.centermask == 0) {
2130 mprintf((0, "Segment %i near vertex %i is contained in segment %i\n", segnum, v, i));
2139 // -----------------------------------------------------------------------------------------------------
2140 // Check for overlapping segments.
2141 void check_for_overlapping_segments(void)
2145 med_compress_mine();
2147 for (i=0; i<=Highest_segment_index; i++) {
2149 check_for_overlapping_segment(i);
2152 mprintf((0, "\nDone!\n"));