Files
HL2Overcharged/game/client/ShaderEditor/SEdit_ModelRender.cpp
2025-05-21 21:09:22 +03:00

424 lines
9.4 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;
}