diff options
| author | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
|---|---|---|
| committer | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
| commit | 39ed87570bdb2f86969d4be821c94b722dc71179 (patch) | |
| tree | abc53757f75f40c80278e87650ea92808274aa59 /mp/src/utils/vbsp/staticprop.cpp | |
| download | source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip | |
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/utils/vbsp/staticprop.cpp')
| -rw-r--r-- | mp/src/utils/vbsp/staticprop.cpp | 741 |
1 files changed, 741 insertions, 0 deletions
diff --git a/mp/src/utils/vbsp/staticprop.cpp b/mp/src/utils/vbsp/staticprop.cpp new file mode 100644 index 00000000..810465b3 --- /dev/null +++ b/mp/src/utils/vbsp/staticprop.cpp @@ -0,0 +1,741 @@ +//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Places "detail" objects which are client-only renderable things
+//
+// $Revision: $
+// $NoKeywords: $
+//=============================================================================//
+
+#include "vbsp.h"
+#include "bsplib.h"
+#include "utlvector.h"
+#include "bspfile.h"
+#include "gamebspfile.h"
+#include "VPhysics_Interface.h"
+#include "Studio.h"
+#include "byteswap.h"
+#include "UtlBuffer.h"
+#include "CollisionUtils.h"
+#include <float.h>
+#include "CModel.h"
+#include "PhysDll.h"
+#include "utlsymbol.h"
+#include "tier1/strtools.h"
+#include "KeyValues.h"
+
+static void SetCurrentModel( studiohdr_t *pStudioHdr );
+static void FreeCurrentModelVertexes();
+
+IPhysicsCollision *s_pPhysCollision = NULL;
+
+//-----------------------------------------------------------------------------
+// These puppies are used to construct the game lumps
+//-----------------------------------------------------------------------------
+static CUtlVector<StaticPropDictLump_t> s_StaticPropDictLump;
+static CUtlVector<StaticPropLump_t> s_StaticPropLump;
+static CUtlVector<StaticPropLeafLump_t> s_StaticPropLeafLump;
+
+
+//-----------------------------------------------------------------------------
+// Used to build the static prop
+//-----------------------------------------------------------------------------
+struct StaticPropBuild_t
+{
+ char const* m_pModelName;
+ char const* m_pLightingOrigin;
+ Vector m_Origin;
+ QAngle m_Angles;
+ int m_Solid;
+ int m_Skin;
+ int m_Flags;
+ float m_FadeMinDist;
+ float m_FadeMaxDist;
+ bool m_FadesOut;
+ float m_flForcedFadeScale;
+ unsigned short m_nMinDXLevel;
+ unsigned short m_nMaxDXLevel;
+};
+
+
+//-----------------------------------------------------------------------------
+// Used to cache collision model generation
+//-----------------------------------------------------------------------------
+struct ModelCollisionLookup_t
+{
+ CUtlSymbol m_Name;
+ CPhysCollide* m_pCollide;
+};
+
+static bool ModelLess( ModelCollisionLookup_t const& src1, ModelCollisionLookup_t const& src2 )
+{
+ return src1.m_Name < src2.m_Name;
+}
+
+static CUtlRBTree<ModelCollisionLookup_t, unsigned short> s_ModelCollisionCache( 0, 32, ModelLess );
+static CUtlVector<int> s_LightingInfo;
+
+
+//-----------------------------------------------------------------------------
+// Gets the keyvalues from a studiohdr
+//-----------------------------------------------------------------------------
+bool StudioKeyValues( studiohdr_t* pStudioHdr, KeyValues *pValue )
+{
+ if ( !pStudioHdr )
+ return false;
+
+ return pValue->LoadFromBuffer( pStudioHdr->pszName(), pStudioHdr->KeyValueText() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Makes sure the studio model is a static prop
+//-----------------------------------------------------------------------------
+enum isstaticprop_ret
+{
+ RET_VALID,
+ RET_FAIL_NOT_MARKED_STATIC_PROP,
+ RET_FAIL_DYNAMIC,
+};
+
+isstaticprop_ret IsStaticProp( studiohdr_t* pHdr )
+{
+ if (!(pHdr->flags & STUDIOHDR_FLAGS_STATIC_PROP))
+ return RET_FAIL_NOT_MARKED_STATIC_PROP;
+
+ // If it's got a propdata section in the model's keyvalues, it's not allowed to be a prop_static
+ KeyValues *modelKeyValues = new KeyValues(pHdr->pszName());
+ if ( StudioKeyValues( pHdr, modelKeyValues ) )
+ {
+ KeyValues *sub = modelKeyValues->FindKey("prop_data");
+ if ( sub )
+ {
+ if ( !(sub->GetInt( "allowstatic", 0 )) )
+ {
+ modelKeyValues->deleteThis();
+ return RET_FAIL_DYNAMIC;
+ }
+ }
+ }
+ modelKeyValues->deleteThis();
+
+ return RET_VALID;
+}
+
+
+//-----------------------------------------------------------------------------
+// Add static prop model to the list of models
+//-----------------------------------------------------------------------------
+
+static int AddStaticPropDictLump( char const* pModelName )
+{
+ StaticPropDictLump_t dictLump;
+ strncpy( dictLump.m_Name, pModelName, DETAIL_NAME_LENGTH );
+
+ for (int i = s_StaticPropDictLump.Size(); --i >= 0; )
+ {
+ if (!memcmp(&s_StaticPropDictLump[i], &dictLump, sizeof(dictLump) ))
+ return i;
+ }
+
+ return s_StaticPropDictLump.AddToTail( dictLump );
+}
+
+
+//-----------------------------------------------------------------------------
+// Load studio model vertex data from a file...
+//-----------------------------------------------------------------------------
+bool LoadStudioModel( char const* pModelName, char const* pEntityType, CUtlBuffer& buf )
+{
+ if ( !g_pFullFileSystem->ReadFile( pModelName, NULL, buf ) )
+ return false;
+
+ // Check that it's valid
+ if (strncmp ((const char *) buf.PeekGet(), "IDST", 4) &&
+ strncmp ((const char *) buf.PeekGet(), "IDAG", 4))
+ {
+ return false;
+ }
+
+ studiohdr_t* pHdr = (studiohdr_t*)buf.PeekGet();
+
+ Studio_ConvertStudioHdrToNewVersion( pHdr );
+
+ if (pHdr->version != STUDIO_VERSION)
+ {
+ return false;
+ }
+
+ isstaticprop_ret isStaticProp = IsStaticProp(pHdr);
+ if ( isStaticProp != RET_VALID )
+ {
+ if ( isStaticProp == RET_FAIL_NOT_MARKED_STATIC_PROP )
+ {
+ Warning("Error! To use model \"%s\"\n"
+ " with %s, it must be compiled with $staticprop!\n", pModelName, pEntityType );
+ }
+ else if ( isStaticProp == RET_FAIL_DYNAMIC )
+ {
+ Warning("Error! %s using model \"%s\", which must be used on a dynamic entity (i.e. prop_physics). Deleted.\n", pEntityType, pModelName );
+ }
+ return false;
+ }
+
+ // ensure reset
+ pHdr->pVertexBase = NULL;
+ pHdr->pIndexBase = NULL;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Computes a convex hull from a studio mesh
+//-----------------------------------------------------------------------------
+static CPhysConvex* ComputeConvexHull( mstudiomesh_t* pMesh )
+{
+ // Generate a list of all verts in the mesh
+ Vector** ppVerts = (Vector**)stackalloc(pMesh->numvertices * sizeof(Vector*) );
+ const mstudio_meshvertexdata_t *vertData = pMesh->GetVertexData();
+ Assert( vertData ); // This can only return NULL on X360 for now
+ for (int i = 0; i < pMesh->numvertices; ++i)
+ {
+ ppVerts[i] = vertData->Position(i);
+ }
+
+ // Generate a convex hull from the verts
+ return s_pPhysCollision->ConvexFromVerts( ppVerts, pMesh->numvertices );
+}
+
+
+//-----------------------------------------------------------------------------
+// Computes a convex hull from the studio model
+//-----------------------------------------------------------------------------
+CPhysCollide* ComputeConvexHull( studiohdr_t* pStudioHdr )
+{
+ CUtlVector<CPhysConvex*> convexHulls;
+
+ for (int body = 0; body < pStudioHdr->numbodyparts; ++body )
+ {
+ mstudiobodyparts_t *pBodyPart = pStudioHdr->pBodypart( body );
+ for( int model = 0; model < pBodyPart->nummodels; ++model )
+ {
+ mstudiomodel_t *pStudioModel = pBodyPart->pModel( model );
+ for( int mesh = 0; mesh < pStudioModel->nummeshes; ++mesh )
+ {
+ // Make a convex hull for each mesh
+ // NOTE: This won't work unless the model has been compiled
+ // with $staticprop
+ mstudiomesh_t *pStudioMesh = pStudioModel->pMesh( mesh );
+ convexHulls.AddToTail( ComputeConvexHull( pStudioMesh ) );
+ }
+ }
+ }
+
+ // Convert an array of convex elements to a compiled collision model
+ // (this deletes the convex elements)
+ return s_pPhysCollision->ConvertConvexToCollide( convexHulls.Base(), convexHulls.Size() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Add, find collision model in cache
+//-----------------------------------------------------------------------------
+static CPhysCollide* GetCollisionModel( char const* pModelName )
+{
+ // Convert to a common string
+ char* pTemp = (char*)_alloca(strlen(pModelName) + 1);
+ strcpy( pTemp, pModelName );
+ _strlwr( pTemp );
+
+ char* pSlash = strchr( pTemp, '\\' );
+ while( pSlash )
+ {
+ *pSlash = '/';
+ pSlash = strchr( pTemp, '\\' );
+ }
+
+ // Find it in the cache
+ ModelCollisionLookup_t lookup;
+ lookup.m_Name = pTemp;
+ int i = s_ModelCollisionCache.Find( lookup );
+ if (i != s_ModelCollisionCache.InvalidIndex())
+ return s_ModelCollisionCache[i].m_pCollide;
+
+ // Load the studio model file
+ CUtlBuffer buf;
+ if (!LoadStudioModel(pModelName, "prop_static", buf))
+ {
+ Warning("Error loading studio model \"%s\"!\n", pModelName );
+
+ // This way we don't try to load it multiple times
+ lookup.m_pCollide = 0;
+ s_ModelCollisionCache.Insert( lookup );
+
+ return 0;
+ }
+
+ // Compute the convex hull of the model...
+ studiohdr_t* pStudioHdr = (studiohdr_t*)buf.PeekGet();
+
+ // necessary for vertex access
+ SetCurrentModel( pStudioHdr );
+
+ lookup.m_pCollide = ComputeConvexHull( pStudioHdr );
+ s_ModelCollisionCache.Insert( lookup );
+
+ if ( !lookup.m_pCollide )
+ {
+ Warning("Bad geometry on \"%s\"!\n", pModelName );
+ }
+
+ // Debugging
+ if (g_DumpStaticProps)
+ {
+ static int propNum = 0;
+ char tmp[128];
+ sprintf( tmp, "staticprop%03d.txt", propNum );
+ DumpCollideToGlView( lookup.m_pCollide, tmp );
+ ++propNum;
+ }
+
+ FreeCurrentModelVertexes();
+
+ // Insert into cache...
+ return lookup.m_pCollide;
+}
+
+
+//-----------------------------------------------------------------------------
+// Tests a single leaf against the static prop
+//-----------------------------------------------------------------------------
+
+static bool TestLeafAgainstCollide( int depth, int* pNodeList,
+ Vector const& origin, QAngle const& angles, CPhysCollide* pCollide )
+{
+ // Copy the planes in the node list into a list of planes
+ float* pPlanes = (float*)_alloca(depth * 4 * sizeof(float) );
+ int idx = 0;
+ for (int i = depth; --i >= 0; ++idx )
+ {
+ int sign = (pNodeList[i] < 0) ? -1 : 1;
+ int node = (sign < 0) ? - pNodeList[i] - 1 : pNodeList[i];
+ dnode_t* pNode = &dnodes[node];
+ dplane_t* pPlane = &dplanes[pNode->planenum];
+
+ pPlanes[idx*4] = sign * pPlane->normal[0];
+ pPlanes[idx*4+1] = sign * pPlane->normal[1];
+ pPlanes[idx*4+2] = sign * pPlane->normal[2];
+ pPlanes[idx*4+3] = sign * pPlane->dist;
+ }
+
+ // Make a convex solid out of the planes
+ CPhysConvex* pPhysConvex = s_pPhysCollision->ConvexFromPlanes( pPlanes, depth, 0.0f );
+
+ // This should never happen, but if it does, return no collision
+ Assert( pPhysConvex );
+ if (!pPhysConvex)
+ return false;
+
+ CPhysCollide* pLeafCollide = s_pPhysCollision->ConvertConvexToCollide( &pPhysConvex, 1 );
+
+ // Collide the leaf solid with the static prop solid
+ trace_t tr;
+ s_pPhysCollision->TraceCollide( vec3_origin, vec3_origin, pLeafCollide, vec3_angle,
+ pCollide, origin, angles, &tr );
+
+ s_pPhysCollision->DestroyCollide( pLeafCollide );
+
+ return (tr.startsolid != 0);
+}
+
+//-----------------------------------------------------------------------------
+// Find all leaves that intersect with this bbox + test against the static prop..
+//-----------------------------------------------------------------------------
+
+static void ComputeConvexHullLeaves_R( int node, int depth, int* pNodeList,
+ Vector const& mins, Vector const& maxs,
+ Vector const& origin, QAngle const& angles, CPhysCollide* pCollide,
+ CUtlVector<unsigned short>& leafList )
+{
+ Assert( pNodeList && pCollide );
+ Vector cornermin, cornermax;
+
+ while( node >= 0 )
+ {
+ dnode_t* pNode = &dnodes[node];
+ dplane_t* pPlane = &dplanes[pNode->planenum];
+
+ // Arbitrary split plane here
+ for (int i = 0; i < 3; ++i)
+ {
+ if (pPlane->normal[i] >= 0)
+ {
+ cornermin[i] = mins[i];
+ cornermax[i] = maxs[i];
+ }
+ else
+ {
+ cornermin[i] = maxs[i];
+ cornermax[i] = mins[i];
+ }
+ }
+
+ if (DotProduct( pPlane->normal, cornermax ) <= pPlane->dist)
+ {
+ // Add the node to the list of nodes
+ pNodeList[depth] = node;
+ ++depth;
+
+ node = pNode->children[1];
+ }
+ else if (DotProduct( pPlane->normal, cornermin ) >= pPlane->dist)
+ {
+ // In this case, we are going in front of the plane. That means that
+ // this plane must have an outward normal facing in the oppisite direction
+ // We indicate this be storing a negative node index in the node list
+ pNodeList[depth] = - node - 1;
+ ++depth;
+
+ node = pNode->children[0];
+ }
+ else
+ {
+ // Here the box is split by the node. First, we'll add the plane as if its
+ // outward facing normal is in the direction of the node plane, then
+ // we'll have to reverse it for the other child...
+ pNodeList[depth] = node;
+ ++depth;
+
+ ComputeConvexHullLeaves_R( pNode->children[1],
+ depth, pNodeList, mins, maxs, origin, angles, pCollide, leafList );
+
+ pNodeList[depth - 1] = - node - 1;
+ ComputeConvexHullLeaves_R( pNode->children[0],
+ depth, pNodeList, mins, maxs, origin, angles, pCollide, leafList );
+ return;
+ }
+ }
+
+ Assert( pNodeList && pCollide );
+
+ // Never add static props to solid leaves
+ if ( (dleafs[-node-1].contents & CONTENTS_SOLID) == 0 )
+ {
+ if (TestLeafAgainstCollide( depth, pNodeList, origin, angles, pCollide ))
+ {
+ leafList.AddToTail( -node - 1 );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Places Static Props in the level
+//-----------------------------------------------------------------------------
+
+static void ComputeStaticPropLeaves( CPhysCollide* pCollide, Vector const& origin,
+ QAngle const& angles, CUtlVector<unsigned short>& leafList )
+{
+ // Compute an axis-aligned bounding box for the collide
+ Vector mins, maxs;
+ s_pPhysCollision->CollideGetAABB( &mins, &maxs, pCollide, origin, angles );
+
+ // Find all leaves that intersect with the bounds
+ int tempNodeList[1024];
+ ComputeConvexHullLeaves_R( 0, 0, tempNodeList, mins, maxs,
+ origin, angles, pCollide, leafList );
+}
+
+
+//-----------------------------------------------------------------------------
+// Computes the lighting origin
+//-----------------------------------------------------------------------------
+static bool ComputeLightingOrigin( StaticPropBuild_t const& build, Vector& lightingOrigin )
+{
+ for (int i = s_LightingInfo.Count(); --i >= 0; )
+ {
+ int entIndex = s_LightingInfo[i];
+
+ // Check against all lighting info entities
+ char const* pTargetName = ValueForKey( &entities[entIndex], "targetname" );
+ if (!Q_strcmp(pTargetName, build.m_pLightingOrigin))
+ {
+ GetVectorForKey( &entities[entIndex], "origin", lightingOrigin );
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Places Static Props in the level
+//-----------------------------------------------------------------------------
+static void AddStaticPropToLump( StaticPropBuild_t const& build )
+{
+ // Get the collision model
+ CPhysCollide* pConvexHull = GetCollisionModel( build.m_pModelName );
+ if (!pConvexHull)
+ return;
+
+ // Compute the leaves the static prop's convex hull hits
+ CUtlVector< unsigned short > leafList;
+ ComputeStaticPropLeaves( pConvexHull, build.m_Origin, build.m_Angles, leafList );
+
+ if ( !leafList.Count() )
+ {
+ Warning( "Static prop %s outside the map (%.2f, %.2f, %.2f)\n", build.m_pModelName, build.m_Origin.x, build.m_Origin.y, build.m_Origin.z );
+ return;
+ }
+ // Insert an element into the lump data...
+ int i = s_StaticPropLump.AddToTail( );
+ StaticPropLump_t& propLump = s_StaticPropLump[i];
+ propLump.m_PropType = AddStaticPropDictLump( build.m_pModelName );
+ VectorCopy( build.m_Origin, propLump.m_Origin );
+ VectorCopy( build.m_Angles, propLump.m_Angles );
+ propLump.m_FirstLeaf = s_StaticPropLeafLump.Count();
+ propLump.m_LeafCount = leafList.Count();
+ propLump.m_Solid = build.m_Solid;
+ propLump.m_Skin = build.m_Skin;
+ propLump.m_Flags = build.m_Flags;
+ if (build.m_FadesOut)
+ {
+ propLump.m_Flags |= STATIC_PROP_FLAG_FADES;
+ }
+ propLump.m_FadeMinDist = build.m_FadeMinDist;
+ propLump.m_FadeMaxDist = build.m_FadeMaxDist;
+ propLump.m_flForcedFadeScale = build.m_flForcedFadeScale;
+ propLump.m_nMinDXLevel = build.m_nMinDXLevel;
+ propLump.m_nMaxDXLevel = build.m_nMaxDXLevel;
+
+ if (build.m_pLightingOrigin && *build.m_pLightingOrigin)
+ {
+ if (ComputeLightingOrigin( build, propLump.m_LightingOrigin ))
+ {
+ propLump.m_Flags |= STATIC_PROP_USE_LIGHTING_ORIGIN;
+ }
+ }
+
+ // Add the leaves to the leaf lump
+ for (int j = 0; j < leafList.Size(); ++j)
+ {
+ StaticPropLeafLump_t insert;
+ insert.m_Leaf = leafList[j];
+ s_StaticPropLeafLump.AddToTail( insert );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Places static props in the lump
+//-----------------------------------------------------------------------------
+
+static void SetLumpData( )
+{
+ GameLumpHandle_t handle = g_GameLumps.GetGameLumpHandle(GAMELUMP_STATIC_PROPS);
+ if (handle != g_GameLumps.InvalidGameLump())
+ g_GameLumps.DestroyGameLump(handle);
+
+ int dictsize = s_StaticPropDictLump.Size() * sizeof(StaticPropDictLump_t);
+ int objsize = s_StaticPropLump.Size() * sizeof(StaticPropLump_t);
+ int leafsize = s_StaticPropLeafLump.Size() * sizeof(StaticPropLeafLump_t);
+ int size = dictsize + objsize + leafsize + 3 * sizeof(int);
+
+ handle = g_GameLumps.CreateGameLump( GAMELUMP_STATIC_PROPS, size, 0, GAMELUMP_STATIC_PROPS_VERSION );
+
+ // Serialize the data
+ CUtlBuffer buf( g_GameLumps.GetGameLump(handle), size );
+ buf.PutInt( s_StaticPropDictLump.Size() );
+ if (dictsize)
+ buf.Put( s_StaticPropDictLump.Base(), dictsize );
+ buf.PutInt( s_StaticPropLeafLump.Size() );
+ if (leafsize)
+ buf.Put( s_StaticPropLeafLump.Base(), leafsize );
+ buf.PutInt( s_StaticPropLump.Size() );
+ if (objsize)
+ buf.Put( s_StaticPropLump.Base(), objsize );
+}
+
+
+//-----------------------------------------------------------------------------
+// Places Static Props in the level
+//-----------------------------------------------------------------------------
+
+void EmitStaticProps()
+{
+ CreateInterfaceFn physicsFactory = GetPhysicsFactory();
+ if ( physicsFactory )
+ {
+ s_pPhysCollision = (IPhysicsCollision *)physicsFactory( VPHYSICS_COLLISION_INTERFACE_VERSION, NULL );
+ if( !s_pPhysCollision )
+ return;
+ }
+
+ // Generate a list of lighting origins, and strip them out
+ int i;
+ for ( i = 0; i < num_entities; ++i)
+ {
+ char* pEntity = ValueForKey(&entities[i], "classname");
+ if (!Q_strcmp(pEntity, "info_lighting"))
+ {
+ s_LightingInfo.AddToTail(i);
+ }
+ }
+
+ // Emit specifically specified static props
+ for ( i = 0; i < num_entities; ++i)
+ {
+ char* pEntity = ValueForKey(&entities[i], "classname");
+ if (!strcmp(pEntity, "static_prop") || !strcmp(pEntity, "prop_static"))
+ {
+ StaticPropBuild_t build;
+
+ GetVectorForKey( &entities[i], "origin", build.m_Origin );
+ GetAnglesForKey( &entities[i], "angles", build.m_Angles );
+ build.m_pModelName = ValueForKey( &entities[i], "model" );
+ build.m_Solid = IntForKey( &entities[i], "solid" );
+ build.m_Skin = IntForKey( &entities[i], "skin" );
+ build.m_FadeMaxDist = FloatForKey( &entities[i], "fademaxdist" );
+ build.m_Flags = 0;//IntForKey( &entities[i], "spawnflags" ) & STATIC_PROP_WC_MASK;
+ if (IntForKey( &entities[i], "ignorenormals" ) == 1)
+ {
+ build.m_Flags |= STATIC_PROP_IGNORE_NORMALS;
+ }
+ if (IntForKey( &entities[i], "disableshadows" ) == 1)
+ {
+ build.m_Flags |= STATIC_PROP_NO_SHADOW;
+ }
+ if (IntForKey( &entities[i], "disablevertexlighting" ) == 1)
+ {
+ build.m_Flags |= STATIC_PROP_NO_PER_VERTEX_LIGHTING;
+ }
+ if (IntForKey( &entities[i], "disableselfshadowing" ) == 1)
+ {
+ build.m_Flags |= STATIC_PROP_NO_SELF_SHADOWING;
+ }
+
+ if (IntForKey( &entities[i], "screenspacefade" ) == 1)
+ {
+ build.m_Flags |= STATIC_PROP_SCREEN_SPACE_FADE;
+ }
+
+ const char *pKey = ValueForKey( &entities[i], "fadescale" );
+ if ( pKey && pKey[0] )
+ {
+ build.m_flForcedFadeScale = FloatForKey( &entities[i], "fadescale" );
+ }
+ else
+ {
+ build.m_flForcedFadeScale = 1;
+ }
+ build.m_FadesOut = (build.m_FadeMaxDist > 0);
+ build.m_pLightingOrigin = ValueForKey( &entities[i], "lightingorigin" );
+ if (build.m_FadesOut)
+ {
+ build.m_FadeMinDist = FloatForKey( &entities[i], "fademindist" );
+ if (build.m_FadeMinDist < 0)
+ {
+ build.m_FadeMinDist = build.m_FadeMaxDist;
+ }
+ }
+ else
+ {
+ build.m_FadeMinDist = 0;
+ }
+ build.m_nMinDXLevel = (unsigned short)IntForKey( &entities[i], "mindxlevel" );
+ build.m_nMaxDXLevel = (unsigned short)IntForKey( &entities[i], "maxdxlevel" );
+ AddStaticPropToLump( build );
+
+ // strip this ent from the .bsp file
+ entities[i].epairs = 0;
+ }
+ }
+
+ // Strip out lighting origins; has to be done here because they are used when
+ // static props are made
+ for ( i = s_LightingInfo.Count(); --i >= 0; )
+ {
+ // strip this ent from the .bsp file
+ entities[s_LightingInfo[i]].epairs = 0;
+ }
+
+
+ SetLumpData( );
+}
+
+static studiohdr_t *g_pActiveStudioHdr;
+static void SetCurrentModel( studiohdr_t *pStudioHdr )
+{
+ // track the correct model
+ g_pActiveStudioHdr = pStudioHdr;
+}
+
+static void FreeCurrentModelVertexes()
+{
+ Assert( g_pActiveStudioHdr );
+
+ if ( g_pActiveStudioHdr->pVertexBase )
+ {
+ free( g_pActiveStudioHdr->pVertexBase );
+ g_pActiveStudioHdr->pVertexBase = NULL;
+ }
+}
+
+const vertexFileHeader_t * mstudiomodel_t::CacheVertexData( void * pModelData )
+{
+ char fileName[260];
+ FileHandle_t fileHandle;
+ vertexFileHeader_t *pVvdHdr;
+
+ Assert( pModelData == NULL );
+ Assert( g_pActiveStudioHdr );
+
+ if ( g_pActiveStudioHdr->pVertexBase )
+ {
+ return (vertexFileHeader_t *)g_pActiveStudioHdr->pVertexBase;
+ }
+
+ // mandatory callback to make requested data resident
+ // load and persist the vertex file
+ strcpy( fileName, "models/" );
+ strcat( fileName, g_pActiveStudioHdr->pszName() );
+ Q_StripExtension( fileName, fileName, sizeof( fileName ) );
+ strcat( fileName, ".vvd" );
+
+ // load the model
+ fileHandle = g_pFileSystem->Open( fileName, "rb" );
+ if ( !fileHandle )
+ {
+ Error( "Unable to load vertex data \"%s\"\n", fileName );
+ }
+
+ // Get the file size
+ int size = g_pFileSystem->Size( fileHandle );
+ if (size == 0)
+ {
+ g_pFileSystem->Close( fileHandle );
+ Error( "Bad size for vertex data \"%s\"\n", fileName );
+ }
+
+ pVvdHdr = (vertexFileHeader_t *)malloc(size);
+ g_pFileSystem->Read( pVvdHdr, size, fileHandle );
+ g_pFileSystem->Close( fileHandle );
+
+ // check header
+ if (pVvdHdr->id != MODEL_VERTEX_FILE_ID)
+ {
+ Error("Error Vertex File %s id %d should be %d\n", fileName, pVvdHdr->id, MODEL_VERTEX_FILE_ID);
+ }
+ if (pVvdHdr->version != MODEL_VERTEX_FILE_VERSION)
+ {
+ Error("Error Vertex File %s version %d should be %d\n", fileName, pVvdHdr->version, MODEL_VERTEX_FILE_VERSION);
+ }
+ if (pVvdHdr->checksum != g_pActiveStudioHdr->checksum)
+ {
+ Error("Error Vertex File %s checksum %d should be %d\n", fileName, pVvdHdr->checksum, g_pActiveStudioHdr->checksum);
+ }
+
+ g_pActiveStudioHdr->pVertexBase = (void*)pVvdHdr;
+ return pVvdHdr;
+}
+
|