/*!\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; }
/* ================ Map_LoadFile ================ */ void Map_LoadFile (char *filename) { char *buf; entity_t *ent; char temp[1024]; Sys_BeginWait (); Select_Deselect(); //SetInspectorMode(W_CONSOLE); QE_ConvertDOSToUnixName( temp, filename ); Sys_Printf ("Map_LoadFile: %s\n", temp ); Map_Free (); //++timo FIXME: maybe even easier to have Group_Init called from Map_Free? Group_Init(); g_qeglobals.d_parsed_brushes = 0; strcpy (currentmap, filename); if (LoadFile (filename, (void **)&buf) != -1) { StartTokenParsing (buf); g_qeglobals.d_num_entities = 0; // Timo // will be used in Entity_Parse to detect if a conversion between brush formats is needed g_qeglobals.bNeedConvert = false; g_qeglobals.bOldBrushes = false; g_qeglobals.bPrimitBrushes = false; while (1) { ent = Entity_Parse (false, &active_brushes); if (!ent) break; if (!strcmp(ValueForKey (ent, "classname"), "worldspawn")) { if (world_entity) Sys_Printf ("WARNING: multiple worldspawn\n"); world_entity = ent; } else if (!strcmp(ValueForKey (ent, "classname"), "group_info")) { // it's a group thing! Group_Add(ent); Entity_Free(ent); } else { // add the entity to the end of the entity list ent->next = &entities; ent->prev = entities.prev; entities.prev->next = ent; entities.prev = ent; g_qeglobals.d_num_entities++; } } } free (buf); if (!world_entity) { Sys_Printf ("No worldspawn in map.\n"); Map_New (); return; } Sys_Printf ("--- LoadMapFile ---\n"); Sys_Printf ("%s\n", temp ); Sys_Printf ("%5i brushes\n", g_qeglobals.d_parsed_brushes ); Sys_Printf ("%5i entities\n", g_qeglobals.d_num_entities); Map_RestoreBetween (); Sys_Printf ("Map_BuildAllDisplayLists\n"); Map_BuildBrushData(); // reset the "need conversion" flag // conversion to the good format done in Map_BuildBrushData g_qeglobals.bNeedConvert=false; // // move the view to a start position // ent = AngledEntity(); g_pParentWnd->GetCamera()->Camera().angles[PITCH] = 0; if (ent) { GetVectorForKey (ent, "origin", g_pParentWnd->GetCamera()->Camera().origin); GetVectorForKey (ent, "origin", g_pParentWnd->GetXYWnd()->GetOrigin()); g_pParentWnd->GetCamera()->Camera().angles[YAW] = FloatForKey (ent, "angle"); } else { g_pParentWnd->GetCamera()->Camera().angles[YAW] = 0; VectorCopy (vec3_origin, g_pParentWnd->GetCamera()->Camera().origin); VectorCopy (vec3_origin, g_pParentWnd->GetXYWnd()->GetOrigin()); } Map_RegionOff (); modified = false; Sys_SetTitle (temp); Texture_ShowInuse (); Sys_EndWait(); Sys_UpdateWindows (W_ALL); }