/* ============ Select_Brush ============ */ void Select_Brush( brush_s* brush, bool bComplete, bool bStatus ) { brush_s* b; entity_s* e; g_ptrSelectedFaces.RemoveAll(); g_ptrSelectedFaceBrushes.RemoveAll(); //selected_face = NULL; if ( g_qeglobals.d_select_count < 2 ) g_qeglobals.d_select_order[g_qeglobals.d_select_count] = brush; g_qeglobals.d_select_count++; //if (brush->patchBrush) // Patch_Select(brush->nPatchID); e = brush->owner; if ( e ) { // select complete entity on first click if ( e != world_entity && bComplete == true ) { for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next ) if ( b->owner == e ) goto singleselect; for ( b = e->brushes.onext ; b != &e->brushes ; b = b->onext ) { Brush_RemoveFromList( b ); Brush_AddToList( b, &selected_brushes ); } } else { singleselect: Brush_RemoveFromList( brush ); Brush_AddToList( brush, &selected_brushes ); UpdateSurfaceDialog(); UpdatePatchInspector(); } if ( e->eclass ) { UpdateEntitySel( brush->owner->eclass ); } } if ( bStatus ) { edVec3_c vMin, vMax, vSize; Select_GetBounds( vMin, vMax ); vSize = vMax - vMin; CString strStatus; strStatus.Format( "Selection X:: %.1f Y:: %.1f Z:: %.1f", vSize[0], vSize[1], vSize[2] ); g_pParentWnd->SetStatusText( 2, strStatus ); } }
void Select_Inside( void ) { brush_s* b, *next; int i; edVec3_c mins, maxs; if ( !QE_SingleBrush() ) return; clearSelection(); mins = selected_brushes.next->getMins(); maxs = selected_brushes.next->getMaxs(); Select_Delete(); for ( b = active_brushes.next ; b != &active_brushes ; b = next ) { next = b->next; if ( FilterBrush( b ) ) continue; for ( i = 0 ; i < 3 ; i++ ) if ( b->getMaxs()[i] > maxs[i] || b->getMins()[i] < mins[i] ) break; if ( i == 3 ) { Brush_RemoveFromList( b ); Brush_AddToList( b, &selected_brushes ); } } Sys_UpdateWindows( W_ALL ); }
/* Turn the currently selected entity back into normal brushes */ void Select_Ungroup (void) { entity_t *e; brush_t *b; e = selected_brushes.next->owner; if (!e || e == world_entity || e->eclass->fixedsize) { Sys_Status ("Not a grouped entity.", 0); return; } for (b=e->brushes.onext ; b != &e->brushes ; b=e->brushes.onext) { Brush_RemoveFromList (b); Brush_AddToList (b, &active_brushes); Entity_UnlinkBrush (b); Entity_LinkBrush (world_entity, b); Brush_Build( b ); b->owner = world_entity; } Entity_Free (e); Sys_UpdateWindows (W_ALL); }
void Select_Inside (void) { brush_t *b, *next; int i; vec3_t mins, maxs; if (!QE_SingleBrush ()) return; g_qeglobals.d_select_mode = sel_brush; Math_VectorCopy (selected_brushes.next->mins, mins); Math_VectorCopy (selected_brushes.next->maxs, maxs); Select_Delete (); for (b=active_brushes.next ; b != &active_brushes ; b=next) { next = b->next; for (i=0 ; i<3 ; i++) if (b->maxs[i] > maxs[i] || b->mins[i] < mins[i]) break; if (i == 3) { Brush_RemoveFromList (b); Brush_AddToList (b, &selected_brushes); } } Sys_UpdateWindows (W_ALL); }
/* Frees the brush with all of its faces and display list. Unlinks the brush from whichever chain it is in. Decrements the owner entity's brushcount. Removes owner entity if this was the last brush unless owner is the world. */ void Brush_Free (brush_t *b) { face_t *f, *next; // free faces for (f=b->brush_faces ; f ; f=next) { next = f->next; Face_Free( f ); } /* for ( i = 0; i < b->d_numwindings; i++ ) { if ( b->d_windings[i] ) { FreeWinding( b->d_windings[i] ); b->d_windings[i] = 0; } } */ // unlink from active/selected list if (b->next) Brush_RemoveFromList (b); // unlink from entity list if (b->onext) Entity_UnlinkBrush (b); free (b); }
/* =========== Map_RegionOff Other filtering options may still be on =========== */ void Map_RegionOff( void ){ brush_t *b, *next; int i; region_active = false; for ( i = 0 ; i < 3 ; i++ ) { region_maxs[i] = g_MaxWorldCoord - 64; region_mins[i] = g_MinWorldCoord + 64; } for ( b = filtered_brushes.next ; b != &filtered_brushes ; b = next ) { next = b->next; if ( Map_IsBrushFiltered( b ) ) { continue; // still filtered } Brush_RemoveFromList( b ); if ( active_brushes.next == NULL || active_brushes.prev == NULL ) { active_brushes.next = &active_brushes; active_brushes.prev = &active_brushes; } Brush_AddToList( b, &active_brushes ); b->bFiltered = FilterBrush( b ); } Sys_UpdateWindows( W_ALL ); }
/* ============ Select_Ray If the origin is inside a brush, that brush will be ignored. ============ */ void Select_Ray (vec3_t origin, vec3_t dir, int flags) { trace_t t; t = Test_Ray (origin, dir, flags); if (!t.brush) return; if (flags == SF_SINGLEFACE) { selected_face = t.face; selected_face_brush = t.brush; Sys_UpdateWindows (W_ALL); g_qeglobals.d_select_mode = sel_brush; Texture_SetTexture (&t.face->texdef); UpdateSurfaceDialog(); return; } // move the brush to the other list g_qeglobals.d_select_mode = sel_brush; if (t.selected) { Brush_RemoveFromList (t.brush); Brush_AddToList (t.brush, &active_brushes); } else { Select_Brush (t.brush, !(GetKeyState(VK_MENU) & 0x8000)); } Sys_UpdateWindows (W_ALL); }
void Select_Touching (void) { brush_t *b, *next; int i; vec3_t mins, maxs; if (!QE_SingleBrush ()) return; g_qeglobals.d_select_mode = sel_brush; VectorCopy (selected_brushes.next->mins, mins); VectorCopy (selected_brushes.next->maxs, maxs); for (b=active_brushes.next ; b != &active_brushes ; b=next) { next = b->next; if (FilterBrush (b)) continue; for (i=0 ; i<3 ; i++) if (b->mins[i] > maxs[i]+1 || b->maxs[i] < mins[i]-1) break; if (i == 3) { Brush_RemoveFromList (b); Brush_AddToList (b, &selected_brushes); } } Sys_UpdateWindows (W_ALL); }
/* ======================================================================================================================= Map_RegionOff Other filtering options may still be on ======================================================================================================================= */ void Map_RegionOff(void) { brush_t *b, *next; int i; region_active = false; for (i = 0; i < 3; i++) { region_maxs[i] = MAX_WORLD_COORD; // 4096; region_mins[i] = MIN_WORLD_COORD; // -4096; } for (b = filtered_brushes.next; b != &filtered_brushes; b = next) { next = b->next; if (Map_IsBrushFiltered(b)) { continue; // still filtered } Brush_RemoveFromList(b); if (active_brushes.next == NULL || active_brushes.prev == NULL) { active_brushes.next = &active_brushes; active_brushes.prev = &active_brushes; } Brush_AddToList(b, &active_brushes); } Sys_UpdateWindows(W_ALL); }
void Select_PartialTall( void ) { brush_s* b, *next; //int i; edVec3_c mins, maxs; if ( !QE_SingleBrush() ) return; clearSelection(); mins = selected_brushes.next->getMins(); maxs = selected_brushes.next->getMaxs(); Select_Delete(); int nDim1 = ( g_pParentWnd->ActiveXY()->GetViewType() == YZ ) ? 1 : 0; int nDim2 = ( g_pParentWnd->ActiveXY()->GetViewType() == XY ) ? 1 : 2; for ( b = active_brushes.next ; b != &active_brushes ; b = next ) { next = b->next; if ( ( b->getMins()[nDim1] > maxs[nDim1] || b->getMaxs()[nDim1] < mins[nDim1] ) || ( b->getMins()[nDim2] > maxs[nDim2] || b->getMaxs()[nDim2] < mins[nDim2] ) ) continue; if ( FilterBrush( b ) ) continue; Brush_RemoveFromList( b ); Brush_AddToList( b, &selected_brushes ); #if 0 // old stuff for ( i = 0 ; i < 2 ; i++ ) if ( b->mins[i] > maxs[i] || b->maxs[i] < mins[i] ) break; if ( i == 2 ) { Brush_RemoveFromList( b ); Brush_AddToList( b, &selected_brushes ); } #endif } Sys_UpdateWindows( W_ALL ); }
void Select_CompleteTall (void) { brush_t *b, *next; //int i; vec3_t mins, maxs; if (!QE_SingleBrush ()) return; g_qeglobals.d_select_mode = sel_brush; VectorCopy (selected_brushes.next->mins, mins); VectorCopy (selected_brushes.next->maxs, maxs); Select_Delete (); int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0; int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2; for (b=active_brushes.next ; b != &active_brushes ; b=next) { next = b->next; if ( (b->maxs[nDim1] > maxs[nDim1] || b->mins[nDim1] < mins[nDim1]) || (b->maxs[nDim2] > maxs[nDim2] || b->mins[nDim2] < mins[nDim2]) ) continue; if (FilterBrush (b)) continue; Brush_RemoveFromList (b); Brush_AddToList (b, &selected_brushes); #if 0 // old stuff for (i=0 ; i<2 ; i++) if (b->maxs[i] > maxs[i] || b->mins[i] < mins[i]) break; if (i == 2) { Brush_RemoveFromList (b); Brush_AddToList (b, &selected_brushes); } #endif } Sys_UpdateWindows (W_ALL); }
void SelectBrush (int entitynum, int brushnum) { entity_t *e; brush_t *b; int i; if (entitynum == 0) e = world_entity; else { e = entities.next; while (--entitynum) { e=e->next; if (e == &entities) { Sys_Status ("No such entity.", 0); return; } } } b = e->brushes.onext; if (b == &e->brushes) { Sys_Status ("No such brush.", 0); return; } while (brushnum--) { b=b->onext; if (b == &e->brushes) { Sys_Status ("No such brush.", 0); return; } } Brush_RemoveFromList (b); Brush_AddToList (b, &selected_brushes); Sys_UpdateWindows (W_ALL); for (i=0 ; i<3 ; i++) { if (g_pParentWnd->GetXYWnd()) g_pParentWnd->GetXYWnd()->GetOrigin()[i] = (b->mins[i] + b->maxs[i])/2; if (g_pParentWnd->GetXZWnd()) g_pParentWnd->GetXZWnd()->GetOrigin()[i] = (b->mins[i] + b->maxs[i])/2; if (g_pParentWnd->GetYZWnd()) g_pParentWnd->GetYZWnd()->GetOrigin()[i] = (b->mins[i] + b->maxs[i])/2; } Sys_Status ("Selected.", 0); }
/* ============ Select_Ray If the origin is inside a brush, that brush will be ignored. ============ */ void Select_Ray( vec3_t origin, vec3_t dir, int flags ) { trace_t t; t = Test_Ray( origin, dir, flags ); if ( !t.brush ) return; if ( flags == SF_SINGLEFACE ) { int nCount = g_SelectedFaces.GetSize(); bool bOk = true; for ( int i = 0; i < nCount; i++ ) { if ( t.face == reinterpret_cast<face_s*>( g_SelectedFaces.GetAt( i ) ) ) { bOk = false; // need to move remove i'th entry g_SelectedFaces.RemoveAt( i, 1 ); g_SelectedFaceBrushes.RemoveAt( i, 1 ); } } if ( bOk ) { g_SelectedFaces.Add( t.face ); g_SelectedFaceBrushes.Add( t.brush ); } //selected_face = t.face; //selected_face_brush = t.brush; Sys_UpdateWindows( W_ALL ); clearSelection(); // Texture_SetTexture requires a brushprimit_texdef fitted to the default width=2 height=2 texture brushprimit_texdef_s brushprimit_texdef; ConvertTexMatWithQTexture( &t.face->brushprimit_texdef, t.face->d_texture, &brushprimit_texdef, NULL ); Texture_SetTexture( &t.face->texdef, &brushprimit_texdef, false, false ); UpdateSurfaceDialog(); return; } // move the brush to the other list clearSelection(); if ( t.selected ) { Brush_RemoveFromList( t.brush ); Brush_AddToList( t.brush, &active_brushes ); UpdatePatchInspector(); } else { Select_Brush( t.brush, !( GetKeyState( VK_MENU ) & 0x8000 ) ); } Sys_UpdateWindows( W_ALL ); }
/* ======================================================================================================================= ======================================================================================================================= */ void Map_ApplyRegion( void ) { brush_t *b, *next; region_active = true; for( b = active_brushes.next; b != &active_brushes; b = next ) { next = b->next; if( !Map_IsBrushFiltered( b ) ) { continue; // still filtered } Brush_RemoveFromList( b ); Brush_AddToList( b, &filtered_brushes ); } Sys_UpdateWindows( W_ALL ); }
void Select_Brush (brush_t *brush) { brush_t *b; entity_t *e; selected_face = NULL; if (g_qeglobals.d_select_count < 2) g_qeglobals.d_select_order[g_qeglobals.d_select_count] = brush; g_qeglobals.d_select_count++; e = brush->owner; if (e) { // select complete entity on first click if (e != world_entity) { for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) if (b->owner == e) goto singleselect; for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext) { Brush_RemoveFromList (b); Brush_AddToList (b, &selected_brushes); } } else { singleselect: Brush_RemoveFromList (brush); Brush_AddToList (brush, &selected_brushes); } if (e->eclass) UpdateEntitySel(brush->owner->eclass); } }
void SelectBrush (int entitynum, int brushnum) { entity_t *e; brush_t *b; int i; if (entitynum == 0) e = world_entity; else { e = entities.next; while (--entitynum) { e=e->next; if (e == &entities) { Sys_Printf ("No such entity.\n"); return; } } } b = e->brushes.onext; if (b == &e->brushes) { Sys_Printf ("No such brush.\n"); return; } while (brushnum--) { b=b->onext; if (b == &e->brushes) { Sys_Printf ("No such brush.\n"); return; } } Brush_RemoveFromList (b); Brush_AddToList (b, &selected_brushes); Sys_UpdateWindows (W_ALL); for (i=0 ; i<3 ; i++) g_qeglobals.d_xyz.origin[i] = (b->mins[i] + b->maxs[i])/2; Sys_Printf ("Selected.\n"); }
/* If the origin is inside a brush, that brush will be ignored. */ void Select_Ray (vec3_t origin, vec3_t dir, int flags) { trace_t t; t = Test_Ray (origin, dir, flags); if(!t.brush) return; if (flags == SF_SINGLEFACE) { // [12/8/2012] Don't let them select entity faces ~hogsy // [22/8/2012] Simplified ~hogsy if(t.brush->owner->eclass->fixedsize) return; selected_face = t.face; selected_face_brush = t.brush; Sys_UpdateWindows (W_ALL); g_qeglobals.d_select_mode = sel_brush; return; } // move the brush to the other list g_qeglobals.d_select_mode = sel_brush; if (t.selected) { Brush_RemoveFromList (t.brush); Brush_AddToList (t.brush, &active_brushes); } else Select_Brush (t.brush); Sys_UpdateWindows (W_ALL); }
/* ============= Undo_Redo ============= */ void Undo_Redo(void) { undo_t *redo; brush_t *pBrush, *pNextBrush; entity_t *pEntity, *pNextEntity, *pRedoEntity; if (!g_lastredo) { Sys_Status("Nothing left to redo.\n"); return; } if (g_lastundo) { if (!g_lastundo->done) { Sys_Status("WARNING: last undo not finished.\n"); } } // get the last redo redo = g_lastredo; if (g_lastredo->prev) g_lastredo->prev->next = NULL; else g_redolist = NULL; g_lastredo = g_lastredo->prev; // Undo_GeneralStart(redo->operation); // remove current selection Select_Deselect(); // move "created" brushes back to the last undo for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pNextBrush) { pNextBrush = pBrush->next; if (pBrush->redoId == redo->id) { //move the brush to the undo Brush_RemoveFromList(pBrush); Brush_AddToList(pBrush, &g_lastundo->brushlist); g_undoMemorySize += Brush_MemorySize(pBrush); pBrush->ownerId = pBrush->owner->entityId; Entity_UnlinkBrush(pBrush); } } // move "created" entities back to the last undo for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pNextEntity) { pNextEntity = pEntity->next; if (pEntity->redoId == redo->id) { // check if this entity is in the redo for (pRedoEntity = redo->entitylist.next; pRedoEntity != NULL && pRedoEntity != &redo->entitylist; pRedoEntity = pRedoEntity->next) { // move brushes to the redo entity if (pRedoEntity->entityId == pEntity->entityId) { pRedoEntity->brushes.next = pEntity->brushes.next; pRedoEntity->brushes.prev = pEntity->brushes.prev; pEntity->brushes.next = &pEntity->brushes; pEntity->brushes.prev = &pEntity->brushes; } } // //Entity_Free(pEntity); //move the entity to the redo Entity_RemoveFromList(pEntity); Entity_AddToList(pEntity, &g_lastundo->entitylist); g_undoMemorySize += Entity_MemorySize(pEntity); } } // add the undo entities back into the entity list for (pEntity = redo->entitylist.next; pEntity != NULL && pEntity != &redo->entitylist; pEntity = redo->entitylist.next) { //if this is the world entity if (pEntity->entityId == world_entity->entityId) { //free the epairs of the world entity Entity_FreeEpairs(world_entity); //set back the original epairs world_entity->epairs = pEntity->epairs; //free the world_entity clone that stored the epairs Entity_Free(pEntity); } else { Entity_RemoveFromList(pEntity); Entity_AddToList(pEntity, &entities); } } // add the redo brushes back into the selected brushes for (pBrush = redo->brushlist.next; pBrush != NULL && pBrush != &redo->brushlist; pBrush = redo->brushlist.next) { Brush_RemoveFromList(pBrush); Brush_AddToList(pBrush, &active_brushes); for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next) { if (pEntity->entityId == pBrush->ownerId) { Entity_LinkBrush(pEntity, pBrush); break; } } //if the brush is not linked then it should be linked into the world entity if (pEntity == NULL || pEntity == &entities) { Entity_LinkBrush(world_entity, pBrush); } //build the brush //Brush_Build(pBrush); Select_Brush(pBrush); } // Undo_End(); // common->Printf("%s redone.\n", redo->operation); // g_redoId--; // free the undo Mem_Free(redo); // g_bScreenUpdates = true; Sys_UpdateWindows(W_ALL); }
/* ============= Undo_Undo ============= */ void Undo_Undo(void) { undo_t *undo, *redo; brush_t *pBrush, *pNextBrush; entity_t *pEntity, *pNextEntity, *pUndoEntity; if (!g_lastundo) { Sys_Status("Nothing left to undo.\n"); return; } if (!g_lastundo->done) { Sys_Status("Undo_Undo: WARNING: last undo not yet finished!\n"); } // get the last undo undo = g_lastundo; if (g_lastundo->prev) g_lastundo->prev->next = NULL; else g_undolist = NULL; g_lastundo = g_lastundo->prev; //allocate a new redo redo = (undo_t *) Mem_ClearedAlloc(sizeof(undo_t), TAG_TOOLS); if (!redo) return; memset(redo, 0, sizeof(undo_t)); redo->brushlist.next = &redo->brushlist; redo->brushlist.prev = &redo->brushlist; redo->entitylist.next = &redo->entitylist; redo->entitylist.prev = &redo->entitylist; if (g_lastredo) g_lastredo->next = redo; else g_redolist = redo; redo->prev = g_lastredo; redo->next = NULL; g_lastredo = redo; redo->time = Sys_DoubleTime(); redo->id = g_redoId++; redo->done = true; redo->operation = undo->operation; //reset the redo IDs of all brushes using the new ID for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pBrush->next) { if (pBrush->redoId == redo->id) { pBrush->redoId = 0; } } for (pBrush = selected_brushes.next; pBrush != NULL && pBrush != &selected_brushes; pBrush = pBrush->next) { if (pBrush->redoId == redo->id) { pBrush->redoId = 0; } } //reset the redo IDs of all entities using thew new ID for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next) { if (pEntity->redoId == redo->id) { pEntity->redoId = 0; } } // remove current selection Select_Deselect(); // move "created" brushes to the redo for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush=pNextBrush) { pNextBrush = pBrush->next; if (pBrush->undoId == undo->id) { //Brush_Free(pBrush); //move the brush to the redo Brush_RemoveFromList(pBrush); Brush_AddToList(pBrush, &redo->brushlist); //make sure the ID of the owner is stored pBrush->ownerId = pBrush->owner->entityId; //unlink the brush from the owner entity Entity_UnlinkBrush(pBrush); } } // move "created" entities to the redo for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pNextEntity) { pNextEntity = pEntity->next; if (pEntity->undoId == undo->id) { // check if this entity is in the undo for (pUndoEntity = undo->entitylist.next; pUndoEntity != NULL && pUndoEntity != &undo->entitylist; pUndoEntity = pUndoEntity->next) { // move brushes to the undo entity if (pUndoEntity->entityId == pEntity->entityId) { pUndoEntity->brushes.next = pEntity->brushes.next; pUndoEntity->brushes.prev = pEntity->brushes.prev; pEntity->brushes.next = &pEntity->brushes; pEntity->brushes.prev = &pEntity->brushes; } } // //Entity_Free(pEntity); //move the entity to the redo Entity_RemoveFromList(pEntity); Entity_AddToList(pEntity, &redo->entitylist); } } // add the undo entities back into the entity list for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = undo->entitylist.next) { g_undoMemorySize -= Entity_MemorySize(pEntity); //if this is the world entity if (pEntity->entityId == world_entity->entityId) { //free the epairs of the world entity Entity_FreeEpairs(world_entity); //set back the original epairs world_entity->epairs = pEntity->epairs; //free the world_entity clone that stored the epairs Entity_Free(pEntity); } else { Entity_RemoveFromList(pEntity); Entity_AddToList(pEntity, &entities); pEntity->redoId = redo->id; } } // add the undo brushes back into the selected brushes for (pBrush = undo->brushlist.next; pBrush != NULL && pBrush != &undo->brushlist; pBrush = undo->brushlist.next) { g_undoMemorySize -= Brush_MemorySize(pBrush); Brush_RemoveFromList(pBrush); Brush_AddToList(pBrush, &active_brushes); for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next) { if (pEntity->entityId == pBrush->ownerId) { Entity_LinkBrush(pEntity, pBrush); break; } } //if the brush is not linked then it should be linked into the world entity if (pEntity == NULL || pEntity == &entities) { Entity_LinkBrush(world_entity, pBrush); } //build the brush //Brush_Build(pBrush); Select_Brush(pBrush); pBrush->redoId = redo->id; } // common->Printf("%s undone.\n", undo->operation); // free the undo g_undoMemorySize -= sizeof(undo_t); Mem_Free(undo); g_undoSize--; g_undoId--; if (g_undoId <= 0) g_undoId = 2 * g_undoMaxSize; // Sys_BeginWait(); brush_t *b, *next; for (b = active_brushes.next ; b != NULL && b != &active_brushes ; b=next) { next = b->next; Brush_Build( b, true, false, false ); } for (b = selected_brushes.next ; b != NULL && b != &selected_brushes ; b=next) { next = b->next; Brush_Build( b, true, false, false ); } Sys_EndWait(); g_bScreenUpdates = true; Sys_UpdateWindows(W_ALL); }
/* ============= Undo_Undo ============= */ void Undo_Undo(boolean bSilent) { // spog - disable undo if undo levels = 0 if (g_PrefsDlg.m_nUndoLevels == 0) { Sys_Printf("Undo_Undo: undo is disabled.\n"); return; } undo_t *undo, *redo; brush_t *pBrush, *pNextBrush; entity_t *pEntity, *pNextEntity, *pUndoEntity; if (!g_lastundo) { Sys_Printf("Nothing left to undo.\n"); return; } if (!g_lastundo->done) { Sys_Printf("Undo_Undo: WARNING: last undo not yet finished!\n"); } // get the last undo undo = g_lastundo; if (g_lastundo->prev) g_lastundo->prev->next = NULL; else g_undolist = NULL; g_lastundo = g_lastundo->prev; //allocate a new redo redo = (undo_t *) malloc(sizeof(undo_t)); if (!redo) return; memset(redo, 0, sizeof(undo_t)); redo->brushlist.next = &redo->brushlist; redo->brushlist.prev = &redo->brushlist; redo->entitylist.next = &redo->entitylist; redo->entitylist.prev = &redo->entitylist; if (g_lastredo) g_lastredo->next = redo; else g_redolist = redo; redo->prev = g_lastredo; redo->next = NULL; g_lastredo = redo; redo->time = Sys_DoubleTime(); redo->id = g_redoId++; redo->done = true; redo->operation = undo->operation; //reset the redo IDs of all brushes using the new ID for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pBrush->next) { if (pBrush->redoId == redo->id) { pBrush->redoId = 0; } } for (pBrush = selected_brushes.next; pBrush != NULL && pBrush != &selected_brushes; pBrush = pBrush->next) { if (pBrush->redoId == redo->id) { pBrush->redoId = 0; } } //reset the redo IDs of all entities using thew new ID for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next) { if (pEntity->redoId == redo->id) { pEntity->redoId = 0; } } // deselect current sutff Select_Deselect(); // move "created" brushes to the redo for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush=pNextBrush) { pNextBrush = pBrush->next; if (pBrush->undoId == undo->id) { //Brush_Free(pBrush); //move the brush to the redo Brush_RemoveFromList(pBrush); Brush_AddToList(pBrush, &redo->brushlist); //make sure the ID of the owner is stored pBrush->ownerId = pBrush->owner->entityId; //unlink the brush from the owner entity Entity_UnlinkBrush(pBrush); } } // move "created" entities to the redo for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pNextEntity) { pNextEntity = pEntity->next; if (pEntity->undoId == undo->id) { // check if this entity is in the undo for (pUndoEntity = undo->entitylist.next; pUndoEntity != NULL && pUndoEntity != &undo->entitylist; pUndoEntity = pUndoEntity->next) { // move brushes to the undo entity if (pUndoEntity->entityId == pEntity->entityId) { pUndoEntity->brushes.next = pEntity->brushes.next; pUndoEntity->brushes.prev = pEntity->brushes.prev; pEntity->brushes.next = &pEntity->brushes; pEntity->brushes.prev = &pEntity->brushes; } } // //Entity_Free(pEntity); //move the entity to the redo Entity_RemoveFromList(pEntity); Entity_AddToList(pEntity, &redo->entitylist); } } // add the undo entities back into the entity list for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = undo->entitylist.next) { g_undoMemorySize -= Entity_MemorySize(pEntity); //if this is the world entity if (pEntity->entityId == world_entity->entityId) { epair_t* tmp = world_entity->epairs; world_entity->epairs = pEntity->epairs; pEntity->epairs = tmp; Entity_Free(pEntity); } else { Entity_RemoveFromList(pEntity); Entity_AddToList(pEntity, &entities); pEntity->redoId = redo->id; } } // add the undo brushes back into the selected brushes for (pBrush = undo->brushlist.next; pBrush != NULL && pBrush != &undo->brushlist; pBrush = undo->brushlist.next) { //Sys_Printf("Owner ID: %i\n",pBrush->ownerId); g_undoMemorySize -= Brush_MemorySize(pBrush); Brush_RemoveFromList(pBrush); Brush_AddToList(pBrush, &active_brushes); for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next) // fixes broken undo on entities { //Sys_Printf("Entity ID: %i\n",pEntity->entityId); if (pEntity->entityId == pBrush->ownerId) { Entity_LinkBrush(pEntity, pBrush); break; } } //if the brush is not linked then it should be linked into the world entity //++timo FIXME: maybe not, maybe we've lost this entity's owner! if (pEntity == NULL || pEntity == &entities) { Entity_LinkBrush(world_entity, pBrush); } //build the brush //Brush_Build(pBrush); Select_Brush(pBrush); pBrush->redoId = redo->id; } if (!bSilent) Sys_Printf("%s undone.\n", undo->operation); // free the undo g_undoMemorySize -= sizeof(undo_t); free(undo); g_undoSize--; g_undoId--; if (g_undoId <= 0) g_undoId = 2 * g_undoMaxSize; // g_bScreenUpdates = true; UpdateSurfaceDialog(); Sys_UpdateWindows(W_ALL); }
/* ============= CSG_Merge ============= */ void CSG_Merge(void) { brush_t *b, *next, *newlist, *newbrush; struct entity_s *owner; Sys_Printf ("Merging...\n"); if (selected_brushes.next == &selected_brushes) { Sys_Printf ("No brushes selected.\n"); return; } if (selected_brushes.next->next == &selected_brushes) { Sys_Printf ("At least two brushes have to be selected.\n"); return; } owner = selected_brushes.next->owner; for (b = selected_brushes.next; b != &selected_brushes; b = next) { next = b->next; if (b->owner->eclass->fixedsize) { // can't use texture from a fixed entity, so don't subtract Sys_Printf ("Cannot add fixed size entities.\n"); return; } if (b->owner != owner) { Sys_Printf ("Cannot add brushes from different entities.\n"); return; } } newlist = NULL; for (b = selected_brushes.next; b != &selected_brushes; b = next) { next = b->next; Brush_RemoveFromList(b); b->next = newlist; b->prev = NULL; newlist = b; } newbrush = Brush_MergeList(newlist, true); // if the new brush would not be convex if (!newbrush) { // add the brushes back into the selection for (b = newlist; b; b = next) { next = b->next; b->next = NULL; b->prev = NULL; Brush_AddToList(b, &selected_brushes); } Sys_Printf ("Cannot add a set of brushes with a concave hull.\n"); return; } // free the original brushes for (b = newlist; b; b = next) { next = b->next; b->next = NULL; b->prev = NULL; Brush_Free(b); } Brush_AddToList(newbrush, &selected_brushes); Sys_Printf ("Done.\n"); Sys_UpdateWindows (W_ALL); }
/* ============= CSG_Subtract ============= */ void CSG_Subtract (void) { brush_t *b, *s, *fragments, *nextfragment, *frag, *next, *snext; brush_t fragmentlist; int i, numfragments, numbrushes; Sys_Printf ("Subtracting...\n"); if (selected_brushes.next == &selected_brushes) { Sys_Printf ("No brushes selected.\n"); return; } fragmentlist.next = &fragmentlist; fragmentlist.prev = &fragmentlist; numfragments = 0; numbrushes = 0; for (b = selected_brushes.next ; b != &selected_brushes ; b=next) { next = b->next; if (b->owner->eclass->fixedsize) continue; // can't use texture from a fixed entity, so don't subtract // chop all fragments further up for (s = fragmentlist.next; s != &fragmentlist; s = snext) { snext = s->next; for (i=0 ; i<3 ; i++) if (b->mins[i] >= s->maxs[i] - ON_EPSILON || b->maxs[i] <= s->mins[i] + ON_EPSILON) break; if (i != 3) continue; // definately don't touch fragments = Brush_Subtract(s, b); // if the brushes did not really intersect if (fragments == s) continue; // try to merge fragments fragments = Brush_MergeListPairs(fragments, true); // add the fragments to the list for (frag = fragments; frag; frag = nextfragment) { nextfragment = frag->next; frag->next = NULL; frag->owner = s->owner; Brush_AddToList(frag, &fragmentlist); } // free the original brush Brush_Free(s); } // chop any active brushes up for (s = active_brushes.next; s != &active_brushes; s = snext) { snext = s->next; if (s->owner->eclass->fixedsize || s->hiddenBrush) continue; for (i=0 ; i<3 ; i++) if (b->mins[i] >= s->maxs[i] - ON_EPSILON || b->maxs[i] <= s->mins[i] + ON_EPSILON) break; if (i != 3) continue; // definately don't touch fragments = Brush_Subtract(s, b); // if the brushes did not really intersect if (fragments == s) continue; // one extra brush chopped up numbrushes++; // try to merge fragments fragments = Brush_MergeListPairs(fragments, true); // add the fragments to the list for (frag = fragments; frag; frag = nextfragment) { nextfragment = frag->next; frag->next = NULL; frag->owner = s->owner; Brush_AddToList(frag, &fragmentlist); } // free the original brush Brush_Free(s); } } // move all fragments to the active brush list for (frag = fragmentlist.next; frag != &fragmentlist; frag = nextfragment) { nextfragment = frag->next; numfragments++; Brush_RemoveFromList(frag); Brush_AddToList(frag, &active_brushes); } if (numfragments == 0) { Sys_Printf ("Selected brush%s did not intersect with any other brushes.\n", (selected_brushes.next->next == &selected_brushes) ? "":"es"); return; } Sys_Printf ("Done. (created %d fragment%s out of %d brush%s)\n", numfragments, (numfragments == 1)?"":"s", numbrushes, (numbrushes == 1)?"":"es"); Sys_UpdateWindows(W_ALL); }
/* ============ Select_Clone Creates an exact duplicate of the selection in place, then moves the selected brushes off of their old positions ============ */ void Select_Clone (void) { brush_t *b, *b2, *n, *next, *next2; vec3_t delta; entity_t *e; g_qeglobals.d_workcount++; g_qeglobals.d_select_mode = sel_brush; delta[0] = g_qeglobals.d_gridsize; delta[1] = g_qeglobals.d_gridsize; delta[2] = 0; for (b=selected_brushes.next ; b != &selected_brushes ; b=next) { next = b->next; // if the brush is a world brush, handle simply if (b->owner == world_entity) { n = Brush_Clone (b); Brush_AddToList (n, &active_brushes); Entity_LinkBrush (world_entity, n); Brush_Build( n ); Brush_Move (b, delta); continue; } e = Entity_Clone (b->owner); // clear the target / targetname DeleteKey (e, "target"); DeleteKey (e, "targetname"); // if the brush is a fixed size entity, create a new entity if (b->owner->eclass->fixedsize) { n = Brush_Clone (b); Brush_AddToList (n, &active_brushes); Entity_LinkBrush (e, n); Brush_Build( n ); Brush_Move (b, delta); continue; } // brush is a complex entity, grab all the other ones now next = &selected_brushes; for ( b2 = b ; b2 != &selected_brushes ; b2=next2) { next2 = b2->next; if (b2->owner != b->owner) { if (next == &selected_brushes) next = b2; continue; } // move b2 to the start of selected_brushes, // so it won't be hit again Brush_RemoveFromList (b2); Brush_AddToList (b2, &selected_brushes); n = Brush_Clone (b2); Brush_AddToList (n, &active_brushes); Entity_LinkBrush (e, n); Brush_Build( n ); Brush_Move (b2, delta); } } Sys_UpdateWindows (W_ALL); }
/* ============ Select_Clone Creates an exact duplicate of the selection in place, then moves the selected brushes off of their old positions ============ */ void Select_Clone( void ) { #if 1 ASSERT( g_pParentWnd->ActiveXY() ); g_bScreenUpdates = false; g_pParentWnd->ActiveXY()->Copy(); g_pParentWnd->ActiveXY()->Paste(); g_pParentWnd->NudgeSelection( 2, g_qeglobals.d_gridsize ); g_pParentWnd->NudgeSelection( 3, g_qeglobals.d_gridsize ); g_bScreenUpdates = true; Sys_UpdateWindows( W_ALL ); #else brush_s* b, *b2, *n, *next, *next2; vec3_t delta; entity_s* e; g_qeglobals.d_workcount++; clearSelection(); delta[0] = g_qeglobals.d_gridsize; delta[1] = g_qeglobals.d_gridsize; delta[2] = 0; for ( b = selected_brushes.next ; b != &selected_brushes ; b = next ) { next = b->next; // if the brush is a world brush, handle simply if ( b->owner == world_entity ) { n = Brush_Clone( b ); Brush_AddToList( n, &active_brushes ); Entity_LinkBrush( world_entity, n ); Brush_Build( n ); Brush_Move( b, delta ); continue; } e = Entity_Clone( b->owner ); // clear the target / targetname DeleteKey( e, "target" ); DeleteKey( e, "targetname" ); // if the brush is a fixed size entity, create a new entity if ( b->owner->eclass->fixedsize ) { n = Brush_Clone( b ); Brush_AddToList( n, &active_brushes ); Entity_LinkBrush( e, n ); Brush_Build( n ); Brush_Move( b, delta ); continue; } // brush is a complex entity, grab all the other ones now next = &selected_brushes; for ( b2 = b ; b2 != &selected_brushes ; b2 = next2 ) { next2 = b2->next; if ( b2->owner != b->owner ) { if ( next == &selected_brushes ) next = b2; continue; } // move b2 to the start of selected_brushes, // so it won't be hit again Brush_RemoveFromList( b2 ); Brush_AddToList( b2, &selected_brushes ); n = Brush_Clone( b2 ); Brush_AddToList( n, &active_brushes ); Entity_LinkBrush( e, n ); Brush_Build( n ); Brush_Move( b2, delta, true ); } } Sys_UpdateWindows( W_ALL ); #endif }
void Select_AllOfType() { brush_s* b, *next; entity_s* e; if ( ( selected_brushes.next == &selected_brushes ) || ( selected_brushes.next->next != &selected_brushes ) ) { CString strName; if ( g_ptrSelectedFaces.GetSize() == 0 ) { strName = g_qeglobals.d_texturewin.texdef.name; } else { face_s* selFace = reinterpret_cast<face_s*>( g_ptrSelectedFaces.GetAt( 0 ) ); strName = selFace->texdef.name; } Select_Deselect(); for ( b = active_brushes.next ; b != &active_brushes ; b = next ) { next = b->next; if ( FilterBrush( b ) ) continue; if ( b->patchBrush ) { if ( strcmpi( strName, b->pPatch->d_texture->name ) == 0 ) { Brush_RemoveFromList( b ); Brush_AddToList( b, &selected_brushes ); } } else { for ( face_s* pFace = b->brush_faces; pFace; pFace = pFace->next ) { if ( strcmpi( strName, pFace->texdef.name ) == 0 ) { Brush_RemoveFromList( b ); Brush_AddToList( b, &selected_brushes ); } } } } Sys_UpdateWindows( W_ALL ); return; } b = selected_brushes.next; e = b->owner; if ( e != NULL ) { if ( e != world_entity ) { CString strName = e->eclass->name; CString strKey, strVal; bool bCriteria = GetSelectAllCriteria( strKey, strVal ); Sys_Printf( "Selecting all %s(s)\n", strName ); Select_Deselect(); for ( b = active_brushes.next ; b != &active_brushes ; b = next ) { next = b->next; if ( FilterBrush( b ) ) continue; e = b->owner; if ( e != NULL ) { if ( strcmpi( e->eclass->name, strName ) == 0 ) { bool doIt = true; if ( bCriteria ) { CString str = ValueForKey( e, strKey ); if ( str.CompareNoCase( strVal ) != 0 ) { doIt = false; } } if ( doIt ) { Brush_RemoveFromList( b ); Brush_AddToList( b, &selected_brushes ); } } } } } } Sys_UpdateWindows( W_ALL ); }
/* ============= Undo_Redo ============= */ void Undo_Redo( void ){ // spog - disable undo if undo levels = 0 if ( g_PrefsDlg.m_nUndoLevels == 0 ) { Sys_Printf( "Undo_Redo: undo is disabled.\n" ); return; } undo_t *redo; brush_t *pBrush, *pNextBrush; entity_t *pEntity, *pNextEntity, *pRedoEntity; if ( !g_lastredo ) { Sys_Printf( "Nothing left to redo.\n" ); return; } if ( g_lastundo ) { if ( !g_lastundo->done ) { Sys_Printf( "WARNING: last undo not finished.\n" ); } } // get the last redo redo = g_lastredo; if ( g_lastredo->prev ) { g_lastredo->prev->next = NULL; } else{g_redolist = NULL; } g_lastredo = g_lastredo->prev; // Undo_GeneralStart( redo->operation ); // remove current selection Select_Deselect(); // move "created" brushes back to the last undo for ( pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pNextBrush ) { pNextBrush = pBrush->next; if ( pBrush->redoId == redo->id ) { //move the brush to the undo Brush_RemoveFromList( pBrush ); Brush_AddToList( pBrush, &g_lastundo->brushlist ); g_undoMemorySize += Brush_MemorySize( pBrush ); pBrush->ownerId = pBrush->owner->entityId; Entity_UnlinkBrush( pBrush ); } } // move "created" entities back to the last undo for ( pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pNextEntity ) { pNextEntity = pEntity->next; if ( pEntity->redoId == redo->id ) { // check if this entity is in the redo for ( pRedoEntity = redo->entitylist.next; pRedoEntity != NULL && pRedoEntity != &redo->entitylist; pRedoEntity = pRedoEntity->next ) { // move brushes to the redo entity if ( pRedoEntity->entityId == pEntity->entityId ) { pRedoEntity->brushes.next = pEntity->brushes.next; pRedoEntity->brushes.prev = pEntity->brushes.prev; pEntity->brushes.next = &pEntity->brushes; pEntity->brushes.prev = &pEntity->brushes; } } // //Entity_Free(pEntity); //move the entity to the redo Entity_RemoveFromList( pEntity ); Entity_AddToList( pEntity, &g_lastundo->entitylist ); g_undoMemorySize += Entity_MemorySize( pEntity ); } } // add the undo entities back into the entity list for ( pEntity = redo->entitylist.next; pEntity != NULL && pEntity != &redo->entitylist; pEntity = redo->entitylist.next ) { //if this is the world entity if ( pEntity->entityId == world_entity->entityId ) { epair_t* tmp = world_entity->epairs; world_entity->epairs = pEntity->epairs; pEntity->epairs = tmp; Entity_Free( pEntity ); } else { Entity_RemoveFromList( pEntity ); Entity_AddToList( pEntity, &entities ); } } // add the redo brushes back into the selected brushes for ( pBrush = redo->brushlist.next; pBrush != NULL && pBrush != &redo->brushlist; pBrush = redo->brushlist.next ) { Brush_RemoveFromList( pBrush ); Brush_AddToList( pBrush, &active_brushes ); for ( pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next ) // fixes broken undo on entities { if ( pEntity->entityId == pBrush->ownerId ) { Entity_LinkBrush( pEntity, pBrush ); break; } } //if the brush is not linked then it should be linked into the world entity if ( pEntity == NULL || pEntity == &entities ) { Entity_LinkBrush( world_entity, pBrush ); } //build the brush //Brush_Build(pBrush); Select_Brush( pBrush ); } // Undo_End(); // Sys_Printf( "%s redone.\n", redo->operation ); // g_redoId--; // free the undo free( redo ); // g_bScreenUpdates = true; UpdateSurfaceDialog(); Sys_UpdateWindows( W_ALL ); }
// // ======================================================================================================================= // CreateEntity Creates a new entity based on the currently selected brush and entity type. // ======================================================================================================================= // void CEntityDlg::CreateEntity() { entity_t *petNew; bool forceFixed = false; // check to make sure we have a brush CXYWnd *pWnd = g_pParentWnd->ActiveXY(); if (pWnd) { CRect rctZ; pWnd->GetClientRect(rctZ); brush_t *pBrush; if (selected_brushes.next == &selected_brushes) { pBrush = CreateEntityBrush(g_nSmartX, rctZ.Height() - 1 - g_nSmartY, pWnd); forceFixed = true; } } else { if (selected_brushes.next == &selected_brushes) { MessageBox("You must have a selected brush to create an entity", "info", 0); return; } } int index = comboClass.GetCurSel(); if (index == LB_ERR) { MessageBox("You must have a selected class to create an entity", "info", 0); return; } CString str; comboClass.GetLBText(index, str); if (!stricmp(str, "worldspawn")) { MessageBox("Can't create an entity with worldspawn.", "info", 0); return; } eclass_t *pecNew = Eclass_ForName (str, false); // create it if ((GetAsyncKeyState(VK_CONTROL) & 0x8000)) { // MAJOR hack for xian extern void Brush_CopyList(brush_t *pFrom, brush_t *pTo); brush_t temp_brushes; temp_brushes.next = &temp_brushes; Brush_CopyList(&selected_brushes, &temp_brushes); Select_Deselect(); brush_t *pBrush = temp_brushes.next; while (pBrush != NULL && pBrush != &temp_brushes) { brush_t *pNext = pBrush->next; Brush_RemoveFromList(pBrush); Brush_AddToList(pBrush, &selected_brushes); pBrush = pNext; petNew = Entity_Create(pecNew, forceFixed); Select_Deselect(); } } else if ((GetAsyncKeyState(VK_SHIFT) & 0x8000)) { Select_Ungroup(); petNew = Entity_Create(pecNew, forceFixed); } else { petNew = Entity_Create(pecNew, forceFixed); } if (petNew == NULL) { MessageBox("Failed to create entity.", "info", 0); return; } if (selected_brushes.next == &selected_brushes) { editEntity = world_entity; } else { editEntity = selected_brushes.next->owner; } SetKeyValPairs(); Select_Deselect(); Select_Brush(editEntity->brushes.onext); Sys_UpdateWindows(W_ALL); }
/* ============= CSG_Merge ============= */ void CSG_Merge(void) { brush_t *b, *next, *newlist, *newbrush; entity_t *owner; Sys_Status("Merging...\n"); if (selected_brushes.next == &selected_brushes) { Sys_Status("No brushes selected.\n"); return; } if (selected_brushes.next->next == &selected_brushes) { Sys_Status("At least two brushes have to be selected.\n"); return; } owner = selected_brushes.next->owner; for (b = selected_brushes.next; b != &selected_brushes; b = next) { next = b->next; if (b->owner->eclass->fixedsize || b->modelHandle > 0) { // can't use texture from a fixed entity, so don't subtract Sys_Status("Cannot add fixed size entities.\n"); return; } if (b->pPatch) { Sys_Status("Cannot add patches.\n"); return; } if ( b->brush_faces->d_texture && ( b->brush_faces->d_texture->GetContentFlags() & CONTENTS_NOCSG ) ) { Sys_Status("Cannot add brushes using shaders that don't allows CSG operations.\n"); return; } if (b->owner != owner) { Sys_Status("Cannot add brushes from different entities.\n"); return; } } newlist = NULL; for (b = selected_brushes.next; b != &selected_brushes; b = next) { next = b->next; Brush_RemoveFromList(b); b->next = newlist; b->prev = NULL; newlist = b; } newbrush = Brush_MergeList(newlist, true); // if the new brush would not be convex if (!newbrush) { // add the brushes back into the selection for (b = newlist; b; b = next) { next = b->next; b->next = NULL; b->prev = NULL; Brush_AddToList(b, &selected_brushes); } Sys_Status("Cannot add a set of brushes with a concave hull.\n"); return; } // free the original brushes for (b = newlist; b; b = next) { next = b->next; b->next = NULL; b->prev = NULL; Brush_Free(b); } Brush_AddToList(newbrush, &selected_brushes); Sys_Status ("done.\n"); Sys_UpdateWindows (W_ALL); }