void CEntityDlg::OnCbnSelchangeComboClass() { int index = comboClass.GetCurSel(); if (index != LB_ERR) { CString str; comboClass.GetLBText(index, str); eclass_t *ent = Eclass_ForName (str, false); if (ent) { if (selected_brushes.next == &selected_brushes) { editEntity = world_entity; multipleEntities = false; } else { editEntity = selected_brushes.next->owner; for (brush_t *b = selected_brushes.next->next; b != &selected_brushes; b = b->next) { if (b->owner != editEntity) { multipleEntities = true; break; } } } listVars.ResetContent(); CPropertyItem *pi = new CPropertyItem("Usage:", ent->desc.c_str(), PIT_VAR, ""); listVars.AddPropItem(pi); int c = ent->vars.Num(); for (int i = 0; i < c; i++) { pi = new CPropertyItem(ent->vars[i].name.c_str(), ent->vars[i].desc.c_str(), PIT_VAR, ""); pi->SetData(ent->vars[i].type); listVars.AddPropItem(pi); } listVars.Invalidate(); SetKeyValPairs(); } } }
/* =========== Map_New =========== */ void Map_New( void ){ Sys_Printf( "Map_New\n" ); Map_Free(); strcpy( currentmap, "unnamed.map" ); Sys_SetTitle( currentmap ); world_entity = (entity_s*)qmalloc( sizeof( *world_entity ) ); world_entity->brushes.onext = world_entity->brushes.oprev = &world_entity->brushes; SetKeyValue( world_entity, "classname", "worldspawn" ); world_entity->eclass = Eclass_ForName( "worldspawn", true ); g_pParentWnd->GetCamWnd()->Camera()->angles[YAW] = 0; g_pParentWnd->GetCamWnd()->Camera()->angles[PITCH] = 0; VectorCopy( vec3_origin, g_pParentWnd->GetCamWnd()->Camera()->origin ); g_pParentWnd->GetCamWnd()->Camera()->origin[2] = 48; VectorCopy( vec3_origin, g_pParentWnd->GetXYWnd()->GetOrigin() ); Map_RestoreBetween(); Group_Init(); Sys_UpdateWindows( W_ALL ); modified = false; }
/* ======================================================================================================================= Map_New ======================================================================================================================= */ void Map_New(void) { common->Printf("Map_New\n"); Map_Free(); Patch_Cleanup(); g_Inspectors->entityDlg.SetEditEntity ( NULL ); world_entity = Entity_New(); world_entity->brushes.onext = world_entity->brushes.oprev = &world_entity->brushes; SetKeyValue(world_entity, "classname", "worldspawn"); world_entity->eclass = Eclass_ForName("worldspawn", true); g_pParentWnd->GetCamera()->Camera().angles[YAW] = 0; g_pParentWnd->GetCamera()->Camera().angles[PITCH] = 0; VectorCopy(vec3_origin, g_pParentWnd->GetCamera()->Camera().origin); g_pParentWnd->GetCamera()->Camera().origin[2] = 48; VectorCopy(vec3_origin, g_pParentWnd->GetXYWnd()->GetOrigin()); Map_RestoreBetween(); Sys_UpdateWindows(W_ALL); mapModified = 0; g_qeglobals.mapVersion = MAP_VERSION; }
/* =========== AddRegionBrushes a regioned map will have temp walls put up at the region boundary \todo TODO TTimo old implementation of region brushes we still add them straight in the worldspawn and take them out after the map is saved with the new implementation we should be able to append them in a temporary manner to the data we pass to the map module =========== */ void AddRegionBrushes( void ){ vec3_t mins, maxs; int i; texdef_t td; if ( !region_active ) { #ifdef _DEBUG Sys_FPrintf( SYS_WRN, "Unexpected AddRegionBrushes call.\n" ); #endif return; } memset( &td, 0, sizeof( td ) ); td.SetName( SHADER_NOT_FOUND ); // set mins VectorSet( mins, region_mins[0] - 32, region_mins[1] - 32, region_mins[2] - 32 ); // vary maxs for ( i = 0; i < 3; i++ ) { VectorSet( maxs, region_maxs[0] + 32, region_maxs[1] + 32, region_maxs[2] + 32 ); maxs[i] = region_mins[i]; region_sides[i] = Brush_Create( mins, maxs, &td ); } // set maxs VectorSet( maxs, region_maxs[0] + 32, region_maxs[1] + 32, region_maxs[2] + 32 ); // vary mins for ( i = 0; i < 3; i++ ) { VectorSet( mins, region_mins[0] - 32, region_mins[1] - 32, region_mins[2] - 32 ); mins[i] = region_maxs[i]; region_sides[i + 3] = Brush_Create( mins, maxs, &td ); } // this is a safe check, but it should not really happen anymore vec3_t vOrig; VectorSet( vOrig, (int)g_pParentWnd->GetCamWnd()->Camera()->origin[0], (int)g_pParentWnd->GetCamWnd()->Camera()->origin[1], (int)g_pParentWnd->GetCamWnd()->Camera()->origin[2] ); for ( i = 0 ; i < 3 ; i++ ) { if ( vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i] ) { Sys_FPrintf( SYS_ERR, "Camera is NOT in the region, it's likely that the region won't compile correctly\n" ); } } // write the info_playerstart region_startpoint = Entity_Alloc(); SetKeyValue( region_startpoint, "classname", "info_player_start" ); region_startpoint->eclass = Eclass_ForName( "info_player_start", false ); char sTmp[1024]; sprintf( sTmp, "%d %d %d", (int)vOrig[0], (int)vOrig[1], (int)vOrig[2] ); SetKeyValue( region_startpoint, "origin", sTmp ); sprintf( sTmp, "%d", (int)g_pParentWnd->GetCamWnd()->Camera()->angles[YAW] ); SetKeyValue( region_startpoint, "angle", sTmp ); // empty array of children region_startpoint->pData = new CPtrArray; }
/*!\todo Possibly make the import Undo-friendly by calling Undo_End for new brushes and ents */ void Map_ImportEntities( CPtrArray *ents, bool bAddSelected = false ){ int num_ents, num_brushes; CPtrArray *brushes; vec3_t mins, maxs; entity_t *e; brush_t *b; face_t *f; int i,j; GPtrArray *new_ents = g_ptr_array_new(); g_qeglobals.bPrimitBrushes = false; brush_t *pBrushList = ( bAddSelected ) ? &selected_brushes : &active_brushes; bool bDoneBPCheck = false; g_qeglobals.bNeedConvert = false; // HACK: find out if this map file was a BP one // check the first brush in the file that is NOT a patch // this will not be necessary when we allow both formats in the same file num_ents = ents->GetSize(); for ( i = 0; !bDoneBPCheck && i < num_ents; i++ ) { e = (entity_t*)ents->GetAt( i ); brushes = (CPtrArray*)e->pData; num_brushes = brushes->GetSize(); for ( j = 0; !bDoneBPCheck && j < num_brushes; j++ ) { /*!todo Allow mixing texdef formats per-face. */ b = (brush_t *)brushes->GetAt( j ); if ( b->patchBrush ) { continue; } bDoneBPCheck = true; int BP_param = -1; if ( b->bBrushDef && !g_qeglobals.m_bBrushPrimitMode ) { BP_param = 0; } else if ( !b->bBrushDef && g_qeglobals.m_bBrushPrimitMode ) { BP_param = 1; } if ( BP_param != -1 ) { switch ( BP_MessageBox( BP_param ) ) { case 0: Map_FreeEntities( ents ); return; case 1: g_qeglobals.bNeedConvert = true; break; case 2: g_qeglobals.bNeedConvert = false; break; } } } } // process the entities into the world geometry num_ents = ents->GetSize(); for ( i = 0; i < num_ents; i++ ) { num_brushes = 0; e = (entity_t*)ents->GetAt( i ); brushes = (CPtrArray*)e->pData; num_brushes = brushes->GetSize(); // link brushes into entity for ( j = 0; j < num_brushes; j++ ) { Entity_LinkBrush( e, (brush_t *)brushes->GetAt( j ) ); g_qeglobals.d_parsed_brushes++; } brushes->RemoveAll(); delete brushes; e->pData = NULL; // set entity origin GetVectorForKey( e, "origin", e->origin ); // set entity eclass /*!\todo Make SetKeyValue check for "classname" change and assign appropriate eclass */ e->eclass = Eclass_ForName( ValueForKey( e, "classname" ), ( e->brushes.onext != &e->brushes ) ); // go through all parsed brushes and build stuff for ( b = e->brushes.onext; b != &e->brushes; b = b->onext ) { for ( f = b->brush_faces; f != NULL; f = f->next ) { f->pShader = QERApp_Shader_ForName( f->texdef.GetName() ); f->d_texture = f->pShader->getTexture(); } // when brushes are in final state, build the planes and windings // NOTE: also converts BP brushes if g_qeglobals.bNeedConvert is true Brush_Build( b ); } //#define TERRAIN_HACK #undef TERRAIN_HACK #ifdef TERRAIN_HACK if ( ( strcmp( ValueForKey( e, "terrain" ),"1" ) == 0 && strcmp( e->eclass->name,"func_group" ) == 0 ) ) { // two aux pointers to the shaders used in the terrain entity // we don't keep refcount on them since they are only temporary // this avoids doing expensive lookups by name for all faces IShader *pTerrainShader, *pCaulk; pTerrainShader = NULL; pCaulk = QERApp_Shader_ForName( SHADER_CAULK ); for ( b = e->brushes.onext; b != &e->brushes; b = b->onext ) { if ( pTerrainShader == NULL ) { for ( f = b->brush_faces; f != NULL; f = f->next ) if ( strcmp( f->texdef.GetName(), SHADER_CAULK ) != 0 ) { pTerrainShader = f->pShader; } } if ( pTerrainShader ) { for ( f = b->brush_faces; f != NULL; f = f->next ) { if ( strcmp( f->texdef.GetName(), SHADER_CAULK ) != 0 ) { // not caulk Face_SetShader( f, pTerrainShader->getName() ); } else{ Face_SetShader( f, pCaulk->getName() ); } } } else{ Sys_FPrintf( SYS_WRN, "WARNING: no terrain shader found for brush\n" ); } } } #endif #define PATCH_HACK #ifdef PATCH_HACK for ( b = e->brushes.onext; b != &e->brushes; b = b->onext ) { // patch hack, to be removed when dependency on brush_faces is removed if ( b->patchBrush ) { Patch_CalcBounds( b->pPatch, mins, maxs ); for ( int i = 0; i < 3; i++ ) { if ( (int)mins[i] == (int)maxs[i] ) { mins[i] -= 4; maxs[i] += 4; } } Brush_Resize( b, mins, maxs ); Brush_Build( b ); } } #endif // add brush for fixedsize entity if ( e->eclass->fixedsize ) { vec3_t mins, maxs; VectorAdd( e->eclass->mins, e->origin, mins ); VectorAdd( e->eclass->maxs, e->origin, maxs ); b = Brush_Create( mins, maxs, &e->eclass->texdef ); Entity_LinkBrush( e, b ); Brush_Build( b ); } for ( b = e->brushes.onext; b != &e->brushes; b = b->onext ) Brush_AddToList( b, pBrushList ); if ( strcmp( e->eclass->name, "worldspawn" ) == 0 ) { if ( world_entity ) { while ( e->brushes.onext != &e->brushes ) { b = e->brushes.onext; Entity_UnlinkBrush( b ); Entity_LinkBrush( world_entity, b ); } Entity_Free( e ); } else { world_entity = e; } } else if ( strcmp( e->eclass->name, "group_info" ) == 0 ) { // it's a group thing! Group_Add( e ); Entity_Free( e ); } else { // fix target/targetname collisions if ( ( g_PrefsDlg.m_bDoTargetFix ) && ( strcmp( ValueForKey( e, "target" ), "" ) != 0 ) ) { GPtrArray *t_ents = g_ptr_array_new(); entity_t *e_target; const char *target = ValueForKey( e, "target" ); qboolean bCollision = FALSE; // check the current map entities for an actual collision for ( e_target = entities.next; e_target != &entities; e_target = e_target->next ) { if ( !strcmp( target, ValueForKey( e_target, "target" ) ) ) { bCollision = TRUE; // make sure the collision is not between two imported entities for ( j = 0; j < (int)new_ents->len; j++ ) { if ( e_target == g_ptr_array_index( new_ents, j ) ) { bCollision = FALSE; } } } } // find the matching targeted entity(s) if ( bCollision ) { for ( j = num_ents - 1; j > 0; j-- ) { e_target = (entity_t*)ents->GetAt( j ); if ( e_target != NULL && e_target != e ) { const char *targetname = ValueForKey( e_target, "targetname" ); if ( ( targetname != NULL ) && ( strcmp( target, targetname ) == 0 ) ) { g_ptr_array_add( t_ents, (gpointer)e_target ); } } } if ( t_ents->len > 0 ) { // link the first to get a unique target/targetname Entity_Connect( e, (entity_t*)g_ptr_array_index( t_ents,0 ) ); // set the targetname of the rest of them manually for ( j = 1; j < (int)t_ents->len; j++ ) SetKeyValue( (entity_t*)g_ptr_array_index( t_ents, j ), "targetname", ValueForKey( e, "target" ) ); } g_ptr_array_free( t_ents, FALSE ); } } // add the entity to the end of the entity list Entity_AddToList( e, &entities ); g_qeglobals.d_num_entities++; // keep a list of ents added to avoid testing collisions against them g_ptr_array_add( new_ents, (gpointer)e ); } } g_ptr_array_free( new_ents, FALSE ); ents->RemoveAll(); g_qeglobals.bNeedConvert = false; }
// // ======================================================================================================================= // 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); }
void CPlugInManager::CommitEntityHandleToMap(LPVOID vpEntity) { entity_t *pe; eclass_t *e; brush_t *b; vec3_t mins,maxs; bool has_brushes; for (int i=0 ; i < m_EntityHandles.GetSize() ; i++ ) { if (vpEntity == m_EntityHandles.GetAt(i)) { m_EntityHandles.RemoveAt(i); pe = reinterpret_cast<entity_t*>(vpEntity); // fill additional fields // straight copy from Entity_Parse // entity_t::origin GetVectorForKey (pe, "origin", pe->origin); // entity_t::eclass if (pe->brushes.onext == &pe->brushes) has_brushes = false; else has_brushes = true; e = Eclass_ForName (ValueForKey (pe, "classname"), has_brushes); pe->eclass = e; // fixedsize if (e->fixedsize) { if (pe->brushes.onext != &pe->brushes) { Sys_Printf("Warning : Fixed size entity with brushes in CPlugInManager::CommitEntityHandleToMap\n"); } // create a custom brush VectorAdd(e->mins, pe->origin, mins); VectorAdd(e->maxs, pe->origin, maxs); float a = 0; if (e->nShowFlags & ECLASS_MISCMODEL) { char* p = ValueForKey(pe, "model"); if (p != NULL && strlen(p) > 0) { vec3_t vMin, vMax; a = FloatForKey (pe, "angle"); if (GetCachedModel(pe, p, vMin, vMax)) { // create a custom brush VectorAdd (pe->md3Class->mins, pe->origin, mins); VectorAdd (pe->md3Class->maxs, pe->origin, maxs); } } } b = Brush_Create (mins, maxs, &e->texdef); if (a) { vec3_t vAngle; vAngle[0] = vAngle[1] = 0; vAngle[2] = a; Brush_Rotate(b, vAngle, pe->origin, false); } b->owner = pe; b->onext = pe->brushes.onext; b->oprev = &pe->brushes; pe->brushes.onext->oprev = b; pe->brushes.onext = b; } else { // brush entity if (pe->brushes.next == &pe->brushes) Sys_Printf ("Warning: Brush entity with no brushes in CPlugInManager::CommitEntityHandleToMap\n"); } // add brushes to the active brushes list // and build them along the way for (b=pe->brushes.onext ; b != &pe->brushes ; b=b->onext) { // convert between old brushes and brush primitive if (g_qeglobals.m_bBrushPrimitMode) { // we only filled the shift scale rot fields, needs conversion Brush_Build( b, true, true, true ); } else { // we are using old brushes Brush_Build( b ); } b->next = active_brushes.next; active_brushes.next->prev = b; b->prev = &active_brushes; active_brushes.next = b; } // handle worldspawn entities // if worldspawn has no brushes, use the new one if (!strcmp(ValueForKey (pe, "classname"), "worldspawn")) { if ( world_entity && ( world_entity->brushes.onext != &world_entity->brushes ) ) { // worldspawn already has brushes Sys_Printf ("Commiting worldspawn as func_group\n"); SetKeyValue(pe, "classname", "func_group"); // add the entity to the end of the entity list pe->next = &entities; pe->prev = entities.prev; entities.prev->next = pe; entities.prev = pe; g_qeglobals.d_num_entities++; } else { // there's a worldspawn with no brushes, we assume the map is empty if ( world_entity ) { Entity_Free( world_entity ); world_entity = pe; } else Sys_Printf("Warning : unexpected world_entity == NULL in CommitEntityHandleToMap\n"); } } else { // add the entity to the end of the entity list pe->next = &entities; pe->prev = entities.prev; entities.prev->next = pe; entities.prev = pe; g_qeglobals.d_num_entities++; } } } }
void CreateEntity(void) { eclass_t *pecNew; entity_t *petNew; int i; HWND hwnd; char sz[1024]; // check to make sure we have a brush if (selected_brushes.next == &selected_brushes) { MessageBox(g_qeglobals.d_hwndMain, "You must have a selected brush to create an entity" , "info", 0); return; } // find out what type of entity we are trying to create hwnd = hwndEnt[EntList]; i = SendMessage(hwndEnt[EntList], LB_GETCURSEL, 0, 0); if (i < 0) { MessageBox(g_qeglobals.d_hwndMain, "You must have a selected class to create an entity" , "info", 0); return; } SendMessage(hwnd, LB_GETTEXT, i, (LPARAM)sz); if (!stricmp(sz, "worldspawn")) { MessageBox(g_qeglobals.d_hwndMain, "Can't create an entity with worldspawn.", "info", 0); return; } pecNew = Eclass_ForName(sz, false); // create it petNew = Entity_Create(pecNew); if (petNew == NULL) { MessageBox(g_qeglobals.d_hwndMain, "Failed to create entity.", "info", 0); return; } if (selected_brushes.next == &selected_brushes) edit_entity = world_entity; else edit_entity = selected_brushes.next->owner; SetKeyValuePairs(); Select_Deselect (); Select_Brush (edit_entity->brushes.onext); Sys_UpdateWindows(W_ALL); }
entity_t *Entity_PostParse(entity_t *ent, brush_t *pList) { bool has_brushes; eclass_t *e; brush_t *b; idVec3 mins, maxs, zero; idBounds bo; zero.Zero(); Entity_SetCurveData( ent ); if (ent->brushes.onext == &ent->brushes) { has_brushes = false; } else { has_brushes = true; } bool needsOrigin = !GetVectorForKey(ent, "origin", ent->origin); const char *pModel = ValueForKey(ent, "model"); const char *cp = ValueForKey(ent, "classname"); if (strlen(cp)) { e = Eclass_ForName(cp, has_brushes); } else { const char *cp2 = ValueForKey(ent, "name"); if (strlen(cp2)) { char buff[1024]; strcpy(buff, cp2); int len = strlen(buff); while ((isdigit(buff[len-1]) || buff[len-1] == '_') && len > 0) { buff[len-1] = '\0'; len--; } e = Eclass_ForName(buff, has_brushes); SetKeyValue(ent, "classname", buff, false); } else { e = Eclass_ForName("", has_brushes); } } idStr str; if (e->defArgs.GetString("model", "", str) && e->entityModel == NULL) { e->entityModel = gameEdit->ANIM_GetModelFromEntityDef( &e->defArgs ); } ent->eclass = e; bool hasModel = EntityHasModel(ent); if (hasModel) { ent->eclass->defArgs.GetString("model", "", str); if (str.Length()) { hasModel = false; ent->epairs.Delete("model"); } } if (e->nShowFlags & ECLASS_WORLDSPAWN) { ent->origin.Zero(); needsOrigin = false; ent->epairs.Delete( "model" ); } else if (e->nShowFlags & ECLASS_LIGHT) { if (GetVectorForKey(ent, "light_origin", ent->lightOrigin)) { GetMatrixForKey(ent, "light_rotation", ent->lightRotation); ent->trackLightOrigin = true; } else if (hasModel) { SetKeyValue(ent, "light_origin", ValueForKey(ent, "origin")); ent->lightOrigin = ent->origin; if (GetMatrixForKey(ent, "rotation", ent->lightRotation)) { SetKeyValue(ent, "light_rotation", ValueForKey(ent, "rotation")); } ent->trackLightOrigin = true; } } else if ( e->nShowFlags & ECLASS_ENV ) { // need to create an origin from the bones here idVec3 org; idAngles ang; bo.Clear(); bool hasBody = false; const idKeyValue *arg = ent->epairs.MatchPrefix( "body ", NULL ); while ( arg ) { sscanf( arg->GetValue(), "%f %f %f %f %f %f", &org.x, &org.y, &org.z, &ang.pitch, &ang.yaw, &ang.roll ); bo.AddPoint( org ); arg = ent->epairs.MatchPrefix( "body ", arg ); hasBody = true; } if (hasBody) { ent->origin = bo.GetCenter(); } } if (e->fixedsize || hasModel) // fixed size entity { if (ent->brushes.onext != &ent->brushes) { for (b = ent->brushes.onext; b != &ent->brushes; b = b->onext) { b->entityModel = true; } } if (hasModel) { // model entity idRenderModel *modelHandle = renderModelManager->FindModel( pModel ); if ( dynamic_cast<idRenderModelPrt*>( modelHandle ) || dynamic_cast<idRenderModelLiquid*>( modelHandle ) ) { bo.Zero(); bo.ExpandSelf( 12.0f ); } else { bo = modelHandle->Bounds( NULL ); } VectorCopy(bo[0], mins); VectorCopy(bo[1], maxs); for (int i = 0; i < 3; i++) { if (mins[i] == maxs[i]) { mins[i]--; maxs[i]++; } } VectorAdd(mins, ent->origin, mins); VectorAdd(maxs, ent->origin, maxs); b = Brush_Create(mins, maxs, &e->texdef); b->modelHandle = modelHandle; float yaw = 0; bool convertAngles = GetFloatForKey(ent, "angle", &yaw); extern void Brush_Rotate(brush_t *b, idMat3 matrix, idVec3 origin, bool bBuild); extern void Brush_Rotate(brush_t *b, idVec3 rot, idVec3 origin, bool bBuild); if (convertAngles) { idVec3 rot(0, 0, yaw); Brush_Rotate(b, rot, ent->origin, false); } if (GetMatrixForKey(ent, "rotation", ent->rotation)) { idBounds bo2; bo2.FromTransformedBounds(bo, ent->origin, ent->rotation); b->owner = ent; Brush_Resize(b, bo2[0], bo2[1]); } Entity_LinkBrush(ent, b); } if (!hasModel || (ent->eclass->nShowFlags & ECLASS_LIGHT && hasModel)) { // create a custom brush if (ent->trackLightOrigin) { mins = e->mins + ent->lightOrigin; maxs = e->maxs + ent->lightOrigin; } else { mins = e->mins + ent->origin; maxs = e->maxs + ent->origin; } b = Brush_Create(mins, maxs, &e->texdef); GetMatrixForKey(ent, "rotation", ent->rotation); Entity_LinkBrush(ent, b); b->trackLightOrigin = ent->trackLightOrigin; if ( e->texdef.name == NULL ) { brushprimit_texdef_t bp; texdef_t td; td.SetName( ent->eclass->defMaterial ); Brush_SetTexture( b, &td, &bp, false ); } } } else // brush entity { if (ent->brushes.next == &ent->brushes) { printf("Warning: Brush entity with no brushes\n"); } if (!needsOrigin) { idStr cn = ValueForKey(ent, "classname"); idStr name = ValueForKey(ent, "name"); idStr model = ValueForKey(ent, "model"); if (cn.Icmp("func_static") == 0) { if (name.Icmp(model) == 0) { needsOrigin = true; } } } if (needsOrigin) { idVec3 mins, maxs, mid; int i; char text[32]; mins[0] = mins[1] = mins[2] = 999999; maxs[0] = maxs[1] = maxs[2] = -999999; // add in the origin for (b = ent->brushes.onext; b != &ent->brushes; b = b->onext) { Brush_Build(b, true, false, false); for (i = 0; i < 3; i++) { if (b->mins[i] < mins[i]) { mins[i] = b->mins[i]; } if (b->maxs[i] > maxs[i]) { maxs[i] = b->maxs[i]; } } } for (i = 0; i < 3; i++) { ent->origin[i] = (mins[i] + ((maxs[i] - mins[i]) / 2)); } sprintf(text, "%i %i %i", (int)ent->origin[0], (int)ent->origin[1], (int)ent->origin[2]); SetKeyValue(ent, "origin", text); } if (!(e->nShowFlags & ECLASS_WORLDSPAWN)) { if (e->defArgs.FindKey("model") == NULL && (pModel == NULL || (pModel && strlen(pModel) == 0))) { SetKeyValue(ent, "model", ValueForKey(ent, "name")); } } else { DeleteKey(ent, "origin"); } } // add all the brushes to the main list if (pList) { for (b = ent->brushes.onext; b != &ent->brushes; b = b->onext) { b->next = pList->next; pList->next->prev = b; b->prev = pList; pList->next = b; } } FixFloats(&ent->epairs); return ent; }
/* ================ Entity_Parse If onlypairs is set, the classname info will not be looked up, and the entity will not be added to the global list. Used for parsing the project. ================ */ entity_t *Entity_Parse (qboolean onlypairs, brush_t* pList) { entity_t *ent; eclass_t *e; brush_t *b; vec3_t mins, maxs; epair_t *ep; qboolean has_brushes; #ifdef SOF float scale; #endif if (!GetToken (true)) return NULL; if (strcmp (token, "{") ) Error ("ParseEntity: { not found"); ent = (entity_t*)qmalloc (sizeof(*ent)); ent->brushes.onext = ent->brushes.oprev = &ent->brushes; do { if (!GetToken (true)) { Warning ("ParseEntity: EOF without closing brace"); return NULL; } if (!strcmp (token, "}") ) break; if (!strcmp (token, "{") ) { b = Brush_Parse (); if (b != NULL) { b->owner = ent; // add to the end of the entity chain b->onext = &ent->brushes; b->oprev = ent->brushes.oprev; ent->brushes.oprev->onext = b; ent->brushes.oprev = b; } else { break; } } else { ep = ParseEpair (); { // update: the original code here may have been simple, but it meant that every map load/save // the key/value pair fields were reversed in the save file, which messes up SourceSafe when it // tries to delta the two versions during check-in... -slc #if 0 ep->next = ent->epairs; ent->epairs = ep; #else // join this onto the END of the chain instead... // if (ent->epairs == NULL) // special case for if there isn't a chain yet... :-) { ep->next = ent->epairs; ent->epairs = ep; } else { for (epair_t* ep2 = ent->epairs ; ep2 ; ep2=ep2->next) { if (ep2->next == NULL) { // found the end, so... // ep2->next = ep; ep->next = NULL; break; } } } #endif } } } while (1); if (onlypairs) return ent; if (ent->brushes.onext == &ent->brushes) has_brushes = false; else has_brushes = true; GetVectorForKey (ent, "origin", ent->origin); e = Eclass_ForName (ValueForKey (ent, "classname"), has_brushes); ent->eclass = e; if (e->fixedsize) { // fixed size entity if (ent->brushes.onext != &ent->brushes) { printf ("Warning: Fixed size entity with brushes\n"); #if 0 while (ent->brushes.onext != &ent->brushes) { // FIXME: this will free the entity and crash! Brush_Free (b); } #endif ent->brushes.next = ent->brushes.prev = &ent->brushes; } // create a custom brush VectorAdd (e->mins, ent->origin, mins); VectorAdd (e->maxs, ent->origin, maxs); float a = 0; if (strnicmp(e->name, "misc_model",10) == 0) { char* p = ValueForKey(ent, "model"); if (p != NULL && strlen(p) > 0) { vec3_t vMin, vMax; a = FloatForKey (ent, "angle"); gEntityToSetBoundsOf = ent; if (GetCachedModel(ent, p, vMin, vMax)) { // create a custom brush VectorAdd (ent->md3Class->mins, ent->origin, mins); VectorAdd (ent->md3Class->maxs, ent->origin, maxs); } } } #ifdef SOF if (strnicmp(e->name, "misc_", 5) == 0 || strnicmp(e->name, "light_", 6) == 0 || strnicmp(e->name, "m_", 2) == 0 || strnicmp(e->name, "item_weapon_", 12)== 0 || strnicmp(e->name, "item_ammo_", 10)== 0 ) a = FloatForKey (ent, "angle"); #endif b = Brush_Create (mins, maxs, &e->texdef); /////// b->owner = ent; b->onext = ent->brushes.onext; b->oprev = &ent->brushes; ent->brushes.onext->oprev = b; ent->brushes.onext = b; /////// Brush_Build(b); #ifdef SOF scale = FloatForKey (ent, "scale"); if (scale) { Brush_Scale2(e, b, scale, ent->origin,false); } #endif // if (a) // { // vec3_t vAngle; // vAngle[0] = vAngle[1] = 0; // vAngle[2] = a; // Brush_Rotate(b, vAngle, ent->origin, false); // } /* b->owner = ent; b->onext = ent->brushes.onext; b->oprev = &ent->brushes; ent->brushes.onext->oprev = b; ent->brushes.onext = b; */ // do this AFTER doing the brush stuff just above, so don't join to the other "if (a)"... // if (a) { // pick any old value to rotate away to, then back from, to avoid 0/360 weirdness on key-compares // SetKeyValue(ent, "angle", "0", false); // false = no tracking, ie just set the angle and nothing else SetKeyValue(ent, "angle", va("%g",a), true); // true = do tracking, ie actually do the brush rotate } } else { // brush entity if (ent->brushes.next == &ent->brushes) printf ("Warning: Brush entity with no brushes\n"); } // add all the brushes to the main list if (pList) { for (b=ent->brushes.onext ; b != &ent->brushes ; b=b->onext) { b->next = pList->next; pList->next->prev = b; b->prev = pList; pList->next = b; } } return ent; }