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 $
18 * $Date: 2004-12-19 11:00:32 $
20 * Interrogation functions for segment data structure.
22 * $Log: not supported by cvs2svn $
23 * Revision 1.2 2004/08/29 14:03:51 schaffner
24 * move more old change logs into ChangeLog-old
26 * Revision 1.1 2001/10/25 02:27:17 bradleyb
27 * attempt at support for editor, makefile changes, etc
29 * Revision 1.2 1999/09/02 13:37:06 sekmu
30 * remove warning in editor compile
32 * Revision 1.1.1.1 1999/06/14 22:04:21 donut
33 * Import of d1x 1.37 source.
52 // #include "segment2.h"
71 int Do_duplicate_vertex_check = 0; // Gets set to 1 in med_create_duplicate_vertex, means to check for duplicate vertices in compress_mine
73 #define BOTTOM_STUFF 0
75 // Remap all vertices in polygons in a segment through translation table xlate_verts.
77 void remap_vertices(segment *segp, int *xlate_verts)
79 int sidenum, facenum, polynum, v;
81 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++)
82 for (facenum=0; facenum<segp->sides[sidenum].num_faces; facenum++)
83 for (polynum=0; polynum<segp->sides[sidenum].faces[facenum].num_polys; polynum++) {
84 poly *pp = &segp->sides[sidenum].faces[facenum].polys[polynum];
85 for (v=0; v<pp->num_vertices; v++)
86 pp->verts[v] = xlate_verts[pp->verts[v]];
90 // Copy everything from sourceside to destside except sourceside->faces[xx].polys[xx].verts
91 void copy_side_except_vertex_ids(side *destside, side *sourceside)
93 int facenum, polynum, v;
95 destside->num_faces = sourceside->num_faces;
96 destside->tri_edge = sourceside->tri_edge;
97 destside->wall_num = sourceside->wall_num;
99 for (facenum=0; facenum<sourceside->num_faces; facenum++) {
100 face *destface = &destside->faces[facenum];
101 face *sourceface = &sourceside->faces[facenum];
103 destface->num_polys = sourceface->num_polys;
104 destface->normal = sourceface->normal;
106 for (polynum=0; polynum<sourceface->num_polys; polynum++) {
107 poly *destpoly = &destface->polys[polynum];
108 poly *sourcepoly = &sourceface->polys[polynum];
110 destpoly->num_vertices = sourcepoly->num_vertices;
111 destpoly->face_type = sourcepoly->face_type;
112 destpoly->tmap_num = sourcepoly->tmap_num;
113 destpoly->tmap_num2 = sourcepoly->tmap_num2;
115 for (v=0; v<sourcepoly->num_vertices; v++)
116 destpoly->uvls[v] = sourcepoly->uvls[v];
122 // [side] [index] [cur:next]
123 // To remap the vertices on a side after a forward rotation
124 sbyte xlate_previous[6][4][2] = {
125 { {7, 3}, {3, 2}, {2, 6}, {6, 7} }, // remapping left to left
126 { {5, 4}, {4, 0}, {7, 3}, {6, 7} }, // remapping back to top
127 { {5, 4}, {1, 5}, {0, 1}, {4, 0} }, // remapping right to right
128 { {0, 1}, {1, 5}, {2, 6}, {3, 2} }, // remapping front to bottom
129 { {1, 5}, {5, 4}, {6, 7}, {2, 6} }, // remapping bottom to back
130 { {4, 0}, {0, 1}, {3, 2}, {7, 3} }, // remapping top to front
133 void remap_vertices_previous(segment *segp, int sidenum)
135 int v, w, facenum, polynum;
137 for (facenum=0; facenum<segp->sides[sidenum].num_faces; facenum++) {
138 for (polynum=0; polynum<segp->sides[sidenum].faces[facenum].num_polys; polynum++) {
139 poly *pp = &segp->sides[sidenum].faces[facenum].polys[polynum];
141 for (v=0; v<pp->num_vertices; v++) {
142 for (w=0; w<4; w++) {
143 if (pp->verts[v] == xlate_previous[sidenum][w][0]) {
144 pp->verts[v] = xlate_previous[sidenum][w][1];
148 Assert(w<4); // If w == 4, then didn't find current vertex in list, which means xlate_previous table is bogus
154 sbyte xlate_previous_right[6][4][2] = {
155 { {5, 6}, {6, 7}, {2, 3}, {1, 2} }, // bottom to left
156 { {6, 7}, {7, 4}, {3, 0}, {2, 3} }, // left to top
157 { {7, 4}, {4, 5}, {0, 1}, {3, 0} }, // top to right
158 { {4, 5}, {5, 6}, {1, 2}, {0, 1} }, // right to bottom
159 { {6, 7}, {5, 6}, {4, 5}, {7, 4} }, // back to back
160 { {3, 2}, {0, 3}, {1, 0}, {2, 1} }, // front to front
163 void remap_vertices_previous_right(segment *segp, int sidenum)
165 int v, w, facenum, polynum;
167 for (facenum=0; facenum<segp->sides[sidenum].num_faces; facenum++) {
168 for (polynum=0; polynum<segp->sides[sidenum].faces[facenum].num_polys; polynum++) {
169 poly *pp = &segp->sides[sidenum].faces[facenum].polys[polynum];
171 for (v=0; v<pp->num_vertices; v++) {
172 for (w=0; w<4; w++) {
173 if (pp->verts[v] == xlate_previous_right[sidenum][w][0]) {
174 pp->verts[v] = xlate_previous_right[sidenum][w][1];
178 Assert(w<4); // If w == 4, then didn't find current vertex in list, which means xlate_previous table is bogus
185 // -----------------------------------------------------------------------------------
186 // Takes top to front
187 void med_rotate_segment_forward(segment *segp)
194 seg_copy.verts[0] = segp->verts[4];
195 seg_copy.verts[1] = segp->verts[0];
196 seg_copy.verts[2] = segp->verts[3];
197 seg_copy.verts[3] = segp->verts[7];
198 seg_copy.verts[4] = segp->verts[5];
199 seg_copy.verts[5] = segp->verts[1];
200 seg_copy.verts[6] = segp->verts[2];
201 seg_copy.verts[7] = segp->verts[6];
203 seg_copy.children[WFRONT] = segp->children[WTOP];
204 seg_copy.children[WTOP] = segp->children[WBACK];
205 seg_copy.children[WBACK] = segp->children[WBOTTOM];
206 seg_copy.children[WBOTTOM] = segp->children[WFRONT];
208 seg_copy.sides[WFRONT] = segp->sides[WTOP];
209 seg_copy.sides[WTOP] = segp->sides[WBACK];
210 seg_copy.sides[WBACK] = segp->sides[WBOTTOM];
211 seg_copy.sides[WBOTTOM] = segp->sides[WFRONT];
214 remap_vertices_previous(&seg_copy, i);
219 // -----------------------------------------------------------------------------------
220 // Takes top to right
221 void med_rotate_segment_right(segment *segp)
228 seg_copy.verts[4] = segp->verts[7];
229 seg_copy.verts[5] = segp->verts[4];
230 seg_copy.verts[1] = segp->verts[0];
231 seg_copy.verts[0] = segp->verts[3];
232 seg_copy.verts[3] = segp->verts[2];
233 seg_copy.verts[2] = segp->verts[1];
234 seg_copy.verts[6] = segp->verts[5];
235 seg_copy.verts[7] = segp->verts[6];
237 seg_copy.children[WRIGHT] = segp->children[WTOP];
238 seg_copy.children[WBOTTOM] = segp->children[WRIGHT];
239 seg_copy.children[WLEFT] = segp->children[WBOTTOM];
240 seg_copy.children[WTOP] = segp->children[WLEFT];
242 seg_copy.sides[WRIGHT] = segp->sides[WTOP];
243 seg_copy.sides[WBOTTOM] = segp->sides[WRIGHT];
244 seg_copy.sides[WLEFT] = segp->sides[WBOTTOM];
245 seg_copy.sides[WTOP] = segp->sides[WLEFT];
248 remap_vertices_previous_right(&seg_copy, i);
253 void make_curside_bottom_side(void)
256 case WRIGHT: med_rotate_segment_right(Cursegp); break;
257 case WTOP: med_rotate_segment_right(Cursegp); med_rotate_segment_right(Cursegp); break;
258 case WLEFT: med_rotate_segment_right(Cursegp); med_rotate_segment_right(Cursegp); med_rotate_segment_right(Cursegp); break;
260 case WFRONT: med_rotate_segment_forward(Cursegp); break;
261 case WBACK: med_rotate_segment_forward(Cursegp); med_rotate_segment_forward(Cursegp); med_rotate_segment_forward(Cursegp); break;
263 Update_flags = UF_WORLD_CHANGED;
267 int ToggleBottom(void)
269 Render_only_bottom = !Render_only_bottom;
270 Update_flags = UF_WORLD_CHANGED;
274 // ---------------------------------------------------------------------------------------------
275 // ---------- Segment interrogation functions ----------
276 // ----------------------------------------------------------------------------
277 // Return a pointer to the list of vertex indices for the current segment in vp and
278 // the number of vertices in *nv.
279 void med_get_vertex_list(segment *s,int *nv,short **vp)
282 *nv = MAX_VERTICES_PER_SEGMENT;
285 // -------------------------------------------------------------------------------
286 // Return number of times vertex vi appears in all segments.
287 // This function can be used to determine whether a vertex is used exactly once in
288 // all segments, in which case it can be freely moved because it is not connected
289 // to any other segment.
290 int med_vertex_count(int vi)
298 for (s=0; s<MAX_SEGMENTS; s++) {
300 if (sp->segnum != -1)
301 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
302 if (sp->verts[v] == vi)
309 // -------------------------------------------------------------------------------
310 int is_free_vertex(int vi)
312 return med_vertex_count(vi) == 1;
316 // -------------------------------------------------------------------------------
317 // Move a free vertex in the segment by adding the vector *vofs to its coordinates.
319 // If the point is not free then:
320 // If the point is not valid (probably valid = in 0..7) then:
321 // If adding *vofs will cause a degenerate segment then:
322 // Note, pi is the point index relative to the segment, not an absolute point index.
323 // For example, 3 is always the front upper left vertex.
324 void med_move_vertex(segment *sp, int pi, vms_vector *vofs)
328 Assert((pi >= 0) && (pi <= 7)); // check valid range of point indices.
330 abspi = sp->verts[pi];
332 // Make sure vertex abspi is free. If it is free, it appears exactly once in Vertices
333 Assert(med_vertex_count(abspi) == 1);
335 Assert(abspi <= MAX_SEGMENT_VERTICES); // Make sure vertex id is not bogus.
337 vm_vec_add(&Vertices[abspi],&Vertices[abspi],vofs);
339 // Here you need to validate the geometry of the segment, which will be quite tricky.
340 // You need to make sure:
341 // The segment is not concave.
342 // None of the sides are concave.
343 validate_segment(sp);
347 // -------------------------------------------------------------------------------
348 // Move a free wall in the segment by adding the vector *vofs to its coordinates.
349 // Wall indices: 0/1/2/3/4/5 = left/top/right/bottom/back/front
350 void med_move_wall(segment *sp,int wi, vms_vector *vofs)
355 Assert( (wi >= 0) && (wi <= 5) );
357 vp = Side_to_verts[wi];
358 for (i=0; i<4; i++) {
359 med_move_vertex(sp,*vp,vofs);
363 validate_segment(sp);
366 // -------------------------------------------------------------------------------
367 // Return true if one fixed point number is very close to another, else return false.
368 int fnear(fix f1, fix f2)
370 return (abs(f1 - f2) <= FIX_EPSILON);
373 // -------------------------------------------------------------------------------
374 int vnear(vms_vector *vp1, vms_vector *vp2)
376 return fnear(vp1->x, vp2->x) && fnear(vp1->y, vp2->y) && fnear(vp1->z, vp2->z);
379 // -------------------------------------------------------------------------------
380 // Add the vertex *vp to the global list of vertices, return its index.
381 // Search until a matching vertex is found (has nearly the same coordinates) or until Num_vertices
382 // vertices have been looked at without a match. If no match, add a new vertex.
383 int med_add_vertex(vms_vector *vp)
386 int count; // number of used vertices found, for loops exits when count == Num_vertices
388 // set_vertex_counts();
390 Assert(Num_vertices < MAX_SEGMENT_VERTICES);
394 for (v=0; (v < MAX_SEGMENT_VERTICES) && (count < Num_vertices); v++)
395 if (Vertex_active[v]) {
397 if (vnear(vp,&Vertices[v])) {
398 // mprintf((0,"[%4i] ",v));
401 } else if (free_index == -1)
402 free_index = v; // we want free_index to be the first free slot to add a vertex
404 if (free_index == -1)
405 free_index = Num_vertices;
407 while (Vertex_active[free_index] && (free_index < MAX_VERTICES))
410 Assert(free_index < MAX_VERTICES);
412 Vertices[free_index] = *vp;
413 Vertex_active[free_index] = 1;
417 if (free_index > Highest_vertex_index)
418 Highest_vertex_index = free_index;
423 // ------------------------------------------------------------------------------------------
424 // Returns the index of a free segment.
425 // Scans the Segments array.
426 int get_free_segment_number(void)
430 for (segnum=0; segnum<MAX_SEGMENTS; segnum++)
431 if (Segments[segnum].segnum == -1) {
433 if (segnum > Highest_segment_index)
434 Highest_segment_index = segnum;
443 // -------------------------------------------------------------------------------
444 // Create a new segment, duplicating exactly, including vertex ids and children, the passed segment.
445 int med_create_duplicate_segment(segment *sp)
449 segnum = get_free_segment_number();
451 Segments[segnum] = *sp;
456 // -------------------------------------------------------------------------------
457 // Add the vertex *vp to the global list of vertices, return its index.
458 // This is the same as med_add_vertex, except that it does not search for the presence of the vertex.
459 int med_create_duplicate_vertex(vms_vector *vp)
463 Assert(Num_vertices < MAX_SEGMENT_VERTICES);
465 Do_duplicate_vertex_check = 1;
467 free_index = Num_vertices;
469 while (Vertex_active[free_index] && (free_index < MAX_VERTICES))
472 Assert(free_index < MAX_VERTICES);
474 Vertices[free_index] = *vp;
475 Vertex_active[free_index] = 1;
479 if (free_index > Highest_vertex_index)
480 Highest_vertex_index = free_index;
486 // -------------------------------------------------------------------------------
487 // Set the vertex *vp at index vnum in the global list of vertices, return its index (just for compatibility).
488 int med_set_vertex(int vnum,vms_vector *vp)
490 Assert(vnum < MAX_VERTICES);
492 Vertices[vnum] = *vp;
494 // Just in case this vertex wasn't active, mark it as active.
495 if (!Vertex_active[vnum]) {
496 Vertex_active[vnum] = 1;
498 if ((vnum > Highest_vertex_index) && (vnum < NEW_SEGMENT_VERTICES)) {
499 mprintf((0,"Warning -- setting a previously unset vertex, index = %i.\n",vnum));
500 Highest_vertex_index = vnum;
510 // A side is determined to be degenerate if the cross products of 3 consecutive points does not point outward.
511 int check_for_degenerate_side(segment *sp, int sidenum)
513 char *vp = Side_to_verts[sidenum];
514 vms_vector vec1, vec2, cross, vec_to_center;
515 vms_vector segc, sidec;
517 int degeneracy_flag = 0;
519 compute_segment_center(&segc, sp);
520 compute_center_point_on_side(&sidec, sp, sidenum);
521 vm_vec_sub(&vec_to_center, &segc, &sidec);
523 //vm_vec_sub(&vec1, &Vertices[sp->verts[vp[1]]], &Vertices[sp->verts[vp[0]]]);
524 //vm_vec_sub(&vec2, &Vertices[sp->verts[vp[2]]], &Vertices[sp->verts[vp[1]]]);
525 //vm_vec_normalize(&vec1);
526 //vm_vec_normalize(&vec2);
527 vm_vec_normalized_dir(&vec1, &Vertices[sp->verts[(int) vp[1]]], &Vertices[sp->verts[(int) vp[0]]]);
528 vm_vec_normalized_dir(&vec2, &Vertices[sp->verts[(int) vp[2]]], &Vertices[sp->verts[(int) vp[1]]]);
529 vm_vec_cross(&cross, &vec1, &vec2);
531 dot = vm_vec_dot(&vec_to_center, &cross);
533 degeneracy_flag |= 1;
535 //vm_vec_sub(&vec1, &Vertices[sp->verts[vp[2]]], &Vertices[sp->verts[vp[1]]]);
536 //vm_vec_sub(&vec2, &Vertices[sp->verts[vp[3]]], &Vertices[sp->verts[vp[2]]]);
537 //vm_vec_normalize(&vec1);
538 //vm_vec_normalize(&vec2);
539 vm_vec_normalized_dir(&vec1, &Vertices[sp->verts[(int) vp[2]]], &Vertices[sp->verts[(int) vp[1]]]);
540 vm_vec_normalized_dir(&vec2, &Vertices[sp->verts[(int) vp[3]]], &Vertices[sp->verts[(int) vp[2]]]);
541 vm_vec_cross(&cross, &vec1, &vec2);
543 dot = vm_vec_dot(&vec_to_center, &cross);
545 degeneracy_flag |= 1;
547 return degeneracy_flag;
551 // -------------------------------------------------------------------------------
552 void create_removable_wall(segment *sp, int sidenum, int tmap_num)
554 create_walls_on_side(sp, sidenum);
556 sp->sides[sidenum].tmap_num = tmap_num;
558 assign_default_uvs_to_side(sp, sidenum);
559 assign_light_to_side(sp, sidenum);
563 // See if a segment has gotten turned inside out, or something.
564 // If so, set global Degenerate_segment_found and return 1, else return 0.
565 int check_for_degenerate_segment(segment *sp)
567 vms_vector fvec, rvec, uvec, cross;
569 int i, degeneracy_flag = 0; // degeneracy flag for current segment
571 extract_forward_vector_from_segment(sp, &fvec);
572 extract_right_vector_from_segment(sp, &rvec);
573 extract_up_vector_from_segment(sp, &uvec);
575 vm_vec_normalize(&fvec);
576 vm_vec_normalize(&rvec);
577 vm_vec_normalize(&uvec);
579 vm_vec_cross(&cross, &fvec, &rvec);
580 dot = vm_vec_dot(&cross, &uvec);
585 mprintf((0, "segment #%i is degenerate due to cross product check.\n", sp-Segments));
589 // Now, see if degenerate because of any side.
590 for (i=0; i<MAX_SIDES_PER_SEGMENT; i++)
591 degeneracy_flag |= check_for_degenerate_side(sp, i);
593 Degenerate_segment_found |= degeneracy_flag;
595 return degeneracy_flag;
601 // ---------------------------------------------------------------------------------------------
602 // Orthogonalize matrix smat, returning result in rmat.
603 // Does not modify smat.
604 // Uses Gram-Schmidt process.
605 // See page 172 of Strang, Gilbert, Linear Algebra and its Applications
606 // Matt -- This routine should be moved to the vector matrix library.
607 // It IS legal for smat == rmat.
608 // We should also have the functions:
609 // mat_a = mat_b * scalar; // we now have mat_a = mat_a * scalar;
610 // mat_a = mat_b + mat_c * scalar; // or maybe not, maybe this is not primitive
611 void make_orthogonal(vms_matrix *rmat,vms_matrix *smat)
614 vms_vector tvec1,tvec2;
617 // Copy source matrix to work area.
620 // Normalize the three rows of the matrix tmat.
621 vm_vec_normalize(&tmat.xrow);
622 vm_vec_normalize(&tmat.yrow);
623 vm_vec_normalize(&tmat.zrow);
625 // Now, compute the first vector.
626 // This is very easy -- just copy the (normalized) source vector.
627 rmat->zrow = tmat.zrow;
629 // Now, compute the second vector.
630 // From page 172 of Strang, we use the equation:
631 // b' = b - [transpose(q1) * b] * q1
632 // where: b = the second row of tmat
633 // q1 = the first row of rmat
634 // b' = the second row of rmat
636 // Compute: transpose(q1) * b
637 dot = vm_vec_dotprod(&rmat->zrow,&tmat.yrow);
639 // Compute: b - dot * q1
640 rmat->yrow.x = tmat.yrow.x - fixmul(dot,rmat->zrow.x);
641 rmat->yrow.y = tmat.yrow.y - fixmul(dot,rmat->zrow.y);
642 rmat->yrow.z = tmat.yrow.z - fixmul(dot,rmat->zrow.z);
644 // Now, compute the third vector.
645 // From page 173 of Strang, we use the equation:
646 // c' = c - (q1*c)*q1 - (q2*c)*q2
647 // where: c = the third row of tmat
648 // q1 = the first row of rmat
649 // q2 = the second row of rmat
650 // c' = the third row of rmat
653 dot = vm_vec_dotprod(&rmat->zrow,&tmat.xrow);
655 tvec1.x = fixmul(dot,rmat->zrow.x);
656 tvec1.y = fixmul(dot,rmat->zrow.y);
657 tvec1.z = fixmul(dot,rmat->zrow.z);
660 dot = vm_vec_dotprod(&rmat->yrow,&tmat.xrow);
662 tvec2.x = fixmul(dot,rmat->yrow.x);
663 tvec2.y = fixmul(dot,rmat->yrow.y);
664 tvec2.z = fixmul(dot,rmat->yrow.z);
666 vm_vec_sub(&rmat->xrow,vm_vec_sub(&rmat->xrow,&tmat.xrow,&tvec1),&tvec2);
671 // ------------------------------------------------------------------------------------------
672 // Given a segment, extract the rotation matrix which defines it.
673 // Do this by extracting the forward, right, up vectors and then making them orthogonal.
674 // In the process of making the vectors orthogonal, favor them in the order forward, up, right.
675 // This means that the forward vector will remain unchanged.
676 void med_extract_matrix_from_segment(segment *sp,vms_matrix *rotmat)
678 vms_vector forwardvec,upvec;
680 extract_forward_vector_from_segment(sp,&forwardvec);
681 extract_up_vector_from_segment(sp,&upvec);
683 if (((forwardvec.x == 0) && (forwardvec.y == 0) && (forwardvec.z == 0)) || ((upvec.x == 0) && (upvec.y == 0) && (upvec.z == 0))) {
684 mprintf((0, "Trapped null vector in med_extract_matrix_from_segment, returning identity matrix.\n"));
685 *rotmat = vmd_identity_matrix;
690 vm_vector_2_matrix(rotmat,&forwardvec,&upvec,NULL);
695 extract_forward_vector_from_segment(sp,&rm.zrow);
696 extract_right_vector_from_segment(sp,&rm.xrow);
697 extract_up_vector_from_segment(sp,&rm.yrow);
699 vm_vec_normalize(&rm.xrow);
700 vm_vec_normalize(&rm.yrow);
701 vm_vec_normalize(&rm.zrow);
703 make_orthogonal(rotmat,&rm);
705 vm_vec_normalize(&rotmat->xrow);
706 vm_vec_normalize(&rotmat->yrow);
707 vm_vec_normalize(&rotmat->zrow);
709 // *rotmat = rm; // include this line (and remove the call to make_orthogonal) if you don't want the matrix orthogonalized
714 // ------------------------------------------------------------------------------------------
715 // Given a rotation matrix *rotmat which describes the orientation of a segment
716 // and a side destside, return the rotation matrix which describes the orientation for the side.
717 void set_matrix_based_on_side(vms_matrix *rotmat,int destside)
719 vms_angvec rotvec,*tmpvec;
724 tmpvec=vm_angvec_make(&rotvec,0,0,-16384);
725 vm_angles_2_matrix(&r1,&rotvec);
726 vm_matrix_x_matrix(&rtemp,rotmat,&r1);
731 tmpvec=vm_angvec_make(&rotvec,-16384,0,0);
732 vm_angles_2_matrix(&r1,&rotvec);
733 vm_matrix_x_matrix(&rtemp,rotmat,&r1);
738 tmpvec=vm_angvec_make(&rotvec,0,0,16384);
739 vm_angles_2_matrix(&r1,&rotvec);
740 vm_matrix_x_matrix(&rtemp,rotmat,&r1);
745 tmpvec=vm_angvec_make(&rotvec,+16384,-32768,0); // bank was -32768, but I think that was an erroneous compensation
746 vm_angles_2_matrix(&r1,&rotvec);
747 vm_matrix_x_matrix(&rtemp,rotmat,&r1);
752 tmpvec=vm_angvec_make(&rotvec,0,0,-32768);
753 vm_angles_2_matrix(&r1,&rotvec);
754 vm_matrix_x_matrix(&rtemp,rotmat,&r1);
764 // -------------------------------------------------------------------------------------
765 void change_vertex_occurrences(int dest, int src)
769 // Fix vertices in groups
770 for (g=0;g<num_groups;g++)
771 for (v=0; v<GroupList[g].num_vertices; v++)
772 if (GroupList[g].vertices[v] == src)
773 GroupList[g].vertices[v] = dest;
775 // now scan all segments, changing occurrences of src to dest
776 for (s=0; s<=Highest_segment_index; s++)
777 if (Segments[s].segnum != -1)
778 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
779 if (Segments[s].verts[v] == src)
780 Segments[s].verts[v] = dest;
783 // --------------------------------------------------------------------------------------------------
784 void compress_vertices(void)
788 if (Highest_vertex_index == Num_vertices - 1)
791 vert = Highest_vertex_index; //MAX_SEGMENT_VERTICES-1;
793 for (hole=0; hole < vert; hole++)
794 if (!Vertex_active[hole]) {
795 // found an unused vertex which is a hole if a used vertex follows (not necessarily immediately) it.
796 for ( ; (vert>hole) && (!Vertex_active[vert]); vert--)
801 // Ok, hole is the index of a hole, vert is the index of a vertex which follows it.
802 // Copy vert into hole, update pointers to it.
803 Vertices[hole] = Vertices[vert];
805 change_vertex_occurrences(hole, vert);
811 Highest_vertex_index = Num_vertices-1;
814 // --------------------------------------------------------------------------------------------------
815 void compress_segments(void)
819 if (Highest_segment_index == Num_segments - 1)
822 seg = Highest_segment_index;
824 for (hole=0; hole < seg; hole++)
825 if (Segments[hole].segnum == -1) {
826 // found an unused segment which is a hole if a used segment follows (not necessarily immediately) it.
827 for ( ; (seg>hole) && (Segments[seg].segnum == -1); seg--)
835 // Ok, hole is the index of a hole, seg is the index of a segment which follows it.
836 // Copy seg into hole, update pointers to it, update Cursegp, Markedsegp if necessary.
837 Segments[hole] = Segments[seg];
838 Segments[seg].segnum = -1;
840 if (Cursegp == &Segments[seg])
841 Cursegp = &Segments[hole];
843 if (Markedsegp == &Segments[seg])
844 Markedsegp = &Segments[hole];
846 // Fix segments in groups
847 for (g=0;g<num_groups;g++)
848 for (s=0; s<GroupList[g].num_segments; s++)
849 if (GroupList[g].segments[s] == seg)
850 GroupList[g].segments[s] = hole;
853 for (w=0;w<Num_walls;w++)
854 if (Walls[w].segnum == seg)
855 Walls[w].segnum = hole;
857 // Fix fuelcenters, robotcens, and triggers... added 2/1/95 -Yuan
858 for (f=0;f<Num_fuelcenters;f++)
859 if (Station[f].segnum == seg)
860 Station[f].segnum = hole;
862 for (f=0;f<Num_robot_centers;f++)
863 if (RobotCenters[f].segnum == seg)
864 RobotCenters[f].segnum = hole;
866 for (t=0;t<Num_triggers;t++)
867 for (l=0;l<Triggers[t].num_links;l++)
868 if (Triggers[t].seg[l] == seg)
869 Triggers[t].seg[l] = hole;
871 sp = &Segments[hole];
872 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
873 if (IS_CHILD(sp->children[s])) {
875 csegp = &Segments[sp->children[s]];
877 // Find out on what side the segment connection to the former seg is on in *csegp.
878 for (t=0; t<MAX_SIDES_PER_SEGMENT; t++) {
879 if (csegp->children[t] == seg) {
880 csegp->children[t] = hole; // It used to be connected to seg, so make it connected to hole
886 //Update object segment pointers
887 for (objnum = sp->objects; objnum != -1; objnum = Objects[objnum].next) {
888 Assert(Objects[objnum].segnum == seg);
889 Objects[objnum].segnum = hole;
894 } // end if (seg > hole)
897 Highest_segment_index = Num_segments-1;
898 med_create_new_segment_from_cursegp();
903 // -------------------------------------------------------------------------------
904 // Combine duplicate vertices.
905 // If two vertices have the same coordinates, within some small tolerance, then assign
906 // the same vertex number to the two vertices, freeing up one of the vertices.
907 void med_combine_duplicate_vertices(sbyte *vlp)
911 for (v=0; v<Highest_vertex_index; v++) // Note: ok to do to <, rather than <= because w for loop starts at v+1
913 vms_vector *vvp = &Vertices[v];
914 for (w=v+1; w<=Highest_vertex_index; w++)
915 if (vlp[w]) { // used to be Vertex_active[w]
916 if (vnear(vvp, &Vertices[w])) {
917 change_vertex_occurrences(v, w);
924 // ------------------------------------------------------------------------------
925 // Compress mine at Segments and Vertices by squeezing out all holes.
926 // If no holes (ie, an unused segment followed by a used segment), then no action.
927 // If Cursegp or Markedsegp is a segment which gets moved to fill in a hole, then
928 // they are properly updated.
929 void med_compress_mine(void)
931 if (Do_duplicate_vertex_check) {
932 med_combine_duplicate_vertices(Vertex_active);
933 Do_duplicate_vertex_check = 0;
940 //--repair-- create_local_segment_data();
942 // This is necessary becuase a segment search (due to click in 3d window) uses the previous frame's
943 // segment information, which could get changed by this.
944 Update_flags = UF_WORLD_CHANGED;
948 // ------------------------------------------------------------------------------------------
949 // Copy texture map ids for each face in sseg to dseg.
950 void copy_tmap_ids(segment *dseg, segment *sseg)
954 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
955 dseg->sides[s].tmap_num = sseg->sides[s].tmap_num;
956 dseg->sides[s].tmap_num2 = 0;
960 // ------------------------------------------------------------------------------------------
961 // Attach a segment with a rotated orientation.
963 // 0 = successful attach
964 // 1 = No room in Segments[].
965 // 2 = No room in Vertices[].
966 // 3 = newside != WFRONT -- for now, the new segment must be attached at its (own) front side
967 // 4 = already a face attached on destseg:destside
968 int med_attach_segment_rotated(segment *destseg, segment *newseg, int destside, int newside,vms_matrix *attmat)
974 vms_matrix rotmat,rotmat1,rotmat2,rotmat3,rotmat4;
975 vms_vector vr,vc,tvs[4],xlate_vec;
977 vms_vector forvec,upvec;
979 // Return if already a face attached on this side.
980 if (IS_CHILD(destseg->children[destside]))
983 segnum = get_free_segment_number();
985 forvec = attmat->fvec;
986 upvec = attmat->uvec;
988 // We are pretty confident we can add the segment.
989 nsp = &Segments[segnum];
990 nsp2 = &Segment2s[segnum];
992 nsp->segnum = segnum;
994 nsp2->matcen_num = -1;
997 nsp->group = destseg->group;
999 // Add segment to proper group list.
1000 if (nsp->group > -1)
1001 add_segment_to_group(nsp-Segments, nsp->group);
1003 // Copy the texture map ids.
1004 copy_tmap_ids(nsp,newseg);
1006 // clear all connections
1007 for (side=0; side<MAX_SIDES_PER_SEGMENT; side++) {
1008 nsp->children[side] = -1;
1009 nsp->sides[side].wall_num = -1;
1012 // Form the connection
1013 destseg->children[destside] = segnum;
1014 // destseg->sides[destside].render_flag = 0;
1015 nsp->children[newside] = destseg-Segments;
1017 // Copy vertex indices of the four vertices forming the joint
1018 dvp = Side_to_verts[destside];
1020 // Set the vertex indices for the four vertices forming the front of the new side
1022 nsp->verts[v] = destseg->verts[(int) dvp[v]];
1024 // The other 4 vertices must be created.
1025 // Their coordinates are determined by the 4 welded vertices and the vector from front
1026 // to back of the original *newseg.
1028 // Do lots of hideous matrix stuff, about 3/4 of which could probably be simplified out.
1029 med_extract_matrix_from_segment(destseg,&rotmat); // get orientation matrix for destseg (orthogonal rotation matrix)
1030 set_matrix_based_on_side(&rotmat,destside);
1031 vm_vector_2_matrix(&rotmat1,&forvec,&upvec,NULL);
1032 vm_matrix_x_matrix(&rotmat4,&rotmat,&rotmat1); // this is the desired orientation of the new segment
1033 med_extract_matrix_from_segment(newseg,&rotmat3); // this is the current orientation of the new segment
1034 vm_transpose_matrix(&rotmat3); // get the inverse of the current orientation matrix
1035 vm_matrix_x_matrix(&rotmat2,&rotmat4,&rotmat3); // now rotmat2 takes the current segment to the desired orientation
1037 // Warning -- look at this line!
1038 vm_transpose_matrix(&rotmat2); // added 12:33 pm, 10/01/93
1040 // Compute and rotate the center point of the attaching face.
1041 compute_center_point_on_side(&vc,newseg,newside);
1042 vm_vec_rotate(&vr,&vc,&rotmat2);
1044 // Now rotate the free vertices in the segment
1046 vm_vec_rotate(&tvs[v],&Vertices[newseg->verts[v+4]],&rotmat2);
1048 // Now translate the new segment so that the center point of the attaching faces are the same.
1049 compute_center_point_on_side(&vc,destseg,destside);
1050 vm_vec_sub(&xlate_vec,&vc,&vr);
1052 // Create and add the 4 new vertices.
1053 for (v=0; v<4; v++) {
1054 vm_vec_add2(&tvs[v],&xlate_vec);
1055 nsp->verts[v+4] = med_add_vertex(&tvs[v]);
1058 set_vertex_counts();
1060 // Now all the vertices are in place. Create the faces.
1061 validate_segment(nsp);
1063 // Say to not render at the joint.
1064 // destseg->sides[destside].render_flag = 0;
1065 // nsp->sides[newside].render_flag = 0;
1072 // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
1074 // ------------------------------------------------------------------------------------------
1075 void scale_free_vertices(segment *sp,vms_vector *vp,fix scale_factor,int min_side,int max_side)
1080 verts = Side_to_verts[min_side];
1083 if (is_free_vertex(sp->verts[(int) verts[i]])) {
1084 Vertices[sp->verts[(int) verts[i]]].x = fixmul(vp->x,scale_factor)/2;
1085 Vertices[sp->verts[(int) verts[i]]].y = fixmul(vp->y,scale_factor)/2;
1086 Vertices[sp->verts[(int) verts[i]]].z = fixmul(vp->z,scale_factor)/2;
1089 verts = Side_to_verts[max_side];
1092 if (is_free_vertex(sp->verts[(int) verts[i]])) {
1093 Vertices[sp->verts[(int) verts[i]]].x = fixmul(vp->x,scale_factor)/2;
1094 Vertices[sp->verts[(int) verts[i]]].y = fixmul(vp->y,scale_factor)/2;
1095 Vertices[sp->verts[(int) verts[i]]].z = fixmul(vp->z,scale_factor)/2;
1100 // ------------------------------------------------------------------------------------------
1101 // Attach side newside of newseg to side destside of destseg.
1102 // Copies *newseg into global array Segments, increments Num_segments.
1103 // Forms a weld between the two segments by making the new segment fit to the old segment.
1104 // Updates number of faces per side if necessitated by new vertex coordinates.
1107 // 0 = successful attach
1108 // 1 = No room in Segments[].
1109 // 2 = No room in Vertices[].
1110 // 3 = newside != WFRONT -- for now, the new segment must be attached at its (own) front side
1111 // 4 = already a face attached on side newside
1112 int med_attach_segment(segment *destseg, segment *newseg, int destside, int newside)
1115 segment *ocursegp = Cursegp;
1117 vms_angvec tang = {0,0,0};
1120 vm_angles_2_matrix(&rotmat,&tang);
1121 rval = med_attach_segment_rotated(destseg,newseg,destside,newside,&rotmat);
1122 med_propagate_tmaps_to_segments(ocursegp,Cursegp,0);
1123 med_propagate_tmaps_to_back_side(Cursegp, Side_opposite[newside],0);
1124 copy_uvs_seg_to_seg(&New_segment,Cursegp);
1129 // -------------------------------------------------------------------------------
1130 // Delete a vertex, sort of.
1131 // Decrement the vertex count. If the count goes to 0, then the vertex is free (has been deleted).
1132 void delete_vertex(short v)
1134 Assert(v < MAX_VERTICES); // abort if vertex is not in array Vertices
1135 Assert(Vertex_active[v] >= 1); // abort if trying to delete a non-existent vertex
1140 // -------------------------------------------------------------------------------
1141 // Update Num_vertices.
1142 // This routine should be called by anyone who calls delete_vertex. It could be called in delete_vertex,
1143 // but then it would be called much more often than necessary, and it is a slow routine.
1144 void update_num_vertices(void)
1148 // Now count the number of vertices.
1150 for (v=0; v<=Highest_vertex_index; v++)
1151 if (Vertex_active[v])
1155 // -------------------------------------------------------------------------------
1156 // Set Vertex_active to number of occurrences of each vertex.
1157 // Set Num_vertices.
1158 void set_vertex_counts(void)
1164 for (v=0; v<=Highest_vertex_index; v++)
1165 Vertex_active[v] = 0;
1167 // Count number of occurrences of each vertex.
1168 for (s=0; s<=Highest_segment_index; s++)
1169 if (Segments[s].segnum != -1)
1170 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++) {
1171 if (!Vertex_active[Segments[s].verts[v]])
1173 Vertex_active[Segments[s].verts[v]]++;
1177 // -------------------------------------------------------------------------------
1178 // Delete all vertices in segment *sp from the vertex list if they are not contained in another segment.
1179 // This is kind of a dangerous routine. It modifies the global array Vertex_active, using the field as
1181 void delete_vertices_in_segment(segment *sp)
1187 set_vertex_counts();
1189 // Subtract one count for each appearance of vertex in deleted segment
1190 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
1191 delete_vertex(sp->verts[v]);
1193 update_num_vertices();
1196 extern void validate_segment_side(segment *sp, int sidenum);
1198 // -------------------------------------------------------------------------------
1199 // Delete segment *sp in Segments array.
1201 // 0 successfully deleted.
1202 // 1 unable to delete.
1203 int med_delete_segment(segment *sp)
1208 segnum = sp-Segments;
1210 // Cannot delete segment if only segment.
1211 if (Num_segments == 1)
1214 // Don't try to delete if segment doesn't exist.
1215 if (sp->segnum == -1) {
1216 mprintf((0,"Hey -- you tried to delete a non-existent segment (segnum == -1)\n"));
1220 // Delete its refueling center if it has one
1223 delete_vertices_in_segment(sp);
1227 // If deleted segment has walls on any side, wipe out the wall.
1228 for (side=0; side < MAX_SIDES_PER_SEGMENT; side++)
1229 if (sp->sides[side].wall_num != -1)
1230 wall_remove_side(sp, side);
1232 // Find out what this segment was connected to and break those connections at the other end.
1233 for (side=0; side < MAX_SIDES_PER_SEGMENT; side++)
1234 if (IS_CHILD(sp->children[side])) {
1235 segment *csp; // the connecting segment
1238 csp = &Segments[sp->children[side]];
1239 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
1240 if (csp->children[s] == segnum) {
1241 csp->children[s] = -1; // this is the side of connection, break it
1242 validate_segment_side(csp,s); // we have converted a connection to a side so validate the segment
1243 med_propagate_tmaps_to_back_side(csp,s,0);
1246 med_create_new_segment_from_cursegp();
1247 copy_uvs_seg_to_seg(&New_segment,Cursegp);
1250 sp->segnum = -1; // Mark segment as inactive.
1252 // If deleted segment = marked segment, then say there is no marked segment
1253 if (sp == Markedsegp)
1256 // If deleted segment = a Group segment ptr, then wipe it out.
1257 for (s=0;s<num_groups;s++)
1258 if (sp == Groupsegp[s])
1261 // If deleted segment = group segment, wipe it off the group list.
1263 delete_segment_from_group(sp-Segments, sp->group);
1265 // If we deleted something which was not connected to anything, must now select a new current segment.
1267 for (s=0; s<MAX_SEGMENTS; s++)
1268 if ((Segments[s].segnum != -1) && (s!=segnum) ) {
1269 Cursegp = &Segments[s];
1270 med_create_new_segment_from_cursegp();
1274 // If deleted segment contains objects, wipe out all objects
1275 if (sp->objects != -1) {
1276 // if (objnum == Objects[objnum].next) {
1277 // mprintf((0, "Warning -- object #%i points to itself. Setting next to -1.\n", objnum));
1278 // Objects[objnum].next = -1;
1280 for (objnum=sp->objects;objnum!=-1;objnum=Objects[objnum].next) {
1282 //if an object is in the seg, delete it
1283 //if the object is the player, move to new curseg
1285 if (objnum == (ConsoleObject-Objects)) {
1286 compute_segment_center(&ConsoleObject->pos,Cursegp);
1287 obj_relink(objnum,Cursegp-Segments);
1293 // Make sure everything deleted ok...
1294 Assert( sp->objects==-1 );
1296 // If we are leaving many holes in Segments or Vertices, then compress mine, because it is inefficient to be that way
1297 // if ((Highest_segment_index > Num_segments+4) || (Highest_vertex_index > Num_vertices+4*8))
1298 // med_compress_mine();
1303 // ------------------------------------------------------------------------------------------
1304 // Copy texture maps from sseg to dseg
1305 void copy_tmaps_to_segment(segment *dseg, segment *sseg)
1309 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
1310 dseg->sides[s].type = sseg->sides[s].type;
1311 dseg->sides[s].tmap_num = sseg->sides[s].tmap_num;
1312 dseg->sides[s].tmap_num2 = sseg->sides[s].tmap_num2;
1317 // ------------------------------------------------------------------------------------------
1318 // Rotate the segment *seg by the pitch, bank, heading defined by *rot, destructively
1319 // modifying its four free vertices in the global array Vertices.
1320 // It is illegal to rotate a segment which has connectivity != 1.
1321 // Pitch, bank, heading are about the point which is the average of the four points
1322 // forming the side of connection.
1324 // 0 = successful rotation
1325 // 1 = Connectivity makes rotation illegal (connected to 0 or 2+ segments)
1326 // 2 = Rotation causes degeneracy, such as self-intersecting segment.
1327 // 3 = Unable to rotate because not connected to exactly 1 segment.
1328 int med_rotate_segment(segment *seg, vms_matrix *rotmat)
1331 int newside=0,destside,s;
1333 int back_side,side_tmaps[MAX_SIDES_PER_SEGMENT];
1335 // Find side of attachment
1337 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
1338 if (IS_CHILD(seg->children[s])) {
1343 // Return if passed in segment is connected to other than 1 segment.
1347 destseg = &Segments[seg->children[newside]];
1350 while ((destseg->children[destside] != seg-Segments) && (destside < MAX_SIDES_PER_SEGMENT))
1353 // Before deleting the segment, copy its texture maps to New_segment
1354 copy_tmaps_to_segment(&New_segment,seg);
1356 if (med_delete_segment(seg))
1357 mprintf((0,"Error in rotation: Unable to delete segment %i\n",seg-Segments));
1359 if (Curside == WFRONT)
1362 med_attach_segment_rotated(destseg,&New_segment,destside,AttachSide,rotmat);
1364 // Save tmap_num on each side to restore after call to med_propagate_tmaps_to_segments and _back_side
1365 // which will change the tmap nums.
1366 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
1367 side_tmaps[s] = seg->sides[s].tmap_num;
1369 back_side = Side_opposite[find_connect_side(destseg, seg)];
1371 med_propagate_tmaps_to_segments(destseg, seg,0);
1372 med_propagate_tmaps_to_back_side(seg, back_side,0);
1374 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
1376 seg->sides[s].tmap_num = side_tmaps[s];
1381 // ----------------------------------------------------------------------------------------
1382 int med_rotate_segment_ang(segment *seg, vms_angvec *ang)
1386 return med_rotate_segment(seg,vm_angles_2_matrix(&rotmat,ang));
1389 // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
1391 // ----------------------------------------------------------------------------
1392 // Compute the sum of the distances between the four pairs of points.
1393 // The connections are:
1394 // firstv1 : 0 (firstv1+1)%4 : 1 (firstv1+2)%4 : 2 (firstv1+3)%4 : 3
1395 fix seg_seg_vertex_distsum(segment *seg1, int side1, segment *seg2, int side2, int firstv1)
1401 for (secondv=0; secondv<4; secondv++) {
1404 firstv = (4-secondv + (3 - firstv1)) % 4;
1405 distsum += vm_vec_dist(&Vertices[seg1->verts[Side_to_verts[side1][firstv]]],&Vertices[seg2->verts[Side_to_verts[side2][secondv]]]);
1412 // ----------------------------------------------------------------------------
1413 // Determine how to connect two segments together with the least amount of twisting.
1414 // Returns vertex index in 0..3 on first segment. Assumed ordering of vertices
1415 // on second segment is 0,1,2,3.
1416 // So, if return value is 2, connect 2:0 3:1 0:2 1:3.
1418 // We select an ordering of vertices for connection. For the first pair of vertices to be connected,
1419 // compute the vector. For the three remaining pairs of vertices, compute the vectors from one vertex
1420 // to the other. Compute the dot products of these vectors with the original vector. Add them up.
1421 // The close we are to 3, the better fit we have. Reason: The largest value for the dot product is
1422 // 1.0, and this occurs for a parallel set of vectors.
1423 int get_index_of_best_fit(segment *seg1, int side1, segment *seg2, int side2)
1429 min_distance = F1_0*30000;
1431 for (firstv=0; firstv<4; firstv++) {
1433 t = seg_seg_vertex_distsum(seg1, side1, seg2, side2, firstv);
1434 if (t <= min_distance) {
1436 best_index = firstv;
1445 #define MAX_VALIDATIONS 50
1447 // ----------------------------------------------------------------------------
1448 // Remap uv coordinates in all sides in segment *sp which have a vertex in vp[4].
1449 // vp contains absolute vertex indices.
1450 void remap_side_uvs(segment *sp,int *vp)
1454 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
1456 for (i=0; i<4; i++) // scan each vertex in vp[4]
1457 if (Side_to_verts[s][v] == vp[i]) {
1458 assign_default_uvs_to_side(sp,s); // Side s needs to be remapped
1465 // ----------------------------------------------------------------------------
1466 // Assign default uv coordinates to Curside.
1467 void assign_default_uvs_to_curside(void)
1469 assign_default_uvs_to_side(Cursegp, Curside);
1472 // ----------------------------------------------------------------------------
1473 // Assign default uv coordinates to all sides in Curside.
1474 void assign_default_uvs_to_curseg(void)
1478 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
1479 assign_default_uvs_to_side(Cursegp,s); // Side s needs to be remapped
1482 // ----------------------------------------------------------------------------
1483 // Modify seg2 to share side2 with seg1:side1. This forms a connection between
1484 // two segments without creating a new segment. It modifies seg2 by sharing
1485 // vertices from seg1. seg1 is not modified. Four vertices from seg2 are
1489 // 1 -- no, this is legal! -- unable to form joint because one or more vertices of side2 is not free
1490 // 2 unable to form joint because side1 is already used
1491 int med_form_joint(segment *seg1, int side1, segment *seg2, int side2)
1494 int bfi,v,s,sv,s1,nv;
1495 int lost_vertices[4],remap_vertices[4];
1496 int validation_list[MAX_VALIDATIONS];
1498 // Make sure that neither side is connected.
1499 if (IS_CHILD(seg1->children[side1]) || IS_CHILD(seg2->children[side2]))
1502 // Make sure there is no wall there
1503 if ((seg1->sides[side1].wall_num != -1) || (seg2->sides[side2].wall_num != -1))
1506 // We can form the joint. Find the best orientation of vertices.
1507 bfi = get_index_of_best_fit(seg1, side1, seg2, side2);
1509 vp1 = Side_to_verts[side1];
1510 vp2 = Side_to_verts[side2];
1512 // Make a copy of the list of vertices in seg2 which will be deleted and set the
1513 // associated vertex number, so that all occurrences of the vertices can be replaced.
1515 lost_vertices[v] = seg2->verts[(int) vp2[v]];
1517 // Now, for each vertex in lost_vertices, determine which vertex it maps to.
1519 remap_vertices[3 - ((v + bfi) % 4)] = seg1->verts[(int) vp1[v]];
1521 // Now, in all segments, replace all occurrences of vertices in lost_vertices with remap_vertices
1523 // Put the one segment we know are being modified into the validation list.
1524 // Note: seg1 does not require a full validation, only a validation of the affected side. Its vertices do not move.
1526 validation_list[0] = seg2 - Segments;
1529 for (s=0; s<=Highest_segment_index; s++)
1530 if (Segments[s].segnum != -1)
1531 for (sv=0; sv<MAX_VERTICES_PER_SEGMENT; sv++)
1532 if (Segments[s].verts[sv] == lost_vertices[v]) {
1533 Segments[s].verts[sv] = remap_vertices[v];
1534 // Add segment to list of segments to be validated.
1535 for (s1=0; s1<nv; s1++)
1536 if (validation_list[s1] == s)
1539 validation_list[nv++] = s;
1540 Assert(nv < MAX_VALIDATIONS);
1543 // Form new connections.
1544 seg1->children[side1] = seg2 - Segments;
1545 seg2->children[side2] = seg1 - Segments;
1547 // validate all segments
1548 validate_segment_side(seg1,side1);
1549 for (s=0; s<nv; s++) {
1550 validate_segment(&Segments[validation_list[s]]);
1551 remap_side_uvs(&Segments[validation_list[s]],remap_vertices); // remap uv coordinates on sides which were reshaped (ie, have a vertex in lost_vertices)
1552 warn_if_concave_segment(&Segments[validation_list[s]]);
1555 set_vertex_counts();
1557 // Make sure connection is open, ie renderable.
1558 // seg1->sides[side1].render_flag = 0;
1559 // seg2->sides[side2].render_flag = 0;
1561 //--// debug -- check all segments, make sure if a children[s] == -1, then side[s].num_faces != 0
1564 //--for (seg=0; seg<MAX_SEGMENTS; seg++)
1565 //-- if (Segments[seg].segnum != -1)
1566 //-- for (side=0; side<MAX_SIDES_PER_SEGMENT; side++)
1567 //-- if (Segments[seg].children[side] == -1) {
1568 //-- if (Segments[seg].sides[side].num_faces == 0) {
1569 //-- mprintf((0,"Error: Segment %i, side %i is not connected, but has 0 faces.\n",seg,side));
1572 //-- } else if (Segments[seg].sides[side].num_faces != 0) {
1573 //-- mprintf((0,"Error: Segment %i, side %i is connected, but has %i faces.\n",seg,side,Segments[seg].sides[side].num_faces));
1581 // ----------------------------------------------------------------------------
1582 // Create a new segment and use it to form a bridge between two existing segments.
1583 // Specify two segment:side pairs. If either segment:side is not open (ie, segment->children[side] != -1)
1584 // then it is not legal to form the brider.
1586 // 0 bridge segment formed
1587 // 1 unable to form bridge because one (or both) of the sides is not open.
1588 // Note that no new vertices are created by this process.
1589 int med_form_bridge_segment(segment *seg1, int side1, segment *seg2, int side2)
1595 if (IS_CHILD(seg1->children[side1]) || IS_CHILD(seg2->children[side2]))
1598 bs = &Segments[get_free_segment_number()];
1599 // mprintf((0,"Forming bridge segment %i from %i to %i\n",bs-Segments,seg1-Segments,seg2-Segments));
1601 bs->segnum = bs-Segments;
1604 // Copy vertices from seg2 into last 4 vertices of bridge segment.
1605 sv = Side_to_verts[side2];
1607 bs->verts[(3-v)+4] = seg2->verts[(int) sv[v]];
1609 // Copy vertices from seg1 into first 4 vertices of bridge segment.
1610 bfi = get_index_of_best_fit(seg1, side1, seg2, side2);
1612 sv = Side_to_verts[side1];
1614 bs->verts[(v + bfi) % 4] = seg1->verts[(int) sv[v]];
1616 // Form connections to children, first initialize all to unconnected.
1617 for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) {
1618 bs->children[i] = -1;
1619 bs->sides[i].wall_num = -1;
1622 // Now form connections between segments.
1624 bs->children[AttachSide] = seg1 - Segments;
1625 bs->children[(int) Side_opposite[AttachSide]] = seg2 - Segments;
1627 seg1->children[side1] = bs-Segments; //seg2 - Segments;
1628 seg2->children[side2] = bs-Segments; //seg1 - Segments;
1630 // Validate bridge segment, and if degenerate, clean up mess.
1631 Degenerate_segment_found = 0;
1633 validate_segment(bs);
1635 if (Degenerate_segment_found) {
1636 seg1->children[side1] = -1;
1637 seg2->children[side2] = -1;
1638 bs->children[AttachSide] = -1;
1639 bs->children[(int) Side_opposite[AttachSide]] = -1;
1640 if (med_delete_segment(bs)) {
1641 mprintf((0, "Oops, tried to delete bridge segment (because it's degenerate), but couldn't.\n"));
1644 editor_status("Bridge segment would be degenerate, not created.\n");
1647 validate_segment(seg1); // used to only validate side, but segment does more error checking: ,side1);
1648 validate_segment(seg2); // ,side2);
1649 med_propagate_tmaps_to_segments(seg1,bs,0);
1651 editor_status("Bridge segment formed.");
1652 warn_if_concave_segment(bs);
1657 // -------------------------------------------------------------------------------
1658 // Create a segment given center, dimensions, rotation matrix.
1659 // Note that the created segment will always have planar sides and rectangular cross sections.
1660 // It will be created with walls on all sides, ie not connected to anything.
1661 void med_create_segment(segment *sp,fix cx, fix cy, fix cz, fix length, fix width, fix height, vms_matrix *mp)
1664 vms_vector v0,v1,cv;
1669 sp->segnum = 1; // What to put here? I don't know.
1670 sp2 = &Segment2s[sp->segnum];
1672 // Form connections to children, of which it has none.
1673 for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) {
1674 sp->children[i] = -1;
1675 // sp->sides[i].render_flag = 0;
1676 sp->sides[i].wall_num = -1;
1680 sp2->matcen_num = -1;
1682 // Create relative-to-center vertices, which are the rotated points on the box defined by length, width, height
1683 sp->verts[0] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,+width/2,+height/2,-length/2),mp));
1684 sp->verts[1] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,+width/2,-height/2,-length/2),mp));
1685 sp->verts[2] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,-width/2,-height/2,-length/2),mp));
1686 sp->verts[3] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,-width/2,+height/2,-length/2),mp));
1687 sp->verts[4] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,+width/2,+height/2,+length/2),mp));
1688 sp->verts[5] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,+width/2,-height/2,+length/2),mp));
1689 sp->verts[6] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,-width/2,-height/2,+length/2),mp));
1690 sp->verts[7] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,-width/2,+height/2,+length/2),mp));
1692 // Now create the vector which is the center of the segment and add that to all vertices.
1693 while (!vm_vec_make(&cv,cx,cy,cz));
1695 // Now, add the center to all vertices, placing the segment in 3 space.
1696 for (i=0; i<MAX_VERTICES_PER_SEGMENT; i++)
1697 vm_vec_add(&Vertices[sp->verts[i]],&Vertices[sp->verts[i]],&cv);
1699 // Set scale vector.
1700 // sp->scale.x = width;
1701 // sp->scale.y = height;
1702 // sp->scale.z = length;
1704 // Add faces to all sides.
1705 for (f=0; f<MAX_SIDES_PER_SEGMENT; f++)
1706 create_walls_on_side(sp,f);
1708 sp->objects = -1; //no objects in this segment
1710 // Assume nothing special about this segment
1713 sp2->static_light = 0;
1714 sp2->matcen_num = -1;
1716 copy_tmaps_to_segment(sp, &New_segment);
1718 assign_default_uvs_to_segment(sp);
1721 // ----------------------------------------------------------------------------------------------
1722 // Create New_segment using a specified scale factor.
1723 void med_create_new_segment(vms_vector *scale)
1727 segment *sp = &New_segment;
1730 fix length,width,height;
1736 sp->segnum = 1; // What to put here? I don't know.
1737 sp2 = &Segment2s[sp->segnum];
1739 // Create relative-to-center vertices, which are the points on the box defined by length, width, height
1741 sp->verts[0] = med_set_vertex(NEW_SEGMENT_VERTICES+0,vm_vec_make(&v0,+width/2,+height/2,-length/2));
1742 sp->verts[1] = med_set_vertex(NEW_SEGMENT_VERTICES+1,vm_vec_make(&v0,+width/2,-height/2,-length/2));
1743 sp->verts[2] = med_set_vertex(NEW_SEGMENT_VERTICES+2,vm_vec_make(&v0,-width/2,-height/2,-length/2));
1744 sp->verts[3] = med_set_vertex(NEW_SEGMENT_VERTICES+3,vm_vec_make(&v0,-width/2,+height/2,-length/2));
1745 sp->verts[4] = med_set_vertex(NEW_SEGMENT_VERTICES+4,vm_vec_make(&v0,+width/2,+height/2,+length/2));
1746 sp->verts[5] = med_set_vertex(NEW_SEGMENT_VERTICES+5,vm_vec_make(&v0,+width/2,-height/2,+length/2));
1747 sp->verts[6] = med_set_vertex(NEW_SEGMENT_VERTICES+6,vm_vec_make(&v0,-width/2,-height/2,+length/2));
1748 sp->verts[7] = med_set_vertex(NEW_SEGMENT_VERTICES+7,vm_vec_make(&v0,-width/2,+height/2,+length/2));
1751 // sp->scale = *scale;
1753 // Form connections to children, of which it has none, init faces and tmaps.
1754 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
1755 sp->children[s] = -1;
1756 // sp->sides[s].render_flag = 0;
1757 sp->sides[s].wall_num = -1;
1758 create_walls_on_side(sp,s);
1759 sp->sides[s].tmap_num = s; // assign some stupid old tmap to this side.
1760 sp->sides[s].tmap_num2 = 0;
1763 Seg_orientation.p = 0; Seg_orientation.b = 0; Seg_orientation.h = 0;
1765 sp->objects = -1; //no objects in this segment
1767 assign_default_uvs_to_segment(sp);
1769 // Assume nothing special about this segment
1772 sp2->static_light = 0;
1773 sp2->matcen_num = -1;
1776 // -------------------------------------------------------------------------------
1777 void med_create_new_segment_from_cursegp(void)
1779 vms_vector scalevec;
1780 vms_vector uvec, rvec, fvec;
1782 med_extract_up_vector_from_segment_side(Cursegp, Curside, &uvec);
1783 med_extract_right_vector_from_segment_side(Cursegp, Curside, &rvec);
1784 extract_forward_vector_from_segment(Cursegp, &fvec);
1786 scalevec.x = vm_vec_mag(&rvec);
1787 scalevec.y = vm_vec_mag(&uvec);
1788 scalevec.z = vm_vec_mag(&fvec);
1790 med_create_new_segment(&scalevec);
1793 // -------------------------------------------------------------------------------
1794 // Initialize all vertices to inactive status.
1795 void init_all_vertices(void)
1800 for (v=0; v<MAX_SEGMENT_VERTICES; v++)
1801 Vertex_active[v] = 0;
1803 for (s=0; s<MAX_SEGMENTS; s++)
1804 Segments[s].segnum = -1;
1808 // --------------------------------------------------------------------------------------
1809 // Create a new mine, set global variables.
1810 int create_new_mine(void)
1814 vms_matrix m1 = IDENTITY_MATRIX;
1816 // initialize_mine_arrays();
1818 // gamestate_not_restored = 1;
1820 // Clear refueling center code
1824 init_all_vertices();
1826 Current_level_num = 0; //0 means not a real level
1827 Current_level_name[0] = 0;
1829 Cur_object_index = -1;
1830 reset_objects(1); //just one object, the player
1835 Num_vertices = 0; // Number of vertices in global array.
1836 Num_segments = 0; // Number of segments in global array, will get increased in med_create_segment
1837 Cursegp = Segments; // Say current segment is the only segment.
1838 Curside = WBACK; // The active side is the back side
1839 Markedsegp = 0; // Say there is no marked segment.
1840 Markedside = WBACK; // Shouldn't matter since Markedsegp == 0, but just in case...
1841 for (s=0;s<MAX_GROUPS+1;s++) {
1842 GroupList[s].num_segments = 0;
1843 GroupList[s].num_vertices = 0;
1844 Groupsegp[s] = NULL;
1848 Num_robot_centers = 0;
1853 // Create New_segment, which is the segment we will be adding at each instance.
1854 med_create_new_segment(vm_vec_make(&sizevec,DEFAULT_X_SIZE,DEFAULT_Y_SIZE,DEFAULT_Z_SIZE)); // New_segment = Segments[0];
1855 // med_create_segment(Segments,0,0,0,DEFAULT_X_SIZE,DEFAULT_Y_SIZE,DEFAULT_Z_SIZE,vm_mat_make(&m1,F1_0,0,0,0,F1_0,0,0,0,F1_0));
1856 med_create_segment(Segments,0,0,0,DEFAULT_X_SIZE,DEFAULT_Y_SIZE,DEFAULT_Z_SIZE,&m1);
1859 N_selected_segs = 0;
1862 //--repair-- create_local_segment_data();
1864 ControlCenterTriggers.num_links = 0;
1866 //editor_status("New mine created.");
1867 return 0; // say no error
1870 // --------------------------------------------------------------------------------------------------
1871 // Copy a segment from *ssp to *dsp. Do not simply copy the struct. Use *dsp's vertices, copying in
1872 // just the values, not the indices.
1873 void med_copy_segment(segment *dsp,segment *ssp)
1876 int verts_copy[MAX_VERTICES_PER_SEGMENT];
1878 // First make a copy of the vertex list.
1879 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
1880 verts_copy[v] = dsp->verts[v];
1882 // Now copy the whole struct.
1885 // Now restore the vertex indices.
1886 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
1887 dsp->verts[v] = verts_copy[v];
1889 // Now destructively modify the vertex values for all vertex indices.
1890 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
1891 Vertices[dsp->verts[v]] = Vertices[ssp->verts[v]];
1894 // -----------------------------------------------------------------------------
1895 // Create coordinate axes in orientation of specified segment, stores vertices at *vp.
1896 void create_coordinate_axes_from_segment(segment *sp,short *vertnums)
1901 med_extract_matrix_from_segment(sp,&rotmat);
1903 compute_segment_center(&Vertices[vertnums[0]],sp);
1906 vm_vec_scale(&t,i2f(32));
1907 vm_vec_add(&Vertices[vertnums[1]],&Vertices[vertnums[0]],&t);
1910 vm_vec_scale(&t,i2f(32));
1911 vm_vec_add(&Vertices[vertnums[2]],&Vertices[vertnums[0]],&t);
1914 vm_vec_scale(&t,i2f(32));
1915 vm_vec_add(&Vertices[vertnums[3]],&Vertices[vertnums[0]],&t);
1918 // -----------------------------------------------------------------------------
1919 // Determine if a segment is concave. Returns true if concave
1920 int check_seg_concavity(segment *s)
1925 for (sn=0;sn<MAX_SIDES_PER_SEGMENT;sn++)
1926 for (vn=0;vn<=4;vn++) {
1929 &Vertices[s->verts[Side_to_verts[sn][vn%4]]],
1930 &Vertices[s->verts[Side_to_verts[sn][(vn+1)%4]]],
1931 &Vertices[s->verts[Side_to_verts[sn][(vn+2)%4]]]);
1933 //vm_vec_normalize(&n1);
1935 if (vn>0) if (vm_vec_dotprod(&n0,&n1) < f0_5) return 1;
1944 // -----------------------------------------------------------------------------
1945 // Find all concave segments and add to list
1946 void find_concave_segs()
1953 for (s=Segments,i=Highest_segment_index;i>=0;s++,i--)
1954 if (s->segnum != -1)
1955 if (check_seg_concavity(s)) Warning_segs[N_warning_segs++]=SEG_PTR_2_NUM(s);
1961 // -----------------------------------------------------------------------------
1962 void warn_if_concave_segments(void)
1966 find_concave_segs();
1968 if (N_warning_segs) {
1969 editor_status("*** WARNING *** %d concave segments in mine! *** WARNING ***",N_warning_segs);
1970 sprintf( temp, "%d", N_warning_segs );
1974 // -----------------------------------------------------------------------------
1975 // Check segment s, if concave, warn
1976 void warn_if_concave_segment(segment *s)
1981 result = check_seg_concavity(s);
1984 Warning_segs[N_warning_segs++] = s-Segments;
1986 if (N_warning_segs) {
1987 editor_status("*** WARNING *** New segment is concave! *** WARNING ***");
1988 sprintf( temp, "%d", N_warning_segs );
1991 // editor_status("");
1993 //editor_status("");
1997 // -------------------------------------------------------------------------------
1998 // Find segment adjacent to sp:side.
1999 // Adjacent means a segment which shares all four vertices.
2000 // Return true if segment found and fill in segment in adj_sp and side in adj_side.
2001 // Return false if unable to find, in which case adj_sp and adj_side are undefined.
2002 int med_find_adjacent_segment_side(segment *sp, int side, segment **adj_sp, int *adj_side)
2007 // Stuff abs_verts[4] array with absolute vertex indices
2009 abs_verts[v] = sp->verts[Side_to_verts[side][v]];
2011 // Scan all segments, looking for a segment which contains the four abs_verts
2012 for (seg=0; seg<=Highest_segment_index; seg++) {
2013 if (seg != sp-Segments) {
2014 for (v=0; v<4; v++) { // do for each vertex in abs_verts
2015 for (vv=0; vv<MAX_VERTICES_PER_SEGMENT; vv++) // do for each vertex in segment
2016 if (abs_verts[v] == Segments[seg].verts[vv])
2017 goto fass_found1; // Current vertex (indexed by v) is present in segment, try next
2018 goto fass_next_seg; // This segment doesn't contain the vertex indexed by v
2022 // All four vertices in sp:side are present in segment seg.
2023 // Determine side and return
2024 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
2025 for (v=0; v<4; v++) {
2026 for (vv=0; vv<4; vv++) {
2027 if (Segments[seg].verts[Side_to_verts[s][v]] == abs_verts[vv])
2030 goto fass_next_side; // Couldn't find vertex v in current side, so try next side.
2033 // Found all four vertices in current side. We are done!
2034 *adj_sp = &Segments[seg];
2039 Assert(0); // Impossible -- we identified this segment as containing all 4 vertices of side "side", but we couldn't find them.
2049 #define JOINT_THRESHOLD 10000*F1_0 // (Huge threshold)
2051 // -------------------------------------------------------------------------------
2052 // Find segment closest to sp:side.
2053 // Return true if segment found and fill in segment in adj_sp and side in adj_side.
2054 // Return false if unable to find, in which case adj_sp and adj_side are undefined.
2055 int med_find_closest_threshold_segment_side(segment *sp, int side, segment **adj_sp, int *adj_side, fix threshold)
2058 vms_vector vsc, vtc; // original segment center, test segment center
2059 fix current_dist, closest_seg_dist;
2061 if (IS_CHILD(sp->children[side]))
2064 compute_center_point_on_side(&vsc, sp, side);
2066 closest_seg_dist = JOINT_THRESHOLD;
2068 // Scan all segments, looking for a segment which contains the four abs_verts
2069 for (seg=0; seg<=Highest_segment_index; seg++)
2070 if (seg != sp-Segments)
2071 for (s=0;s<MAX_SIDES_PER_SEGMENT;s++) {
2072 if (!IS_CHILD(Segments[seg].children[s])) {
2073 compute_center_point_on_side(&vtc, &Segments[seg], s);
2074 current_dist = vm_vec_dist( &vsc, &vtc );
2075 if (current_dist < closest_seg_dist) {
2076 *adj_sp = &Segments[seg];
2078 closest_seg_dist = current_dist;
2083 if (closest_seg_dist < threshold)
2091 void med_check_all_vertices()
2099 for (s=0; s<Num_segments; s++) {
2101 if (sp->segnum != -1)
2102 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
2103 Assert(sp->verts[v] <= Highest_vertex_index);
2109 // -----------------------------------------------------------------------------------------------------
2110 void check_for_overlapping_segment(int segnum)
2114 vms_vector segcenter;
2116 compute_segment_center(&segcenter, &Segments[segnum]);
2118 for (i=0;i<=Highest_segment_index; i++) {
2120 masks = get_seg_masks(&segcenter, i, 0);
2121 if (masks.centermask == 0) {
2122 mprintf((0, "Segment %i center is contained in segment %i\n", segnum, i));
2126 for (v=0; v<8; v++) {
2127 vms_vector pdel, presult;
2129 vm_vec_sub(&pdel, &Vertices[Segments[segnum].verts[v]], &segcenter);
2130 vm_vec_scale_add(&presult, &segcenter, &pdel, (F1_0*15)/16);
2131 masks = get_seg_masks(&presult, i, 0);
2132 if (masks.centermask == 0) {
2133 mprintf((0, "Segment %i near vertex %i is contained in segment %i\n", segnum, v, i));
2142 // -----------------------------------------------------------------------------------------------------
2143 // Check for overlapping segments.
2144 void check_for_overlapping_segments(void)
2148 med_compress_mine();
2150 for (i=0; i<=Highest_segment_index; i++) {
2152 check_for_overlapping_segment(i);
2155 mprintf((0, "\nDone!\n"));