Example #1
0
/*!\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;
}
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;

}