diff --git a/engine/cmodel.cpp b/engine/cmodel.cpp index 466d445..ddd545d 100644 --- a/engine/cmodel.cpp +++ b/engine/cmodel.cpp @@ -392,6 +392,65 @@ vcollide_t* CM_VCollideForModel( int modelindex, const model_t* pModel ) return 0; } +//----------------------------------------------------------------------------- +// returns a physcollide that is scaled based off input data +//----------------------------------------------------------------------------- +CPhysCollide* CM_ScalePhysCollide( vcollide_t *pVCollide, float flScale ) +{ + CPhysCollide *pNewCollide = pVCollide->solids[0]; + + if ( flScale != 1.0f ) + { + // Create a query to get more information from the collision object + ICollisionQuery *pQuery = physcollision->CreateQueryModel( pVCollide->solids[0] ); // FIXME: This should iterate over all solids! + if ( pQuery == NULL ) + return pVCollide->solids[0]; + + // Create a container to hold all the convexes we'll create + const int nNumConvex = pQuery->ConvexCount(); + CPhysConvex **pConvexes = (CPhysConvex **) stackalloc( sizeof( CPhysConvex * ) * nNumConvex ); + + // For each convex, collect the verts and create a convex from it we'll retain for later + for ( int i = 0; i < nNumConvex; i++ ) + { + int nNumTris = pQuery->TriangleCount( i ); + int nNumVerts = nNumTris * 3; + // FIXME: Really? stackalloc? + Vector *pVerts = (Vector *) stackalloc( sizeof( Vector ) * nNumVerts ); + Vector **ppVerts = (Vector **) stackalloc( sizeof( Vector * ) * nNumVerts ); + for ( int j = 0; j < nNumTris; j++ ) + { + // Get all the verts for this triangle and scale them up + pQuery->GetTriangleVerts( i, j, pVerts + (j * 3) ); + *(pVerts + (j * 3)) *= flScale; + *(pVerts + (j * 3) + 1) *= flScale; + *(pVerts + (j * 3) + 2) *= flScale; + + // Setup our pointers (blech!) + *(ppVerts + (j * 3)) = pVerts + (j * 3); + *(ppVerts + (j * 3) + 1) = pVerts + (j * 3) + 1; + *(ppVerts + (j * 3) + 2) = pVerts + (j * 3) + 2; + } + + // Convert it back to a convex + pConvexes[i] = physcollision->ConvexFromVerts( ppVerts, nNumVerts ); + Assert( pConvexes[i] != NULL ); + if ( pConvexes[i] == NULL ) + return pVCollide->solids[0]; + } + + // Clean up + physcollision->DestroyQueryModel( pQuery ); + + // Create a collision model from all the convexes + pNewCollide = physcollision->ConvertConvexToCollide( pConvexes, nNumConvex ); + if ( !pNewCollide ) + return pVCollide->solids[0]; + } + + return pNewCollide; +} + diff --git a/engine/cmodel_engine.h b/engine/cmodel_engine.h index f8d0de4..3f477b3 100644 --- a/engine/cmodel_engine.h +++ b/engine/cmodel_engine.h @@ -80,6 +80,7 @@ int CM_BoxVisible( const Vector& mins, const Vector& maxs, const byte *visbits typedef struct cmodel_collision_s cmodel_collision_t; vcollide_t *CM_GetVCollide( int modelIndex ); vcollide_t* CM_VCollideForModel( int modelindex, const model_t* pModel ); +CPhysCollide* CM_ScalePhysCollide( vcollide_t *pVCollide, float flScale ); // gets a virtual physcollide for a displacement CPhysCollide *CM_PhysCollideForDisp( int index ); diff --git a/engine/enginetrace.cpp b/engine/enginetrace.cpp index 54ac243..46abee9 100644 --- a/engine/enginetrace.cpp +++ b/engine/enginetrace.cpp @@ -861,11 +861,15 @@ bool CEngineTrace::ClipRayToVPhysics( const Ray_t &ray, unsigned int fMask, ICol vcollide_t *pCollide = g_pMDLCache->GetVCollide( pModel->studio ); if ( pCollide && pCollide->solidCount ) { + CPhysCollide *pPhysCollide = pCollide->solids[0]; // UNDONE: Support other solid indices?!?!?!? (forced zero) + if ( StaticPropMgr()->IsStaticProp( pEntity->GetEntityHandle() ) ) + pPhysCollide = StaticPropMgr()->GetStaticPropCollide( pEntity->GetEntityHandle() ); + physcollision->TraceBox( ray, fMask, &studioConvex, - pCollide->solids[0], // UNDONE: Support other solid indices?!?!?!? (forced zero) + pPhysCollide, pEntity->GetCollisionOrigin(), pEntity->GetCollisionAngles(), pTrace ); diff --git a/engine/staticpropmgr.cpp b/engine/staticpropmgr.cpp index 04db0be..271c7ac 100644 --- a/engine/staticpropmgr.cpp +++ b/engine/staticpropmgr.cpp @@ -315,7 +315,10 @@ private: Vector m_RenderBBoxMin; Vector m_RenderBBoxMax; matrix3x4_t m_ModelToWorld; + matrix3x4_t m_ModelToWorldPreScaled; float m_flRadius; + Vector m_ModelBBoxMin; + Vector m_ModelBBoxMax; Vector m_WorldRenderBBoxMin; Vector m_WorldRenderBBoxMax; @@ -327,6 +330,7 @@ private: // CSGO port Vector4D m_DiffuseModulation; float m_Scale; + CPhysCollide *m_pPhysCollide; }; @@ -355,6 +359,7 @@ public: virtual bool IsStaticProp( CBaseHandle handle ) const; virtual int GetStaticPropIndex( IHandleEntity *pHandleEntity ) const; virtual ICollideable *GetStaticPropByIndex( int propIndex ); + virtual CPhysCollide *GetStaticPropCollide( IHandleEntity *pHandleEntity ) const; // methods of IStaticPropMgrClient virtual void ComputePropOpacity( const Vector &viewOrigin, float factor ); @@ -497,6 +502,7 @@ bool CStaticProp::Init( int index, StaticPropLump_t &lump, model_t *pModel ) m_LeafCount = lump.m_LeafCount; m_nSolidType = lump.m_Solid; m_FadeIndex = INVALID_FADE_INDEX; + m_pPhysCollide = NULL; MDLCACHE_CRITICAL_SECTION_( g_pMDLCache ); @@ -551,17 +557,18 @@ bool CStaticProp::Init( int index, StaticPropLump_t &lump, model_t *pModel ) } // Cache the model to world matrix since it never changes. - AngleMatrix( lump.m_Angles, lump.m_Origin, m_ModelToWorld ); - - matrix3x4_t matScale; - SetScaleMatrix(Vector(m_Scale), matScale); - MatrixMultiply(m_ModelToWorld, matScale, m_ModelToWorld); + AngleMatrix( lump.m_Angles, lump.m_Origin, m_ModelToWorldPreScaled ); + MatrixCopy( m_ModelToWorldPreScaled, m_ModelToWorld ); + MatrixScaleBy( m_Scale, m_ModelToWorld ); // Cache the collision bounding box since it'll never change. modelinfo->GetModelRenderBounds( m_pModel, m_RenderBBoxMin, m_RenderBBoxMax ); m_flRadius = m_RenderBBoxMin.DistTo( m_RenderBBoxMax ) * 0.5f; TransformAABB( m_ModelToWorld, m_RenderBBoxMin, m_RenderBBoxMax, m_WorldRenderBBoxMin, m_WorldRenderBBoxMax ); + m_ModelBBoxMin = m_pModel->mins * m_Scale; + m_ModelBBoxMax = m_pModel->maxs * m_Scale; + // FIXME: Sucky, but unless we want to re-read the static prop lump when the client is // initialized (possible, but also gross), we need to cache off the illum center now if (lump.m_Flags & STATIC_PROP_USE_LIGHTING_ORIGIN) @@ -608,7 +615,7 @@ const Vector& CStaticProp::OBBMins( ) const { if ( GetSolid() == SOLID_VPHYSICS ) { - return m_pModel->mins; + return m_ModelBBoxMin; } Vector& tv = AllocTempVector(); // FIXME: why doesn't this just return m_RenderBBoxMin? @@ -620,7 +627,7 @@ const Vector& CStaticProp::OBBMaxs( ) const { if ( GetSolid() == SOLID_VPHYSICS ) { - return m_pModel->maxs; + return m_ModelBBoxMax; } Vector& tv = AllocTempVector(); // FIXME: why doesn't this just return m_RenderBBoxMax? @@ -844,7 +851,9 @@ const QAngle& CStaticProp::GetCollisionAngles() const const matrix3x4_t& CStaticProp::CollisionToWorldTransform() const { - return m_ModelToWorld; + // PiMoN: in theory, this shouldn't be scaled as the physics mesh is being scaled separately + // but I dont remember whether changing this had any effect at all. + return m_ModelToWorldPreScaled; } @@ -1067,7 +1076,7 @@ int CStaticProp::DrawModelSlow( int flags ) else if ( m_nSolidType == SOLID_BBOX ) { static Color debugColor( 0, 255, 255, 255 ); - RenderWireframeBox( m_Origin, vec3_angle, m_pModel->mins, m_pModel->maxs, debugColor, true ); + RenderWireframeBox( m_Origin, m_Angles, m_ModelBBoxMin, m_ModelBBoxMax, debugColor, true ); } } @@ -1185,7 +1194,7 @@ void CStaticProp::InsertPropIntoKDTree() Vector mins, maxs; matrix3x4_t propToWorld; AngleMatrix( m_Angles, m_Origin, propToWorld ); - TransformAABB( propToWorld, m_pModel->mins, m_pModel->maxs, mins, maxs ); + TransformAABB( propToWorld, m_ModelBBoxMin, m_ModelBBoxMax, mins, maxs ); // If it's using vphysics, get a good AABB if ( m_nSolidType == SOLID_VPHYSICS ) @@ -1193,7 +1202,7 @@ void CStaticProp::InsertPropIntoKDTree() vcollide_t *pCollide = CM_VCollideForModel( -1, m_pModel ); if ( pCollide && pCollide->solidCount ) { - physcollision->CollideGetAABB( &mins, &maxs, pCollide->solids[0], m_Origin, m_Angles ); + physcollision->CollideGetAABB( &mins, &maxs, CM_ScalePhysCollide( pCollide, m_Scale ), m_Origin, m_Angles ); } else { @@ -1246,7 +1255,7 @@ void CStaticProp::CreateVPhysics( IPhysicsEnvironment *pPhysEnv, IVPhysicsKeyHan if (pVCollide) { - pPhysCollide = pVCollide->solids[0]; + pPhysCollide = CM_ScalePhysCollide( pVCollide, m_Scale ); IVPhysicsKeyParser *pParse = physcollision->VPhysicsKeyParserCreate( pVCollide->pKeyValues ); while ( !pParse->Finished() ) @@ -1280,7 +1289,7 @@ void CStaticProp::CreateVPhysics( IPhysicsEnvironment *pPhysEnv, IVPhysicsKeyHan #endif // If there's no collide, we need a bbox... - pPhysCollide = physcollision->BBoxToCollide( m_pModel->mins, m_pModel->maxs ); + pPhysCollide = physcollision->BBoxToCollide( m_ModelBBoxMin, m_ModelBBoxMax ); solid.params = g_PhysDefaultObjectParams; } @@ -1293,6 +1302,7 @@ void CStaticProp::CreateVPhysics( IPhysicsEnvironment *pPhysEnv, IVPhysicsKeyHan pPhysEnv->CreatePolyObjectStatic( pPhysCollide, surfaceData, m_Origin, m_Angles, &solid.params ); //PhysCheckAdd( pPhys, "Static" ); + m_pPhysCollide = pPhysCollide; } @@ -1901,6 +1911,17 @@ bool CStaticPropMgr::PropHasBakedLightingDisabled( IHandleEntity *pHandleEntity return ( (prop.Flags() & STATIC_PROP_NO_PER_VERTEX_LIGHTING ) != 0 ); } +CPhysCollide *CStaticPropMgr::GetStaticPropCollide( IHandleEntity *pHandleEntity ) const +{ + // Strip off the bits + int nIndex = HandleEntityToIndex( pHandleEntity ); + + // Get the prop + const CStaticProp &prop = m_StaticProps[nIndex]; + + return prop.m_pPhysCollide; +} + //----------------------------------------------------------------------------- // Compute static lighting //----------------------------------------------------------------------------- diff --git a/engine/staticpropmgr.h b/engine/staticpropmgr.h index 3e68f84..e98a824 100644 --- a/engine/staticpropmgr.h +++ b/engine/staticpropmgr.h @@ -69,6 +69,8 @@ public: virtual int GetStaticPropIndex( IHandleEntity *pHandleEntity ) const = 0; virtual bool PropHasBakedLightingDisabled( IHandleEntity *pHandleEntity) const = 0; + + virtual CPhysCollide *GetStaticPropCollide( IHandleEntity *pHandleEntity ) const = 0; }; diff --git a/utils/vrad/vradstaticprops.cpp b/utils/vrad/vradstaticprops.cpp index e4d92ed..4c863f1 100644 --- a/utils/vrad/vradstaticprops.cpp +++ b/utils/vrad/vradstaticprops.cpp @@ -232,7 +232,7 @@ static void ConvertTexelDataToTexture(unsigned int _resX, unsigned int _resY, Im // Such a monstrosity. :( static void GenerateLightmapSamplesForMesh( const matrix3x4_t& _matPos, const matrix3x4_t& _matNormal, int _iThread, int _skipProp, int _nFlags, int _lightmapResX, int _lightmapResY, - studiohdr_t* _pStudioHdr, mstudiomodel_t* _pStudioModel, OptimizedModel::ModelHeader_t* _pVtxModel, int _meshID, + studiohdr_t* _pStudioHdr, mstudiomodel_t* _pStudioModel, OptimizedModel::ModelHeader_t* _pVtxModel, int _meshID, float _flScale, CComputeStaticPropLightingResults *_pResults ); // Debug function, converts lightmaps to linear space then dumps them out. @@ -320,6 +320,8 @@ private: unsigned int m_LightmapImageWidth; unsigned int m_LightmapImageHeight; + float m_Scale; + }; // Enumeration context @@ -1047,6 +1049,8 @@ void CVradStaticPropMgr::UnserializeModels( CUtlBuffer& buf ) m_StaticProps[i].m_LightmapImageFormat = IMAGE_FORMAT_RGB888; m_StaticProps[i].m_LightmapImageWidth = lump.m_nLightmapResolutionX; m_StaticProps[i].m_LightmapImageHeight = lump.m_nLightmapResolutionY; + + m_StaticProps[i].m_Scale = lump.m_Scale; } } @@ -1370,7 +1374,7 @@ void CVradStaticPropMgr::ComputeLighting( CStaticProp &prop, int iThread, int pr // TODO: Move this into its own function. In fact, refactor this whole function. if (withTexelLighting) { - GenerateLightmapSamplesForMesh( matPos, matNormal, iThread, skip_prop, nFlags, prop.m_LightmapImageWidth, prop.m_LightmapImageHeight, pStudioHdr, pStudioModel, pVtxModel, meshID, pResults ); + GenerateLightmapSamplesForMesh( matPos, matNormal, iThread, skip_prop, nFlags, prop.m_LightmapImageWidth, prop.m_LightmapImageHeight, pStudioHdr, pStudioModel, pVtxModel, meshID, prop.m_Scale, pResults ); } // If we do lightmapping, we also do vertex lighting as a potential fallback. This may change. @@ -1379,7 +1383,7 @@ void CVradStaticPropMgr::ComputeLighting( CStaticProp &prop, int iThread, int pr Vector sampleNormal; Vector samplePosition; // transform position and normal into world coordinate system - VectorTransform(*vertData->Position(vertexID), matPos, samplePosition); + VectorTransform(*vertData->Position(vertexID) * prop.m_Scale, matPos, samplePosition); VectorTransform(*vertData->Normal(vertexID), matNormal, sampleNormal); if ( PositionInSolid( samplePosition ) ) @@ -1843,6 +1847,7 @@ void CVradStaticPropMgr::AddPolysForRayTrace( void ) { Vector verts[3]; queryModel->GetTriangleVerts( nConvex, nTri, verts ); + *verts *= prop.m_Scale; // TODO: is it needed? for ( int nVert = 0; nVert < 3; ++nVert ) verts[nVert] = xform.VMul4x3(verts[nVert]); g_RtEnv.AddTriangle ( TRACE_ID_STATICPROP | nProp, verts[0], verts[1], verts[2], fullCoverage ); @@ -1945,6 +1950,7 @@ void CVradStaticPropMgr::AddPolysForRayTrace( void ) // transform position into world coordinate system matrix3x4_t matrix; AngleMatrix( prop.m_Angles, prop.m_Origin, matrix ); + MatrixScaleBy( prop.m_Scale, matrix ); Vector position1; Vector position2; @@ -2129,6 +2135,7 @@ void CVradStaticPropMgr::BuildTriList( CStaticProp &prop ) // transform position into world coordinate system matrix3x4_t matrix; AngleMatrix( prop.m_Angles, prop.m_Origin, matrix ); + MatrixScaleBy( prop.m_Scale, matrix ); Vector position1; Vector position2; @@ -2274,7 +2281,7 @@ inline float ComputeBarycentricDistanceToTri( Vector _barycentricCoord, Vector2D } // ------------------------------------------------------------------------------------------------ -static void GenerateLightmapSamplesForMesh( const matrix3x4_t& _matPos, const matrix3x4_t& _matNormal, int _iThread, int _skipProp, int _flags, int _lightmapResX, int _lightmapResY, studiohdr_t* _pStudioHdr, mstudiomodel_t* _pStudioModel, OptimizedModel::ModelHeader_t* _pVtxModel, int _meshID, CComputeStaticPropLightingResults *_outResults ) +static void GenerateLightmapSamplesForMesh( const matrix3x4_t& _matPos, const matrix3x4_t& _matNormal, int _iThread, int _skipProp, int _flags, int _lightmapResX, int _lightmapResY, studiohdr_t* _pStudioHdr, mstudiomodel_t* _pStudioModel, OptimizedModel::ModelHeader_t* _pVtxModel, int _meshID, float _flScale, CComputeStaticPropLightingResults *_outResults ) { // Could iterate and gen this if needed. int nLod = 0; @@ -2323,9 +2330,9 @@ static void GenerateLightmapSamplesForMesh( const matrix3x4_t& _matPos, const ma int vertex3 = pStripGroup->pVertex(i3)->origMeshVertID; Vector modelPos[3] = { - *vertData->Position(vertex1), - *vertData->Position(vertex2), - *vertData->Position(vertex3) + *vertData->Position(vertex1)* _flScale, + *vertData->Position(vertex2)* _flScale, + *vertData->Position(vertex3)* _flScale }; Vector modelNormal[3] = {