/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/editor/group.c,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:45:48 $ * * group functions * * $Log: group.c,v $ * Revision 1.1.1.1 2006/03/17 19:45:48 zicodxx * initial import * * Revision 1.1.1.1 1999/06/14 22:03:16 donut * Import of d1x 1.37 source. * * Revision 2.0 1995/02/27 11:35:05 john * Version 2.0! No anonymous unions, Watcom 10.0, with no need * for bitmaps.tbl. * * Revision 1.65 1994/11/27 23:17:21 matt * Made changes for new mprintf calling convention * * Revision 1.64 1994/11/17 14:48:08 mike * validation functions moved from editor to game. * * Revision 1.63 1994/11/17 11:38:56 matt * Ripped out code to load old mines * * Revision 1.62 1994/10/27 10:06:20 mike * adapt to no inverse table. * * Revision 1.61 1994/10/03 23:40:08 mike * New fuelcen_activate parameters. * * Revision 1.60 1994/09/28 17:32:01 mike * Make group copying work for copying a group's walls. * * Revision 1.59 1994/09/20 14:35:28 mike * Fix bugs in group subtraction code. Don't allow to attach a group if the attach side is unfree. * * Revision 1.58 1994/08/25 21:58:07 mike * IS_CHILD stuff. * * Revision 1.57 1994/08/04 19:12:58 matt * Changed a bunch of vecmat calls to use multiple-function routines, and to * allow the use of C macros for some functions * * Revision 1.56 1994/08/03 15:40:01 mike * Enable calls to compress_mine to get rid of bugs in group * copying -- was creating invalid segments. * * Revision 1.55 1994/06/30 10:59:13 yuan * Fixed texture translations. * * Revision 1.54 1994/06/22 17:36:00 mike * Fix bug in group creation, was stuffing first two group segs over number * of segments in group (then number would overwrite them), so there would * be two bogus segments in group, one of which was always 0, the other * would be a small number. * * Revision 1.53 1994/06/14 17:07:15 john * *** empty log message *** * * Revision 1.52 1994/06/14 16:59:09 mike * Fix references to tmap_num2, must strip off orientation bits. * * Revision 1.51 1994/05/23 14:56:37 mike * make current segment be add segment. * * Revision 1.50 1994/05/19 12:10:01 matt * Use new vecmat macros and globals * * Revision 1.49 1994/05/17 10:33:59 matt * Deleted unused get_free_object_num() func. * * Revision 1.48 1994/05/09 23:34:17 mike * Punch all sloppy sides in a group, speed up segment rotation. * * Revision 1.47 1994/05/06 14:39:56 mike * Make objects move and copy with groups. * * Revision 1.46 1994/05/05 16:05:54 yuan * Added fuelcen/repaircens to groups... * * Eventually, walls will be added too... * * Revision 1.45 1994/05/05 12:56:25 yuan * Fixed a bunch of group bugs. * * Revision 1.44 1994/05/04 14:10:04 mike * Assert added to prevent bombing out when current_group = -1 * * Revision 1.43 1994/05/02 17:59:18 yuan * Changed undo_status into an array rather than malloced pointers. * * Revision 1.42 1994/05/02 15:23:19 mike * Call med_combine_duplicate_vertices in med_copy_group and med_move_group. * * Revision 1.41 1994/04/27 12:11:23 mike * Fix bug in group rotation. * * Revision 1.40 1994/04/22 10:07:37 yuan * Make sure we don't get obj->next equal itself error. * * Revision 1.39 1994/04/18 17:15:13 yuan * Added error checking for select prev, and next group. * */ #ifdef RCS static char rcsid[] = "$Id: group.c,v 1.1.1.1 2006/03/17 19:45:48 zicodxx Exp $"; #endif #include #include #include "mono.h" #include "gr.h" #include "nocfile.h" #include "ui.h" #include "inferno.h" #include "segment.h" #include "editor/editor.h" #include "error.h" #include "gamemine.h" #include "gameseg.h" #include "bm.h" // For MAX_TEXTURES. #include "textures.h" #include "hash.h" #include "fuelcen.h" #include "medwall.h" void validate_selected_segments(void); struct { int fileinfo_version; int fileinfo_sizeof; } group_top_fileinfo; // Should be same as first two fields below... struct { int fileinfo_version; int fileinfo_sizeof; int header_offset; // Stuff common to game & editor int header_size; int editor_offset; // Editor specific stuff int editor_size; int vertex_offset; int vertex_howmany; int vertex_sizeof; int segment_offset; int segment_howmany; int segment_sizeof; int texture_offset; int texture_howmany; int texture_sizeof; } group_fileinfo; struct { int num_vertices; int num_segments; } group_header; struct { int current_seg; int newsegment_offset; int newsegment_size; int Groupsegp; int Groupside; } group_editor; group GroupList[MAX_GROUPS+1]; segment *Groupsegp[MAX_GROUPS+1]; int Groupside[MAX_GROUPS+1]; int Group_orientation[MAX_GROUPS+1]; int current_group=-1; int num_groups=0; extern void validate_segment_side(segment *sp, int sidenum); // -- void swap_negate_columns(vms_matrix *rotmat, int col1, int col2) // -- { // -- fix col1_1,col1_2,col1_3; // -- fix col2_1,col2_2,col2_3; // -- // -- switch (col1) { // -- case 0: // -- col1_1 = rotmat->m1; // -- col1_2 = rotmat->m2; // -- col1_3 = rotmat->m3; // -- break; // -- // -- case 1: // -- col1_1 = rotmat->m4; // -- col1_2 = rotmat->m5; // -- col1_3 = rotmat->m6; // -- break; // -- // -- case 2: // -- col1_1 = rotmat->m7; // -- col1_2 = rotmat->m8; // -- col1_3 = rotmat->m9; // -- break; // -- } // -- // -- switch (col2) { // -- case 0: // -- col2_1 = rotmat->m1; // -- col2_2 = rotmat->m2; // -- col2_3 = rotmat->m3; // -- break; // -- // -- case 1: // -- col2_1 = rotmat->m4; // -- col2_2 = rotmat->m5; // -- col2_3 = rotmat->m6; // -- break; // -- // -- case 2: // -- col2_1 = rotmat->m7; // -- col2_2 = rotmat->m8; // -- col2_3 = rotmat->m9; // -- break; // -- } // -- // -- switch (col2) { // -- case 0: // -- rotmat->m1 = -col1_1; // -- rotmat->m2 = -col1_2; // -- rotmat->m3 = -col1_3; // -- break; // -- // -- case 1: // -- rotmat->m4 = -col1_1; // -- rotmat->m5 = -col1_2; // -- rotmat->m6 = -col1_3; // -- break; // -- // -- case 2: // -- rotmat->m7 = -col1_1; // -- rotmat->m8 = -col1_2; // -- rotmat->m9 = -col1_3; // -- break; // -- } // -- // -- switch (col1) { // -- case 0: // -- rotmat->m1 = -col2_1; // -- rotmat->m2 = -col2_2; // -- rotmat->m3 = -col2_3; // -- break; // -- // -- case 1: // -- rotmat->m4 = -col2_1; // -- rotmat->m5 = -col2_2; // -- rotmat->m6 = -col2_3; // -- break; // -- // -- case 2: // -- rotmat->m7 = -col2_1; // -- rotmat->m8 = -col2_2; // -- rotmat->m9 = -col2_3; // -- break; // -- } // -- // -- } // -- // -- void swap_negate_rows(vms_matrix *rotmat, int row1, int row2) // -- { // -- fix row1_1,row1_2,row1_3; // -- fix row2_1,row2_2,row2_3; // -- // -- switch (row1) { // -- case 0: // -- row1_1 = rotmat->m1; // -- row1_2 = rotmat->m4; // -- row1_3 = rotmat->m7; // -- break; // -- // -- case 1: // -- row1_1 = rotmat->m2; // -- row1_2 = rotmat->m5; // -- row1_3 = rotmat->m8; // -- break; // -- // -- case 2: // -- row1_1 = rotmat->m3; // -- row1_2 = rotmat->m6; // -- row1_3 = rotmat->m9; // -- break; // -- } // -- // -- switch (row2) { // -- case 0: // -- row2_1 = rotmat->m1; // -- row2_2 = rotmat->m4; // -- row2_3 = rotmat->m7; // -- break; // -- // -- case 1: // -- row2_1 = rotmat->m2; // -- row2_2 = rotmat->m5; // -- row2_3 = rotmat->m8; // -- break; // -- // -- case 2: // -- row2_1 = rotmat->m3; // -- row2_2 = rotmat->m6; // -- row2_3 = rotmat->m9; // -- break; // -- } // -- // -- switch (row2) { // -- case 0: // -- rotmat->m1 = -row1_1; // -- rotmat->m4 = -row1_2; // -- rotmat->m7 = -row1_3; // -- break; // -- // -- case 1: // -- rotmat->m2 = -row1_1; // -- rotmat->m5 = -row1_2; // -- rotmat->m8 = -row1_3; // -- break; // -- // -- case 2: // -- rotmat->m3 = -row1_1; // -- rotmat->m6 = -row1_2; // -- rotmat->m9 = -row1_3; // -- break; // -- } // -- // -- switch (row1) { // -- case 0: // -- rotmat->m1 = -row2_1; // -- rotmat->m4 = -row2_2; // -- rotmat->m7 = -row2_3; // -- break; // -- // -- case 1: // -- rotmat->m2 = -row2_1; // -- rotmat->m5 = -row2_2; // -- rotmat->m8 = -row2_3; // -- break; // -- // -- case 2: // -- rotmat->m3 = -row2_1; // -- rotmat->m6 = -row2_2; // -- rotmat->m9 = -row2_3; // -- break; // -- } // -- // -- } // -- // -- // ------------------------------------------------------------------------------------------------ // -- void side_based_matrix(vms_matrix *rotmat,int destside) // -- { // -- vms_angvec rotvec; // -- vms_matrix r1,rtemp; // -- // -- switch (destside) { // -- case WLEFT: // -- // swap_negate_columns(rotmat,1,2); // -- // swap_negate_rows(rotmat,1,2); // -- break; // -- // -- case WTOP: // -- break; // -- // -- case WRIGHT: // -- // swap_negate_columns(rotmat,1,2); // -- // swap_negate_rows(rotmat,1,2); // -- break; // -- // -- case WBOTTOM: // -- break; // -- // -- case WFRONT: // -- break; // -- // -- case WBACK: // -- break; // -- } // -- // -- } // ------------------------------------------------------------------------------------------------ // Rotate a group about a point. // The segments in the group are indicated (by segment number) in group_seglist. There are group_size segments. // The point about which the groups is rotated is the center of first_seg:first_side. // delta_flag: // 0 absolute rotation, destination specified in terms of base_seg:base_side, used in moving or copying a group // 1 relative rotation, destination specified relative to current orientation of first_seg:first_side // Note: The group must exist in the mine, consisting of actual points in the world. If any points in the // segments in the group are shared by segments not in the group, those points will get rotated and the // segments not in the group will have their shapes modified. // Return value: // 0 group rotated // 1 unable to rotate group 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) { vms_matrix rotmat2,rotmat,rotmat3,rotmat4; vms_angvec pbh = {0,0,0}; // Determine whether this rotation is a delta rotation, meaning to just rotate in place, or an absolute rotation, // which means that the destination rotation is specified, not as a delta, but as an absolute if (delta_flag) { // Create rotation matrix describing rotation. med_extract_matrix_from_segment(first_seg, &rotmat4); // get rotation matrix describing current orientation of first seg set_matrix_based_on_side(&rotmat4, first_side); rotmat3 = *orient_matrix; vm_transpose_matrix(&rotmat3); vm_matrix_x_matrix(&rotmat,&rotmat4,&rotmat3); // this is the desired orientation of the new segment vm_transpose_matrix(&rotmat4); vm_matrix_x_matrix(&rotmat2,&rotmat,&rotmat4); // this is the desired orientation of the new segment } else { // Create rotation matrix describing rotation. med_extract_matrix_from_segment(base_seg, &rotmat); // get rotation matrix describing desired orientation set_matrix_based_on_side(&rotmat, base_side); // modify rotation matrix for desired side // If the new segment is to be attached without rotation, then its orientation is the same as the base_segment vm_matrix_x_matrix(&rotmat4,&rotmat,orient_matrix); // this is the desired orientation of the new segment pbh.b = orientation*16384; vm_angles_2_matrix(&rotmat3,&pbh); vm_matrix_x_matrix(&rotmat, &rotmat4, &rotmat3); rotmat4 = rotmat; rotmat = rotmat4; med_extract_matrix_from_segment(first_seg, &rotmat3); // get rotation matrix describing current orientation of first seg // It is curious that the following statement has no analogue in the med_attach_segment_rotated code. // Perhaps it is because segments are always attached at their front side. If the back side is the side // passed to the function, then the matrix is not modified, which might suggest that what you need to do below // is use Side_opposite[first_side]. set_matrix_based_on_side(&rotmat3, Side_opposite[first_side]); // modify rotation matrix for desired side vm_transpose_matrix(&rotmat3); // get the inverse of the current orientation matrix vm_matrix_x_matrix(&rotmat2,&rotmat,&rotmat3); // now rotmat2 takes the current segment to the desired orientation vm_transpose_matrix(&rotmat2); } *result_mat = rotmat2; } // ----------------------------------------------------------------------------------------- // Rotate all vertices and objects in group. void med_rotate_group(vms_matrix *rotmat, short *group_seglist, int group_size, segment *first_seg, int first_side) { int v,s, objnum; byte vertex_list[MAX_VERTICES]; vms_vector rotate_center; compute_center_point_on_side(&rotate_center, first_seg, first_side); // Create list of points to rotate. for (v=0; v<=Highest_vertex_index; v++) vertex_list[v] = 0; for (s=0; sverts[v]] = 1; // Rotate center of all objects in group. objnum = sp->objects; while (objnum != -1) { vms_vector tv, tv1; mprintf((0, "%2i ", objnum)); vm_vec_sub(&tv1,&Objects[objnum].pos,&rotate_center); vm_vec_rotate(&tv,&tv1,rotmat); vm_vec_add(&Objects[objnum].pos, &tv, &rotate_center); objnum = Objects[objnum].next; } } // Do the pre-rotation xlate, do the rotation, do the post-rotation xlate for (v=0; v<=Highest_vertex_index; v++) if (vertex_list[v]) { vms_vector tv,tv1; vm_vec_sub(&tv1,&Vertices[v],&rotate_center); vm_vec_rotate(&tv,&tv1,rotmat); vm_vec_add(&Vertices[v],&tv,&rotate_center); } } // ------------------------------------------------------------------------------------------------ void cgl_aux(segment *segp, short *seglistp, int *num_segs, short *ignore_list, int num_ignore_segs) { int i, side; int curseg = segp-Segments; for (i=0; i= MAX_SEGMENTS)) { mprintf((0,"Warning -- invalid segment index = %i, max = %i\n",segp-Segments,MAX_SEGMENTS)); Int3(); } if (!Been_visited[segp-Segments]) { seglistp[(*num_segs)++] = segp-Segments; Been_visited[segp-Segments] = 1; for (side=0; sidechildren[side])) cgl_aux(&Segments[segp->children[side]], seglistp, num_segs, ignore_list, num_ignore_segs); } } // ------------------------------------------------------------------------------------------------ // Sets Been_visited[n] if n is reachable from segp void create_group_list(segment *segp, short *seglistp, int *num_segs, short *ignore_list, int num_ignore_segs) { int i; for (i=0; isegnum = %i\n", objnum, Objects[objnum].segnum, new_obj_id, new_segment_id, Objects[new_obj_id].segnum)); } objnum = Objects[objnum].next; } } // Now, for each segment in segment_ids, correct its children numbers by translating through new_segment_ids // and correct its vertex numbers by translating through new_vertex_ids for (s=0; schildren[sidenum]; if (IS_CHILD(seg)) { for (ss=0; ssverts[v]]) { sp->verts[v] = new_vertex_ids[sp->verts[v]]; } } } // end for (s=0... // Now, copy new_segment_ids into segment_ids for (s=0; schildren[base_side])) { editor_status("Error -- unable to copy group, base_seg:base_side must be free."); return 1; } if (num_groups == MAX_GROUPS) { x = MessageBox( -2, -2, 2, "Warning: You have reached the MAXIMUM group number limit. Continue?", "No", "Yes" ); if (x==1) return 0; } if (num_groups < MAX_GROUPS) { num_groups++; new_current_group = num_groups-1; } else new_current_group = 0; Assert(current_group >= 0); // Find groupsegp index for (s=0;sverts[v]] = 1; else { for (v=0; v<=Highest_vertex_index; v++) in_vertex_list[v] = 0; for (s=0; schildren[c])) { if (!in_group(segp->children[c], new_current_group)) { mprintf((0, "2: Breaking connection at seg:side = %i:%i\n", segp-Segments, c)); segp->children[c] = -1; validate_segment_side(segp,c); // we have converted a connection to a side so validate the segment } } } copy_uvs_seg_to_seg(&New_segment, Groupsegp[new_current_group]); // Now do the copy // First, xlate all vertices so center of group_seg:group_side is at origin compute_center_point_on_side(&srcv,group_seg,group_side); for (v=0; v<=Highest_vertex_index; v++) if (in_vertex_list[v]) vm_vec_sub2(&Vertices[v],&srcv); // Now, translate all object positions. for (s=0; schildren[base_side])) if (base_seg->children[base_side] != group_seg-Segments) { editor_status("Error -- unable to move group, base_seg:base_side must be free or point to group_seg."); return 1; } // // See if any vertices in base_seg are contained in any vertex in group_list // for (v=0; vverts[v]) { // editor_status("Error -- unable to move group, it shares a vertex with destination segment."); // return 1; // } for (v=0; v<=Highest_vertex_index; v++) { in_vertex_list[v] = 0; out_vertex_list[v] = 0; } // Make a list of all vertices in group. for (s=0; sverts[vv] == v) sp->verts[vv] = new_vertex_id; } } for (s=0;schildren[c])) { csegp = &Segments[segp->children[c]]; if (csegp->group != current_group) { for (d=0; dchildren[d])) { dsegp = &Segments[csegp->children[d]]; if (dsegp->group == current_group) { csegp->children[d] = -1; validate_segment_side(csegp,d); // we have converted a connection to a side so validate the segment } } segp->children[c] = -1; validate_segment_side(segp,c); // we have converted a connection to a side so validate the segment } } } copy_uvs_seg_to_seg(&New_segment, Groupsegp[current_group]); // Now do the move // First, xlate all vertices so center of group_seg:group_side is at origin compute_center_point_on_side(&srcv,group_seg,group_side); for (v=0; v<=Highest_vertex_index; v++) if (in_vertex_list[v]) vm_vec_sub2(&Vertices[v],&srcv); // Now, move all object positions. for (s=0; schildren[(int) Side_opposite[Curside]])) { // -- I don't understand this, MK, 01/25/94: if (Cursegp->children[Curside] != group_seg-Segments) { editor_status("Error -- unable to rotate group, Cursegp:Side_opposite[Curside] cannot be free."); return 1; } current_group_save = current_group; current_group = ROT_GROUP; Groupsegp[ROT_GROUP] = Cursegp; save_selected_segs(&n_selected_segs_save, selected_segs_save); GroupList[ROT_GROUP].num_segments = 0; newseg = Cursegp - Segments; newseg_side = Side_opposite[Curside]; // Create list of segments to rotate. // Sever connection between first seg to rotate and its connection on Side_opposite[Curside]. child_save = Cursegp->children[newseg_side]; // save connection we are about to sever Cursegp->children[newseg_side] = -1; // sever connection create_group_list(Cursegp, GroupList[ROT_GROUP].segments, &GroupList[ROT_GROUP].num_segments, Selected_segs, 0); // create list of segments in group //mprintf((0, "NumSegs = %d\n", GroupList[ROT_GROUP].num_segments)); Cursegp->children[newseg_side] = child_save; // restore severed connection GroupList[ROT_GROUP].segments[0] = newseg; baseseg = Segments[newseg].children[newseg_side]; if (!IS_CHILD(baseseg)) { editor_status("Error -- unable to rotate segment, side opposite curside is not attached."); restore_selected_segs(n_selected_segs_save,selected_segs_save); current_group = current_group_save; return 1; } baseseg_side = find_connect_side(&Segments[newseg], &Segments[baseseg]); med_extract_matrix_from_segment(&Segments[newseg],&tm1); tm1 = vmd_identity_matrix; vm_angles_2_matrix(&tm2,pbh); vm_matrix_x_matrix(&orient_matrix,&tm1,&tm2); Segments[baseseg].children[baseseg_side] = -1; Segments[newseg].children[newseg_side] = -1; if (!med_move_group(1, &Segments[baseseg], baseseg_side, &Segments[newseg], newseg_side, &orient_matrix, 0)) { Cursegp = &Segments[newseg]; med_create_new_segment_from_cursegp(); // validate_selected_segments(); med_propagate_tmaps_to_segments(&Segments[baseseg], &Segments[newseg], 1); med_propagate_tmaps_to_back_side(&Segments[newseg], Curside, 1); } restore_selected_segs(n_selected_segs_save,selected_segs_save); current_group = current_group_save; return 1; } // ----------------------------------------------------------------------------- // Attach segment in the new-fangled way, which is by using the CopyGroup code. int RotateSegmentNew(vms_angvec *pbh) { int rval; autosave_mine(mine_filename); rval = rotate_segment_new(pbh); if (Lock_view_to_cursegp) set_view_target_from_segment(Cursegp); Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; warn_if_concave_segment(Cursegp); return rval; } static char current_tmap_list[MAX_TEXTURES][13]; // ----------------------------------------------------------------------------- // Save mine will: // 1. Write file info, header info, editor info, vertex data, segment data, // and new_segment in that order, marking their file offset. // 2. Go through all the fields and fill in the offset, size, and sizeof // values in the headers. int med_save_group( char *filename, short *vertex_ids, short *segment_ids, int num_vertices, int num_segments) { FILE * SaveFile; int header_offset, editor_offset, vertex_offset, segment_offset, texture_offset; char ErrorMessage[100]; int i, j, k; int segnum; segment tseg; vms_vector tvert; int found; SaveFile = fopen( filename, "wb" ); if (!SaveFile) { sprintf( ErrorMessage, "ERROR: Unable to open %s\n", filename ); MessageBox( -2, -2, 1, ErrorMessage, "Ok" ); return 1; } //===================== SAVE FILE INFO ======================== group_fileinfo.fileinfo_version = MINE_VERSION; group_fileinfo.fileinfo_sizeof = sizeof(group_fileinfo); group_fileinfo.header_offset = -1; group_fileinfo.header_size = sizeof(group_header); group_fileinfo.editor_offset = -1; group_fileinfo.editor_size = sizeof(group_editor); group_fileinfo.vertex_offset = -1; group_fileinfo.vertex_howmany = num_vertices; group_fileinfo.vertex_sizeof = sizeof(vms_vector); group_fileinfo.segment_offset = -1; group_fileinfo.segment_howmany = num_segments; group_fileinfo.segment_sizeof = sizeof(segment); group_fileinfo.texture_offset = -1; group_fileinfo.texture_howmany = 0; group_fileinfo.texture_sizeof = 13; // num characters in a name // Write the fileinfo fwrite( &group_fileinfo, sizeof(group_fileinfo), 1, SaveFile ); //===================== SAVE HEADER INFO ======================== group_header.num_vertices = num_vertices; group_header.num_segments = num_segments; // Write the editor info header_offset = ftell(SaveFile); fwrite( &group_header, sizeof(group_header), 1, SaveFile ); //===================== SAVE EDITOR INFO ========================== group_editor.newsegment_offset = -1; // To be written group_editor.newsegment_size = sizeof(segment); // Next 3 vars added 10/07 by JAS if (Groupsegp[current_group]) { segnum = Groupsegp[current_group]-Segments; for (i=0;i -1 ) { if (cfseek( LoadFile,group_fileinfo.header_offset, SEEK_SET )) Error( "Error seeking to header_offset in group.c" ); if (cfread( &group_header, group_fileinfo.header_size,1,LoadFile )!=1) Error( "Error reading group_header in group.c" ); } //===================== READ EDITOR INFO ========================== // Set default values group_editor.current_seg = 0; group_editor.newsegment_offset = -1; // To be written group_editor.newsegment_size = sizeof(segment); group_editor.Groupsegp = -1; group_editor.Groupside = 0; if (group_fileinfo.editor_offset > -1 ) { if (cfseek( LoadFile,group_fileinfo.editor_offset, SEEK_SET )) Error( "Error seeking to editor_offset in group.c" ); if (cfread( &group_editor, group_fileinfo.editor_size,1,LoadFile )!=1) Error( "Error reading group_editor in group.c" ); } //===================== READ VERTEX INFO ========================== if ( (group_fileinfo.vertex_offset > -1) && (group_fileinfo.vertex_howmany > 0)) { if (cfseek( LoadFile,group_fileinfo.vertex_offset, SEEK_SET )) Error( "Error seeking to vertex_offset in group.c" ); for (i=0;i -1) && (group_fileinfo.segment_howmany > 0)) { if (cfseek( LoadFile,group_fileinfo.segment_offset, SEEK_SET )) Error( "Error seeking to segment_offset in group.c" ); for (i=0;i -1) && (group_fileinfo.texture_howmany > 0)) { if (cfseek( LoadFile, group_fileinfo.texture_offset, SEEK_SET )) Error( "Error seeking to texture_offset in gamemine.c" ); for (i=0; i< group_fileinfo.texture_howmany; i++ ) { if (cfread( &old_tmap_list[i], group_fileinfo.texture_sizeof, 1, LoadFile )!=1) Error( "Error reading old_tmap_list[i] in gamemine.c" ); } } //=============== GENERATE TEXTURE TRANSLATION TABLE =============== translate = 0; Assert (NumTextures < MAX_TEXTURES); { hashtable ht; hashtable_init( &ht, NumTextures ); // Remove all the file extensions in the textures list for (i=0;igroup == current_group) { Cursegp->group = -1; delete_segment_from_group( Cursegp-Segments, current_group ); Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; diagnostic_message("Segment Ungrouped from Group %d.", current_group); return 1; } else return 0; } int GroupSegment( void ) { if (Cursegp->group == -1) { Cursegp->group = current_group; add_segment_to_group( Cursegp-Segments, current_group ); Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; diagnostic_message("Segment Added to Group %d.", current_group); return 1; } else return 0; } int Degroup( void ) { int i; // GroupList[current_group].num_segments = 0; // Groupsegp[current_group] = 0; if (num_groups==0) return 0; for (i=0; i num_groups-1) current_group--; if (num_groups == 0) current_group = -1; if (Lock_view_to_cursegp) set_view_target_from_segment(Cursegp); Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; diagnostic_message("Group UNgrouped."); return 1; } void NextGroup( void ) { if (num_groups > 0) { current_group++; if (current_group >= num_groups ) current_group = 0; Update_flags |= UF_ED_STATE_CHANGED; mine_changed = 1; } else editor_status("No Next Group\n"); } void PrevGroup( void ) { if (num_groups > 0) { current_group--; if (current_group < 0 ) current_group = num_groups-1; Update_flags |= UF_ED_STATE_CHANGED; mine_changed = 1; } else editor_status("No Previous Group\n"); } // Returns: // 0 = successfully selected // 1 = bad group number int select_group( int num ) { if ((num>=0) && (numchildren[Groupside[current_group]]; if (attach_seg != -1) { int i; for (i=0; ichildren[Groupside[current_group]]); return 1; } } med_compress_mine(); if (!med_copy_group(0, Cursegp, Curside, Groupsegp[current_group], Groupside[current_group], &vmd_identity_matrix)) { autosave_mine(mine_filename); Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; diagnostic_message("Group copied."); return 0; } else return 1; } // ----------------------------------------------------------------------------- int RotateGroup(void) { if (!Groupsegp[current_group]) { editor_status("Error -- Cannot rotate group, no group segment."); return 1; } Group_orientation[current_group]++; if ((Group_orientation[current_group] <0) || (Group_orientation[current_group] >4)) Group_orientation[current_group]=0; med_compress_mine(); if (!med_move_group(0, Cursegp, Curside, Groupsegp[current_group], Groupside[current_group], &vmd_identity_matrix, Group_orientation[current_group])) { Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; diagnostic_message("Group rotated."); return 0; } else return 1; } // ----------------------------------------------------------------------------- // Creates a group from all segments connected to marked segment. int SubtractFromGroup(void) { int x, s, original_group; short *gp; int cur_num_segs; if (!Markedsegp) { editor_status("Error -- Cannot create group, no marked segment."); return 1; } med_compress_mine(); autosave_mine(mine_filename); if (num_groups == MAX_GROUPS) { x = MessageBox( -2, -2, 2, "Warning: You are about to wipe out a group.", "ARGH! NO!", "No problemo." ); if (x==1) return 0; } if (current_group == -1) { editor_status("Error -- No current group. Cannot subtract."); return 1; } original_group = current_group; current_group = (current_group + 1) % MAX_GROUPS; // if (num_groups < MAX_GROUPS) { // current_group = num_groups; // num_groups++; // } else // current_group = 0; // mprintf((0, "Old group: ")); // for (s=0; s num_groups-1) current_group--; if (num_groups==0) current_group = -1; strcpy(undo_status[Autosave_count], "Delete Group UNDONE."); if (Lock_view_to_cursegp) set_view_target_from_segment(Cursegp); Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; diagnostic_message("Group deleted."); // warn_if_concave_segments(); // This could be faster -- just check if deleted segment was concave, warn accordingly return 1; } int MarkGroupSegment( void ) { if ((Cursegp->group != -1) && (Cursegp->group == current_group)) { autosave_mine(mine_filename); Groupsegp[current_group] = Cursegp; Groupside[current_group] = Curside; editor_status("Group Segment Marked."); Update_flags |= UF_ED_STATE_CHANGED; strcpy(undo_status[Autosave_count], "Mark Group Segment UNDONE."); mine_changed = 1; return 1; } else return 0; }