From bcbcbfcc953bfcc6df7f5b060d0515a2e680bcac Mon Sep 17 00:00:00 2001 From: copperpixel <48454166+copperpixel@users.noreply.github.com> Date: Mon, 10 Nov 2025 02:23:03 +0100 Subject: [PATCH 1/6] add CParticleSystemQuery handling for particle systems in mdl panels --- .../client/game_controls/basemodel_panel.cpp | 3 + .../client/game_controls/basemodel_panel.h | 1 + src/game/shared/particlesystemquery.cpp | 116 ++++++++++++++++++ 3 files changed, 120 insertions(+) diff --git a/src/game/client/game_controls/basemodel_panel.cpp b/src/game/client/game_controls/basemodel_panel.cpp index 0fed0085787..654e6784314 100644 --- a/src/game/client/game_controls/basemodel_panel.cpp +++ b/src/game/client/game_controls/basemodel_panel.cpp @@ -803,6 +803,7 @@ void CBaseModelPanel::particle_data_t::UpdateControlPoints( CStudioHdr *pStudioH MatrixPosition( matAttachToWorld, vecPosition ); m_pParticleSystem->SetControlPointOrientation( i, vecForward, vecRight, vecUp ); + m_pParticleSystem->SetControlPointObject( i, ( void * )m_pOuter->GetVPanel() ); m_pParticleSystem->SetControlPoint( i, vecPosition + vecParticleOffset ); } } @@ -813,6 +814,7 @@ void CBaseModelPanel::particle_data_t::UpdateControlPoints( CStudioHdr *pStudioH MatrixPosition( matAttachToWorld, vecPosition ); m_pParticleSystem->SetControlPointOrientation( 0, vecForward, vecRight, vecUp ); + m_pParticleSystem->SetControlPointObject( 0, ( void * )m_pOuter->GetVPanel() ); m_pParticleSystem->SetControlPoint( 0, vecPosition + vecParticleOffset ); } } @@ -837,6 +839,7 @@ CBaseModelPanel::particle_data_t *CBaseModelPanel::CreateParticleData( const cha particle_data_t *pData = new particle_data_t; pData->m_bIsUpdateToDate = false; pData->m_pParticleSystem = pParticle; + pData->m_pOuter = this; m_particleList.AddToTail( pData ); diff --git a/src/game/client/game_controls/basemodel_panel.h b/src/game/client/game_controls/basemodel_panel.h index 438be08e71c..e102a4f6bb7 100644 --- a/src/game/client/game_controls/basemodel_panel.h +++ b/src/game/client/game_controls/basemodel_panel.h @@ -248,6 +248,7 @@ class CBaseModelPanel : public CMDLPanel bool m_bIsUpdateToDate; CParticleCollection *m_pParticleSystem; + CBaseModelPanel *m_pOuter; }; CUtlVector< particle_data_t* > m_particleList; diff --git a/src/game/shared/particlesystemquery.cpp b/src/game/shared/particlesystemquery.cpp index 9a7332315da..658a2a9610d 100644 --- a/src/game/shared/particlesystemquery.cpp +++ b/src/game/shared/particlesystemquery.cpp @@ -11,6 +11,7 @@ #include "collisionutils.h" #if defined( CLIENT_DLL ) +#include "basemodel_panel.h" #include "c_pixel_visibility.h" #endif @@ -208,6 +209,15 @@ void CParticleSystemQuery::GetRandomPointsOnControllingObjectHitBox( { pMoveParent = *( phMoveParent ); } + CBaseModelPanel *pPanel = NULL; + if ( !pMoveParent ) + { + vgui::VPANEL hPanel = reinterpret_cast< vgui::VPANEL >( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ); + if ( hPanel ) + { + pPanel = dynamic_cast< CBaseModelPanel * >( vgui::ipanel()->GetPanel( hPanel, vgui::GetControlsModuleName() ) ); + } + } if ( pMoveParent ) { float flRandMax = flBBoxScale; @@ -371,6 +381,74 @@ void CParticleSystemQuery::GetRandomPointsOnControllingObjectHitBox( s_BoneMutex.Unlock(); } + else if ( pPanel ) + { + float flRandMax = flBBoxScale; + float flRandMin = 1.0 - flBBoxScale; + Vector vecBasePos; + pParticles->GetControlPointAtTime( nControlPointNumber, pParticles->m_flCurTime, &vecBasePos ); + + studiohdr_t *pStudioHdr = pPanel->GetStudioHdr(); + if ( pStudioHdr ) + { + mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( 0 /*default*/ ); + if ( set ) + { + bSucesss = true; + + Vector vecWorldPosition( 0, 0, 0 ); + float u = 0, v = 0, w = 0; + int nHitbox = 0; + int nNumIters = nNumTrysToGetAPointInsideTheModel; + if ( !vecDirectionalBias.IsZero( 0.0001 ) ) + nNumIters = MAX( nNumIters, 5 ); + + for ( int i = 0; i < nNumPtsOut; i++ ) + { + float flBestPointGoodness = -1.0e20; + int nTryCnt = nNumIters; + do + { + int nTryHitbox = pParticles->RandomInt( 0, set->numhitboxes - 1 ); + mstudiobbox_t *pBox = set->pHitbox( nTryHitbox ); + + float flTryU = pParticles->RandomFloat( flRandMin, flRandMax ); + float flTryV = pParticles->RandomFloat( flRandMin, flRandMax ); + float flTryW = pParticles->RandomFloat( flRandMin, flRandMax ); + + Vector vecLocalPosition; + vecLocalPosition.x = GetSurfaceCoord( flTryU, pBox->bbmin.x, pBox->bbmax.x ); + vecLocalPosition.y = GetSurfaceCoord( flTryV, pBox->bbmin.y, pBox->bbmax.y ); + vecLocalPosition.z = GetSurfaceCoord( flTryW, pBox->bbmin.z, pBox->bbmax.z ); + + // Model panels don't cache bone transforms as an entity would + // so instead we approximate world space locations by sampling + // hitbox positions in model-local space and offsetting them by + // the control point's position + Vector vecTryWorldPosition = vecBasePos + vecLocalPosition; + + float flPointGoodness = pParticles->RandomFloat( 0, 72 ) + + DotProduct( vecTryWorldPosition - vecBasePos, vecDirectionalBias ); + + if ( flPointGoodness > flBestPointGoodness ) + { + u = flTryU; + v = flTryV; + w = flTryW; + vecWorldPosition = vecTryWorldPosition; + nHitbox = nTryHitbox; + flBestPointGoodness = flPointGoodness; + } + } while ( nTryCnt-- ); + *( pPntsOut++ ) = vecWorldPosition; + if ( pHitBoxRelativeCoordOut ) + ( pHitBoxRelativeCoordOut++ )->Init( u, v, w ); + if ( pHitBoxIndexOut ) + *( pHitBoxIndexOut++ ) = nHitbox; + } + } + } + } #endif if (! bSucesss ) { @@ -406,6 +484,15 @@ int CParticleSystemQuery::GetControllingObjectHitBoxInfo( { pMoveParent = *( phMoveParent ); } + CBaseModelPanel *pPanel = NULL; + if ( !pMoveParent ) + { + vgui::VPANEL hPanel = reinterpret_cast< vgui::VPANEL >( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ); + if ( hPanel ) + { + pPanel = dynamic_cast< CBaseModelPanel * >( vgui::ipanel()->GetPanel( hPanel, vgui::GetControlsModuleName() ) ); + } + } if ( pMoveParent ) { @@ -456,6 +543,35 @@ int CParticleSystemQuery::GetControllingObjectHitBoxInfo( nRet = 1; } } + else if ( pPanel ) + { + studiohdr_t *pStudioHdr = pPanel->GetStudioHdr(); + + if ( pStudioHdr ) + { + mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( 0 ); + + if ( set ) + { + nRet = MIN( nBufSize, set->numhitboxes ); + for ( int i = 0; i < nRet; i++ ) + { + mstudiobbox_t *pBox = set->pHitbox( i ); + pHitBoxOutputBuffer[ i ].m_vecBoxMins.x = pBox->bbmin.x; + pHitBoxOutputBuffer[ i ].m_vecBoxMins.y = pBox->bbmin.y; + pHitBoxOutputBuffer[ i ].m_vecBoxMins.z = pBox->bbmin.z; + + pHitBoxOutputBuffer[ i ].m_vecBoxMaxes.x = pBox->bbmax.x; + pHitBoxOutputBuffer[ i ].m_vecBoxMaxes.y = pBox->bbmax.y; + pHitBoxOutputBuffer[ i ].m_vecBoxMaxes.z = pBox->bbmax.z; + + // Model panels don't cache bone transforms as an entity would so + // use identity matrix instead so we only offset from the control point + SetIdentityMatrix( pHitBoxOutputBuffer[ i ].m_Transform ); + } + } + } + } s_BoneMutex.Unlock(); #endif return nRet; From c8c75eb3269e6ab7fcb549a791d6aef2cbad8e40 Mon Sep 17 00:00:00 2001 From: copperpixel <48454166+copperpixel@users.noreply.github.com> Date: Tue, 11 Nov 2025 15:59:42 +0100 Subject: [PATCH 2/6] - fix imperfections in particle positioning - cache last mdl panel bone transforms for use in particle system query --- .../client/game_controls/basemodel_panel.cpp | 6 +- .../client/game_controls/basemodel_panel.h | 22 +++--- src/game/shared/particlesystemquery.cpp | 41 +++++------ src/public/matsys_controls/mdlpanel.h | 4 ++ src/vgui2/matsys_controls/mdlpanel.cpp | 71 +++++++++++++++++-- 5 files changed, 103 insertions(+), 41 deletions(-) diff --git a/src/game/client/game_controls/basemodel_panel.cpp b/src/game/client/game_controls/basemodel_panel.cpp index 654e6784314..8c6f66cafc0 100644 --- a/src/game/client/game_controls/basemodel_panel.cpp +++ b/src/game/client/game_controls/basemodel_panel.cpp @@ -803,7 +803,7 @@ void CBaseModelPanel::particle_data_t::UpdateControlPoints( CStudioHdr *pStudioH MatrixPosition( matAttachToWorld, vecPosition ); m_pParticleSystem->SetControlPointOrientation( i, vecForward, vecRight, vecUp ); - m_pParticleSystem->SetControlPointObject( i, ( void * )m_pOuter->GetVPanel() ); + m_pParticleSystem->SetControlPointObject( i, this ); m_pParticleSystem->SetControlPoint( i, vecPosition + vecParticleOffset ); } } @@ -814,12 +814,13 @@ void CBaseModelPanel::particle_data_t::UpdateControlPoints( CStudioHdr *pStudioH MatrixPosition( matAttachToWorld, vecPosition ); m_pParticleSystem->SetControlPointOrientation( 0, vecForward, vecRight, vecUp ); - m_pParticleSystem->SetControlPointObject( 0, ( void * )m_pOuter->GetVPanel() ); + m_pParticleSystem->SetControlPointObject( 0, this ); m_pParticleSystem->SetControlPoint( 0, vecPosition + vecParticleOffset ); } } m_bIsUpdateToDate = true; + m_pStudioHdr = pStudioHdr; } @@ -840,6 +841,7 @@ CBaseModelPanel::particle_data_t *CBaseModelPanel::CreateParticleData( const cha pData->m_bIsUpdateToDate = false; pData->m_pParticleSystem = pParticle; pData->m_pOuter = this; + pData->m_pStudioHdr = NULL; m_particleList.AddToTail( pData ); diff --git a/src/game/client/game_controls/basemodel_panel.h b/src/game/client/game_controls/basemodel_panel.h index e102a4f6bb7..b8a6c9db25e 100644 --- a/src/game/client/game_controls/basemodel_panel.h +++ b/src/game/client/game_controls/basemodel_panel.h @@ -212,6 +212,18 @@ class CBaseModelPanel : public CMDLPanel void SetupModelAnimDefaults( void ); public: + struct particle_data_t + { + ~particle_data_t(); + + void UpdateControlPoints( CStudioHdr *pStudioHdr, matrix3x4_t *pWorldMatrix, const CUtlVector< int > &vecAttachments, int iDefaultBone = 0, const Vector &vecParticleOffset = vec3_origin ); + + bool m_bIsUpdateToDate; + CParticleCollection *m_pParticleSystem; + CStudioHdr *m_pStudioHdr; + CBaseModelPanel *m_pOuter; + }; + BMPResData_t m_BMPResData; // Base model panel data set in the .res file. QAngle m_angPlayer; Vector m_vecPlayerPos; @@ -240,16 +252,6 @@ class CBaseModelPanel : public CMDLPanel CPanelAnimationVar( bool, m_bUseParticle, "use_particle", "0" ); CPanelAnimationVar( float, m_flMaxPitch, "max_pitch", "90" ); - struct particle_data_t - { - ~particle_data_t(); - - void UpdateControlPoints( CStudioHdr *pStudioHdr, matrix3x4_t *pWorldMatrix, const CUtlVector< int >& vecAttachments, int iDefaultBone = 0, const Vector& vecParticleOffset = vec3_origin ); - - bool m_bIsUpdateToDate; - CParticleCollection *m_pParticleSystem; - CBaseModelPanel *m_pOuter; - }; CUtlVector< particle_data_t* > m_particleList; diff --git a/src/game/shared/particlesystemquery.cpp b/src/game/shared/particlesystemquery.cpp index 658a2a9610d..f50162808bc 100644 --- a/src/game/shared/particlesystemquery.cpp +++ b/src/game/shared/particlesystemquery.cpp @@ -9,6 +9,7 @@ #include "baseparticleentity.h" #include "entityparticletrail_shared.h" #include "collisionutils.h" +#include "bone_setup.h" #if defined( CLIENT_DLL ) #include "basemodel_panel.h" @@ -209,14 +210,10 @@ void CParticleSystemQuery::GetRandomPointsOnControllingObjectHitBox( { pMoveParent = *( phMoveParent ); } - CBaseModelPanel *pPanel = NULL; + CBaseModelPanel::particle_data_t *pPanelParticleData = NULL; if ( !pMoveParent ) { - vgui::VPANEL hPanel = reinterpret_cast< vgui::VPANEL >( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ); - if ( hPanel ) - { - pPanel = dynamic_cast< CBaseModelPanel * >( vgui::ipanel()->GetPanel( hPanel, vgui::GetControlsModuleName() ) ); - } + pPanelParticleData = reinterpret_cast< CBaseModelPanel::particle_data_t * >( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ); } if ( pMoveParent ) { @@ -381,14 +378,16 @@ void CParticleSystemQuery::GetRandomPointsOnControllingObjectHitBox( s_BoneMutex.Unlock(); } - else if ( pPanel ) + else if ( pPanelParticleData ) { float flRandMax = flBBoxScale; float flRandMin = 1.0 - flBBoxScale; Vector vecBasePos; pParticles->GetControlPointAtTime( nControlPointNumber, pParticles->m_flCurTime, &vecBasePos ); - studiohdr_t *pStudioHdr = pPanel->GetStudioHdr(); + matrix3x4_t *pmatBoneToWorld = pPanelParticleData->m_pOuter->BoneArray( pPanelParticleData->m_pStudioHdr ); + const studiohdr_t *pStudioHdr = pPanelParticleData->m_pStudioHdr->GetRenderHdr(); + if ( pStudioHdr ) { mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( 0 /*default*/ ); @@ -421,11 +420,8 @@ void CParticleSystemQuery::GetRandomPointsOnControllingObjectHitBox( vecLocalPosition.y = GetSurfaceCoord( flTryV, pBox->bbmin.y, pBox->bbmax.y ); vecLocalPosition.z = GetSurfaceCoord( flTryW, pBox->bbmin.z, pBox->bbmax.z ); - // Model panels don't cache bone transforms as an entity would - // so instead we approximate world space locations by sampling - // hitbox positions in model-local space and offsetting them by - // the control point's position - Vector vecTryWorldPosition = vecBasePos + vecLocalPosition; + Vector vecTryWorldPosition; + VectorTransform( vecLocalPosition, pmatBoneToWorld[ pBox->bone ], vecTryWorldPosition ); float flPointGoodness = pParticles->RandomFloat( 0, 72 ) + DotProduct( vecTryWorldPosition - vecBasePos, vecDirectionalBias ); @@ -484,14 +480,10 @@ int CParticleSystemQuery::GetControllingObjectHitBoxInfo( { pMoveParent = *( phMoveParent ); } - CBaseModelPanel *pPanel = NULL; + CBaseModelPanel::particle_data_t *pPanelParticleData = NULL; if ( !pMoveParent ) { - vgui::VPANEL hPanel = reinterpret_cast< vgui::VPANEL >( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ); - if ( hPanel ) - { - pPanel = dynamic_cast< CBaseModelPanel * >( vgui::ipanel()->GetPanel( hPanel, vgui::GetControlsModuleName() ) ); - } + pPanelParticleData = reinterpret_cast< CBaseModelPanel::particle_data_t * > ( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ); } if ( pMoveParent ) @@ -543,13 +535,14 @@ int CParticleSystemQuery::GetControllingObjectHitBoxInfo( nRet = 1; } } - else if ( pPanel ) + else if ( pPanelParticleData ) { - studiohdr_t *pStudioHdr = pPanel->GetStudioHdr(); + matrix3x4_t *pmatBoneToWorld = pPanelParticleData->m_pOuter->BoneArray( pPanelParticleData->m_pStudioHdr ); + const studiohdr_t *pStudioHdr = pPanelParticleData->m_pStudioHdr->GetRenderHdr(); if ( pStudioHdr ) { - mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( 0 ); + mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( 0 /*default*/ ); if ( set ) { @@ -565,9 +558,7 @@ int CParticleSystemQuery::GetControllingObjectHitBoxInfo( pHitBoxOutputBuffer[ i ].m_vecBoxMaxes.y = pBox->bbmax.y; pHitBoxOutputBuffer[ i ].m_vecBoxMaxes.z = pBox->bbmax.z; - // Model panels don't cache bone transforms as an entity would so - // use identity matrix instead so we only offset from the control point - SetIdentityMatrix( pHitBoxOutputBuffer[ i ].m_Transform ); + pHitBoxOutputBuffer[ i ].m_Transform = pmatBoneToWorld[ pBox->bone ]; } } } diff --git a/src/public/matsys_controls/mdlpanel.h b/src/public/matsys_controls/mdlpanel.h index ab96a408265..d9e7ca102a1 100644 --- a/src/public/matsys_controls/mdlpanel.h +++ b/src/public/matsys_controls/mdlpanel.h @@ -106,6 +106,8 @@ class CMDLPanel : public CPotteryWheelPanel virtual void FireEvent( const char *pszEventName, const char *pszEventOptions ); void ResetAnimationEventState( MDLAnimEventState_t *pEventState ); + matrix3x4_t *BoneArray( CStudioHdr *pStudioHdr ) const; + protected: virtual void SetupRenderState( int nDisplayWidth, int nDisplayHeight ) OVERRIDE; @@ -118,6 +120,8 @@ class CMDLPanel : public CPotteryWheelPanel float m_flCycleStartTime; CStudioHdr *m_pStudioHdr; uint32 m_unMdlCacheSerial; + int m_nLastBoneCount; + matrix3x4_t *m_pmatLastBoneToWorld; }; MDLData_t m_RootMDL; diff --git a/src/vgui2/matsys_controls/mdlpanel.cpp b/src/vgui2/matsys_controls/mdlpanel.cpp index baa3af33647..47eb5660345 100644 --- a/src/vgui2/matsys_controls/mdlpanel.cpp +++ b/src/vgui2/matsys_controls/mdlpanel.cpp @@ -75,6 +75,8 @@ CMDLPanel::CMDLPanel( vgui::Panel *pParent, const char *pName ) : BaseClass( pPa SetIdentityMatrix( m_RootMDL.m_MDLToWorld ); m_RootMDL.m_pStudioHdr = NULL; m_RootMDL.m_unMdlCacheSerial = 0; + m_RootMDL.m_nLastBoneCount = -1; + m_RootMDL.m_pmatLastBoneToWorld = NULL; m_bDrawCollisionModel = false; m_bWireFrame = false; m_bGroundGrid = false; @@ -90,6 +92,11 @@ CMDLPanel::~CMDLPanel() m_aMergeMDLs.Purge(); m_DefaultEnvCubemap.Shutdown( ); m_DefaultHDREnvCubemap.Shutdown(); + if ( m_RootMDL.m_pmatLastBoneToWorld ) + { + delete[] m_RootMDL.m_pmatLastBoneToWorld; + m_RootMDL.m_pmatLastBoneToWorld = NULL; + } if ( m_RootMDL.m_pStudioHdr ) { delete m_RootMDL.m_pStudioHdr; @@ -168,6 +175,9 @@ void CMDLPanel::SetMDL( MDLHandle_t handle, void *pProxyData ) m_RootMDL.m_flCycleStartTime = 0.f; + m_RootMDL.m_nLastBoneCount = -1; + m_RootMDL.m_pmatLastBoneToWorld = NULL; + // Set the pose parameters to the default for the mdl SetPoseParameters( NULL, 0 ); @@ -473,6 +483,18 @@ void CMDLPanel::OnPaint3D() pOverrideMaterial = NULL; + // Cache root bone transforms for external access + if ( m_RootMDL.m_nLastBoneCount != studioHdr.numbones() ) + { + m_RootMDL.m_nLastBoneCount = studioHdr.numbones(); + if ( m_RootMDL.m_pmatLastBoneToWorld ) + { + delete[] m_RootMDL.m_pmatLastBoneToWorld; + } + m_RootMDL.m_pmatLastBoneToWorld = new matrix3x4_t[ m_RootMDL.m_nLastBoneCount ]; + } + Q_memcpy( m_RootMDL.m_pmatLastBoneToWorld, pBoneToWorld, m_RootMDL.m_nLastBoneCount * sizeof( matrix3x4_t ) ); + // Draw the merge MDLs. matrix3x4_t matMergeBoneToWorld[MAXSTUDIOBONES]; int nMergeCount = m_aMergeMDLs.Count(); @@ -501,6 +523,18 @@ void CMDLPanel::OnPaint3D() if ( pOverrideMaterial != NULL ) g_pStudioRender->ForcedMaterialOverride( NULL ); + // Cache merge bone transforms for external access + if ( m_aMergeMDLs[iMerge].m_nLastBoneCount != mergeHdr.numbones() ) + { + m_aMergeMDLs[iMerge].m_nLastBoneCount = mergeHdr.numbones(); + if ( m_aMergeMDLs[iMerge].m_pmatLastBoneToWorld ) + { + delete[] m_aMergeMDLs[iMerge].m_pmatLastBoneToWorld; + } + m_aMergeMDLs[iMerge].m_pmatLastBoneToWorld = new matrix3x4_t[ m_aMergeMDLs[iMerge].m_nLastBoneCount ]; + } + Q_memcpy( m_aMergeMDLs[iMerge].m_pmatLastBoneToWorld, pMergeBoneToWorld, m_aMergeMDLs[iMerge].m_nLastBoneCount * sizeof( matrix3x4_t ) ); + // Notify of model render RenderingMergedModel( pRenderContext, &mergeHdr, m_aMergeMDLs[iMerge].m_MDL.GetMDL(), pMergeBoneToWorld ); } @@ -856,6 +890,9 @@ void CMDLPanel::SetMergeMDL( MDLHandle_t handle, void *pProxyData, int nSkin /*= m_aMergeMDLs[iIndex].m_pStudioHdr = new CStudioHdr( m_aMergeMDLs[iIndex].m_MDL.GetStudioHdr(), g_pMDLCache ); + m_aMergeMDLs[iIndex].m_nLastBoneCount = -1; + m_aMergeMDLs[iIndex].m_pmatLastBoneToWorld = NULL; + // Need to invalidate the layout so the panel will adjust is LookAt for the new model. InvalidateLayout(); } @@ -950,12 +987,16 @@ void CMDLPanel::ClearMergeMDLs( void ) const int nMergeCount = m_aMergeMDLs.Count(); for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge ) { - if ( !m_aMergeMDLs[iMerge].m_pStudioHdr ) + if ( m_aMergeMDLs[iMerge].m_pmatLastBoneToWorld ) { - continue; + delete[] m_aMergeMDLs[iMerge].m_pmatLastBoneToWorld; + m_aMergeMDLs[iMerge].m_pmatLastBoneToWorld = NULL; + } + if ( m_aMergeMDLs[iMerge].m_pStudioHdr ) + { + delete m_aMergeMDLs[iMerge].m_pStudioHdr; + m_aMergeMDLs[iMerge].m_pStudioHdr = NULL; } - delete m_aMergeMDLs[iMerge].m_pStudioHdr; - m_aMergeMDLs[iMerge].m_pStudioHdr = NULL; } m_aMergeMDLs.Purge(); @@ -981,3 +1022,25 @@ void CMDLPanel::ValidateMDLs() } } } + +//----------------------------------------------------------------------------- +// Purpose: Gets last bone to world matrices +//----------------------------------------------------------------------------- +matrix3x4_t *CMDLPanel::BoneArray( CStudioHdr *pStudioHdr ) const +{ + if ( pStudioHdr == m_RootMDL.m_pStudioHdr ) + { + return m_RootMDL.m_pmatLastBoneToWorld; + } + + int cMerge = m_aMergeMDLs.Count(); + for ( int iMerge = 0; iMerge < cMerge; ++iMerge ) + { + if ( pStudioHdr == m_aMergeMDLs[ iMerge ].m_pStudioHdr ) + { + return m_aMergeMDLs[ iMerge ].m_pmatLastBoneToWorld; + } + } + + return NULL; +} From 55cb58545a7b20492dc6ce44c59fc6a3618581c6 Mon Sep 17 00:00:00 2001 From: copperpixel <48454166+copperpixel@users.noreply.github.com> Date: Tue, 11 Nov 2025 16:44:08 +0100 Subject: [PATCH 3/6] merge model entity & panel paths to a lambda --- src/game/shared/particlesystemquery.cpp | 295 ++++++++---------------- 1 file changed, 97 insertions(+), 198 deletions(-) diff --git a/src/game/shared/particlesystemquery.cpp b/src/game/shared/particlesystemquery.cpp index f50162808bc..e038f198325 100644 --- a/src/game/shared/particlesystemquery.cpp +++ b/src/game/shared/particlesystemquery.cpp @@ -204,105 +204,96 @@ void CParticleSystemQuery::GetRandomPointsOnControllingObjectHitBox( #ifndef GAME_DLL - EHANDLE *phMoveParent = reinterpret_cast ( pParticles->m_ControlPoints[nControlPointNumber].m_pObject ); - CBaseEntity *pMoveParent = NULL; - if ( phMoveParent ) - { - pMoveParent = *( phMoveParent ); - } - CBaseModelPanel::particle_data_t *pPanelParticleData = NULL; - if ( !pMoveParent ) + EHANDLE *phMoveParent = reinterpret_cast< EHANDLE * > ( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ); + CBaseEntity *pMoveParent = phMoveParent ? *( phMoveParent ) : NULL; + CBaseModelPanel::particle_data_t *pPanelParticleData = !pMoveParent ? reinterpret_cast< CBaseModelPanel::particle_data_t * > ( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ) : NULL; + + float flRandMax = flBBoxScale; + float flRandMin = 1.f - flBBoxScale; + Vector vecBasePos; + pParticles->GetControlPointAtTime( nControlPointNumber, pParticles->m_flCurTime, &vecBasePos ); + + auto lambdaStudioGetRandomPoints = [ & ]( const studiohdr_t *pStudioHdr, matrix3x4_t *pmatBoneToWorld, int nHitBoxSet = 0, float flModelScale = 1.f, bool bEntity = false ) { - pPanelParticleData = reinterpret_cast< CBaseModelPanel::particle_data_t * >( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ); - } + mstudiohitboxset_t *pSet = pStudioHdr->pHitboxSet( nHitBoxSet ); + if ( pSet ) + { + bSucesss = true; + + Vector vecWorldPosition( 0.f, 0.f, 0.f ); + float u = 0.f, v = 0.f, w = 0.f; + int nHitbox = 0; + int nNumIters = nNumTrysToGetAPointInsideTheModel; + if ( !vecDirectionalBias.IsZero( 0.0001f ) ) + nNumIters = MAX( nNumIters, 5 ); + + for ( int i = 0; i < nNumPtsOut; i++ ) + { + int nTryCnt = nNumIters; + float flBestPointGoodness = -1.0e20f; + do + { + int nTryHitbox = pParticles->RandomInt( 0, pSet->numhitboxes - 1 ); + mstudiobbox_t *pBox = pSet->pHitbox( nTryHitbox ); + + float flTryU = pParticles->RandomFloat( flRandMin, flRandMax ); + float flTryV = pParticles->RandomFloat( flRandMin, flRandMax ); + float flTryW = pParticles->RandomFloat( flRandMin, flRandMax ); + + Vector vecLocalPosition; + vecLocalPosition.x = GetSurfaceCoord( flTryU, pBox->bbmin.x * flModelScale, pBox->bbmax.x * flModelScale ); + vecLocalPosition.y = GetSurfaceCoord( flTryV, pBox->bbmin.y * flModelScale, pBox->bbmax.y * flModelScale ); + vecLocalPosition.z = GetSurfaceCoord( flTryW, pBox->bbmin.z * flModelScale, pBox->bbmax.z * flModelScale ); + + Vector vecTryWorldPosition; + VectorTransform( vecLocalPosition, pmatBoneToWorld[ pBox->bone ], vecTryWorldPosition ); + + float flPointGoodness = pParticles->RandomFloat( 0.f, 72.f ) + + DotProduct( vecTryWorldPosition - vecBasePos, + vecDirectionalBias ); + + if ( bEntity && nNumTrysToGetAPointInsideTheModel ) + { + // do a point in solid test + Ray_t ray; + trace_t tr; + ray.Init( vecTryWorldPosition, vecTryWorldPosition ); + enginetrace->ClipRayToEntity( ray, MASK_ALL, pMoveParent, &tr ); + if ( tr.startsolid ) + flPointGoodness += 1000.f; // got a point inside! + } + if ( flPointGoodness > flBestPointGoodness ) + { + u = flTryU; + v = flTryV; + w = flTryW; + vecWorldPosition = vecTryWorldPosition; + nHitbox = nTryHitbox; + flBestPointGoodness = flPointGoodness; + } + } while ( nTryCnt-- ); + *( pPntsOut++ ) = vecWorldPosition; + if ( pHitBoxRelativeCoordOut ) + ( pHitBoxRelativeCoordOut++ )->Init( u, v, w ); + if ( pHitBoxIndexOut ) + *( pHitBoxIndexOut++ ) = nHitbox; + } + } + }; + if ( pMoveParent ) { - float flRandMax = flBBoxScale; - float flRandMin = 1.0 - flBBoxScale; - Vector vecBasePos; - pParticles->GetControlPointAtTime( nControlPointNumber, pParticles->m_flCurTime, &vecBasePos ); - s_BoneMutex.Lock(); C_BaseAnimating *pAnimating = pMoveParent->GetBaseAnimating(); if ( pAnimating ) { - matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; - if ( pAnimating->HitboxToWorldTransforms( hitboxbones ) ) { - studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); - if ( pStudioHdr ) { - mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() ); - - if ( set ) - { - bSucesss = true; - - Vector vecWorldPosition(0, 0, 0); - float u = 0, v = 0, w = 0; - int nHitbox = 0; - int nNumIters = nNumTrysToGetAPointInsideTheModel; - if (! vecDirectionalBias.IsZero( 0.0001 ) ) - nNumIters = MAX( nNumIters, 5 ); - - for( int i=0 ; i < nNumPtsOut; i++) - { - int nTryCnt = nNumIters; - float flBestPointGoodness = -1.0e20; - do - { - int nTryHitbox = pParticles->RandomInt( 0, set->numhitboxes - 1 ); - mstudiobbox_t *pBox = set->pHitbox(nTryHitbox); - - float flTryU = pParticles->RandomFloat( flRandMin, flRandMax ); - float flTryV = pParticles->RandomFloat( flRandMin, flRandMax ); - float flTryW = pParticles->RandomFloat( flRandMin, flRandMax ); - - Vector vecLocalPosition; - vecLocalPosition.x = GetSurfaceCoord( flTryU, pBox->bbmin.x * pAnimating->GetModelScale(), pBox->bbmax.x * pAnimating->GetModelScale() ); - vecLocalPosition.y = GetSurfaceCoord( flTryV, pBox->bbmin.y * pAnimating->GetModelScale(), pBox->bbmax.y * pAnimating->GetModelScale() ); - vecLocalPosition.z = GetSurfaceCoord( flTryW, pBox->bbmin.z * pAnimating->GetModelScale(), pBox->bbmax.z * pAnimating->GetModelScale() ); - - Vector vecTryWorldPosition; - - VectorTransform( vecLocalPosition, *hitboxbones[pBox->bone], vecTryWorldPosition ); - - - float flPointGoodness = pParticles->RandomFloat( 0, 72 ) - + DotProduct( vecTryWorldPosition - vecBasePos, - vecDirectionalBias ); - - if ( nNumTrysToGetAPointInsideTheModel ) - { - // do a point in solid test - Ray_t ray; - trace_t tr; - ray.Init( vecTryWorldPosition, vecTryWorldPosition ); - enginetrace->ClipRayToEntity( ray, MASK_ALL, pMoveParent, &tr ); - if ( tr.startsolid ) - flPointGoodness += 1000.; // got a point inside! - } - if ( flPointGoodness > flBestPointGoodness ) - { - u = flTryU; - v = flTryV; - w = flTryW; - vecWorldPosition = vecTryWorldPosition; - nHitbox = nTryHitbox; - flBestPointGoodness = flPointGoodness; - } - } while ( nTryCnt-- ); - *( pPntsOut++ ) = vecWorldPosition; - if ( pHitBoxRelativeCoordOut ) - ( pHitBoxRelativeCoordOut++ )->Init( u, v, w ); - if ( pHitBoxIndexOut ) - *( pHitBoxIndexOut++ ) = nHitbox; - } - } + lambdaStudioGetRandomPoints( pStudioHdr, *hitboxbones, pAnimating->GetHitboxSet(), pAnimating->GetModelScale(), true ); } } } @@ -317,8 +308,6 @@ void CParticleSystemQuery::GetRandomPointsOnControllingObjectHitBox( VecOrigin = pMoveParent->GetRenderOrigin(); matOrientation = pMoveParent->EntityToWorldTransform(); - - Vector vecWorldPosition(0, 0, 0); float u = 0, v = 0, w = 0; int nHitbox = 0; @@ -380,69 +369,11 @@ void CParticleSystemQuery::GetRandomPointsOnControllingObjectHitBox( } else if ( pPanelParticleData ) { - float flRandMax = flBBoxScale; - float flRandMin = 1.0 - flBBoxScale; - Vector vecBasePos; - pParticles->GetControlPointAtTime( nControlPointNumber, pParticles->m_flCurTime, &vecBasePos ); - matrix3x4_t *pmatBoneToWorld = pPanelParticleData->m_pOuter->BoneArray( pPanelParticleData->m_pStudioHdr ); const studiohdr_t *pStudioHdr = pPanelParticleData->m_pStudioHdr->GetRenderHdr(); - if ( pStudioHdr ) { - mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( 0 /*default*/ ); - if ( set ) - { - bSucesss = true; - - Vector vecWorldPosition( 0, 0, 0 ); - float u = 0, v = 0, w = 0; - int nHitbox = 0; - int nNumIters = nNumTrysToGetAPointInsideTheModel; - if ( !vecDirectionalBias.IsZero( 0.0001 ) ) - nNumIters = MAX( nNumIters, 5 ); - - for ( int i = 0; i < nNumPtsOut; i++ ) - { - float flBestPointGoodness = -1.0e20; - int nTryCnt = nNumIters; - do - { - int nTryHitbox = pParticles->RandomInt( 0, set->numhitboxes - 1 ); - mstudiobbox_t *pBox = set->pHitbox( nTryHitbox ); - - float flTryU = pParticles->RandomFloat( flRandMin, flRandMax ); - float flTryV = pParticles->RandomFloat( flRandMin, flRandMax ); - float flTryW = pParticles->RandomFloat( flRandMin, flRandMax ); - - Vector vecLocalPosition; - vecLocalPosition.x = GetSurfaceCoord( flTryU, pBox->bbmin.x, pBox->bbmax.x ); - vecLocalPosition.y = GetSurfaceCoord( flTryV, pBox->bbmin.y, pBox->bbmax.y ); - vecLocalPosition.z = GetSurfaceCoord( flTryW, pBox->bbmin.z, pBox->bbmax.z ); - - Vector vecTryWorldPosition; - VectorTransform( vecLocalPosition, pmatBoneToWorld[ pBox->bone ], vecTryWorldPosition ); - - float flPointGoodness = pParticles->RandomFloat( 0, 72 ) - + DotProduct( vecTryWorldPosition - vecBasePos, vecDirectionalBias ); - - if ( flPointGoodness > flBestPointGoodness ) - { - u = flTryU; - v = flTryV; - w = flTryW; - vecWorldPosition = vecTryWorldPosition; - nHitbox = nTryHitbox; - flBestPointGoodness = flPointGoodness; - } - } while ( nTryCnt-- ); - *( pPntsOut++ ) = vecWorldPosition; - if ( pHitBoxRelativeCoordOut ) - ( pHitBoxRelativeCoordOut++ )->Init( u, v, w ); - if ( pHitBoxIndexOut ) - *( pHitBoxIndexOut++ ) = nHitbox; - } - } + lambdaStudioGetRandomPoints( pStudioHdr, pmatBoneToWorld ); } } #endif @@ -475,16 +406,24 @@ int CParticleSystemQuery::GetControllingObjectHitBoxInfo( s_BoneMutex.Lock(); EHANDLE *phMoveParent = reinterpret_cast ( pParticles->m_ControlPoints[nControlPointNumber].m_pObject ); - CBaseEntity *pMoveParent = NULL; - if ( phMoveParent ) - { - pMoveParent = *( phMoveParent ); - } - CBaseModelPanel::particle_data_t *pPanelParticleData = NULL; - if ( !pMoveParent ) + CBaseEntity *pMoveParent = phMoveParent ? *( phMoveParent ) : NULL; + CBaseModelPanel::particle_data_t *pPanelParticleData = !pMoveParent ? reinterpret_cast< CBaseModelPanel::particle_data_t * > ( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ) : NULL; + + auto lambdaStudioGetHitBoxInfo = [ & ]( const studiohdr_t *pStudioHdr, matrix3x4_t *pmatBoneToWorld, int nHitBoxSet = 0 ) { - pPanelParticleData = reinterpret_cast< CBaseModelPanel::particle_data_t * > ( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ); - } + mstudiohitboxset_t *pSet = pStudioHdr->pHitboxSet( nHitBoxSet ); + if ( pSet ) + { + nRet = Min( nBufSize, pSet->numhitboxes ); + for ( int i = 0; i < nRet; i++ ) + { + mstudiobbox_t *pBox = pSet->pHitbox( i ); + pHitBoxOutputBuffer[ i ].m_vecBoxMins = pBox->bbmin; + pHitBoxOutputBuffer[ i ].m_vecBoxMaxes = pBox->bbmax; + pHitBoxOutputBuffer[ i ].m_Transform = pmatBoneToWorld[ pBox->bone ]; + } + } + }; if ( pMoveParent ) { @@ -492,33 +431,12 @@ int CParticleSystemQuery::GetControllingObjectHitBoxInfo( if ( pAnimating ) { matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; - if ( pAnimating->HitboxToWorldTransforms( hitboxbones ) ) { - studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); - if ( pStudioHdr ) { - mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() ); - - if ( set ) - { - nRet = MIN( nBufSize, set->numhitboxes ); - for( int i=0 ; i < nRet; i++ ) - { - mstudiobbox_t *pBox = set->pHitbox( i ); - pHitBoxOutputBuffer[i].m_vecBoxMins.x = pBox->bbmin.x; - pHitBoxOutputBuffer[i].m_vecBoxMins.y = pBox->bbmin.y; - pHitBoxOutputBuffer[i].m_vecBoxMins.z = pBox->bbmin.z; - - pHitBoxOutputBuffer[i].m_vecBoxMaxes.x = pBox->bbmax.x; - pHitBoxOutputBuffer[i].m_vecBoxMaxes.y = pBox->bbmax.y; - pHitBoxOutputBuffer[i].m_vecBoxMaxes.z = pBox->bbmax.z; - - pHitBoxOutputBuffer[i].m_Transform = *hitboxbones[pBox->bone]; - } - } + lambdaStudioGetHitBoxInfo( pStudioHdr, *hitboxbones, pAnimating->GetHitboxSet() ); } } } @@ -539,28 +457,9 @@ int CParticleSystemQuery::GetControllingObjectHitBoxInfo( { matrix3x4_t *pmatBoneToWorld = pPanelParticleData->m_pOuter->BoneArray( pPanelParticleData->m_pStudioHdr ); const studiohdr_t *pStudioHdr = pPanelParticleData->m_pStudioHdr->GetRenderHdr(); - if ( pStudioHdr ) { - mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( 0 /*default*/ ); - - if ( set ) - { - nRet = MIN( nBufSize, set->numhitboxes ); - for ( int i = 0; i < nRet; i++ ) - { - mstudiobbox_t *pBox = set->pHitbox( i ); - pHitBoxOutputBuffer[ i ].m_vecBoxMins.x = pBox->bbmin.x; - pHitBoxOutputBuffer[ i ].m_vecBoxMins.y = pBox->bbmin.y; - pHitBoxOutputBuffer[ i ].m_vecBoxMins.z = pBox->bbmin.z; - - pHitBoxOutputBuffer[ i ].m_vecBoxMaxes.x = pBox->bbmax.x; - pHitBoxOutputBuffer[ i ].m_vecBoxMaxes.y = pBox->bbmax.y; - pHitBoxOutputBuffer[ i ].m_vecBoxMaxes.z = pBox->bbmax.z; - - pHitBoxOutputBuffer[ i ].m_Transform = pmatBoneToWorld[ pBox->bone ]; - } - } + lambdaStudioGetHitBoxInfo( pStudioHdr, pmatBoneToWorld ); } } s_BoneMutex.Unlock(); From 7f27358d52af095fd99f06aa56ec2f031ad8bd18 Mon Sep 17 00:00:00 2001 From: copperpixel <48454166+copperpixel@users.noreply.github.com> Date: Wed, 12 Nov 2025 01:02:53 +0100 Subject: [PATCH 4/6] - add BMPParticleQueryObject_t - fix m_pmatLastBoneToWorld leak --- .../client/game_controls/basemodel_panel.cpp | 9 +++-- .../client/game_controls/basemodel_panel.h | 38 +++++++++++++------ src/game/shared/particlesystemquery.cpp | 29 +++++++------- src/public/matsys_controls/mdlpanel.h | 2 +- src/vgui2/matsys_controls/mdlpanel.cpp | 8 +++- 5 files changed, 52 insertions(+), 34 deletions(-) diff --git a/src/game/client/game_controls/basemodel_panel.cpp b/src/game/client/game_controls/basemodel_panel.cpp index 8c6f66cafc0..5d917f29425 100644 --- a/src/game/client/game_controls/basemodel_panel.cpp +++ b/src/game/client/game_controls/basemodel_panel.cpp @@ -789,6 +789,9 @@ void CBaseModelPanel::particle_data_t::UpdateControlPoints( CStudioHdr *pStudioH { if ( m_pParticleSystem ) { + m_BMPQueryObj.m_pStudioHdr = pStudioHdr->GetRenderHdr(); + m_BMPQueryObj.m_pmatBoneToWorld = m_pOuter->BoneArray( pStudioHdr ); + // Update control points which is updating the position of the particles matrix3x4_t matAttachToWorld; Vector vecPosition, vecForward, vecRight, vecUp; @@ -803,7 +806,7 @@ void CBaseModelPanel::particle_data_t::UpdateControlPoints( CStudioHdr *pStudioH MatrixPosition( matAttachToWorld, vecPosition ); m_pParticleSystem->SetControlPointOrientation( i, vecForward, vecRight, vecUp ); - m_pParticleSystem->SetControlPointObject( i, this ); + m_pParticleSystem->SetControlPointObject( i, &m_BMPQueryObj ); m_pParticleSystem->SetControlPoint( i, vecPosition + vecParticleOffset ); } } @@ -814,13 +817,12 @@ void CBaseModelPanel::particle_data_t::UpdateControlPoints( CStudioHdr *pStudioH MatrixPosition( matAttachToWorld, vecPosition ); m_pParticleSystem->SetControlPointOrientation( 0, vecForward, vecRight, vecUp ); - m_pParticleSystem->SetControlPointObject( 0, this ); + m_pParticleSystem->SetControlPointObject( 0, &m_BMPQueryObj ); m_pParticleSystem->SetControlPoint( 0, vecPosition + vecParticleOffset ); } } m_bIsUpdateToDate = true; - m_pStudioHdr = pStudioHdr; } @@ -841,7 +843,6 @@ CBaseModelPanel::particle_data_t *CBaseModelPanel::CreateParticleData( const cha pData->m_bIsUpdateToDate = false; pData->m_pParticleSystem = pParticle; pData->m_pOuter = this; - pData->m_pStudioHdr = NULL; m_particleList.AddToTail( pData ); diff --git a/src/game/client/game_controls/basemodel_panel.h b/src/game/client/game_controls/basemodel_panel.h index b8a6c9db25e..e16be9079a9 100644 --- a/src/game/client/game_controls/basemodel_panel.h +++ b/src/game/client/game_controls/basemodel_panel.h @@ -11,6 +11,21 @@ #include "matsys_controls/mdlpanel.h" +//----------------------------------------------------------------------------- +// Particle data we want the particle system query to have. +//----------------------------------------------------------------------------- +struct BMPParticleQueryObject_t +{ + const studiohdr_t *m_pStudioHdr; + const matrix3x4_t *m_pmatBoneToWorld; + + BMPParticleQueryObject_t( void ) + { + m_pStudioHdr = NULL; + m_pmatBoneToWorld = NULL; + } +}; + //----------------------------------------------------------------------------- // Resource file data used in posing the model inside of the model panel. //----------------------------------------------------------------------------- @@ -212,18 +227,6 @@ class CBaseModelPanel : public CMDLPanel void SetupModelAnimDefaults( void ); public: - struct particle_data_t - { - ~particle_data_t(); - - void UpdateControlPoints( CStudioHdr *pStudioHdr, matrix3x4_t *pWorldMatrix, const CUtlVector< int > &vecAttachments, int iDefaultBone = 0, const Vector &vecParticleOffset = vec3_origin ); - - bool m_bIsUpdateToDate; - CParticleCollection *m_pParticleSystem; - CStudioHdr *m_pStudioHdr; - CBaseModelPanel *m_pOuter; - }; - BMPResData_t m_BMPResData; // Base model panel data set in the .res file. QAngle m_angPlayer; Vector m_vecPlayerPos; @@ -252,6 +255,17 @@ class CBaseModelPanel : public CMDLPanel CPanelAnimationVar( bool, m_bUseParticle, "use_particle", "0" ); CPanelAnimationVar( float, m_flMaxPitch, "max_pitch", "90" ); + struct particle_data_t + { + ~particle_data_t(); + + void UpdateControlPoints( CStudioHdr *pStudioHdr, matrix3x4_t *pWorldMatrix, const CUtlVector< int > &vecAttachments, int iDefaultBone = 0, const Vector &vecParticleOffset = vec3_origin ); + + bool m_bIsUpdateToDate; + CParticleCollection *m_pParticleSystem; + CBaseModelPanel *m_pOuter; + BMPParticleQueryObject_t m_BMPQueryObj; + }; CUtlVector< particle_data_t* > m_particleList; diff --git a/src/game/shared/particlesystemquery.cpp b/src/game/shared/particlesystemquery.cpp index e038f198325..3438c6bbefe 100644 --- a/src/game/shared/particlesystemquery.cpp +++ b/src/game/shared/particlesystemquery.cpp @@ -9,7 +9,6 @@ #include "baseparticleentity.h" #include "entityparticletrail_shared.h" #include "collisionutils.h" -#include "bone_setup.h" #if defined( CLIENT_DLL ) #include "basemodel_panel.h" @@ -204,16 +203,16 @@ void CParticleSystemQuery::GetRandomPointsOnControllingObjectHitBox( #ifndef GAME_DLL - EHANDLE *phMoveParent = reinterpret_cast< EHANDLE * > ( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ); + EHANDLE *phMoveParent = reinterpret_cast< EHANDLE * >( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ); CBaseEntity *pMoveParent = phMoveParent ? *( phMoveParent ) : NULL; - CBaseModelPanel::particle_data_t *pPanelParticleData = !pMoveParent ? reinterpret_cast< CBaseModelPanel::particle_data_t * > ( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ) : NULL; + BMPParticleQueryObject_t *pBMPObj = !pMoveParent ? reinterpret_cast< BMPParticleQueryObject_t * >( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ) : NULL; float flRandMax = flBBoxScale; float flRandMin = 1.f - flBBoxScale; Vector vecBasePos; pParticles->GetControlPointAtTime( nControlPointNumber, pParticles->m_flCurTime, &vecBasePos ); - auto lambdaStudioGetRandomPoints = [ & ]( const studiohdr_t *pStudioHdr, matrix3x4_t *pmatBoneToWorld, int nHitBoxSet = 0, float flModelScale = 1.f, bool bEntity = false ) + auto lambdaStudioGetRandomPoints = [ & ]( const studiohdr_t *pStudioHdr, const matrix3x4_t *pmatBoneToWorld, int nHitBoxSet = 0, float flModelScale = 1.f, bool bEntity = false ) { mstudiohitboxset_t *pSet = pStudioHdr->pHitboxSet( nHitBoxSet ); if ( pSet ) @@ -367,11 +366,11 @@ void CParticleSystemQuery::GetRandomPointsOnControllingObjectHitBox( s_BoneMutex.Unlock(); } - else if ( pPanelParticleData ) + else if ( pBMPObj ) { - matrix3x4_t *pmatBoneToWorld = pPanelParticleData->m_pOuter->BoneArray( pPanelParticleData->m_pStudioHdr ); - const studiohdr_t *pStudioHdr = pPanelParticleData->m_pStudioHdr->GetRenderHdr(); - if ( pStudioHdr ) + const matrix3x4_t *pmatBoneToWorld = pBMPObj->m_pmatBoneToWorld; + const studiohdr_t *pStudioHdr = pBMPObj->m_pStudioHdr; + if ( pStudioHdr && pmatBoneToWorld ) { lambdaStudioGetRandomPoints( pStudioHdr, pmatBoneToWorld ); } @@ -405,11 +404,11 @@ int CParticleSystemQuery::GetControllingObjectHitBoxInfo( #ifndef GAME_DLL s_BoneMutex.Lock(); - EHANDLE *phMoveParent = reinterpret_cast ( pParticles->m_ControlPoints[nControlPointNumber].m_pObject ); + EHANDLE *phMoveParent = reinterpret_cast< EHANDLE * >( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ); CBaseEntity *pMoveParent = phMoveParent ? *( phMoveParent ) : NULL; - CBaseModelPanel::particle_data_t *pPanelParticleData = !pMoveParent ? reinterpret_cast< CBaseModelPanel::particle_data_t * > ( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ) : NULL; + BMPParticleQueryObject_t *pBMPObj = !pMoveParent ? reinterpret_cast< BMPParticleQueryObject_t * >( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ) : NULL; - auto lambdaStudioGetHitBoxInfo = [ & ]( const studiohdr_t *pStudioHdr, matrix3x4_t *pmatBoneToWorld, int nHitBoxSet = 0 ) + auto lambdaStudioGetHitBoxInfo = [ & ]( const studiohdr_t *pStudioHdr, const matrix3x4_t *pmatBoneToWorld, int nHitBoxSet = 0 ) { mstudiohitboxset_t *pSet = pStudioHdr->pHitboxSet( nHitBoxSet ); if ( pSet ) @@ -453,11 +452,11 @@ int CParticleSystemQuery::GetControllingObjectHitBoxInfo( nRet = 1; } } - else if ( pPanelParticleData ) + else if ( pBMPObj ) { - matrix3x4_t *pmatBoneToWorld = pPanelParticleData->m_pOuter->BoneArray( pPanelParticleData->m_pStudioHdr ); - const studiohdr_t *pStudioHdr = pPanelParticleData->m_pStudioHdr->GetRenderHdr(); - if ( pStudioHdr ) + const matrix3x4_t *pmatBoneToWorld = pBMPObj->m_pmatBoneToWorld; + const studiohdr_t *pStudioHdr = pBMPObj->m_pStudioHdr; + if ( pStudioHdr && pmatBoneToWorld ) { lambdaStudioGetHitBoxInfo( pStudioHdr, pmatBoneToWorld ); } diff --git a/src/public/matsys_controls/mdlpanel.h b/src/public/matsys_controls/mdlpanel.h index d9e7ca102a1..86499fa1809 100644 --- a/src/public/matsys_controls/mdlpanel.h +++ b/src/public/matsys_controls/mdlpanel.h @@ -106,7 +106,7 @@ class CMDLPanel : public CPotteryWheelPanel virtual void FireEvent( const char *pszEventName, const char *pszEventOptions ); void ResetAnimationEventState( MDLAnimEventState_t *pEventState ); - matrix3x4_t *BoneArray( CStudioHdr *pStudioHdr ) const; + const matrix3x4_t *BoneArray( CStudioHdr *pStudioHdr ); protected: diff --git a/src/vgui2/matsys_controls/mdlpanel.cpp b/src/vgui2/matsys_controls/mdlpanel.cpp index 47eb5660345..10750d69ff9 100644 --- a/src/vgui2/matsys_controls/mdlpanel.cpp +++ b/src/vgui2/matsys_controls/mdlpanel.cpp @@ -176,7 +176,11 @@ void CMDLPanel::SetMDL( MDLHandle_t handle, void *pProxyData ) m_RootMDL.m_flCycleStartTime = 0.f; m_RootMDL.m_nLastBoneCount = -1; - m_RootMDL.m_pmatLastBoneToWorld = NULL; + if ( m_RootMDL.m_pmatLastBoneToWorld ) + { + delete[] m_RootMDL.m_pmatLastBoneToWorld; + m_RootMDL.m_pmatLastBoneToWorld = NULL; + } // Set the pose parameters to the default for the mdl SetPoseParameters( NULL, 0 ); @@ -1026,7 +1030,7 @@ void CMDLPanel::ValidateMDLs() //----------------------------------------------------------------------------- // Purpose: Gets last bone to world matrices //----------------------------------------------------------------------------- -matrix3x4_t *CMDLPanel::BoneArray( CStudioHdr *pStudioHdr ) const +const matrix3x4_t *CMDLPanel::BoneArray( CStudioHdr *pStudioHdr ) { if ( pStudioHdr == m_RootMDL.m_pStudioHdr ) { From 62b1794dc8a0e435c9c6286a48a7ae738127cf42 Mon Sep 17 00:00:00 2001 From: copperpixel <48454166+copperpixel@users.noreply.github.com> Date: Wed, 12 Nov 2025 02:58:49 +0100 Subject: [PATCH 5/6] remove bEntity overload --- src/game/shared/particlesystemquery.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/game/shared/particlesystemquery.cpp b/src/game/shared/particlesystemquery.cpp index 3438c6bbefe..dc537217541 100644 --- a/src/game/shared/particlesystemquery.cpp +++ b/src/game/shared/particlesystemquery.cpp @@ -212,7 +212,7 @@ void CParticleSystemQuery::GetRandomPointsOnControllingObjectHitBox( Vector vecBasePos; pParticles->GetControlPointAtTime( nControlPointNumber, pParticles->m_flCurTime, &vecBasePos ); - auto lambdaStudioGetRandomPoints = [ & ]( const studiohdr_t *pStudioHdr, const matrix3x4_t *pmatBoneToWorld, int nHitBoxSet = 0, float flModelScale = 1.f, bool bEntity = false ) + auto lambdaStudioGetRandomPoints = [ & ]( const studiohdr_t *pStudioHdr, const matrix3x4_t *pmatBoneToWorld, int nHitBoxSet = 0, float flModelScale = 1.f ) { mstudiohitboxset_t *pSet = pStudioHdr->pHitboxSet( nHitBoxSet ); if ( pSet ) @@ -251,7 +251,7 @@ void CParticleSystemQuery::GetRandomPointsOnControllingObjectHitBox( + DotProduct( vecTryWorldPosition - vecBasePos, vecDirectionalBias ); - if ( bEntity && nNumTrysToGetAPointInsideTheModel ) + if ( pMoveParent && nNumTrysToGetAPointInsideTheModel ) { // do a point in solid test Ray_t ray; @@ -292,7 +292,7 @@ void CParticleSystemQuery::GetRandomPointsOnControllingObjectHitBox( studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); if ( pStudioHdr ) { - lambdaStudioGetRandomPoints( pStudioHdr, *hitboxbones, pAnimating->GetHitboxSet(), pAnimating->GetModelScale(), true ); + lambdaStudioGetRandomPoints( pStudioHdr, *hitboxbones, pAnimating->GetHitboxSet(), pAnimating->GetModelScale() ); } } } From 30bf6afd6d55d79f685fcc9f1c19927f3695f72c Mon Sep 17 00:00:00 2001 From: copperpixel <48454166+copperpixel@users.noreply.github.com> Date: Fri, 14 Nov 2025 00:35:55 +0100 Subject: [PATCH 6/6] improve the way bone transforms are saved --- .../client/game_controls/basemodel_panel.cpp | 18 ++++- .../client/game_controls/basemodel_panel.h | 11 +-- .../client/tf/vgui/tf_playermodelpanel.cpp | 6 +- src/game/shared/particlesystemquery.cpp | 16 ++-- src/public/matsys_controls/mdlpanel.h | 4 - src/vgui2/matsys_controls/mdlpanel.cpp | 75 +------------------ 6 files changed, 37 insertions(+), 93 deletions(-) diff --git a/src/game/client/game_controls/basemodel_panel.cpp b/src/game/client/game_controls/basemodel_panel.cpp index 5d917f29425..493bff6db71 100644 --- a/src/game/client/game_controls/basemodel_panel.cpp +++ b/src/game/client/game_controls/basemodel_panel.cpp @@ -774,6 +774,11 @@ void CBaseModelPanel::LookAtBounds( const Vector &vecBoundsMin, const Vector &ve //----------------------------------------------------------------------------- CBaseModelPanel::particle_data_t::~particle_data_t() { + if ( m_BMPQueryObj.m_pmatBoneToWorld ) + { + delete[] m_BMPQueryObj.m_pmatBoneToWorld; + m_BMPQueryObj.m_pmatBoneToWorld = NULL; + } if ( m_pParticleSystem ) { delete m_pParticleSystem; @@ -790,7 +795,17 @@ void CBaseModelPanel::particle_data_t::UpdateControlPoints( CStudioHdr *pStudioH if ( m_pParticleSystem ) { m_BMPQueryObj.m_pStudioHdr = pStudioHdr->GetRenderHdr(); - m_BMPQueryObj.m_pmatBoneToWorld = m_pOuter->BoneArray( pStudioHdr ); + // Save off bone transforms for the particle system query + if ( m_BMPQueryObj.m_numbones != pStudioHdr->numbones() ) + { + m_BMPQueryObj.m_numbones = pStudioHdr->numbones(); + if ( m_BMPQueryObj.m_pmatBoneToWorld ) + { + delete[] m_BMPQueryObj.m_pmatBoneToWorld; + } + m_BMPQueryObj.m_pmatBoneToWorld = new matrix3x4_t[ m_BMPQueryObj.m_numbones ]; + } + Q_memcpy( m_BMPQueryObj.m_pmatBoneToWorld, pWorldMatrix, m_BMPQueryObj.m_numbones * sizeof( matrix3x4_t ) ); // Update control points which is updating the position of the particles matrix3x4_t matAttachToWorld; @@ -842,7 +857,6 @@ CBaseModelPanel::particle_data_t *CBaseModelPanel::CreateParticleData( const cha particle_data_t *pData = new particle_data_t; pData->m_bIsUpdateToDate = false; pData->m_pParticleSystem = pParticle; - pData->m_pOuter = this; m_particleList.AddToTail( pData ); diff --git a/src/game/client/game_controls/basemodel_panel.h b/src/game/client/game_controls/basemodel_panel.h index e16be9079a9..d0e2ce3f269 100644 --- a/src/game/client/game_controls/basemodel_panel.h +++ b/src/game/client/game_controls/basemodel_panel.h @@ -17,11 +17,13 @@ struct BMPParticleQueryObject_t { const studiohdr_t *m_pStudioHdr; - const matrix3x4_t *m_pmatBoneToWorld; + int m_numbones; + matrix3x4_t *m_pmatBoneToWorld; BMPParticleQueryObject_t( void ) { m_pStudioHdr = NULL; + m_numbones = -1; m_pmatBoneToWorld = NULL; } }; @@ -259,11 +261,10 @@ class CBaseModelPanel : public CMDLPanel { ~particle_data_t(); - void UpdateControlPoints( CStudioHdr *pStudioHdr, matrix3x4_t *pWorldMatrix, const CUtlVector< int > &vecAttachments, int iDefaultBone = 0, const Vector &vecParticleOffset = vec3_origin ); + void UpdateControlPoints( CStudioHdr *pStudioHdr, matrix3x4_t *pWorldMatrix, const CUtlVector< int >& vecAttachments, int iDefaultBone = 0, const Vector& vecParticleOffset = vec3_origin ); - bool m_bIsUpdateToDate; - CParticleCollection *m_pParticleSystem; - CBaseModelPanel *m_pOuter; + bool m_bIsUpdateToDate; + CParticleCollection *m_pParticleSystem; BMPParticleQueryObject_t m_BMPQueryObj; }; CUtlVector< particle_data_t* > m_particleList; diff --git a/src/game/client/tf/vgui/tf_playermodelpanel.cpp b/src/game/client/tf/vgui/tf_playermodelpanel.cpp index 29e2d018fed..d652b176f97 100644 --- a/src/game/client/tf/vgui/tf_playermodelpanel.cpp +++ b/src/game/client/tf/vgui/tf_playermodelpanel.cpp @@ -1808,11 +1808,11 @@ void CTFPlayerModelPanel::UpdateTauntEffects( m_aParticleSystems[SYSTEM_TAUNT] = CreateParticleData( strParticleName.String() ); } - matrix3x4_t matAttachToWorld; - SetIdentityMatrix( matAttachToWorld ); + Vector vecBonePos; + MatrixPosition( *pWorldMatrix, vecBonePos ); CUtlVector< int > vecAttachments; - m_aParticleSystems[SYSTEM_TAUNT]->UpdateControlPoints( pStudioHdr, &matAttachToWorld, vecAttachments, 0, m_vecPlayerPos ); + m_aParticleSystems[SYSTEM_TAUNT]->UpdateControlPoints( pStudioHdr, pWorldMatrix, vecAttachments, 0, m_vecPlayerPos - vecBonePos ); } //----------------------------------------------------------------------------- diff --git a/src/game/shared/particlesystemquery.cpp b/src/game/shared/particlesystemquery.cpp index dc537217541..cb036cbfed1 100644 --- a/src/game/shared/particlesystemquery.cpp +++ b/src/game/shared/particlesystemquery.cpp @@ -205,7 +205,7 @@ void CParticleSystemQuery::GetRandomPointsOnControllingObjectHitBox( EHANDLE *phMoveParent = reinterpret_cast< EHANDLE * >( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ); CBaseEntity *pMoveParent = phMoveParent ? *( phMoveParent ) : NULL; - BMPParticleQueryObject_t *pBMPObj = !pMoveParent ? reinterpret_cast< BMPParticleQueryObject_t * >( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ) : NULL; + BMPParticleQueryObject_t *pBMPQueryObj = !pMoveParent ? reinterpret_cast< BMPParticleQueryObject_t * >( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ) : NULL; float flRandMax = flBBoxScale; float flRandMin = 1.f - flBBoxScale; @@ -366,10 +366,10 @@ void CParticleSystemQuery::GetRandomPointsOnControllingObjectHitBox( s_BoneMutex.Unlock(); } - else if ( pBMPObj ) + else if ( pBMPQueryObj ) { - const matrix3x4_t *pmatBoneToWorld = pBMPObj->m_pmatBoneToWorld; - const studiohdr_t *pStudioHdr = pBMPObj->m_pStudioHdr; + matrix3x4_t *pmatBoneToWorld = pBMPQueryObj->m_pmatBoneToWorld; + const studiohdr_t *pStudioHdr = pBMPQueryObj->m_pStudioHdr; if ( pStudioHdr && pmatBoneToWorld ) { lambdaStudioGetRandomPoints( pStudioHdr, pmatBoneToWorld ); @@ -406,7 +406,7 @@ int CParticleSystemQuery::GetControllingObjectHitBoxInfo( EHANDLE *phMoveParent = reinterpret_cast< EHANDLE * >( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ); CBaseEntity *pMoveParent = phMoveParent ? *( phMoveParent ) : NULL; - BMPParticleQueryObject_t *pBMPObj = !pMoveParent ? reinterpret_cast< BMPParticleQueryObject_t * >( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ) : NULL; + BMPParticleQueryObject_t *pBMPQueryObj = !pMoveParent ? reinterpret_cast< BMPParticleQueryObject_t * >( pParticles->m_ControlPoints[ nControlPointNumber ].m_pObject ) : NULL; auto lambdaStudioGetHitBoxInfo = [ & ]( const studiohdr_t *pStudioHdr, const matrix3x4_t *pmatBoneToWorld, int nHitBoxSet = 0 ) { @@ -452,10 +452,10 @@ int CParticleSystemQuery::GetControllingObjectHitBoxInfo( nRet = 1; } } - else if ( pBMPObj ) + else if ( pBMPQueryObj ) { - const matrix3x4_t *pmatBoneToWorld = pBMPObj->m_pmatBoneToWorld; - const studiohdr_t *pStudioHdr = pBMPObj->m_pStudioHdr; + matrix3x4_t *pmatBoneToWorld = pBMPQueryObj->m_pmatBoneToWorld; + const studiohdr_t *pStudioHdr = pBMPQueryObj->m_pStudioHdr; if ( pStudioHdr && pmatBoneToWorld ) { lambdaStudioGetHitBoxInfo( pStudioHdr, pmatBoneToWorld ); diff --git a/src/public/matsys_controls/mdlpanel.h b/src/public/matsys_controls/mdlpanel.h index 86499fa1809..ab96a408265 100644 --- a/src/public/matsys_controls/mdlpanel.h +++ b/src/public/matsys_controls/mdlpanel.h @@ -106,8 +106,6 @@ class CMDLPanel : public CPotteryWheelPanel virtual void FireEvent( const char *pszEventName, const char *pszEventOptions ); void ResetAnimationEventState( MDLAnimEventState_t *pEventState ); - const matrix3x4_t *BoneArray( CStudioHdr *pStudioHdr ); - protected: virtual void SetupRenderState( int nDisplayWidth, int nDisplayHeight ) OVERRIDE; @@ -120,8 +118,6 @@ class CMDLPanel : public CPotteryWheelPanel float m_flCycleStartTime; CStudioHdr *m_pStudioHdr; uint32 m_unMdlCacheSerial; - int m_nLastBoneCount; - matrix3x4_t *m_pmatLastBoneToWorld; }; MDLData_t m_RootMDL; diff --git a/src/vgui2/matsys_controls/mdlpanel.cpp b/src/vgui2/matsys_controls/mdlpanel.cpp index 10750d69ff9..baa3af33647 100644 --- a/src/vgui2/matsys_controls/mdlpanel.cpp +++ b/src/vgui2/matsys_controls/mdlpanel.cpp @@ -75,8 +75,6 @@ CMDLPanel::CMDLPanel( vgui::Panel *pParent, const char *pName ) : BaseClass( pPa SetIdentityMatrix( m_RootMDL.m_MDLToWorld ); m_RootMDL.m_pStudioHdr = NULL; m_RootMDL.m_unMdlCacheSerial = 0; - m_RootMDL.m_nLastBoneCount = -1; - m_RootMDL.m_pmatLastBoneToWorld = NULL; m_bDrawCollisionModel = false; m_bWireFrame = false; m_bGroundGrid = false; @@ -92,11 +90,6 @@ CMDLPanel::~CMDLPanel() m_aMergeMDLs.Purge(); m_DefaultEnvCubemap.Shutdown( ); m_DefaultHDREnvCubemap.Shutdown(); - if ( m_RootMDL.m_pmatLastBoneToWorld ) - { - delete[] m_RootMDL.m_pmatLastBoneToWorld; - m_RootMDL.m_pmatLastBoneToWorld = NULL; - } if ( m_RootMDL.m_pStudioHdr ) { delete m_RootMDL.m_pStudioHdr; @@ -175,13 +168,6 @@ void CMDLPanel::SetMDL( MDLHandle_t handle, void *pProxyData ) m_RootMDL.m_flCycleStartTime = 0.f; - m_RootMDL.m_nLastBoneCount = -1; - if ( m_RootMDL.m_pmatLastBoneToWorld ) - { - delete[] m_RootMDL.m_pmatLastBoneToWorld; - m_RootMDL.m_pmatLastBoneToWorld = NULL; - } - // Set the pose parameters to the default for the mdl SetPoseParameters( NULL, 0 ); @@ -487,18 +473,6 @@ void CMDLPanel::OnPaint3D() pOverrideMaterial = NULL; - // Cache root bone transforms for external access - if ( m_RootMDL.m_nLastBoneCount != studioHdr.numbones() ) - { - m_RootMDL.m_nLastBoneCount = studioHdr.numbones(); - if ( m_RootMDL.m_pmatLastBoneToWorld ) - { - delete[] m_RootMDL.m_pmatLastBoneToWorld; - } - m_RootMDL.m_pmatLastBoneToWorld = new matrix3x4_t[ m_RootMDL.m_nLastBoneCount ]; - } - Q_memcpy( m_RootMDL.m_pmatLastBoneToWorld, pBoneToWorld, m_RootMDL.m_nLastBoneCount * sizeof( matrix3x4_t ) ); - // Draw the merge MDLs. matrix3x4_t matMergeBoneToWorld[MAXSTUDIOBONES]; int nMergeCount = m_aMergeMDLs.Count(); @@ -527,18 +501,6 @@ void CMDLPanel::OnPaint3D() if ( pOverrideMaterial != NULL ) g_pStudioRender->ForcedMaterialOverride( NULL ); - // Cache merge bone transforms for external access - if ( m_aMergeMDLs[iMerge].m_nLastBoneCount != mergeHdr.numbones() ) - { - m_aMergeMDLs[iMerge].m_nLastBoneCount = mergeHdr.numbones(); - if ( m_aMergeMDLs[iMerge].m_pmatLastBoneToWorld ) - { - delete[] m_aMergeMDLs[iMerge].m_pmatLastBoneToWorld; - } - m_aMergeMDLs[iMerge].m_pmatLastBoneToWorld = new matrix3x4_t[ m_aMergeMDLs[iMerge].m_nLastBoneCount ]; - } - Q_memcpy( m_aMergeMDLs[iMerge].m_pmatLastBoneToWorld, pMergeBoneToWorld, m_aMergeMDLs[iMerge].m_nLastBoneCount * sizeof( matrix3x4_t ) ); - // Notify of model render RenderingMergedModel( pRenderContext, &mergeHdr, m_aMergeMDLs[iMerge].m_MDL.GetMDL(), pMergeBoneToWorld ); } @@ -894,9 +856,6 @@ void CMDLPanel::SetMergeMDL( MDLHandle_t handle, void *pProxyData, int nSkin /*= m_aMergeMDLs[iIndex].m_pStudioHdr = new CStudioHdr( m_aMergeMDLs[iIndex].m_MDL.GetStudioHdr(), g_pMDLCache ); - m_aMergeMDLs[iIndex].m_nLastBoneCount = -1; - m_aMergeMDLs[iIndex].m_pmatLastBoneToWorld = NULL; - // Need to invalidate the layout so the panel will adjust is LookAt for the new model. InvalidateLayout(); } @@ -991,16 +950,12 @@ void CMDLPanel::ClearMergeMDLs( void ) const int nMergeCount = m_aMergeMDLs.Count(); for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge ) { - if ( m_aMergeMDLs[iMerge].m_pmatLastBoneToWorld ) + if ( !m_aMergeMDLs[iMerge].m_pStudioHdr ) { - delete[] m_aMergeMDLs[iMerge].m_pmatLastBoneToWorld; - m_aMergeMDLs[iMerge].m_pmatLastBoneToWorld = NULL; - } - if ( m_aMergeMDLs[iMerge].m_pStudioHdr ) - { - delete m_aMergeMDLs[iMerge].m_pStudioHdr; - m_aMergeMDLs[iMerge].m_pStudioHdr = NULL; + continue; } + delete m_aMergeMDLs[iMerge].m_pStudioHdr; + m_aMergeMDLs[iMerge].m_pStudioHdr = NULL; } m_aMergeMDLs.Purge(); @@ -1026,25 +981,3 @@ void CMDLPanel::ValidateMDLs() } } } - -//----------------------------------------------------------------------------- -// Purpose: Gets last bone to world matrices -//----------------------------------------------------------------------------- -const matrix3x4_t *CMDLPanel::BoneArray( CStudioHdr *pStudioHdr ) -{ - if ( pStudioHdr == m_RootMDL.m_pStudioHdr ) - { - return m_RootMDL.m_pmatLastBoneToWorld; - } - - int cMerge = m_aMergeMDLs.Count(); - for ( int iMerge = 0; iMerge < cMerge; ++iMerge ) - { - if ( pStudioHdr == m_aMergeMDLs[ iMerge ].m_pStudioHdr ) - { - return m_aMergeMDLs[ iMerge ].m_pmatLastBoneToWorld; - } - } - - return NULL; -}