#include "qedefs.h" #import "Project.h" extern Project *project; id map_i; @implementation Map /* =============================================================================== FILE METHODS =============================================================================== */ - (id) init { [super init]; map_i = self; minz = 0; maxz = 80; oldselection = [[NSMutableArray alloc] init]; return self; } - (void) saveSelected { int i, c; id o, w; [oldselection removeAllObjects]; w = [self objectAtIndex: 0]; c = [w count]; sb_newowner = oldselection; for (i = 0; i < c; i++) { o = [w objectAtIndex: 0]; if ([o selected]) { [o moveToEntity]; } else { [w removeObjectAtIndex: 0]; [o release]; } } c = [self count]; for (i = 0; i < c; i++) { o = [self objectAtIndex: 0]; [self removeObjectAtIndex: 0]; [o removeAllObjects]; [o release]; } return; } - (void) addSelected { int i, c; id n, w; c = [oldselection count]; w = [self objectAtIndex: 0]; // world object sb_newowner = w; for (i = 0; i < c; i++) { n = [oldselection objectAtIndex: i--]; [n moveToEntity]; c--; } [oldselection removeAllObjects]; return; } - (void) newMap { id ent; [self saveSelected]; ent = [[Entity alloc] initClass: "worldspawn"]; [self addObject: ent]; currentEntity = NULL; [self setCurrentEntity: ent]; [self addSelected]; return; } - (id) currentEntity { return currentEntity; } - (void) setCurrentEntity: ent { id old; old = currentEntity; currentEntity = ent; if (old != ent) { [things_i newCurrentEntity]; // update inspector [inspcontrol_i changeInspectorTo:i_things]; } return; } - (float) currentMinZ { float grid; grid = [xyview_i gridsize]; minz = grid * rint(minz/grid); return minz; } - (void) setCurrentMinZ: (float) m { if (m > -2048) minz = m; return; } - (float) currentMaxZ { float grid; [self currentMinZ]; // grid align grid = [xyview_i gridsize]; maxz = grid * rint(maxz/grid); if (maxz <= minz) maxz = minz + grid; return maxz; } - (void) setCurrentMaxZ: (float) m { if (m < 2048) maxz = m; return; } - (void) removeObject: (id) o { [super removeObject: o]; if (o == currentEntity) { // select the world [self setCurrentEntity: [self objectAtIndex: 0]]; } } - (void) writeStats { FILE *f; extern int c_updateall; struct timeval tp; struct timezone tzp; gettimeofday (&tp, &tzp); f = fopen ([developerLogFile cString], "a"); fprintf (f,"%i %i\n", (int) tp.tv_sec, c_updateall); c_updateall = 0; fclose (f); return; } - (int) numSelected { int i, c; int num = 0; c = [currentEntity count]; for (i = 0; i < c; i++) if ([[currentEntity objectAtIndex: i] selected]) num++; return num; } - (id) selectedBrush { int i, c; c = [currentEntity count]; for (i=0 ; i= 0; i--) { ent = [self objectAtIndex: i]; c2 = [ent count]; for (j = 0; j < c2; j++) { brush = [ent objectAtIndex: j]; [brush hitByRay: p1 : p2 : &time : &face]; if (time < 0 || time >besttime) continue; bestent = ent; besttime = time; bestbrush = brush; bestface = face; } if (i == 1 && ef && bestbrush) break; // found an entity, so don't check the world } if (besttime == 99999) { qprintf ("trace missed"); return self; } if ( [bestbrush regioned] ) { qprintf ("WANRING: clicked on regioned brush"); return self; } if (bestent != currentEntity) { [self makeSelectedPerform: @selector(deselect)]; [self setCurrentEntity: bestent]; } [quakeed_i disableFlushWindow]; if (![bestbrush selected]) { if ([map_i numSelected] == 0) { // don't grab texture if others are selected td = [bestbrush texturedefForFace: bestface]; [texturepalette_i setTextureDef: td]; } [bestbrush setSelected: YES]; qprintf ("selected entity %i brush %i face %i", [self indexOfObject:bestent], [bestent indexOfObject: bestbrush], bestface); } else { [bestbrush setSelected: NO]; qprintf ("deselected entity %i brush %i face %i", [self indexOfObject:bestent], [bestent indexOfObject: bestbrush], bestface); } [quakeed_i enableFlushWindow]; [quakeed_i updateAll]; return self; } /* ================= grabRay only checks the selected brushes Returns the brush hit, or nil if missed. ================= */ - grabRay: (vec3_t)p1 : (vec3_t)p2 { int i, j, c, c2; id ent; id brush, bestbrush; int face; float time, besttime; bestbrush = nil; besttime = 99999; c = [self count]; for (i=0 ; ibesttime) continue; besttime = time; bestbrush = brush; } } if (besttime == 99999) return nil; return bestbrush; } /* ================= getTextureRay ================= */ - getTextureRay: (vec3_t)p1 : (vec3_t)p2 { int i, j, c, c2; id ent, bestent; id brush, bestbrush; int face, bestface; float time, besttime; texturedef_t *td; vec3_t mins, maxs; bestbrush = nil; bestent = nil; besttime = 99999; bestface = -1; c = [self count]; for (i=0 ; ibesttime) continue; bestent = ent; bestface = face; besttime = time; bestbrush = brush; } } if (besttime == 99999) return nil; if ( ![bestent modifiable]) { qprintf ("can't modify spawned entities"); return self; } td = [bestbrush texturedefForFace: bestface]; [texturepalette_i setTextureDef: td]; qprintf ("grabbed texturedef and sizes"); [bestbrush getMins: mins maxs: maxs]; minz = mins[2]; maxz = maxs[2]; return bestbrush; } /* ================= setTextureRay ================= */ - setTextureRay: (vec3_t)p1 : (vec3_t)p2 : (BOOL)allsides; { int i, j, c, c2; id ent, bestent; id brush, bestbrush; int face, bestface; float time, besttime; texturedef_t td; bestent = nil; bestface = -1; bestbrush = nil; besttime = 99999; c = [self count]; for (i=0 ; ibesttime) continue; bestent = ent; besttime = time; bestbrush = brush; bestface = face; } } if (besttime == 99999) { qprintf ("trace missed"); return self; } if ( ![bestent modifiable]) { qprintf ("can't modify spawned entities"); return self; } if ( [bestbrush regioned] ) { qprintf ("WANRING: clicked on regioned brush"); return self; } [texturepalette_i setTextureDef: &td]; [quakeed_i disableFlushWindow]; if (allsides) { [bestbrush setTexturedef: &td]; qprintf ("textured entity %i brush %i", [self indexOfObject:bestent], [bestent indexOfObject: bestbrush]); } else { [bestbrush setTexturedef: &td forFace: bestface]; qprintf ("deselected entity %i brush %i face %i", [self indexOfObject:bestent], [bestent indexOfObject: bestbrush], bestface); } [quakeed_i enableFlushWindow]; [quakeed_i updateAll]; return self; } /* ============================================================================== OPERATIONS ON SELECTIONS ============================================================================== */ - makeSelectedPerform: (SEL)sel { int i,j, c, c2; id ent, brush; int total; total = 0; c = [self count]; for (i=c-1 ; i>=0 ; i--) { ent = [self objectAtIndex: i]; c2 = [ent count]; for (j = c2-1 ; j >=0 ; j--) { brush = [ent objectAtIndex: j]; if (! [brush selected] ) continue; if ([brush regioned]) continue; total++; [brush perform:sel]; } } // if (!total) // qprintf ("nothing selected"); return self; } - makeUnselectedPerform: (SEL)sel { int i,j, c, c2; id ent, brush; c = [self count]; for (i=c-1 ; i>=0 ; i--) { ent = [self objectAtIndex: i]; c2 = [ent count]; for (j = c2-1 ; j >=0 ; j--) { brush = [ent objectAtIndex: j]; if ( [brush selected] ) continue; if ([brush regioned]) continue; [brush perform:sel]; } } return self; } - makeAllPerform: (SEL)sel { int i,j, c, c2; id ent, brush; c = [self count]; for (i=c-1 ; i>=0 ; i--) { ent = [self objectAtIndex: i]; c2 = [ent count]; for (j = c2-1 ; j >=0 ; j--) { brush = [ent objectAtIndex: j]; if ([brush regioned]) continue; [brush perform:sel]; } } return self; } - makeGlobalPerform: (SEL)sel // in and out of region { int i,j, c, c2; id ent, brush; c = [self count]; for (i=c-1 ; i>=0 ; i--) { ent = [self objectAtIndex: i]; c2 = [ent count]; for (j = c2-1 ; j >=0 ; j--) { brush = [ent objectAtIndex: j]; [brush perform:sel]; } } return self; } void sel_identity (void) { sel_x[0]=1; sel_x[1]=0; sel_x[2]=0; sel_y[0]=0; sel_y[1]=1; sel_y[2]=0; sel_z[0]=0; sel_z[1]=0; sel_z[2]=1; } - transformSelection { if ( ![currentEntity modifiable]) { qprintf ("can't modify spawned entities"); return self; } // find an origin to apply the transformation to sb_mins[0] = sb_mins[1] = sb_mins[2] = 99999; sb_maxs[0] = sb_maxs[1] = sb_maxs[2] = -99999; [self makeSelectedPerform: @selector(addToBBox)]; sel_org[0] = [xyview_i snapToGrid: (sb_mins[0] + sb_maxs[0])/2]; sel_org[1] = [xyview_i snapToGrid: (sb_mins[1] + sb_maxs[1])/2]; sel_org[2] = [xyview_i snapToGrid: (sb_mins[2] + sb_maxs[2])/2]; // do it! [self makeSelectedPerform: @selector(transform)]; [quakeed_i updateAll]; return self; } void swapvectors (vec3_t a, vec3_t b) { vec3_t temp; VectorCopy (a, temp); VectorCopy (b, a); VectorSubtract (vec3_origin, temp, b); } /* =============================================================================== UI operations =============================================================================== */ - rotate_x: sender { sel_identity (); swapvectors(sel_y, sel_z); [self transformSelection]; return self; } - rotate_y: sender { sel_identity (); swapvectors(sel_x, sel_z); [self transformSelection]; return self; } - rotate_z: sender { sel_identity (); swapvectors(sel_x, sel_y); [self transformSelection]; return self; } - flip_x: sender { sel_identity (); sel_x[0] = -1; [self transformSelection]; [map_i makeSelectedPerform: @selector(flipNormals)]; return self; } - flip_y: sender { sel_identity (); sel_y[1] = -1; [self transformSelection]; [map_i makeSelectedPerform: @selector(flipNormals)]; return self; } - flip_z: sender { sel_identity (); sel_z[2] = -1; [self transformSelection]; [map_i makeSelectedPerform: @selector(flipNormals)]; return self; } - cloneSelection: sender { int i,j , c, originalElements; id o, b; id new; sb_translate[0] = sb_translate[1] = [xyview_i gridsize]; sb_translate[2] = 0; // copy individual brushes in the world entity o = [self objectAtIndex: 0]; c = [o count]; for (i=0 ; i