Files
BCWSsrc/sp/src/game/client/ShaderEditor/SEdit_ModelRender.cpp
2022-09-04 13:08:22 +03:00

424 lines
9.6 KiB
C++

// ******************************************************
//
// Purpose:
// - Handles model rendering requests from the
// shader editor library
//
// ******************************************************
#include "cbase.h"
#include "vgui/iinput.h"
#include "vgui_controls/controls.h"
#include "ShaderEditor/SEdit_ModelRender.h"
#include "model_types.h"
#ifndef SOURCE_2006
#include "viewpostprocess.h"
#endif
#include "view.h"
#include "input.h"
#include "beamdraw.h"
#ifdef SOURCE_2006
void ScreenToWorld( int mousex, int mousey, float fov,
const Vector& vecRenderOrigin,
const QAngle& vecRenderAngles,
Vector& vecPickingRay )
{
float dx, dy;
float c_x, c_y;
float dist;
Vector vpn, vup, vright;
float scaled_fov = ScaleFOVByWidthRatio( fov, engine->GetScreenAspectRatio() * 0.75f );
c_x = ScreenWidth() / 2;
c_y = ScreenHeight() / 2;
dx = (float)mousex - c_x;
dy = c_y - (float)mousey;
float dist_denom = tan(M_PI * scaled_fov / 360.0f);
dist = c_x / dist_denom;
AngleVectors( vecRenderAngles, &vpn, &vright, &vup );
vecPickingRay = vpn * dist + vright * ( dx ) + vup * ( dy );
VectorNormalize( vecPickingRay );
}
#else
extern void ScreenToWorld( int mousex, int mousey, float fov,
const Vector& vecRenderOrigin,
const QAngle& vecRenderAngles,
Vector& vecPickingRay );
#endif
SEditModelRender __g_ShaderEditorMReder( "ShEditMRender" );
SEditModelRender *sEditMRender = &__g_ShaderEditorMReder;
SEditModelRender::SEditModelRender( char const *name ) : CAutoGameSystemPerFrame( name )
{
pModelInstance = NULL;
m_iNumPoseParams = 0;
DestroyModel();
}
SEditModelRender::~SEditModelRender()
{
DestroyModel();
}
bool SEditModelRender::Init()
{
return true;
}
void SEditModelRender::Shutdown()
{
}
void SEditModelRender::Update( float frametime )
{
if ( !IsModelReady() )
return;
pModelInstance->StudioFrameAdvance();
if ( pModelInstance->GetCycle() >= 1.0f )
pModelInstance->SetCycle( pModelInstance->GetCycle() - 1.0f );
}
void SEditModelRender::LevelInitPostEntity()
{
ResetModel();
}
void SEditModelRender::LevelShutdownPostEntity()
{
ResetModel();
}
void SEditModelRender::ResetModel()
{
if ( !IsModelReady() )
return;
pModelInstance->m_flAnimTime = gpGlobals->curtime;
pModelInstance->m_flOldAnimTime = gpGlobals->curtime;
}
bool SEditModelRender::IsModelReady()
{
if ( !pModelInstance )
return false;
bool bValid = !!pModelInstance->GetModel();
if ( bValid && Q_strlen( m_szModelPath ) )
{
const model_t *pMdl = modelinfo ? modelinfo->FindOrLoadModel( m_szModelPath ) : NULL;
if ( pMdl )
pModelInstance->SetModelPointer( pMdl );
bValid = !!pMdl;
}
if ( !bValid )
DestroyModel();
return bValid;
}
bool SEditModelRender::LoadModel( const char *localPath )
{
DestroyModel();
const model_t *mdl = modelinfo->FindOrLoadModel( localPath );
if ( !mdl )
return false;
Q_strcpy( m_szModelPath, localPath );
C_BaseFlex *pEnt = new C_BaseFlex();
pEnt->InitializeAsClientEntity( NULL,
#if SWARM_DLL
false
#else
RENDER_GROUP_OPAQUE_ENTITY
#endif
);
MDLCACHE_CRITICAL_SECTION();
pEnt->SetModelPointer( mdl );
pEnt->Spawn();
pEnt->SetAbsAngles( vec3_angle );
pEnt->SetAbsOrigin( vec3_origin );
pEnt->AddEffects( EF_NODRAW | EF_NOINTERP );
pEnt->m_EntClientFlags |= ENTCLIENTFLAG_DONTUSEIK;
// leave it alone.
pEnt->RemoveFromLeafSystem();
cl_entitylist->RemoveEntity( pEnt->GetRefEHandle() );
pEnt->CollisionProp()->DestroyPartitionHandle();
CStudioHdr *pHdr = pEnt->GetModelPtr();
m_iNumPoseParams = pHdr ? pHdr->GetNumPoseParameters() : 0;
pModelInstance = pEnt;
return true;
}
void SEditModelRender::DestroyModel()
{
if ( pModelInstance )
pModelInstance->Remove();
pModelInstance = NULL;
m_szModelPath[0] = '\0';
m_iNumPoseParams = 0;
}
void SEditModelRender::GetModelCenter( float *pFl3_ViewOffset )
{
Q_memset( pFl3_ViewOffset, 0, sizeof(float) * 3 );
if ( IsModelReady() )
{
MDLCACHE_CRITICAL_SECTION();
if ( pModelInstance->GetModelPtr() )
{
const Vector &vecMin = pModelInstance->GetModelPtr()->hull_min();
const Vector &vecMax = pModelInstance->GetModelPtr()->hull_max();
Vector vecPos = ( vecMin + ( vecMax - vecMin ) * 0.5f );
if ( pFl3_ViewOffset )
Q_memcpy( pFl3_ViewOffset, vecPos.Base(), sizeof(float) * 3 );
}
}
}
void SEditModelRender::DestroyCharPtrList( char ***szList )
{
Assert( szList );
if ( *szList )
{
delete [] (**szList);
delete [] (*szList);
*szList = NULL;
}
}
int SequenceSort( mstudioseqdesc_t *const *seq1, mstudioseqdesc_t *const *seq2 )
{
return Q_stricmp( ( *seq1 )->pszLabel(), ( *seq2 )->pszLabel() );
}
int SEditModelRender::QuerySequences( char ***list )
{
if ( !IsModelReady() )
return 0;
MDLCACHE_CRITICAL_SECTION();
CStudioHdr *pHdr = pModelInstance->GetModelPtr();
if ( !pHdr )
return 0;
CUtlVector< mstudioseqdesc_t* >hSeqs;
for ( int i = 0; i < pHdr->GetNumSeq(); i++ )
if ( !( pHdr->pSeqdesc( i ).flags & STUDIO_HIDDEN ) )
hSeqs.AddToTail( &pHdr->pSeqdesc( i ) );
int numSequences = hSeqs.Count();
if ( !numSequences )
return 0;
hSeqs.Sort( SequenceSort );
CUtlVector< const char* >hNameList;
for ( int i = 0; i < numSequences; i++ )
{
const char *seqName = NULL;
const mstudioseqdesc_t &seqPtr = *hSeqs[ i ];
if ( seqPtr.pszLabel() )
seqName = seqPtr.pszLabel();
else
seqName = "Unknown Sequence";
hNameList.AddToTail( seqName );
}
*list = new char*[numSequences];
int iTotalLength = 0;
for ( int i = 0; i < numSequences; i++ )
iTotalLength += Q_strlen( hNameList[i] ) + 1;
**list = new char[ iTotalLength ];
int curpos = 0;
for ( int i = 0; i < numSequences; i++ )
{
int curLength = Q_strlen( hNameList[i] ) + 1;
(*list)[ i ] = **list + curpos;
Q_strcpy( (*list)[ i ], hNameList[i] );
curpos += curLength;
}
hNameList.Purge();
hSeqs.Purge();
return numSequences;
}
void SEditModelRender::SetSequence( const char *name )
{
if ( !IsModelReady() )
return;
MDLCACHE_CRITICAL_SECTION();
pModelInstance->ResetSequence( pModelInstance->LookupSequence( name ) );
}
void SEditModelRender::ExecRender()
{
if ( !IsModelReady() )
return;
MDLCACHE_CRITICAL_SECTION();
for ( int i = 0; i < m_iNumPoseParams; i++ )
pModelInstance->SetPoseParameter( i, 0 );
#if SWARM_DLL
RenderableInstance_t instance;
instance.m_nAlpha = 255;
#endif
pModelInstance->DrawModel( STUDIO_RENDER
#if SWARM_DLL
, instance
#endif
);
}
void SEditModelRender::DoPostProc( int x, int y, int w, int h )
{
#ifndef SOURCE_2006
if ( view && view->GetPlayerViewSetup()->m_bDoBloomAndToneMapping )
DoEnginePostProcessing( x, y, w, h, false, false );
#endif
}
int SEditModelRender::MaterialPicker( char ***szMat )
{
int mx, my;
#ifdef SOURCE_2006
vgui::input()->GetCursorPos( mx, my );
#else
vgui::input()->GetCursorPosition( mx, my );
#endif
Vector ray;
const CViewSetup *pViewSetup = view->GetPlayerViewSetup();
float ratio =engine->GetScreenAspectRatio(
#if SWARM_DLL
pViewSetup->width, pViewSetup->height
#endif
);
ratio = ( 1.0f / ratio ) * (4.0f/3.0f);
float flFov = ScaleFOVByWidthRatio( pViewSetup->fov, ratio );
ScreenToWorld( mx, my, flFov, pViewSetup->origin, pViewSetup->angles, ray );
Vector start = pViewSetup->origin;
Vector end = start + ray * MAX_TRACE_LENGTH;
trace_t tr;
C_BaseEntity *pIgnore = input->CAM_IsThirdPerson() ? NULL : C_BasePlayer::GetLocalPlayer();
UTIL_TraceLine( start, end, MASK_SOLID, pIgnore, COLLISION_GROUP_NONE, &tr );
if ( !tr.DidHit() )
return 0;
int numMaterials = 0;
IMaterial **MatList = NULL;
studiohdr_t *pSHdr = NULL;
if ( tr.DidHitWorld() )
{
if ( tr.hitbox == 0 )
{
Vector dummy;
IMaterial *pMat = engine->TraceLineMaterialAndLighting( start, end, dummy, dummy );
if ( pMat )
{
numMaterials = 1;
MatList = new IMaterial*[1];
MatList[0] = pMat;
}
}
else
{
ICollideable *prop = staticpropmgr->GetStaticPropByIndex( tr.hitbox - 1 );
if ( prop )
{
IClientRenderable *pRenderProp = prop->GetIClientUnknown()->GetClientRenderable();
if ( pRenderProp )
{
const model_t *pModel = pRenderProp->GetModel();
if ( pModel )
pSHdr = modelinfo->GetStudiomodel( pModel );
}
}
}
}
else if ( tr.m_pEnt )
{
const model_t *pModel = tr.m_pEnt->GetModel();
if ( pModel )
pSHdr = modelinfo->GetStudiomodel( pModel );
}
if ( pSHdr )
{
Assert( !numMaterials && !MatList );
numMaterials = pSHdr->numtextures;
const int numPaths = pSHdr->numcdtextures;
if ( numMaterials )
{
CUtlVector< IMaterial* >hValidMaterials;
for ( int i = 0; i < numMaterials; i++ )
{
mstudiotexture_t *pStudioTex = pSHdr->pTexture( i );
const char *matName = pStudioTex->pszName();
for ( int p = 0; p < numPaths; p++ )
{
char tmpPath[MAX_PATH];
Q_snprintf( tmpPath, MAX_PATH, "%s%s\0", pSHdr->pCdtexture( p ), matName );
Q_FixSlashes( tmpPath );
IMaterial *pTempMat = materials->FindMaterial( tmpPath, TEXTURE_GROUP_MODEL );
if ( !IsErrorMaterial( pTempMat ) )
{
hValidMaterials.AddToTail( pTempMat );
break;
}
}
}
numMaterials = hValidMaterials.Count();
if ( numMaterials )
{
MatList = new IMaterial*[ numMaterials ];
for ( int i = 0; i < numMaterials; i++ )
MatList[i] = hValidMaterials[i];
}
hValidMaterials.Purge();
}
}
*szMat = new char*[ numMaterials ];
int iTotalLength = 0;
for ( int i = 0; i < numMaterials; i++ )
iTotalLength += Q_strlen( MatList[i]->GetName() ) + 1;
**szMat = new char[ iTotalLength ];
int curpos = 0;
for ( int i = 0; i < numMaterials; i++ )
{
const char *pszName = MatList[i]->GetName();
int curLength = Q_strlen( pszName ) + 1;
(*szMat)[ i ] = **szMat + curpos;
Q_strcpy( (*szMat)[ i ], pszName );
curpos += curLength;
}
if ( MatList )
delete [] MatList;
return numMaterials;
}