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.
14 * $Source: /cvs/cvsroot/d2x/main/editor/group.c,v $
17 * $Date: 2004-12-19 13:54:27 $
21 * $Log: not supported by cvs2svn $
22 * Revision 1.2 2003/03/09 06:34:09 donut
23 * change byte typedef to sbyte to avoid conflict with win32 byte which is unsigned
25 * Revision 1.1.1.1 1999/06/14 22:03:16 donut
26 * Import of d1x 1.37 source.
28 * Revision 2.0 1995/02/27 11:35:05 john
29 * Version 2.0! No anonymous unions, Watcom 10.0, with no need
32 * Revision 1.65 1994/11/27 23:17:21 matt
33 * Made changes for new mprintf calling convention
35 * Revision 1.64 1994/11/17 14:48:08 mike
36 * validation functions moved from editor to game.
38 * Revision 1.63 1994/11/17 11:38:56 matt
39 * Ripped out code to load old mines
41 * Revision 1.62 1994/10/27 10:06:20 mike
42 * adapt to no inverse table.
44 * Revision 1.61 1994/10/03 23:40:08 mike
45 * New fuelcen_activate parameters.
47 * Revision 1.60 1994/09/28 17:32:01 mike
48 * Make group copying work for copying a group's walls.
50 * Revision 1.59 1994/09/20 14:35:28 mike
51 * Fix bugs in group subtraction code. Don't allow to attach a group if the attach side is unfree.
53 * Revision 1.58 1994/08/25 21:58:07 mike
56 * Revision 1.57 1994/08/04 19:12:58 matt
57 * Changed a bunch of vecmat calls to use multiple-function routines, and to
58 * allow the use of C macros for some functions
60 * Revision 1.56 1994/08/03 15:40:01 mike
61 * Enable calls to compress_mine to get rid of bugs in group
62 * copying -- was creating invalid segments.
64 * Revision 1.55 1994/06/30 10:59:13 yuan
65 * Fixed texture translations.
67 * Revision 1.54 1994/06/22 17:36:00 mike
68 * Fix bug in group creation, was stuffing first two group segs over number
69 * of segments in group (then number would overwrite them), so there would
70 * be two bogus segments in group, one of which was always 0, the other
71 * would be a small number.
73 * Revision 1.53 1994/06/14 17:07:15 john
74 * *** empty log message ***
76 * Revision 1.52 1994/06/14 16:59:09 mike
77 * Fix references to tmap_num2, must strip off orientation bits.
79 * Revision 1.51 1994/05/23 14:56:37 mike
80 * make current segment be add segment.
82 * Revision 1.50 1994/05/19 12:10:01 matt
83 * Use new vecmat macros and globals
85 * Revision 1.49 1994/05/17 10:33:59 matt
86 * Deleted unused get_free_object_num() func.
88 * Revision 1.48 1994/05/09 23:34:17 mike
89 * Punch all sloppy sides in a group, speed up segment rotation.
91 * Revision 1.47 1994/05/06 14:39:56 mike
92 * Make objects move and copy with groups.
94 * Revision 1.46 1994/05/05 16:05:54 yuan
95 * Added fuelcen/repaircens to groups...
97 * Eventually, walls will be added too...
99 * Revision 1.45 1994/05/05 12:56:25 yuan
100 * Fixed a bunch of group bugs.
102 * Revision 1.44 1994/05/04 14:10:04 mike
103 * Assert added to prevent bombing out when current_group = -1
105 * Revision 1.43 1994/05/02 17:59:18 yuan
106 * Changed undo_status into an array rather than malloced pointers.
108 * Revision 1.42 1994/05/02 15:23:19 mike
109 * Call med_combine_duplicate_vertices in med_copy_group and med_move_group.
111 * Revision 1.41 1994/04/27 12:11:23 mike
112 * Fix bug in group rotation.
114 * Revision 1.40 1994/04/22 10:07:37 yuan
115 * Make sure we don't get obj->next equal itself error.
117 * Revision 1.39 1994/04/18 17:15:13 yuan
118 * Added error checking for select prev, and next group.
124 static char rcsid[] = "$Id: group.c,v 1.1 2004-12-19 13:54:27 btb Exp $";
138 #include "editor/editor.h"
140 #include "gamemine.h"
143 #include "bm.h" // For MAX_TEXTURES.
144 #include "textures.h"
150 void validate_selected_segments(void);
153 int fileinfo_version;
155 } group_top_fileinfo; // Should be same as first two fields below...
158 int fileinfo_version;
160 int header_offset; // Stuff common to game & editor
162 int editor_offset; // Editor specific stuff
182 int newsegment_offset;
188 group GroupList[MAX_GROUPS+1];
189 segment *Groupsegp[MAX_GROUPS+1];
190 int Groupside[MAX_GROUPS+1];
191 int Group_orientation[MAX_GROUPS+1];
192 int current_group=-1;
195 extern void validate_segment_side(segment *sp, int sidenum);
197 // -- void swap_negate_columns(vms_matrix *rotmat, int col1, int col2)
199 // -- fix col1_1,col1_2,col1_3;
200 // -- fix col2_1,col2_2,col2_3;
202 // -- switch (col1) {
204 // -- col1_1 = rotmat->m1;
205 // -- col1_2 = rotmat->m2;
206 // -- col1_3 = rotmat->m3;
210 // -- col1_1 = rotmat->m4;
211 // -- col1_2 = rotmat->m5;
212 // -- col1_3 = rotmat->m6;
216 // -- col1_1 = rotmat->m7;
217 // -- col1_2 = rotmat->m8;
218 // -- col1_3 = rotmat->m9;
222 // -- switch (col2) {
224 // -- col2_1 = rotmat->m1;
225 // -- col2_2 = rotmat->m2;
226 // -- col2_3 = rotmat->m3;
230 // -- col2_1 = rotmat->m4;
231 // -- col2_2 = rotmat->m5;
232 // -- col2_3 = rotmat->m6;
236 // -- col2_1 = rotmat->m7;
237 // -- col2_2 = rotmat->m8;
238 // -- col2_3 = rotmat->m9;
242 // -- switch (col2) {
244 // -- rotmat->m1 = -col1_1;
245 // -- rotmat->m2 = -col1_2;
246 // -- rotmat->m3 = -col1_3;
250 // -- rotmat->m4 = -col1_1;
251 // -- rotmat->m5 = -col1_2;
252 // -- rotmat->m6 = -col1_3;
256 // -- rotmat->m7 = -col1_1;
257 // -- rotmat->m8 = -col1_2;
258 // -- rotmat->m9 = -col1_3;
262 // -- switch (col1) {
264 // -- rotmat->m1 = -col2_1;
265 // -- rotmat->m2 = -col2_2;
266 // -- rotmat->m3 = -col2_3;
270 // -- rotmat->m4 = -col2_1;
271 // -- rotmat->m5 = -col2_2;
272 // -- rotmat->m6 = -col2_3;
276 // -- rotmat->m7 = -col2_1;
277 // -- rotmat->m8 = -col2_2;
278 // -- rotmat->m9 = -col2_3;
284 // -- void swap_negate_rows(vms_matrix *rotmat, int row1, int row2)
286 // -- fix row1_1,row1_2,row1_3;
287 // -- fix row2_1,row2_2,row2_3;
289 // -- switch (row1) {
291 // -- row1_1 = rotmat->m1;
292 // -- row1_2 = rotmat->m4;
293 // -- row1_3 = rotmat->m7;
297 // -- row1_1 = rotmat->m2;
298 // -- row1_2 = rotmat->m5;
299 // -- row1_3 = rotmat->m8;
303 // -- row1_1 = rotmat->m3;
304 // -- row1_2 = rotmat->m6;
305 // -- row1_3 = rotmat->m9;
309 // -- switch (row2) {
311 // -- row2_1 = rotmat->m1;
312 // -- row2_2 = rotmat->m4;
313 // -- row2_3 = rotmat->m7;
317 // -- row2_1 = rotmat->m2;
318 // -- row2_2 = rotmat->m5;
319 // -- row2_3 = rotmat->m8;
323 // -- row2_1 = rotmat->m3;
324 // -- row2_2 = rotmat->m6;
325 // -- row2_3 = rotmat->m9;
329 // -- switch (row2) {
331 // -- rotmat->m1 = -row1_1;
332 // -- rotmat->m4 = -row1_2;
333 // -- rotmat->m7 = -row1_3;
337 // -- rotmat->m2 = -row1_1;
338 // -- rotmat->m5 = -row1_2;
339 // -- rotmat->m8 = -row1_3;
343 // -- rotmat->m3 = -row1_1;
344 // -- rotmat->m6 = -row1_2;
345 // -- rotmat->m9 = -row1_3;
349 // -- switch (row1) {
351 // -- rotmat->m1 = -row2_1;
352 // -- rotmat->m4 = -row2_2;
353 // -- rotmat->m7 = -row2_3;
357 // -- rotmat->m2 = -row2_1;
358 // -- rotmat->m5 = -row2_2;
359 // -- rotmat->m8 = -row2_3;
363 // -- rotmat->m3 = -row2_1;
364 // -- rotmat->m6 = -row2_2;
365 // -- rotmat->m9 = -row2_3;
371 // -- // ------------------------------------------------------------------------------------------------
372 // -- void side_based_matrix(vms_matrix *rotmat,int destside)
374 // -- vms_angvec rotvec;
375 // -- vms_matrix r1,rtemp;
377 // -- switch (destside) {
379 // -- // swap_negate_columns(rotmat,1,2);
380 // -- // swap_negate_rows(rotmat,1,2);
387 // -- // swap_negate_columns(rotmat,1,2);
388 // -- // swap_negate_rows(rotmat,1,2);
404 // ------------------------------------------------------------------------------------------------
405 // Rotate a group about a point.
406 // The segments in the group are indicated (by segment number) in group_seglist. There are group_size segments.
407 // The point about which the groups is rotated is the center of first_seg:first_side.
409 // 0 absolute rotation, destination specified in terms of base_seg:base_side, used in moving or copying a group
410 // 1 relative rotation, destination specified relative to current orientation of first_seg:first_side
411 // Note: The group must exist in the mine, consisting of actual points in the world. If any points in the
412 // segments in the group are shared by segments not in the group, those points will get rotated and the
413 // segments not in the group will have their shapes modified.
416 // 1 unable to rotate group
417 void med_create_group_rotation_matrix(vms_matrix *result_mat, int delta_flag, segment *first_seg, int first_side, segment *base_seg, int base_side, vms_matrix *orient_matrix, int orientation)
419 vms_matrix rotmat2,rotmat,rotmat3,rotmat4;
420 vms_angvec pbh = {0,0,0};
422 // Determine whether this rotation is a delta rotation, meaning to just rotate in place, or an absolute rotation,
423 // which means that the destination rotation is specified, not as a delta, but as an absolute
425 // Create rotation matrix describing rotation.
426 med_extract_matrix_from_segment(first_seg, &rotmat4); // get rotation matrix describing current orientation of first seg
427 set_matrix_based_on_side(&rotmat4, first_side);
428 rotmat3 = *orient_matrix;
429 vm_transpose_matrix(&rotmat3);
430 vm_matrix_x_matrix(&rotmat,&rotmat4,&rotmat3); // this is the desired orientation of the new segment
431 vm_transpose_matrix(&rotmat4);
432 vm_matrix_x_matrix(&rotmat2,&rotmat,&rotmat4); // this is the desired orientation of the new segment
434 // Create rotation matrix describing rotation.
436 med_extract_matrix_from_segment(base_seg, &rotmat); // get rotation matrix describing desired orientation
437 set_matrix_based_on_side(&rotmat, base_side); // modify rotation matrix for desired side
439 // If the new segment is to be attached without rotation, then its orientation is the same as the base_segment
440 vm_matrix_x_matrix(&rotmat4,&rotmat,orient_matrix); // this is the desired orientation of the new segment
442 pbh.b = orientation*16384;
443 vm_angles_2_matrix(&rotmat3,&pbh);
444 vm_matrix_x_matrix(&rotmat, &rotmat4, &rotmat3);
449 med_extract_matrix_from_segment(first_seg, &rotmat3); // get rotation matrix describing current orientation of first seg
451 // It is curious that the following statement has no analogue in the med_attach_segment_rotated code.
452 // Perhaps it is because segments are always attached at their front side. If the back side is the side
453 // passed to the function, then the matrix is not modified, which might suggest that what you need to do below
454 // is use Side_opposite[first_side].
455 set_matrix_based_on_side(&rotmat3, Side_opposite[first_side]); // modify rotation matrix for desired side
457 vm_transpose_matrix(&rotmat3); // get the inverse of the current orientation matrix
458 vm_matrix_x_matrix(&rotmat2,&rotmat,&rotmat3); // now rotmat2 takes the current segment to the desired orientation
459 vm_transpose_matrix(&rotmat2);
462 *result_mat = rotmat2;
466 // -----------------------------------------------------------------------------------------
467 // Rotate all vertices and objects in group.
468 void med_rotate_group(vms_matrix *rotmat, short *group_seglist, int group_size, segment *first_seg, int first_side)
471 sbyte vertex_list[MAX_VERTICES];
472 vms_vector rotate_center;
474 compute_center_point_on_side(&rotate_center, first_seg, first_side);
476 // Create list of points to rotate.
477 for (v=0; v<=Highest_vertex_index; v++)
480 for (s=0; s<group_size; s++) {
481 segment *sp = &Segments[group_seglist[s]];
483 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
484 vertex_list[sp->verts[v]] = 1;
486 // Rotate center of all objects in group.
487 objnum = sp->objects;
488 while (objnum != -1) {
491 mprintf((0, "%2i ", objnum));
492 vm_vec_sub(&tv1,&Objects[objnum].pos,&rotate_center);
493 vm_vec_rotate(&tv,&tv1,rotmat);
494 vm_vec_add(&Objects[objnum].pos, &tv, &rotate_center);
496 objnum = Objects[objnum].next;
500 // Do the pre-rotation xlate, do the rotation, do the post-rotation xlate
501 for (v=0; v<=Highest_vertex_index; v++)
502 if (vertex_list[v]) {
505 vm_vec_sub(&tv1,&Vertices[v],&rotate_center);
506 vm_vec_rotate(&tv,&tv1,rotmat);
507 vm_vec_add(&Vertices[v],&tv,&rotate_center);
514 // ------------------------------------------------------------------------------------------------
515 void cgl_aux(segment *segp, short *seglistp, int *num_segs, short *ignore_list, int num_ignore_segs)
518 int curseg = segp-Segments;
520 for (i=0; i<num_ignore_segs; i++)
521 if (curseg == ignore_list[i])
524 if ((segp-Segments < 0) || (segp-Segments >= MAX_SEGMENTS)) {
525 mprintf((0,"Warning -- invalid segment index = %i, max = %i\n",segp-Segments,MAX_SEGMENTS));
529 if (!Been_visited[segp-Segments]) {
530 seglistp[(*num_segs)++] = segp-Segments;
531 Been_visited[segp-Segments] = 1;
533 for (side=0; side<MAX_SIDES_PER_SEGMENT; side++)
534 if (IS_CHILD(segp->children[side]))
535 cgl_aux(&Segments[segp->children[side]], seglistp, num_segs, ignore_list, num_ignore_segs);
539 // ------------------------------------------------------------------------------------------------
540 // Sets Been_visited[n] if n is reachable from segp
541 void create_group_list(segment *segp, short *seglistp, int *num_segs, short *ignore_list, int num_ignore_segs)
545 for (i=0; i<MAX_SEGMENTS; i++)
548 cgl_aux(segp, seglistp, num_segs, ignore_list, num_ignore_segs);
552 #define MXS MAX_SEGMENTS
553 #define MXV MAX_VERTICES
555 // ------------------------------------------------------------------------------------------------
556 void duplicate_group(sbyte *vertex_ids, short *segment_ids, int num_segments)
558 int v,s,ss,new_vertex_id,new_segment_id,sidenum;
559 short new_segment_ids[MAX_SEGMENTS];
560 short new_vertex_ids[MAX_VERTICES]; // If new_vertex_ids[v] != -1, then vertex v has been remapped to new_vertex_ids[v]
561 short new_object_ids[MAX_OBJECTS];
563 // duplicate vertices
564 for (v=0; v<MXV; v++)
565 new_vertex_ids[v] = -1;
567 for (v=0; v<MAX_OBJECTS; v++)
568 new_object_ids[v] = -1;
570 // duplicate vertices
571 for (v=0; v<=Highest_vertex_index; v++) {
573 new_vertex_id = med_create_duplicate_vertex(&Vertices[v]);
574 new_vertex_ids[v] = new_vertex_id;
578 // duplicate segments
579 for (s=0; s<num_segments; s++) {
582 new_segment_id = med_create_duplicate_segment(&Segments[segment_ids[s]]);
583 new_segment_ids[s] = new_segment_id;
584 objnum = Segments[new_segment_id].objects;
585 Segments[new_segment_id].objects = -1;
586 while (objnum != -1) {
587 if (Objects[objnum].type != OBJ_PLAYER) {
589 new_obj_id = obj_create_copy(objnum, &Objects[objnum].pos, new_segment_id);
590 mprintf((0, "Object #%i in segment #%i copied to object #%i, segment #%i: new_obj->segnum = %i\n", objnum, Objects[objnum].segnum, new_obj_id, new_segment_id, Objects[new_obj_id].segnum));
592 objnum = Objects[objnum].next;
596 // Now, for each segment in segment_ids, correct its children numbers by translating through new_segment_ids
597 // and correct its vertex numbers by translating through new_vertex_ids
598 for (s=0; s<num_segments; s++) {
599 segment *sp = &Segments[new_segment_ids[s]];
600 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
601 int seg = sp->children[sidenum];
603 for (ss=0; ss<num_segments; ss++) {
604 if (seg == segment_ids[ss])
605 Segments[new_segment_ids[s]].children[sidenum] = new_segment_ids[ss];
608 } // end for (sidenum=0...
610 // Now fixup vertex ids
611 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++) {
612 if (vertex_ids[sp->verts[v]]) {
613 sp->verts[v] = new_vertex_ids[sp->verts[v]];
618 // Now, copy new_segment_ids into segment_ids
619 for (s=0; s<num_segments; s++) {
620 segment_ids[s] = new_segment_ids[s];
623 // Now, copy new_vertex_ids into vertex_ids
624 for (v=0; v<MXV; v++)
627 for (v=0; v<MXV; v++) {
628 if (new_vertex_ids[v] != -1)
629 vertex_ids[new_vertex_ids[v]] = 1;
635 // ------------------------------------------------------------------------------------------------
636 int in_group(int segnum, int group_num)
640 for (i=0; i<GroupList[group_num].num_segments; i++)
641 if (segnum == GroupList[group_num].segments[i])
647 // ------------------------------------------------------------------------------------------------
648 // Copy a group of segments.
649 // The group is defined as all segments accessible from group_seg.
650 // The group is copied so group_seg:group_side is incident upon base_seg:base_side.
651 // group_seg and its vertices are bashed to coincide with base_seg.
652 // If any vertex of base_seg is contained in a segment that is reachable from group_seg, then errror.
653 int med_copy_group(int delta_flag, segment *base_seg, int base_side, segment *group_seg, int group_side, vms_matrix *orient_matrix)
656 vms_vector srcv,destv;
658 int new_current_group;
662 sbyte in_vertex_list[MAX_VERTICES];
666 if (IS_CHILD(base_seg->children[base_side])) {
667 editor_status("Error -- unable to copy group, base_seg:base_side must be free.");
671 if (num_groups == MAX_GROUPS) {
672 x = MessageBox( -2, -2, 2, "Warning: You have reached the MAXIMUM group number limit. Continue?", "No", "Yes" );
677 if (num_groups < MAX_GROUPS) {
679 new_current_group = num_groups-1;
681 new_current_group = 0;
683 Assert(current_group >= 0);
685 // Find groupsegp index
686 for (s=0;s<GroupList[current_group].num_segments;s++)
687 if (GroupList[current_group].segments[s] == (Groupsegp[current_group]-Segments))
690 GroupList[new_current_group] = GroupList[current_group];
692 // Make a list of all vertices in group.
693 if (group_seg == &New_segment)
694 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
695 in_vertex_list[group_seg->verts[v]] = 1;
697 for (v=0; v<=Highest_vertex_index; v++)
698 in_vertex_list[v] = 0;
700 for (s=0; s<GroupList[new_current_group].num_segments; s++)
701 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
702 in_vertex_list[Segments[GroupList[new_current_group].segments[s]].verts[v]] = 1;
705 // Show which objects are in which segments before group copy.
706 // for (s=0; s<=Highest_segment_index; s++) {
707 // int objnum = Segments[s].objects;
709 // mprintf((0, "Before: Segment #%2i contains objects ", s));
711 // while (objnum != -1) {
712 // mprintf((0, "%2i ",objnum));
713 // objnum = Objects[objnum].next;
715 // mprintf((0, "\n"));
718 // Given a list of vertex indices (indicated by !0 in in_vertex_list) and segment indices (in list GroupList[current_group].segments, there
719 // are GroupList[current_group].num_segments segments), copy all segments and vertices
720 // Return updated lists of vertices and segments in in_vertex_list and GroupList[current_group].segments
721 duplicate_group(in_vertex_list, GroupList[new_current_group].segments, GroupList[new_current_group].num_segments);
723 //group_seg = &Segments[GroupList[new_current_group].segments[0]]; // connecting segment in group has been changed, so update group_seg
725 Groupsegp[new_current_group] = group_seg = &Segments[GroupList[new_current_group].segments[gs_index]];
726 Groupside[new_current_group] = Groupside[current_group];
728 for (s=0; s<GroupList[new_current_group].num_segments; s++) {
729 Segments[GroupList[new_current_group].segments[s]].group = new_current_group;
730 Segments[GroupList[new_current_group].segments[s]].special = SEGMENT_IS_NOTHING;
731 Segments[GroupList[new_current_group].segments[s]].matcen_num = -1;
734 // Breaking connections between segments in the current group and segments not in the group.
735 for (s=0; s<GroupList[new_current_group].num_segments; s++) {
736 mprintf((0, "[%3i %3i] ", GroupList[new_current_group].segments[s], GroupList[current_group].segments[s]));
737 segp = &Segments[GroupList[new_current_group].segments[s]];
738 for (c=0; c<MAX_SIDES_PER_SEGMENT; c++)
739 if (IS_CHILD(segp->children[c])) {
740 if (!in_group(segp->children[c], new_current_group)) {
741 mprintf((0, "2: Breaking connection at seg:side = %i:%i\n", segp-Segments, c));
742 segp->children[c] = -1;
743 validate_segment_side(segp,c); // we have converted a connection to a side so validate the segment
748 copy_uvs_seg_to_seg(&New_segment, Groupsegp[new_current_group]);
751 // First, xlate all vertices so center of group_seg:group_side is at origin
752 compute_center_point_on_side(&srcv,group_seg,group_side);
753 for (v=0; v<=Highest_vertex_index; v++)
754 if (in_vertex_list[v])
755 vm_vec_sub2(&Vertices[v],&srcv);
757 // Now, translate all object positions.
758 for (s=0; s<GroupList[new_current_group].num_segments; s++) {
759 int segnum = GroupList[new_current_group].segments[s];
761 objnum = Segments[segnum].objects;
763 while (objnum != -1) {
764 vm_vec_sub2(&Objects[objnum].pos, &srcv);
765 objnum = Objects[objnum].next;
769 // Now, rotate segments in group so orientation of group_seg is same as base_seg.
770 med_create_group_rotation_matrix(&rotmat, delta_flag, group_seg, group_side, base_seg, base_side, orient_matrix, 0);
771 med_rotate_group(&rotmat, GroupList[new_current_group].segments, GroupList[new_current_group].num_segments, group_seg, group_side);
773 // Now xlate all vertices so group_seg:group_side shares center point with base_seg:base_side
774 compute_center_point_on_side(&destv,base_seg,base_side);
775 for (v=0; v<=Highest_vertex_index; v++)
776 if (in_vertex_list[v])
777 vm_vec_add2(&Vertices[v],&destv);
779 // Now, xlate all object positions.
780 for (s=0; s<GroupList[new_current_group].num_segments; s++) {
781 int segnum = GroupList[new_current_group].segments[s];
782 int objnum = Segments[segnum].objects;
784 while (objnum != -1) {
785 vm_vec_add2(&Objects[objnum].pos, &destv);
786 objnum = Objects[objnum].next;
790 // Now, copy all walls (ie, doors, illusionary, etc.) into the new group.
791 copy_group_walls(current_group, new_current_group);
793 current_group = new_current_group;
795 // Now, form joint on connecting sides.
796 med_form_joint(base_seg,base_side,Groupsegp[current_group],Groupside[new_current_group]);
798 validate_selected_segments();
799 med_combine_duplicate_vertices(in_vertex_list);
805 // ------------------------------------------------------------------------------------------------
806 // Move a group of segments.
807 // The group is defined as all segments accessible from group_seg.
808 // The group is moved so group_seg:group_side is incident upon base_seg:base_side.
809 // group_seg and its vertices are bashed to coincide with base_seg.
810 // If any vertex of base_seg is contained in a segment that is reachable from group_seg, then errror.
811 int med_move_group(int delta_flag, segment *base_seg, int base_side, segment *group_seg, int group_side, vms_matrix *orient_matrix, int orientation)
814 vms_vector srcv,destv;
815 segment *segp, *csegp, *dsegp;
816 sbyte in_vertex_list[MAX_VERTICES], out_vertex_list[MAX_VERTICES];
820 if (IS_CHILD(base_seg->children[base_side]))
821 if (base_seg->children[base_side] != group_seg-Segments) {
822 editor_status("Error -- unable to move group, base_seg:base_side must be free or point to group_seg.");
826 // // See if any vertices in base_seg are contained in any vertex in group_list
827 // for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
828 // for (s=0; s<GroupList[current_group].num_segments; s++)
829 // for (vv=0; vv<MAX_VERTICES_PER_SEGMENT; vv++)
830 // if (Segments[GroupList[current_group].segments[s]].verts[vv] == base_seg->verts[v]) {
831 // editor_status("Error -- unable to move group, it shares a vertex with destination segment.");
835 for (v=0; v<=Highest_vertex_index; v++) {
836 in_vertex_list[v] = 0;
837 out_vertex_list[v] = 0;
840 // Make a list of all vertices in group.
841 for (s=0; s<GroupList[current_group].num_segments; s++)
842 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
843 in_vertex_list[Segments[GroupList[current_group].segments[s]].verts[v]] = 1;
845 // For all segments which are not in GroupList[current_group].segments, mark all their vertices in the out list.
846 for (s=0; s<=Highest_segment_index; s++) {
847 for (ss=0; ss<GroupList[current_group].num_segments; ss++)
848 if (GroupList[current_group].segments[ss] == s)
850 if (ss == GroupList[current_group].num_segments)
851 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
852 out_vertex_list[Segments[s].verts[v]] = 1;
855 // Now, for all vertices present in both the in (part of group segment) and out (part of non-group segment)
856 // create an extra copy of the vertex so we can just move the ones in the in list.
857 local_hvi = Highest_vertex_index; // Can't use Highest_vertex_index as loop termination because it gets increased by med_create_duplicate_vertex.
859 for (v=0; v<=local_hvi; v++)
860 if (in_vertex_list[v])
861 if (out_vertex_list[v]) {
864 new_vertex_id = med_create_duplicate_vertex(&Vertices[v]);
865 in_vertex_list[v] = 0;
866 in_vertex_list[new_vertex_id] = 1;
868 // Create a new vertex and assign all occurrences of vertex v in IN list to new vertex number.
869 for (s=0; s<GroupList[current_group].num_segments; s++) {
870 segment *sp = &Segments[GroupList[current_group].segments[s]];
871 for (vv=0; vv<MAX_VERTICES_PER_SEGMENT; vv++)
872 if (sp->verts[vv] == v)
873 sp->verts[vv] = new_vertex_id;
877 for (s=0;s<GroupList[current_group].num_segments;s++)
878 Segments[GroupList[current_group].segments[s]].group = current_group;
880 // Breaking connections between segments in the group and segments not in the group.
881 for (s=0; s<GroupList[current_group].num_segments; s++)
883 segp = &Segments[GroupList[current_group].segments[s]];
884 for (c=0; c<MAX_SIDES_PER_SEGMENT; c++)
885 if (IS_CHILD(segp->children[c]))
887 csegp = &Segments[segp->children[c]];
888 if (csegp->group != current_group)
890 for (d=0; d<MAX_SIDES_PER_SEGMENT; d++)
891 if (IS_CHILD(csegp->children[d]))
893 dsegp = &Segments[csegp->children[d]];
894 if (dsegp->group == current_group)
896 csegp->children[d] = -1;
897 validate_segment_side(csegp,d); // we have converted a connection to a side so validate the segment
900 segp->children[c] = -1;
901 validate_segment_side(segp,c); // we have converted a connection to a side so validate the segment
906 copy_uvs_seg_to_seg(&New_segment, Groupsegp[current_group]);
909 // First, xlate all vertices so center of group_seg:group_side is at origin
910 compute_center_point_on_side(&srcv,group_seg,group_side);
911 for (v=0; v<=Highest_vertex_index; v++)
912 if (in_vertex_list[v])
913 vm_vec_sub2(&Vertices[v],&srcv);
915 // Now, move all object positions.
916 for (s=0; s<GroupList[current_group].num_segments; s++) {
917 int segnum = GroupList[current_group].segments[s];
918 int objnum = Segments[segnum].objects;
920 // mprintf((0, "Translating objects in segment #%2i by [%7.3f %7.3f %7.3f]: ", segnum, f2fl(srcv.x), f2fl(srcv.y), f2fl(srcv.z)));
922 while (objnum != -1) {
923 mprintf((0, "%2i ", objnum));
924 vm_vec_sub2(&Objects[objnum].pos, &srcv);
925 objnum = Objects[objnum].next;
928 // mprintf((0, "\n"));
930 // Now, rotate segments in group so orientation of group_seg is same as base_seg.
931 med_create_group_rotation_matrix(&rotmat, delta_flag, group_seg, group_side, base_seg, base_side, orient_matrix, orientation);
932 med_rotate_group(&rotmat, GroupList[current_group].segments, GroupList[current_group].num_segments, group_seg, group_side);
934 // Now xlate all vertices so group_seg:group_side shares center point with base_seg:base_side
935 compute_center_point_on_side(&destv,base_seg,base_side);
936 for (v=0; v<=Highest_vertex_index; v++)
937 if (in_vertex_list[v])
938 vm_vec_add2(&Vertices[v],&destv);
940 // Now, rotate all object positions.
941 for (s=0; s<GroupList[current_group].num_segments; s++) {
942 int segnum = GroupList[current_group].segments[s];
943 int objnum = Segments[segnum].objects;
945 while (objnum != -1) {
946 vm_vec_add2(&Objects[objnum].pos, &destv);
947 objnum = Objects[objnum].next;
951 // Now, form joint on connecting sides.
952 med_form_joint(base_seg,base_side,group_seg,group_side);
954 validate_selected_segments();
955 med_combine_duplicate_vertices(in_vertex_list);
961 // -----------------------------------------------------------------------------
962 int place_new_segment_in_world(void)
966 segnum = get_free_segment_number();
968 Segments[segnum] = New_segment;
970 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
971 Segments[segnum].verts[v] = med_create_duplicate_vertex(&Vertices[New_segment.verts[v]]);
977 // -----------------------------------------------------------------------------
978 // Attach segment in the new-fangled way, which is by using the CopyGroup code.
979 int AttachSegmentNewAng(vms_angvec *pbh)
982 vms_matrix orient_matrix;
984 GroupList[current_group].num_segments = 1;
985 newseg = place_new_segment_in_world();
986 GroupList[current_group].segments[0] = newseg;
988 if (!med_move_group(1, Cursegp, Curside, &Segments[newseg], AttachSide, vm_angles_2_matrix(&orient_matrix,pbh),0)) {
989 autosave_mine(mine_filename);
991 med_propagate_tmaps_to_segments(Cursegp,&Segments[newseg],0);
992 med_propagate_tmaps_to_back_side(&Segments[newseg], Side_opposite[AttachSide],0);
993 copy_uvs_seg_to_seg(&New_segment,&Segments[newseg]);
995 Cursegp = &Segments[newseg];
996 Curside = Side_opposite[AttachSide];
997 med_create_new_segment_from_cursegp();
999 if (Lock_view_to_cursegp)
1000 set_view_target_from_segment(Cursegp);
1002 Update_flags |= UF_WORLD_CHANGED;
1004 warn_if_concave_segment(Cursegp);
1010 int AttachSegmentNew(void)
1018 AttachSegmentNewAng(&pbh);
1023 // -----------------------------------------------------------------------------
1024 void save_selected_segs(int *num, short *segs)
1028 for (i=0; i<GroupList[current_group].num_segments; i++)
1029 segs[i] = GroupList[current_group].segments[i];
1031 *num = GroupList[current_group].num_segments;
1034 // -----------------------------------------------------------------------------
1035 void restore_selected_segs(int num, short *segs)
1039 for (i=0; i<GroupList[current_group].num_segments; i++)
1040 GroupList[current_group].segments[i] = segs[i];
1042 GroupList[current_group].num_segments = num;
1045 // -----------------------------------------------------------------------------
1046 void validate_selected_segments(void)
1050 for (i=0; i<GroupList[current_group].num_segments; i++)
1051 validate_segment(&Segments[GroupList[current_group].segments[i]]);
1054 // =====================================================================================
1057 // -----------------------------------------------------------------------------
1058 void delete_segment_from_group(int segment_num, int group_num)
1060 int g, del_seg_index;
1063 for (g=0; g<GroupList[group_num].num_segments; g++)
1064 if (segment_num == GroupList[group_num].segments[g]) {
1069 //mprintf((0, "segment_num=%d delseg_index=%d\n", segment_num, del_seg_index));
1071 if (IS_CHILD(del_seg_index)) {
1072 for (g=del_seg_index;g<GroupList[group_num].num_segments-1;g++) {
1073 GroupList[group_num].segments[g] = GroupList[group_num].segments[g+1];
1075 GroupList[group_num].num_segments--;
1076 //mprintf((0, "num_segments=%d\n\n", GroupList[group_num].num_segments));
1077 Segments[segment_num].group = -1;
1081 // =====================================================================================
1084 // -----------------------------------------------------------------------------
1085 void add_segment_to_group(int segment_num, int group_num)
1087 GroupList[group_num].num_segments++;
1088 GroupList[group_num].segments[GroupList[group_num].num_segments-1] = segment_num;
1090 // =====================================================================================
1093 // -----------------------------------------------------------------------------
1094 int rotate_segment_new(vms_angvec *pbh)
1096 int newseg,baseseg,newseg_side,baseseg_side;
1097 vms_matrix orient_matrix,tm1,tm2;
1098 int n_selected_segs_save;
1099 short selected_segs_save[MAX_SEGMENTS];
1101 int current_group_save;
1103 if (!IS_CHILD(Cursegp->children[(int) Side_opposite[Curside]])) {
1104 // -- I don't understand this, MK, 01/25/94: if (Cursegp->children[Curside] != group_seg-Segments) {
1105 editor_status("Error -- unable to rotate group, Cursegp:Side_opposite[Curside] cannot be free.");
1109 current_group_save = current_group;
1110 current_group = ROT_GROUP;
1111 Groupsegp[ROT_GROUP] = Cursegp;
1113 save_selected_segs(&n_selected_segs_save, selected_segs_save);
1114 GroupList[ROT_GROUP].num_segments = 0;
1115 newseg = Cursegp - Segments;
1116 newseg_side = Side_opposite[Curside];
1118 // Create list of segments to rotate.
1119 // Sever connection between first seg to rotate and its connection on Side_opposite[Curside].
1120 child_save = Cursegp->children[newseg_side]; // save connection we are about to sever
1121 Cursegp->children[newseg_side] = -1; // sever connection
1122 create_group_list(Cursegp, GroupList[ROT_GROUP].segments, &GroupList[ROT_GROUP].num_segments, Selected_segs, 0); // create list of segments in group
1123 //mprintf((0, "NumSegs = %d\n", GroupList[ROT_GROUP].num_segments));
1124 Cursegp->children[newseg_side] = child_save; // restore severed connection
1125 GroupList[ROT_GROUP].segments[0] = newseg;
1127 baseseg = Segments[newseg].children[newseg_side];
1128 if (!IS_CHILD(baseseg)) {
1129 editor_status("Error -- unable to rotate segment, side opposite curside is not attached.");
1130 restore_selected_segs(n_selected_segs_save,selected_segs_save);
1131 current_group = current_group_save;
1135 baseseg_side = find_connect_side(&Segments[newseg], &Segments[baseseg]);
1137 med_extract_matrix_from_segment(&Segments[newseg],&tm1);
1138 tm1 = vmd_identity_matrix;
1139 vm_angles_2_matrix(&tm2,pbh);
1140 vm_matrix_x_matrix(&orient_matrix,&tm1,&tm2);
1142 Segments[baseseg].children[baseseg_side] = -1;
1143 Segments[newseg].children[newseg_side] = -1;
1145 if (!med_move_group(1, &Segments[baseseg], baseseg_side, &Segments[newseg], newseg_side, &orient_matrix, 0)) {
1146 Cursegp = &Segments[newseg];
1147 med_create_new_segment_from_cursegp();
1148 // validate_selected_segments();
1149 med_propagate_tmaps_to_segments(&Segments[baseseg], &Segments[newseg], 1);
1150 med_propagate_tmaps_to_back_side(&Segments[newseg], Curside, 1);
1153 restore_selected_segs(n_selected_segs_save,selected_segs_save);
1154 current_group = current_group_save;
1159 // -----------------------------------------------------------------------------
1160 // Attach segment in the new-fangled way, which is by using the CopyGroup code.
1161 int RotateSegmentNew(vms_angvec *pbh)
1165 autosave_mine(mine_filename);
1167 rval = rotate_segment_new(pbh);
1169 if (Lock_view_to_cursegp)
1170 set_view_target_from_segment(Cursegp);
1172 Update_flags |= UF_WORLD_CHANGED;
1174 warn_if_concave_segment(Cursegp);
1179 static char current_tmap_list[MAX_TEXTURES][13];
1181 // -----------------------------------------------------------------------------
1183 // 1. Write file info, header info, editor info, vertex data, segment data,
1184 // and new_segment in that order, marking their file offset.
1185 // 2. Go through all the fields and fill in the offset, size, and sizeof
1186 // values in the headers.
1187 int med_save_group( char *filename, short *vertex_ids, short *segment_ids, int num_vertices, int num_segments)
1190 int header_offset, editor_offset, vertex_offset, segment_offset, texture_offset;
1191 char ErrorMessage[100];
1198 SaveFile = fopen( filename, "wb" );
1201 sprintf( ErrorMessage, "ERROR: Unable to open %s\n", filename );
1202 MessageBox( -2, -2, 1, ErrorMessage, "Ok" );
1206 //===================== SAVE FILE INFO ========================
1208 group_fileinfo.fileinfo_version = MINE_VERSION;
1209 group_fileinfo.fileinfo_sizeof = sizeof(group_fileinfo);
1210 group_fileinfo.header_offset = -1;
1211 group_fileinfo.header_size = sizeof(group_header);
1212 group_fileinfo.editor_offset = -1;
1213 group_fileinfo.editor_size = sizeof(group_editor);
1214 group_fileinfo.vertex_offset = -1;
1215 group_fileinfo.vertex_howmany = num_vertices;
1216 group_fileinfo.vertex_sizeof = sizeof(vms_vector);
1217 group_fileinfo.segment_offset = -1;
1218 group_fileinfo.segment_howmany = num_segments;
1219 group_fileinfo.segment_sizeof = sizeof(segment);
1220 group_fileinfo.texture_offset = -1;
1221 group_fileinfo.texture_howmany = 0;
1222 group_fileinfo.texture_sizeof = 13; // num characters in a name
1224 // Write the fileinfo
1225 fwrite( &group_fileinfo, sizeof(group_fileinfo), 1, SaveFile );
1227 //===================== SAVE HEADER INFO ========================
1229 group_header.num_vertices = num_vertices;
1230 group_header.num_segments = num_segments;
1232 // Write the editor info
1233 header_offset = ftell(SaveFile);
1234 fwrite( &group_header, sizeof(group_header), 1, SaveFile );
1236 //===================== SAVE EDITOR INFO ==========================
1237 group_editor.newsegment_offset = -1; // To be written
1238 group_editor.newsegment_size = sizeof(segment);
1239 // Next 3 vars added 10/07 by JAS
1240 if (Groupsegp[current_group]) {
1241 segnum = Groupsegp[current_group]-Segments;
1242 for (i=0;i<num_segments;i++)
1243 if (segnum == segment_ids[i])
1244 group_editor.Groupsegp = i;
1247 group_editor.Groupsegp = 0;
1248 group_editor.Groupside = Groupside[current_group];
1250 editor_offset = ftell(SaveFile);
1251 fwrite( &group_editor, sizeof(group_editor), 1, SaveFile );
1254 //===================== SAVE VERTEX INFO ==========================
1256 vertex_offset = ftell(SaveFile);
1257 for (i=0;i<num_vertices;i++) {
1258 tvert = Vertices[vertex_ids[i]];
1259 fwrite( &tvert, sizeof(tvert), 1, SaveFile );
1262 //===================== SAVE SEGMENT INFO =========================
1265 segment_offset = ftell(SaveFile);
1266 for (i=0;i<num_segments;i++) {
1267 tseg = Segments[segment_ids[i]];
1271 for (k=0;k<num_segments;k++)
1272 if (tseg.children[j] == segment_ids[k]) {
1273 tseg.children[j] = k;
1277 if (found==0) tseg.children[j] = -1;
1281 for (k=0;k<num_vertices;k++)
1282 if (tseg.verts[j] == vertex_ids[k]) {
1287 fwrite( &tseg, sizeof(tseg), 1, SaveFile );
1291 //===================== SAVE TEXTURE INFO ==========================
1293 texture_offset = ftell(SaveFile);
1295 for (i=0;i<NumTextures;i++)
1296 strncpy(current_tmap_list[i], TmapInfo[i].filename, 13);
1298 fwrite( current_tmap_list, 13, NumTextures, SaveFile );
1300 //============= REWRITE FILE INFO, TO SAVE OFFSETS ===============
1302 // Update the offset fields
1303 group_fileinfo.header_offset = header_offset;
1304 group_fileinfo.editor_offset = editor_offset;
1305 group_fileinfo.vertex_offset = vertex_offset;
1306 group_fileinfo.segment_offset = segment_offset;
1307 group_fileinfo.texture_offset = texture_offset;
1309 // Write the fileinfo
1310 fseek( SaveFile, 0, SEEK_SET ); // Move to TOF
1311 fwrite( &group_fileinfo, sizeof(group_fileinfo), 1, SaveFile );
1313 //==================== CLOSE THE FILE =============================
1320 static char old_tmap_list[MAX_TEXTURES][13];
1321 static short tmap_xlate_table[MAX_TEXTURES];
1323 // -----------------------------------------------------------------------------
1325 //int med_load_group(char * filename)
1326 int med_load_group( char *filename, short *vertex_ids, short *segment_ids, int *num_vertices, int *num_segments)
1328 int segnum, vertnum;
1329 char ErrorMessage[200];
1338 LoadFile = cfopen( filename, CF_READ_MODE );
1341 sprintf( ErrorMessage, "ERROR: Unable to open %s\n", filename );
1342 MessageBox( -2, -2, 1, ErrorMessage, "Ok" );
1346 //===================== READ FILE INFO ========================
1348 // These are the default values... version and fileinfo_sizeof
1349 // don't have defaults.
1350 group_fileinfo.header_offset = -1;
1351 group_fileinfo.header_size = sizeof(group_header);
1352 group_fileinfo.editor_offset = -1;
1353 group_fileinfo.editor_size = sizeof(group_editor);
1354 group_fileinfo.vertex_offset = -1;
1355 group_fileinfo.vertex_howmany = 0;
1356 group_fileinfo.vertex_sizeof = sizeof(vms_vector);
1357 group_fileinfo.segment_offset = -1;
1358 group_fileinfo.segment_howmany = 0;
1359 group_fileinfo.segment_sizeof = sizeof(segment);
1360 group_fileinfo.texture_offset = -1;
1361 group_fileinfo.texture_howmany = 0;
1362 group_fileinfo.texture_sizeof = 13; // num characters in a name
1364 // Read in group_top_fileinfo to get size of saved fileinfo.
1366 if (cfseek( LoadFile, 0, SEEK_SET ))
1367 Error( "Error seeking to 0 in group.c" );
1369 if (cfread( &group_top_fileinfo, sizeof(group_top_fileinfo),1,LoadFile )!=1)
1370 Error( "Error reading top_fileinfo in group.c" );
1372 // Check version number
1373 if (group_top_fileinfo.fileinfo_version < COMPATIBLE_VERSION )
1375 sprintf( ErrorMessage, "ErrorMessage: You are trying to load %s\n" \
1376 "a version %d group, which is known to be incompatible\n" \
1377 "with the current expected version %d groups.", \
1378 filename, group_top_fileinfo.fileinfo_version, MINE_VERSION );
1380 if (MessageBox( -2, -2, 2, ErrorMessage, "Forget it", "Try anyway" )==1)
1382 cfclose( LoadFile );
1386 MessageBox( -2, -2, 1, "Good luck!", "I need it" );
1389 // Now, Read in the fileinfo
1391 if (cfseek( LoadFile, 0, SEEK_SET ))
1392 Error( "Error seeking to 0b in group.c" );
1394 if (cfread( &group_fileinfo, group_top_fileinfo.fileinfo_sizeof,1,LoadFile )!=1)
1395 Error( "Error reading group_fileinfo in group.c" );
1397 //===================== READ HEADER INFO ========================
1399 // Set default values.
1400 group_header.num_vertices = 0;
1401 group_header.num_segments = 0;
1403 if (group_fileinfo.header_offset > -1 )
1405 if (cfseek( LoadFile,group_fileinfo.header_offset, SEEK_SET ))
1406 Error( "Error seeking to header_offset in group.c" );
1408 if (cfread( &group_header, group_fileinfo.header_size,1,LoadFile )!=1)
1409 Error( "Error reading group_header in group.c" );
1412 //===================== READ EDITOR INFO ==========================
1414 // Set default values
1415 group_editor.current_seg = 0;
1416 group_editor.newsegment_offset = -1; // To be written
1417 group_editor.newsegment_size = sizeof(segment);
1418 group_editor.Groupsegp = -1;
1419 group_editor.Groupside = 0;
1421 if (group_fileinfo.editor_offset > -1 )
1423 if (cfseek( LoadFile,group_fileinfo.editor_offset, SEEK_SET ))
1424 Error( "Error seeking to editor_offset in group.c" );
1426 if (cfread( &group_editor, group_fileinfo.editor_size,1,LoadFile )!=1)
1427 Error( "Error reading group_editor in group.c" );
1431 //===================== READ VERTEX INFO ==========================
1433 if ( (group_fileinfo.vertex_offset > -1) && (group_fileinfo.vertex_howmany > 0))
1435 if (cfseek( LoadFile,group_fileinfo.vertex_offset, SEEK_SET ))
1436 Error( "Error seeking to vertex_offset in group.c" );
1438 for (i=0;i<group_header.num_vertices;i++) {
1440 if (cfread( &tvert, sizeof(tvert),1,LoadFile )!=1)
1441 Error( "Error reading tvert in group.c" );
1442 vertex_ids[i] = med_create_duplicate_vertex( &tvert );
1443 //mprintf((0, "vertex %d created from original %d\n", vertex_ids[i], i));
1448 //==================== READ SEGMENT INFO ===========================
1450 if ( (group_fileinfo.segment_offset > -1) && (group_fileinfo.segment_howmany > 0))
1452 if (cfseek( LoadFile,group_fileinfo.segment_offset, SEEK_SET ))
1453 Error( "Error seeking to segment_offset in group.c" );
1455 for (i=0;i<group_header.num_segments;i++) {
1456 if (cfread( &tseg, sizeof(segment),1,LoadFile )!=1)
1457 Error( "Error reading tseg in group.c" );
1459 segment_ids[i] = get_free_segment_number();
1460 Segments[segment_ids[i]] = tseg;
1461 Segments[segment_ids[i]].objects = -1;
1463 fuelcen_activate( &Segments[segment_ids[i]], Segments[segment_ids[i]].special );
1466 for (i=0;i<group_header.num_segments;i++) {
1468 for (j=0;j<MAX_VERTICES_PER_SEGMENT;j++) {
1469 vertnum = vertex_ids[Segments[segment_ids[i]].verts[j]];
1470 Segments[segment_ids[i]].verts[j] = vertnum;
1473 // Fix children and walls.
1474 for (j=0;j<MAX_SIDES_PER_SEGMENT;j++) {
1475 Segments[segment_ids[i]].sides[j].wall_num = -1;
1476 if (IS_CHILD(Segments[segment_ids[i]].children[j])) {
1477 segnum = segment_ids[Segments[segment_ids[i]].children[j]];
1478 Segments[segment_ids[i]].children[j] = segnum;
1480 //Translate textures.
1481 if (translate == 1) {
1483 tmap_xlate = Segments[segment_ids[i]].sides[j].tmap_num;
1484 Segments[segment_ids[i]].sides[j].tmap_num = tmap_xlate_table[tmap_xlate];
1485 temp = Segments[segment_ids[i]].sides[j].tmap_num2;
1486 tmap_xlate = temp & 0x3fff; // strip off orientation bits
1487 if (tmap_xlate != 0)
1488 Segments[segment_ids[i]].sides[j].tmap_num2 = (temp & (!0x3fff)) | tmap_xlate_table[tmap_xlate]; // mask on original orientation bits
1494 //===================== READ TEXTURE INFO ==========================
1496 if ( (group_fileinfo.texture_offset > -1) && (group_fileinfo.texture_howmany > 0))
1498 if (cfseek( LoadFile, group_fileinfo.texture_offset, SEEK_SET ))
1499 Error( "Error seeking to texture_offset in gamemine.c" );
1501 for (i=0; i< group_fileinfo.texture_howmany; i++ )
1503 if (cfread( &old_tmap_list[i], group_fileinfo.texture_sizeof, 1, LoadFile )!=1)
1504 Error( "Error reading old_tmap_list[i] in gamemine.c" );
1508 //=============== GENERATE TEXTURE TRANSLATION TABLE ===============
1512 Assert (NumTextures < MAX_TEXTURES);
1516 hashtable_init( &ht, NumTextures );
1518 // Remove all the file extensions in the textures list
1520 for (i=0;i<NumTextures;i++) {
1521 temptr = strchr(TmapInfo[i].filename, '.');
1522 if (temptr) *temptr = '\0';
1523 // mprintf( (0, "Texture %d is '%s'\n", i, TmapInfo[i].filename ));
1525 hashtable_insert( &ht, TmapInfo[i].filename, i );
1528 // For every texture, search through the texture list
1529 // to find a matching name.
1530 for (j=0;j<group_fileinfo.texture_howmany;j++) {
1531 // Remove this texture name's extension
1532 temptr = strchr(old_tmap_list[j], '.');
1533 if (temptr) *temptr = '\0';
1535 tmap_xlate_table[j] = hashtable_search( &ht,old_tmap_list[j]);
1536 if (tmap_xlate_table[j] < 0 )
1537 tmap_xlate_table[j] = 0;
1538 if (tmap_xlate_table[j] != j ) translate = 1;
1541 hashtable_free( &ht );
1545 //======================== CLOSE FILE ==============================
1546 cfclose( LoadFile );
1548 //========================= UPDATE VARIABLES ======================
1550 if (group_editor.Groupsegp != -1 )
1551 Groupsegp[current_group] = &Segments[segment_ids[group_editor.Groupsegp]];
1553 Groupsegp[current_group] = NULL;
1555 Groupside[current_group] = group_editor.Groupside;
1557 *num_vertices = group_fileinfo.vertex_howmany;
1558 *num_segments = group_fileinfo.segment_howmany;
1559 warn_if_concave_segments();
1564 char group_filename[128] = "*.GRP";
1566 void checkforgrpext( char * f )
1570 for (i=1; i<strlen(f); i++ )
1572 if (f[i]=='.') return;
1574 if ((f[i]==' '||f[i]==0) )
1596 //short vertex_list[MAX_VERTICES];
1603 char ErrorMessage[200];
1604 sbyte vertex_list[MAX_VERTICES];
1606 if (current_group == -1)
1608 sprintf( ErrorMessage, "ERROR: No current group." );
1609 MessageBox( -2, -2, 1, ErrorMessage, "Ok" );
1613 for (v=0; v<=Highest_vertex_index; v++) {
1617 // Make a list of all vertices in group.
1618 for (s=0; s<GroupList[current_group].num_segments; s++)
1619 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++) {
1620 vertex_list[Segments[GroupList[current_group].segments[s]].verts[v]] = 1;
1624 for (i=0; i<=Highest_vertex_index; i++)
1625 if (vertex_list[i] == 1) {
1626 GroupList[current_group].vertices[v++] = i;
1628 GroupList[current_group].num_vertices = v;
1629 //mprintf((0, "Saving %d vertices, %d segments\n", GroupList[current_group].num_vertices, GroupList[current_group].num_segments));
1630 med_save_group("TEMP.GRP", GroupList[current_group].vertices, GroupList[current_group].segments,
1631 GroupList[current_group].num_vertices, GroupList[current_group].num_segments);
1632 if (ui_get_filename( group_filename, "*.GRP", "SAVE GROUP" ))
1634 checkforgrpext(group_filename);
1635 if (med_save_group(group_filename, GroupList[current_group].vertices, GroupList[current_group].segments,
1636 GroupList[current_group].num_vertices, GroupList[current_group].num_segments))
1649 if (num_groups == MAX_GROUPS)
1651 x = MessageBox( -2, -2, 2, "Warning: You are about to wipe out a group.", "ARGH! NO!", "No problemo." );
1655 if (num_groups < MAX_GROUPS)
1658 current_group = num_groups-1;
1660 else current_group = 0;
1662 if (ui_get_filename( group_filename, "*.GRP", "LOAD GROUP" ))
1664 checkforgrpext(group_filename);
1665 med_load_group(group_filename, GroupList[current_group].vertices, GroupList[current_group].segments,
1666 &GroupList[current_group].num_vertices, &GroupList[current_group].num_segments) ;
1667 //mprintf((0, "Loaded %d vertices, %d segments\n", GroupList[current_group].num_vertices, GroupList[current_group].num_segments));
1669 if (!med_move_group(0, Cursegp, Curside, Groupsegp[current_group], Groupside[current_group], &vmd_identity_matrix, 0)) {
1670 autosave_mine(mine_filename);
1671 set_view_target_from_segment(Cursegp);
1672 Update_flags |= UF_WORLD_CHANGED;
1674 diagnostic_message("Group moved.");
1684 int UngroupSegment( void )
1686 if (Cursegp->group == current_group) {
1688 Cursegp->group = -1;
1689 delete_segment_from_group( Cursegp-Segments, current_group );
1691 Update_flags |= UF_WORLD_CHANGED;
1693 diagnostic_message("Segment Ungrouped from Group %d.", current_group);
1700 int GroupSegment( void )
1702 if (Cursegp->group == -1) {
1704 Cursegp->group = current_group;
1705 add_segment_to_group( Cursegp-Segments, current_group );
1707 Update_flags |= UF_WORLD_CHANGED;
1709 diagnostic_message("Segment Added to Group %d.", current_group);
1720 // GroupList[current_group].num_segments = 0;
1721 // Groupsegp[current_group] = 0;
1723 if (num_groups==0) return 0;
1725 for (i=0; i<GroupList[current_group].num_segments; i++)
1726 delete_segment_from_group( GroupList[current_group].segments[i], current_group );
1728 // delete_segment_from_group( &Segments[GroupList[current_group].segments[i]]-Segments, current_group );
1730 for (i=current_group;i<num_groups-1;i++)
1732 GroupList[i] = GroupList[i+1];
1733 Groupsegp[i] = Groupsegp[i+1];
1738 GroupList[num_groups].num_segments = 0;
1739 Groupsegp[num_groups] = 0;
1741 if (current_group > num_groups-1) current_group--;
1743 if (num_groups == 0)
1746 if (Lock_view_to_cursegp)
1747 set_view_target_from_segment(Cursegp);
1748 Update_flags |= UF_WORLD_CHANGED;
1750 diagnostic_message("Group UNgrouped.");
1755 void NextGroup( void )
1761 if (current_group >= num_groups ) current_group = 0;
1763 Update_flags |= UF_ED_STATE_CHANGED;
1766 else editor_status("No Next Group\n");
1769 void PrevGroup( void )
1774 if (current_group < 0 ) current_group = num_groups-1;
1776 Update_flags |= UF_ED_STATE_CHANGED;
1779 else editor_status("No Previous Group\n");
1783 // 0 = successfully selected
1784 // 1 = bad group number
1785 int select_group( int num )
1787 if ((num>=0) && (num<num_groups))
1789 current_group = num;
1796 // -----------------------------------------------------------------------------
1799 if (!Groupsegp[current_group]) {
1800 editor_status("Error -- Cannot move group, no group segment.");
1804 med_compress_mine();
1806 if (!med_move_group(0, Cursegp, Curside, Groupsegp[current_group], Groupside[current_group], &vmd_identity_matrix, 0)) {
1807 autosave_mine(mine_filename);
1808 Update_flags |= UF_WORLD_CHANGED;
1810 diagnostic_message("Group moved.");
1817 // -----------------------------------------------------------------------------
1822 if (!Groupsegp[current_group]) {
1823 editor_status("Error -- Cannot copy group, no group segment.");
1827 // See if the attach side in the group is attached to another segment.
1828 // If so, it must not be in the group for group copy to be legal.
1829 attach_seg = Groupsegp[current_group]->children[Groupside[current_group]];
1830 if (attach_seg != -1) {
1833 for (i=0; i<GroupList[current_group].num_segments; i++)
1834 if (GroupList[current_group].segments[i] == attach_seg)
1837 if (i != GroupList[current_group].num_segments) {
1838 editor_status("Error -- Cannot copy group, attach side has a child (segment %i) attached.", Groupsegp[current_group]->children[Groupside[current_group]]);
1843 med_compress_mine();
1845 if (!med_copy_group(0, Cursegp, Curside, Groupsegp[current_group], Groupside[current_group], &vmd_identity_matrix)) {
1846 autosave_mine(mine_filename);
1847 Update_flags |= UF_WORLD_CHANGED;
1849 diagnostic_message("Group copied.");
1856 // -----------------------------------------------------------------------------
1857 int RotateGroup(void)
1860 if (!Groupsegp[current_group]) {
1861 editor_status("Error -- Cannot rotate group, no group segment.");
1865 Group_orientation[current_group]++;
1866 if ((Group_orientation[current_group] <0) || (Group_orientation[current_group] >4))
1867 Group_orientation[current_group]=0;
1869 med_compress_mine();
1871 if (!med_move_group(0, Cursegp, Curside, Groupsegp[current_group], Groupside[current_group],
1872 &vmd_identity_matrix, Group_orientation[current_group]))
1874 Update_flags |= UF_WORLD_CHANGED;
1876 diagnostic_message("Group rotated.");
1884 // -----------------------------------------------------------------------------
1885 // Creates a group from all segments connected to marked segment.
1886 int SubtractFromGroup(void)
1888 int x, s, original_group;
1893 editor_status("Error -- Cannot create group, no marked segment.");
1897 med_compress_mine();
1898 autosave_mine(mine_filename);
1900 if (num_groups == MAX_GROUPS) {
1901 x = MessageBox( -2, -2, 2, "Warning: You are about to wipe out a group.", "ARGH! NO!", "No problemo." );
1905 if (current_group == -1) {
1906 editor_status("Error -- No current group. Cannot subtract.");
1910 original_group = current_group;
1912 current_group = (current_group + 1) % MAX_GROUPS;
1914 // if (num_groups < MAX_GROUPS) {
1915 // current_group = num_groups;
1918 // current_group = 0;
1920 // mprintf((0, "Old group: "));
1921 // for (s=0; s<GroupList[original_group].num_segments; s++)
1922 // mprintf((0, "%3i ", GroupList[original_group].segments[s]));
1923 // mprintf((0, "\n"));
1925 // Create a list of segments to copy.
1926 GroupList[current_group].num_segments = 0;
1927 create_group_list(Markedsegp, GroupList[current_group].segments, &GroupList[current_group].num_segments, Selected_segs, N_selected_segs);
1929 // mprintf((0, "New group: "));
1930 // for (s=0; s<GroupList[current_group].num_segments; s++)
1931 // mprintf((0, "%3i ", GroupList[current_group].segments[s]));
1932 // mprintf((0, "\n"));
1934 // Now, scan the two groups, forming a group which consists of only those segments common to the two groups.
1935 gp = GroupList[current_group].segments;
1936 cur_num_segs = GroupList[current_group].num_segments;
1937 for (s=0; s<cur_num_segs; s++) {
1938 short *gp1 = GroupList[original_group].segments;
1942 for (s1=0; s1<GroupList[original_group].num_segments; s1++)
1944 break; // If break executed, then segment found in both lists.
1946 // If current segment was not found in both lists, remove it by copying the last segment over
1947 // it and decreasing the number of segments.
1948 if (s1 == GroupList[original_group].num_segments) {
1949 gp[s] = gp[cur_num_segs];
1954 // Go through mine and seg group number of all segments which are in group
1955 // All segments which were subtracted from group get group set to -1.
1956 mprintf((0, "In segments: "));
1957 for (s=0; s<cur_num_segs; s++) {
1958 Segments[GroupList[current_group].segments[s]].group = current_group;
1959 mprintf((0, "%2i ", GroupList[current_group].segments[s]));
1962 mprintf((0, "\nRemoved segments: "));
1963 for (s=0; s<=Highest_segment_index; s++) {
1965 if (Segments[s].group == current_group) {
1966 for (t=0; t<cur_num_segs; t++)
1967 if (GroupList[current_group].segments[t] == s)
1969 if (s == cur_num_segs) {
1970 Segments[s].group = -1;
1971 mprintf((0, "%2i ", s));
1976 // mprintf((0, "Combined group: "));
1977 // for (s=0; s<GroupList[current_group].num_segments; s++)
1978 // mprintf((0, "%3i ", GroupList[current_group].segments[s]));
1979 // mprintf((0, "\n\n"));
1981 GroupList[current_group].num_segments = cur_num_segs;
1983 // Replace Marked segment with Group Segment.
1984 Groupsegp[current_group] = Markedsegp;
1985 Groupside[current_group] = Markedside;
1987 for (x=0;x<GroupList[current_group].num_segments;x++)
1988 Segments[GroupList[current_group].segments[x]].group = current_group;
1990 Update_flags |= UF_WORLD_CHANGED;
1992 diagnostic_message("Group created.");
1998 // -----------------------------------------------------------------------------
1999 // Creates a group from all segments already in CurrentGroup which can be reached from marked segment
2000 // without passing through current segment.
2001 int CreateGroup(void)
2006 editor_status("Error -- Cannot create group, no marked segment.");
2010 med_compress_mine();
2011 autosave_mine(mine_filename);
2013 if (num_groups == MAX_GROUPS) {
2014 x = MessageBox( -2, -2, 2, "Warning: You are about to wipe out a group.", "ARGH! NO!", "No problemo." );
2016 return 0; // Aborting at user's request.
2019 if (num_groups < MAX_GROUPS) {
2021 current_group = num_groups-1;
2025 // Create a list of segments to copy.
2026 GroupList[current_group].num_segments = 0;
2027 create_group_list(Markedsegp, GroupList[current_group].segments, &GroupList[current_group].num_segments, Selected_segs, 0);
2029 // Replace Marked segment with Group Segment.
2030 Groupsegp[current_group] = Markedsegp;
2031 Groupside[current_group] = Markedside;
2033 // Markedside = WBACK;
2035 for (x=0;x<GroupList[current_group].num_segments;x++)
2036 Segments[GroupList[current_group].segments[x]].group = current_group;
2038 Update_flags |= UF_WORLD_CHANGED;
2040 diagnostic_message("Group created.");
2046 // -----------------------------------------------------------------------------
2047 // Deletes current group.
2048 int DeleteGroup( void )
2052 autosave_mine(mine_filename);
2054 if (num_groups==0) return 0;
2056 //mprintf((0, "num_segments = %d\n", GroupList[current_group].num_segments));
2058 numsegs = GroupList[current_group].num_segments;
2060 for (i=0; i<numsegs; i++) {
2061 med_delete_segment(&Segments[GroupList[current_group].segments[0]]);
2064 for (i=current_group;i<num_groups-1;i++) {
2065 GroupList[i] = GroupList[i+1];
2066 Groupsegp[i] = Groupsegp[i+1];
2070 GroupList[num_groups].num_segments = 0;
2071 Groupsegp[num_groups] = 0;
2073 if (current_group > num_groups-1) current_group--;
2078 strcpy(undo_status[Autosave_count], "Delete Group UNDONE.");
2079 if (Lock_view_to_cursegp)
2080 set_view_target_from_segment(Cursegp);
2082 Update_flags |= UF_WORLD_CHANGED;
2084 diagnostic_message("Group deleted.");
2085 // warn_if_concave_segments(); // This could be faster -- just check if deleted segment was concave, warn accordingly
2092 int MarkGroupSegment( void )
2094 if ((Cursegp->group != -1) && (Cursegp->group == current_group))
2096 autosave_mine(mine_filename);
2097 Groupsegp[current_group] = Cursegp;
2098 Groupside[current_group] = Curside;
2099 editor_status("Group Segment Marked.");
2100 Update_flags |= UF_ED_STATE_CHANGED;
2101 strcpy(undo_status[Autosave_count], "Mark Group Segment UNDONE.");