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