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

1833 lines
52 KiB
C++

// ******************************************************
//
// Purpose:
// - Connects the shader editor
// - Sends data from the main viewsetup
// - exposes client callbacks to shaders
//
// ******************************************************
#include "cbase.h"
#include "client_factorylist.h"
#include "ShaderEditor/IVShaderEditor.h"
#include "ShaderEditor/SEdit_ModelRender.h"
#include "ivrenderview.h"
#include "iviewrender.h"
#include "viewrender.h"
#include "view.h"
#include "view_scene.h"
#include "view_shared.h"
#include "beamdraw.h"
#include "c_sun.h"
#include "tier0/icommandline.h"
#include "rendertexture.h"
#include "c_rope.h"
#include "model_types.h"
#ifdef SWARM_DLL
#include "modelrendersystem.h"
#endif
#if SWARM_DLL
#define Editor_MainViewOrigin MainViewOrigin( 0 )
#define Editor_MainViewForward MainViewForward( 0 )
#else
#define Editor_MainViewOrigin MainViewOrigin()
#define Editor_MainViewForward MainViewForward()
#endif
ShaderEditorHandler __g_ShaderEditorSystem("ShEditUpdate");
ShaderEditorHandler *g_ShaderEditorSystem = &__g_ShaderEditorSystem;
CSysModule *shaderEditorModule = NULL;
IVShaderEditor *shaderEdit = NULL;
ShaderEditorHandler::ShaderEditorHandler(char const *name) : CAutoGameSystemPerFrame(name)
{
m_bReady = false;
m_piCurrentViewId = NULL;
m_flNextAlpha = 0.f;
m_flAlpha = 0.f;
}
ShaderEditorHandler::~ShaderEditorHandler()
{
}
const bool ShaderEditorHandler::IsReady()
{
return m_bReady;
}
bool ShaderEditorHandler::Init()
{
factorylist_t factories;
FactoryList_Retrieve(factories);
#ifdef SOURCE_2006
ConVar *pCVarDev = cvar->FindVar("developer");
bool bShowPrimDebug = pCVarDev != NULL && pCVarDev->GetInt() != 0;
#else
ConVarRef devEnabled("developer", true);
bool bShowPrimDebug = devEnabled.GetInt() != 0;
#endif
bool bCreateEditor = true;//(CommandLine() != NULL) && (CommandLine()->FindParm("-SSE") != 0);
SEDIT_SKYMASK_MODE iEnableSkymask = SKYMASK_QUARTER;
#ifdef SHADEREDITOR_FORCE_ENABLED
bCreateEditor = true;
iEnableSkymask = SKYMASK_QUARTER;
#endif
char modulePath[MAX_PATH * 4];
#ifdef SWARM_DLL
Q_snprintf(modulePath, sizeof(modulePath), "%s/bin/shadereditor_swarm.dll\0", engine->GetGameDirectory());
#elif SOURCE_2006
Q_snprintf(modulePath, sizeof(modulePath), "%s/bin/shadereditor_2006.dll\0", engine->GetGameDirectory());
#elif SOURCE_2013
Q_snprintf(modulePath, sizeof(modulePath), "%s/bin/shadereditor_2007.dll\0", engine->GetGameDirectory());
#else
Q_snprintf(modulePath, sizeof(modulePath), "%s/bin/shadereditor_2013.dll\0", engine->GetGameDirectory());//shadereditor_2013// Q_snprintf(modulePath, sizeof(modulePath), "%s/bin/shadereditor_2013.dll\0", engine->GetGameDirectory());//shadereditor_2013
#endif
shaderEditorModule = Sys_LoadModule(modulePath);
if (shaderEditorModule)
{
CreateInterfaceFn shaderEditorDLLFactory = Sys_GetFactory(shaderEditorModule);
shaderEdit = shaderEditorDLLFactory ? ((IVShaderEditor *)shaderEditorDLLFactory(SHADEREDIT_INTERFACE_VERSION, NULL)) : NULL;
if (!shaderEdit)
{
Warning("Unable to pull IVShaderEditor interface.\n");
}
else if (!shaderEdit->Init(factories.appSystemFactory, gpGlobals, sEditMRender,
bCreateEditor, bShowPrimDebug, iEnableSkymask))
{
Warning("Cannot initialize IVShaderEditor.\n");
shaderEdit = NULL;
}
}
else
{
Warning("Cannot load shadereditor.dll from %s!\n", modulePath);
}
m_bReady = shaderEdit != NULL;
RegisterCallbacks();
RegisterViewRenderCallbacks();
if (IsReady())
{
shaderEdit->PrecacheData();
}
return true;
}
#ifdef SHADEREDITOR_FORCE_ENABLED
CON_COMMAND(sedit_debug_toggle_ppe, "")
{
if (!g_ShaderEditorSystem->IsReady())
return Warning("lib not ready.\n");
if (args.ArgC() < 2)
return;
const int idx = shaderEdit->GetPPEIndex(args[1]);
if (idx < 0)
return Warning("can't find ppe named: %s\n", args[1]);
shaderEdit->SetPPEEnabled(idx, !shaderEdit->IsPPEEnabled(idx));
}
#endif
void ShaderEditorHandler::Shutdown()
{
if (shaderEdit)
shaderEdit->Shutdown();
if (shaderEditorModule)
Sys_UnloadModule(shaderEditorModule);
}
void ShaderEditorHandler::Update(float frametime)
{
if (IsReady())
shaderEdit->OnFrame(frametime);
}
CThreadMutex m_Lock;
void ShaderEditorHandler::PreRender()
{
if (IsReady() && view)
{
// make sure the class matches
const CViewSetup *v = view->GetPlayerViewSetup();
CViewSetup_SEdit_Shared stableVSetup(*v);
shaderEdit->OnPreRender(&stableVSetup);
m_Lock.Lock();
PrepareCallbackData();
m_Lock.Unlock();
}
}
void ShaderEditorHandler::PostRender()
{
}
#ifdef SOURCE_2006
void ShaderEditorHandler::CustomViewRender(int *viewId, const VisibleFogVolumeInfo_t &fogVolumeInfo)
#else
void ShaderEditorHandler::CustomViewRender(int *viewId, const VisibleFogVolumeInfo_t &fogVolumeInfo, const WaterRenderInfo_t &waterRenderInfo)
#endif
{
m_piCurrentViewId = viewId;
m_tFogVolumeInfo = fogVolumeInfo;
#ifndef SOURCE_2006
m_tWaterRenderInfo = waterRenderInfo;
#endif
if (IsReady())
shaderEdit->OnSceneRender();
}
void ShaderEditorHandler::UpdateSkymask(int x, int y, int w, int h, bool bCombineMode)
{
if (IsReady())
shaderEdit->OnUpdateSkymask(true, x, y, w, h);
}
void ShaderEditorHandler::CustomPostRender()
{
if (IsReady())
shaderEdit->OnPostRender(true);
}
struct CallbackData_t
{
void Reset()
{
sun_data.Init();
sun_dir.Init();
player_speed.Init();
player_pos.Init();
scope_alpha.Init();
scope_color.Init();
};
Vector4D sun_data;
Vector sun_dir;
Vector4D player_speed;
Vector player_pos;
Vector scope_alpha;
Vector scope_color;
};
static CallbackData_t clCallback_data;
static int FrustumTransform2(const VMatrix &worldToSurface, const Vector& point, Vector& screen)
{
// UNDONE: Clean this up some, handle off-screen vertices
float w;
screen.x = worldToSurface[0][0] * point[0] + worldToSurface[0][1] * point[1] + worldToSurface[0][2] * point[2] + worldToSurface[0][3];
screen.y = worldToSurface[1][0] * point[0] + worldToSurface[1][1] * point[1] + worldToSurface[1][2] * point[2] + worldToSurface[1][3];
// z = worldToSurface[2][0] * point[0] + worldToSurface[2][1] * point[1] + worldToSurface[2][2] * point[2] + worldToSurface[2][3];
w = worldToSurface[3][0] * point[0] + worldToSurface[3][1] * point[1] + worldToSurface[3][2] * point[2] + worldToSurface[3][3];
// Just so we have something valid here
screen.z = 0.0f;
bool behind;
if (w < 0.001f)
{
behind = true;
screen.x *= 100000;
screen.y *= 100000;
}
else
{
behind = false;
float invw = 1.0f / w;
screen.x *= invw;
screen.y *= invw;
}
return behind;
}
/*void ShaderEditorHandler::PrepareCallbackData()
{
clCallback_data.Reset();
float flSunAmt_Goal = 0;
static float s_flSunAmt_Last = 0;
C_BaseEntity *pEnt = ClientEntityList().FirstBaseEntity();
while (pEnt)
{
if (!Q_stricmp(pEnt->GetClassname(), "class C_Sun"))//C_Sun
{
C_Sun *pSun = (C_Sun*)pEnt;
Vector dir = pSun->m_vDirection;
dir.NormalizeInPlace();
Vector MainView;
C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer();
if (pbp)
MainView = pbp->EyePosition();
Vector screen;
if (FrustumTransform2(MainWorldToViewMatrix(), MainView + dir * 512, screen))
FrustumTransform2(MainWorldToViewMatrix(), (MainView - dir * 512), screen);*/
//VMatrix *mat = new VMatrix();
#include "engine/ivdebugoverlay.h"
void ShaderEditorHandler::PrepareCallbackData()
{
clCallback_data.Reset();
float flSunAmt_Goal = 0;
static float s_flSunAmt_Last = 0;
C_BaseEntity *pEnt = ClientEntityList().FirstBaseEntity();
while (pEnt)
{
if (!Q_stricmp(pEnt->GetClassname(), "class C_Sun"))//C_Sun
{
C_Sun *pSun = (C_Sun*)pEnt;
Vector dir = pSun->m_vDirection;
dir.NormalizeInPlace();
Vector screen;
/*trace_t tr2;
C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer();
if (pbp)
{
//screen = pbp->GetViewOffset();
UTIL_TraceLine(pbp->GetAbsOrigin(), pbp->GetAbsOrigin() - pSun->m_vDirection, MASK_SOLID, NULL, COLLISION_GROUP_DEBRIS, &tr2);
}*/
/*if (ScreenTransform(Editor_MainViewOrigin + dir * 512, screen))
ScreenTransform((Editor_MainViewOrigin - dir * 512), screen);*/
//engine->WorldToScreenMatrix()
//MainWorldToViewMatrix()
/**mat = engine->WorldToScreenMatrix();
C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer();
VMatrix worldToView, viewToProjection, worldToProjection, worldToPixels;
if (pbp)
{
CViewSetup shadowView;
shadowView.m_flAspectRatio = 1.0f;
shadowView.x = shadowView.y = 0;
shadowView.m_bOrtho = false;
shadowView.origin = pSun->GetAbsOrigin();
render->GetMatricesForView(shadowView, &worldToView, &viewToProjection, &worldToProjection, &worldToPixels);
}*/
/*CMatRenderContextPtr pRenderContext(materials);
VMatrix viewMatrix, projectionMatrix, viewProjectionMatrix, inverseViewProjectionMatrix;
pRenderContext->GetMatrix(MATERIAL_VIEW, &viewMatrix);
pRenderContext->GetMatrix(MATERIAL_PROJECTION, &projectionMatrix);*/
//MatrixMultiply(projectionMatrix, viewMatrix, viewProjectionMatrix);
//MatrixInverseGeneral(viewProjectionMatrix, inverseViewProjectionMatrix);
//MainWorldToViewMatrix()
//engine->WorldToScreenMatrix()
if (cvar->FindVar("mat_queue_mode")->GetInt() == 0)
{
if (ScreenTransform(Editor_MainViewOrigin + dir * 512, screen))
ScreenTransform((Editor_MainViewOrigin - dir * 512), screen);
}
else
{
if (FrustumTransform2(MainWorldToViewMatrix(), Editor_MainViewOrigin + dir * 512, screen))
FrustumTransform2(MainWorldToViewMatrix(), (Editor_MainViewOrigin - dir * 512), screen);
}
/*if (ScreenTransform(Editor_MainViewOrigin + dir * 512, screen))
ScreenTransform((Editor_MainViewOrigin - dir * 512), screen);*/
screen = screen * Vector(0.5f, -0.5f, 0) + Vector(0.5f, 0.5f, 0);
Q_memcpy(clCallback_data.sun_data.Base(), screen.Base(), sizeof(float) * 2);
//Q_memcpy(clCallback_data.sun_data.Base(), tr2.endpos.Base(), sizeof(float) * 2);
//if (pbp)
{
/* fw;
AngleVectors(pbp->EyeAngles(), &fw);
Vector pos = fw + dir * 512;
pos.NormalizeInPlace();
debugoverlay->AddLineOverlay(pbp->EyePosition(), pbp->EyePosition() - dir * 512, 255, 0, 0, false, 0.1f);*/
//Q_memcpy(clCallback_data.sun_data.Base(), pos.Base(), sizeof(float) * 4);
//clCallback_data.sun_data[0] = screen.x;// -pbp->EyeAngles().x;
//clCallback_data.sun_data[1] = screen.y;// -pbp->EyeAngles().z;
//DevMsg("x: %.2f\n y: %.2f\n z: %.2f\n", clCallback_data.sun_data[0], clCallback_data.sun_data[1], clCallback_data.sun_data[2]);
}
clCallback_data.sun_data[2] = DotProduct(dir, Editor_MainViewForward);
clCallback_data.sun_dir = dir;
trace_t tr;
UTIL_TraceLine(Editor_MainViewOrigin, Editor_MainViewOrigin + dir * MAX_TRACE_LENGTH, MASK_SOLID, NULL, COLLISION_GROUP_DEBRIS, &tr);
if (!tr.DidHitWorld())
break;
if (tr.surface.flags & SURF_SKY)
flSunAmt_Goal = 1;
break;
}
pEnt = ClientEntityList().NextBaseEntity(pEnt);
}
if (s_flSunAmt_Last != flSunAmt_Goal)
s_flSunAmt_Last = Approach(flSunAmt_Goal, s_flSunAmt_Last, gpGlobals->frametime * ((!!flSunAmt_Goal) ? 4.0f : 0.75f));
clCallback_data.sun_data[3] = s_flSunAmt_Last;
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
if (pPlayer)
{
Vector velo = pPlayer->GetLocalVelocity();
clCallback_data.player_speed[3] = velo.NormalizeInPlace();
Q_memcpy(clCallback_data.player_speed.Base(), velo.Base(), sizeof(float) * 3);
clCallback_data.player_pos = pPlayer->GetLocalOrigin();
if (cvar->FindVar("oc_weapons_allow_rt_blend")->GetBool())
{
C_BaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon();
if (pWeapon)
{
if (pWeapon->IsIronSighted())
{
if (m_flNextAlpha < gpGlobals->curtime && m_flAlpha <= 1)
{
m_flNextAlpha = gpGlobals->curtime + 0.02f;
m_flAlpha += 0.07f;
}
}
else
{
if (m_flNextAlpha < gpGlobals->curtime && m_flAlpha >= 0)
{
m_flNextAlpha = gpGlobals->curtime + 0.02f;
m_flAlpha -= 0.07f;
}
}
m_flAlpha = Clamp(m_flAlpha, 0.f, 1.f);
m_flNextAlpha = (m_flAlpha <= 0 || m_flAlpha >= 1) ? 0 : m_flNextAlpha;
//DevMsg("Alpha: %.2f\n", m_flAlpha);
Vector color;
color.Init(pWeapon->GetWpnData().rtColor.r*0.0039, pWeapon->GetWpnData().rtColor.g*0.0039, pWeapon->GetWpnData().rtColor.b*0.0039);
clCallback_data.scope_color = color;
clCallback_data.scope_alpha.x = m_flAlpha;
}
}
else
{
C_BaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon();
if (pWeapon)
{
Vector color;
color.Init(pWeapon->GetWpnData().rtColor.r*0.0039, pWeapon->GetWpnData().rtColor.g*0.0039, pWeapon->GetWpnData().rtColor.b*0.0039);
clCallback_data.scope_color = color;
}
clCallback_data.scope_alpha.x = 1.f;
}
}
}
pFnClCallback_Declare(ClCallback_SunData)
{
m_Lock.Lock();
Q_memcpy(pfl4, clCallback_data.sun_data.Base(), sizeof(float) * 4);
m_Lock.Unlock();
}
pFnClCallback_Declare(ClCallback_SunDirection)
{
m_Lock.Lock();
Q_memcpy(pfl4, clCallback_data.sun_dir.Base(), sizeof(float) * 3);
m_Lock.Unlock();
}
pFnClCallback_Declare(ClCallback_PlayerVelocity)
{
m_Lock.Lock();
Q_memcpy(pfl4, clCallback_data.player_speed.Base(), sizeof(float) * 4);
m_Lock.Unlock();
}
pFnClCallback_Declare(ClCallback_PlayerPos)
{
m_Lock.Lock();
Q_memcpy(pfl4, clCallback_data.player_pos.Base(), sizeof(float) * 3);
m_Lock.Unlock();
}
pFnClCallback_Declare(ClCallback_ScopeAlpha)
{
m_Lock.Lock();
Q_memcpy(pfl4, clCallback_data.scope_alpha.Base(), sizeof(float) * 1);
m_Lock.Unlock();
}
pFnClCallback_Declare(ClCallback_ScopeColor)
{
m_Lock.Lock();
Q_memcpy(pfl4, clCallback_data.scope_color.Base(), sizeof(float) * 3);
m_Lock.Unlock();
}
void ShaderEditorHandler::RegisterCallbacks()
{
if (!IsReady())
return;
// 4 components max
shaderEdit->RegisterClientCallback("sun data", ClCallback_SunData, 4);
shaderEdit->RegisterClientCallback("sun dir", ClCallback_SunDirection, 3);
shaderEdit->RegisterClientCallback("local player velocity", ClCallback_PlayerVelocity, 4);
shaderEdit->RegisterClientCallback("local player position", ClCallback_PlayerPos, 3);
shaderEdit->RegisterClientCallback("scope alpha", ClCallback_ScopeAlpha, 1);
shaderEdit->RegisterClientCallback("scope color", ClCallback_ScopeColor, 3);
shaderEdit->LockClientCallbacks();
}
#ifdef SOURCE_2006
void ShaderEditorHandler::RegisterViewRenderCallbacks(){}
#else
extern bool DoesViewPlaneIntersectWater(float waterZ, int leafWaterDataID);
// copy pasta from baseworldview
class CBaseVCallbackView : public CRendering3dView
{
DECLARE_CLASS(CBaseVCallbackView, CRendering3dView);
protected:
CBaseVCallbackView(CViewRender *pMainView) : CRendering3dView(pMainView)
{
};
virtual bool AdjustView(float waterHeight){ return false; };
virtual void CallbackInitRenderList(int viewId)
{
BuildRenderableRenderLists(viewId);
};
virtual bool ShouldDrawParticles()
{
return true;
};
virtual bool ShouldDrawRopes()
{
return true;
};
virtual bool ShouldDrawWorld()
{
return true;
};
virtual bool ShouldDrawTranslucents()
{
return true;
};
virtual bool ShouldDrawTranslucentWorld()
{
return true;
};
void DrawSetup(float waterHeight, int nSetupFlags, float waterZAdjust, int iForceViewLeaf = -1)
{
int savedViewID = g_ShaderEditorSystem->GetViewIdForModify();
g_ShaderEditorSystem->GetViewIdForModify() = VIEW_ILLEGAL;
render->BeginUpdateLightmaps();
bool bDrawEntities = (nSetupFlags & DF_DRAW_ENTITITES) != 0;
BuildWorldRenderLists(bDrawEntities, iForceViewLeaf, true, false, NULL);
PruneWorldListInfo();
if (bDrawEntities)
CallbackInitRenderList(savedViewID);
render->EndUpdateLightmaps();
g_ShaderEditorSystem->GetViewIdForModify() = savedViewID;
};
void DrawExecute(float waterHeight, view_id_t viewID, float waterZAdjust)
{
// ClientWorldListInfo_t is defined in viewrender.cpp...
//g_pClientShadowMgr->ComputeShadowTextures( *this, m_pWorldListInfo->m_LeafCount, m_pWorldListInfo->m_pLeafList );
engine->Sound_ExtraUpdate();
int savedViewID = g_ShaderEditorSystem->GetViewIdForModify();
g_ShaderEditorSystem->GetViewIdForModify() = viewID;
int iDrawFlagsBackup = m_DrawFlags;
m_DrawFlags |= m_pMainView->GetBaseDrawFlags();
PushView(waterHeight);
CMatRenderContextPtr pRenderContext(materials);
ITexture *pSaveFrameBufferCopyTexture = pRenderContext->GetFrameBufferCopyTexture(0);
if (engine->GetDXSupportLevel() >= 80)
{
pRenderContext->SetFrameBufferCopyTexture(GetPowerOfTwoFrameBufferTexture());
}
pRenderContext.SafeRelease();
static ConVarRef translucentNoWorld("r_drawtranslucentworld");
const int tnoWorldSaved = translucentNoWorld.GetInt();
translucentNoWorld.SetValue(ShouldDrawWorld() ? 0 : 1);
if (m_DrawFlags & DF_DRAW_ENTITITES)
{
if (ShouldDrawWorld())
DrawWorld(waterZAdjust);
DrawOpaqueRenderables_Custom(false);
if (ShouldDrawTranslucents() && ShouldDrawTranslucentWorld())
DrawTranslucentRenderables(false, false);
else if (ShouldDrawTranslucents())
DrawTranslucentRenderablesNoWorld(false);
else if (ShouldDrawTranslucentWorld())
DrawTranslucentWorldInLeaves(false);
}
else if (ShouldDrawWorld())
{
DrawWorld(waterZAdjust);
if (ShouldDrawTranslucentWorld())
DrawTranslucentWorldInLeaves(false);
}
translucentNoWorld.SetValue(tnoWorldSaved);
if (CurrentViewID() != VIEW_MAIN && CurrentViewID() != VIEW_INTRO_CAMERA)
PixelVisibility_EndCurrentView();
pRenderContext.GetFrom(materials);
pRenderContext->SetFrameBufferCopyTexture(pSaveFrameBufferCopyTexture);
PopView();
m_DrawFlags = iDrawFlagsBackup;
g_ShaderEditorSystem->GetViewIdForModify() = savedViewID;
};
virtual void PushView(float waterHeight)
{
float spread = 2.0f;
if (m_DrawFlags & DF_FUDGE_UP)
{
waterHeight += spread;
}
else
{
waterHeight -= spread;
}
MaterialHeightClipMode_t clipMode = MATERIAL_HEIGHTCLIPMODE_DISABLE;
if ((m_DrawFlags & DF_CLIP_Z))
{
if (m_DrawFlags & DF_CLIP_BELOW)
{
clipMode = MATERIAL_HEIGHTCLIPMODE_RENDER_ABOVE_HEIGHT;
}
else
{
clipMode = MATERIAL_HEIGHTCLIPMODE_RENDER_BELOW_HEIGHT;
}
}
CMatRenderContextPtr pRenderContext(materials);
if (m_ClearFlags & (VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR | VIEW_CLEAR_STENCIL))
{
if (m_ClearFlags & VIEW_CLEAR_OBEY_STENCIL)
{
pRenderContext->ClearBuffersObeyStencil((m_ClearFlags & VIEW_CLEAR_COLOR) != 0, (m_ClearFlags & VIEW_CLEAR_DEPTH) != 0);
}
else
{
pRenderContext->ClearBuffers((m_ClearFlags & VIEW_CLEAR_COLOR) != 0, (m_ClearFlags & VIEW_CLEAR_DEPTH) != 0, (m_ClearFlags & VIEW_CLEAR_STENCIL) != 0);
}
}
pRenderContext->SetHeightClipMode(clipMode);
if (clipMode != MATERIAL_HEIGHTCLIPMODE_DISABLE)
{
pRenderContext->SetHeightClipZ(waterHeight);
}
};
virtual void PopView()
{
CMatRenderContextPtr pRenderContext(materials);
pRenderContext->SetHeightClipMode(MATERIAL_HEIGHTCLIPMODE_DISABLE);
};
void DrawOpaqueRenderables_Custom(bool bShadowDepth)
{
//if( !r_drawopaquerenderables.GetBool() )
// return;
//Not sure why this causes an error when I updated the base version, but i'll be keeping this commented so we can compile. -Bitl
//if( !m_pMainView->ShouldDrawEntities() )
//return;
render->SetBlend(1);
const bool bRopes = ShouldDrawRopes();
const bool bParticles = ShouldDrawParticles();
//
// Prepare to iterate over all leaves that were visible, and draw opaque things in them.
//
if (bRopes)
RopeManager()->ResetRenderCache();
if (bParticles)
g_pParticleSystemMgr->ResetRenderCache();
#ifdef SWARM_DLL
extern ConVar cl_modelfastpath;
extern ConVar r_drawothermodels;
// Categorize models by type
int nOpaqueRenderableCount = m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_OPAQUE];
CUtlVector< CClientRenderablesList::CEntry* > brushModels((CClientRenderablesList::CEntry **)stackalloc(nOpaqueRenderableCount * sizeof(CClientRenderablesList::CEntry*)), nOpaqueRenderableCount);
CUtlVector< CClientRenderablesList::CEntry* > staticProps((CClientRenderablesList::CEntry **)stackalloc(nOpaqueRenderableCount * sizeof(CClientRenderablesList::CEntry*)), nOpaqueRenderableCount);
CUtlVector< CClientRenderablesList::CEntry* > otherRenderables((CClientRenderablesList::CEntry **)stackalloc(nOpaqueRenderableCount * sizeof(CClientRenderablesList::CEntry*)), nOpaqueRenderableCount);
CClientRenderablesList::CEntry *pOpaqueList = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_OPAQUE];
for (int i = 0; i < nOpaqueRenderableCount; ++i)
{
switch (pOpaqueList[i].m_nModelType)
{
case RENDERABLE_MODEL_BRUSH: brushModels.AddToTail(&pOpaqueList[i]); break;
case RENDERABLE_MODEL_STATIC_PROP: staticProps.AddToTail(&pOpaqueList[i]); break;
default: otherRenderables.AddToTail(&pOpaqueList[i]); break;
}
}
//
// First do the brush models
//
DrawOpaqueRenderables_DrawBrushModels(brushModels.Count(), brushModels.Base(), bShadowDepth);
// Move all static props to modelrendersystem
bool bUseFastPath = (cl_modelfastpath.GetInt() != 0);
//
// Sort everything that's not a static prop
//
int nStaticPropCount = staticProps.Count();
int numOpaqueEnts = otherRenderables.Count();
CUtlVector< CClientRenderablesList::CEntry* > arrRenderEntsNpcsFirst((CClientRenderablesList::CEntry **)stackalloc(numOpaqueEnts * sizeof(CClientRenderablesList::CEntry)), numOpaqueEnts);
CUtlVector< ModelRenderSystemData_t > arrModelRenderables((ModelRenderSystemData_t *)stackalloc((numOpaqueEnts + nStaticPropCount) * sizeof(ModelRenderSystemData_t)), numOpaqueEnts + nStaticPropCount);
// Queue up RENDER_GROUP_OPAQUE_ENTITY entities to be rendered later.
CClientRenderablesList::CEntry *itEntity;
if (r_drawothermodels.GetBool())
{
for (int i = 0; i < numOpaqueEnts; ++i)
{
itEntity = otherRenderables[i];
if (!itEntity->m_pRenderable)
continue;
IClientUnknown *pUnknown = itEntity->m_pRenderable->GetIClientUnknown();
IClientModelRenderable *pModelRenderable = pUnknown->GetClientModelRenderable();
C_BaseEntity *pEntity = pUnknown->GetBaseEntity();
// FIXME: Strangely, some static props are in the non-static prop bucket
// which is what the last case in this if statement is for
if (bUseFastPath && pModelRenderable)
{
ModelRenderSystemData_t data;
data.m_pRenderable = itEntity->m_pRenderable;
data.m_pModelRenderable = pModelRenderable;
data.m_InstanceData = itEntity->m_InstanceData;
arrModelRenderables.AddToTail(data);
otherRenderables.FastRemove(i);
--i; --numOpaqueEnts;
continue;
}
if (!pEntity)
continue;
if (pEntity->IsNPC())
{
arrRenderEntsNpcsFirst.AddToTail(itEntity);
otherRenderables.FastRemove(i);
--i; --numOpaqueEnts;
continue;
}
}
}
// Queue up the static props to be rendered later.
for (int i = 0; i < nStaticPropCount; ++i)
{
itEntity = staticProps[i];
if (!itEntity->m_pRenderable)
continue;
IClientUnknown *pUnknown = itEntity->m_pRenderable->GetIClientUnknown();
IClientModelRenderable *pModelRenderable = pUnknown->GetClientModelRenderable();
if (!bUseFastPath || !pModelRenderable)
continue;
ModelRenderSystemData_t data;
data.m_pRenderable = itEntity->m_pRenderable;
data.m_pModelRenderable = pModelRenderable;
data.m_InstanceData = itEntity->m_InstanceData;
arrModelRenderables.AddToTail(data);
staticProps.FastRemove(i);
--i; --nStaticPropCount;
}
//
// Draw model renderables now (ie. models that use the fast path)
//
DrawOpaqueRenderables_ModelRenderables(arrModelRenderables.Count(), arrModelRenderables.Base(), bShadowDepth);
// Turn off z pass here. Don't want non-fastpath models with potentially large dynamic VB requirements overwrite
// stuff in the dynamic VB ringbuffer. We're calling End360ZPass again in DrawExecute, but that's not a problem.
// Begin360ZPass/End360ZPass don't have to be matched exactly.
End360ZPass();
//
// Draw static props + opaque entities that aren't using the fast path.
//
DrawOpaqueRenderables_Range(otherRenderables.Count(), otherRenderables.Base(), bShadowDepth);
DrawOpaqueRenderables_DrawStaticProps(staticProps.Count(), staticProps.Base(), bShadowDepth);
//
// Draw NPCs now
//
DrawOpaqueRenderables_NPCs(arrRenderEntsNpcsFirst.Count(), arrRenderEntsNpcsFirst.Base(), bShadowDepth);
#else
bool const bDrawopaquestaticpropslast = false; //r_drawopaquestaticpropslast.GetBool();
//
// First do the brush models
//
{
CClientRenderablesList::CEntry *pEntitiesBegin, *pEntitiesEnd;
pEntitiesBegin = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_OPAQUE_BRUSH];
pEntitiesEnd = pEntitiesBegin + m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_OPAQUE_BRUSH];
DrawOpaqueRenderables_DrawBrushModels(pEntitiesBegin, pEntitiesEnd, bShadowDepth);
}
//
// Sort everything that's not a static prop
//
int numOpaqueEnts = 0;
for (int bucket = 0; bucket < RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS; ++bucket)
numOpaqueEnts += m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket];
CUtlVector< C_BaseAnimating * > arrBoneSetupNpcsLast((C_BaseAnimating **)_alloca(numOpaqueEnts * sizeof(C_BaseAnimating *)), numOpaqueEnts, numOpaqueEnts);
CUtlVector< CClientRenderablesList::CEntry > arrRenderEntsNpcsFirst((CClientRenderablesList::CEntry *)_alloca(numOpaqueEnts * sizeof(CClientRenderablesList::CEntry)), numOpaqueEnts, numOpaqueEnts);
int numNpcs = 0, numNonNpcsAnimating = 0;
for (int bucket = 0; bucket < RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS; ++bucket)
{
for (CClientRenderablesList::CEntry
* const pEntitiesBegin = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket],
*const pEntitiesEnd = pEntitiesBegin + m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket],
*itEntity = pEntitiesBegin; itEntity < pEntitiesEnd; ++itEntity)
{
C_BaseEntity *pEntity = itEntity->m_pRenderable ? itEntity->m_pRenderable->GetIClientUnknown()->GetBaseEntity() : NULL;
if (pEntity)
{
if (pEntity->IsNPC())
{
C_BaseAnimating *pba = assert_cast<C_BaseAnimating *>(pEntity);
arrRenderEntsNpcsFirst[numNpcs++] = *itEntity;
arrBoneSetupNpcsLast[numOpaqueEnts - numNpcs] = pba;
itEntity->m_pRenderable = NULL; // We will render NPCs separately
itEntity->m_RenderHandle = NULL;
continue;
}
else if (pEntity->GetBaseAnimating())
{
C_BaseAnimating *pba = assert_cast<C_BaseAnimating *>(pEntity);
arrBoneSetupNpcsLast[numNonNpcsAnimating++] = pba;
// fall through
}
}
}
}
//
// Draw static props + opaque entities from the biggest bucket to the smallest
//
{
CClientRenderablesList::CEntry * pEnts[RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS][2];
CClientRenderablesList::CEntry * pProps[RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS][2];
for (int bucket = 0; bucket < RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS; ++bucket)
{
pEnts[bucket][0] = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket];
pEnts[bucket][1] = pEnts[bucket][0] + m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket];
pProps[bucket][0] = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_OPAQUE_STATIC_HUGE + 2 * bucket];
pProps[bucket][1] = pProps[bucket][0] + m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_OPAQUE_STATIC_HUGE + 2 * bucket];
}
for (int bucket = 0; bucket < RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS; ++bucket)
{
if (bDrawopaquestaticpropslast)
{
DrawOpaqueRenderables_Range(pEnts[bucket][0], pEnts[bucket][1], bShadowDepth);
DrawOpaqueRenderables_DrawStaticProps(pProps[bucket][0], pProps[bucket][1], bShadowDepth);
}
else
{
DrawOpaqueRenderables_Range(pEnts[bucket][0], pEnts[bucket][1], bShadowDepth);
DrawOpaqueRenderables_DrawStaticProps(pProps[bucket][0], pProps[bucket][1], bShadowDepth);
}
}
}
//
// Draw NPCs now
//
DrawOpaqueRenderables_Range(arrRenderEntsNpcsFirst.Base(), arrRenderEntsNpcsFirst.Base() + numNpcs, bShadowDepth);
#endif
//
// Ropes and particles
//
if (bRopes)
RopeManager()->DrawRenderCache(bShadowDepth);
if (bParticles)
g_pParticleSystemMgr->DrawRenderCache(bShadowDepth);
};
#ifdef SWARM_DLL
void DrawOpaqueRenderables_ModelRenderables(int nCount, ModelRenderSystemData_t* pModelRenderables, bool bShadowDepth)
{
g_pModelRenderSystem->DrawModels(pModelRenderables, nCount, bShadowDepth ? MODEL_RENDER_MODE_SHADOW_DEPTH : MODEL_RENDER_MODE_NORMAL);
}
void DrawOpaqueRenderables_NPCs(int nCount, CClientRenderablesList::CEntry **ppEntities, bool bShadowDepth)
{
DrawOpaqueRenderables_Range(nCount, ppEntities, bShadowDepth);
}
void DrawRenderable(IClientRenderable *pEnt, int flags, const RenderableInstance_t &instance)
{
extern ConVar r_entityclips;
float *pRenderClipPlane = NULL;
if (r_entityclips.GetBool())
pRenderClipPlane = pEnt->GetRenderClipPlane();
if (pRenderClipPlane)
{
CMatRenderContextPtr pRenderContext(materials);
if (!materials->UsingFastClipping()) //do NOT change the fast clip plane mid-scene, depth problems result. Regular user clip planes are fine though
pRenderContext->PushCustomClipPlane(pRenderClipPlane);
#if DEBUG
else
AssertMsg(0, "can't link DrawClippedDepthBox externally so you either have to cope with even more redundancy or move all this crap to viewrender");
#endif
// DrawClippedDepthBox( pEnt, pRenderClipPlane );
Assert(view->GetCurrentlyDrawingEntity() == NULL);
view->SetCurrentlyDrawingEntity(pEnt->GetIClientUnknown()->GetBaseEntity());
bool bBlockNormalDraw = false; //BlurTest( pEnt, flags, true, instance );
if (!bBlockNormalDraw)
pEnt->DrawModel(flags, instance);
//BlurTest( pEnt, flags, false, instance );
view->SetCurrentlyDrawingEntity(NULL);
if (!materials->UsingFastClipping())
pRenderContext->PopCustomClipPlane();
}
else
{
Assert(view->GetCurrentlyDrawingEntity() == NULL);
view->SetCurrentlyDrawingEntity(pEnt->GetIClientUnknown()->GetBaseEntity());
bool bBlockNormalDraw = false; //BlurTest( pEnt, flags, true, instance );
if (!bBlockNormalDraw)
pEnt->DrawModel(flags, instance);
//BlurTest( pEnt, flags, false, instance );
view->SetCurrentlyDrawingEntity(NULL);
}
};
void DrawOpaqueRenderable(IClientRenderable *pEnt, bool bTwoPass, bool bShadowDepth)
{
ASSERT_LOCAL_PLAYER_RESOLVABLE();
float color[3];
Assert(!IsSplitScreenSupported() || pEnt->ShouldDrawForSplitScreenUser(GET_ACTIVE_SPLITSCREEN_SLOT()));
Assert((pEnt->GetIClientUnknown() == NULL) || (pEnt->GetIClientUnknown()->GetIClientEntity() == NULL) || (pEnt->GetIClientUnknown()->GetIClientEntity()->IsBlurred() == false));
pEnt->GetColorModulation(color);
render->SetColorModulation(color);
int flags = STUDIO_RENDER;
if (bTwoPass)
{
flags |= STUDIO_TWOPASS;
}
if (bShadowDepth)
{
flags |= STUDIO_SHADOWDEPTHTEXTURE;
}
RenderableInstance_t instance;
instance.m_nAlpha = 255;
DrawRenderable(pEnt, flags, instance);
};
#else
void DrawOpaqueRenderable(IClientRenderable *pEnt, bool bTwoPass, bool bShadowDepth)
{
float color[3];
pEnt->GetColorModulation(color);
render->SetColorModulation(color);
int flags = STUDIO_RENDER;
if (bTwoPass)
{
flags |= STUDIO_TWOPASS;
}
if (bShadowDepth)
{
flags |= STUDIO_SHADOWDEPTHTEXTURE;
}
float *pRenderClipPlane = NULL;
if (true) //r_entityclips.GetBool() )
pRenderClipPlane = pEnt->GetRenderClipPlane();
if (pRenderClipPlane)
{
CMatRenderContextPtr pRenderContext(materials);
if (!materials->UsingFastClipping()) //do NOT change the fast clip plane mid-scene, depth problems result. Regular user clip planes are fine though
pRenderContext->PushCustomClipPlane(pRenderClipPlane);
#if DEBUG
else
AssertMsg(0, "can't link DrawClippedDepthBox externally so you either have to cope with even more redundancy or move all this crap to viewrender");
#endif
// DrawClippedDepthBox( pEnt, pRenderClipPlane );
Assert(view->GetCurrentlyDrawingEntity() == NULL);
view->SetCurrentlyDrawingEntity(pEnt->GetIClientUnknown()->GetBaseEntity());
pEnt->DrawModel(flags);
view->SetCurrentlyDrawingEntity(NULL);
if (pRenderClipPlane && !materials->UsingFastClipping())
pRenderContext->PopCustomClipPlane();
}
else
{
Assert(view->GetCurrentlyDrawingEntity() == NULL);
view->SetCurrentlyDrawingEntity(pEnt->GetIClientUnknown()->GetBaseEntity());
pEnt->DrawModel(flags);
view->SetCurrentlyDrawingEntity(NULL);
}
};
#endif
#ifdef SWARM_DLL
void DrawOpaqueRenderables_DrawBrushModels(int nCount, CClientRenderablesList::CEntry **ppEntities, bool bShadowDepth)
{
for (int i = 0; i < nCount; ++i)
DrawOpaqueRenderable(ppEntities[i]->m_pRenderable, false, bShadowDepth);
};
#else
void DrawOpaqueRenderables_DrawBrushModels(CClientRenderablesList::CEntry *pEntitiesBegin, CClientRenderablesList::CEntry *pEntitiesEnd, bool bShadowDepth)
{
for (CClientRenderablesList::CEntry *itEntity = pEntitiesBegin; itEntity < pEntitiesEnd; ++itEntity)
DrawOpaqueRenderable(itEntity->m_pRenderable, false, bShadowDepth);
};
#endif
#ifdef SWARM_DLL
void DrawOpaqueRenderables_DrawStaticProps(int nCount, CClientRenderablesList::CEntry **ppEntities, bool bShadowDepth)
{
if (nCount == 0)
return;
float one[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
render->SetColorModulation(one);
render->SetBlend(1.0f);
const int MAX_STATICS_PER_BATCH = 512;
IClientRenderable *pStatics[MAX_STATICS_PER_BATCH];
RenderableInstance_t pInstances[MAX_STATICS_PER_BATCH];
int numScheduled = 0, numAvailable = MAX_STATICS_PER_BATCH;
for (int i = 0; i < nCount; ++i)
{
CClientRenderablesList::CEntry *itEntity = ppEntities[i];
if (itEntity->m_pRenderable)
NULL;
else
continue;
pInstances[numScheduled] = itEntity->m_InstanceData;
pStatics[numScheduled++] = itEntity->m_pRenderable;
if (--numAvailable > 0)
continue; // place a hint for compiler to predict more common case in the loop
staticpropmgr->DrawStaticProps(pStatics, pInstances, numScheduled, bShadowDepth, vcollide_wireframe.GetBool());
numScheduled = 0;
numAvailable = MAX_STATICS_PER_BATCH;
}
if (numScheduled)
staticpropmgr->DrawStaticProps(pStatics, pInstances, numScheduled, bShadowDepth, vcollide_wireframe.GetBool());
}
#else
void DrawOpaqueRenderables_DrawStaticProps(CClientRenderablesList::CEntry *pEntitiesBegin, CClientRenderablesList::CEntry *pEntitiesEnd, bool bShadowDepth)
{
if (pEntitiesEnd == pEntitiesBegin)
return;
float one[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
render->SetColorModulation(one);
render->SetBlend(1.0f);
const int MAX_STATICS_PER_BATCH = 512;
IClientRenderable *pStatics[MAX_STATICS_PER_BATCH];
int numScheduled = 0, numAvailable = MAX_STATICS_PER_BATCH;
for (CClientRenderablesList::CEntry *itEntity = pEntitiesBegin; itEntity < pEntitiesEnd; ++itEntity)
{
if (itEntity->m_pRenderable)
NULL;
else
continue;
pStatics[numScheduled++] = itEntity->m_pRenderable;
if (--numAvailable > 0)
continue; // place a hint for compiler to predict more common case in the loop
staticpropmgr->DrawStaticProps(pStatics, numScheduled, bShadowDepth, vcollide_wireframe.GetBool());
numScheduled = 0;
numAvailable = MAX_STATICS_PER_BATCH;
}
if (numScheduled)
staticpropmgr->DrawStaticProps(pStatics, numScheduled, bShadowDepth, vcollide_wireframe.GetBool());
};
#endif
#ifdef SWARM_DLL
void DrawOpaqueRenderables_Range(int nCount, CClientRenderablesList::CEntry **ppEntities, bool bShadowDepth)
{
for (int i = 0; i < nCount; ++i)
{
CClientRenderablesList::CEntry *itEntity = ppEntities[i];
if (itEntity->m_pRenderable)
DrawOpaqueRenderable(itEntity->m_pRenderable, (itEntity->m_TwoPass != 0), bShadowDepth);
}
};
#else
void DrawOpaqueRenderables_Range(CClientRenderablesList::CEntry *pEntitiesBegin, CClientRenderablesList::CEntry *pEntitiesEnd, bool bShadowDepth)
{
for (CClientRenderablesList::CEntry *itEntity = pEntitiesBegin; itEntity < pEntitiesEnd; ++itEntity)
if (itEntity->m_pRenderable)
DrawOpaqueRenderable(itEntity->m_pRenderable, (itEntity->m_TwoPass != 0), bShadowDepth);
// DrawOpaqueRenderable(itEntity->m_pRenderable, ((itEntity->m_TwoPassSkip & CClientRenderablesList::CEntry::IS_TWO_PASS) != 0), bShadowDepth);//GSTRING
};
#endif
};
class CSimpleVCallbackView : public CBaseVCallbackView
{
DECLARE_CLASS(CSimpleVCallbackView, CBaseVCallbackView);
public:
CSimpleVCallbackView(CViewRender *pMainView) : CBaseVCallbackView(pMainView) {}
struct EditorViewSettings
{
public:
bool bDrawPlayers;
bool bDrawWeapons;
bool bDrawStaticProps;
bool bDrawMisc;
bool bDrawTranslucents;
bool bDrawWater;
bool bDrawWorld;
bool bDrawParticles;
bool bDrawRopes;
bool bDrawSkybox;
bool bClipSkybox;
bool bClearColor;
bool bClearDepth;
bool bClearStencil;
bool bClearObeyStencil;
bool bFogOverride;
bool bFogEnabled;
int iClearColorR;
int iClearColorG;
int iClearColorB;
int iClearColorA;
int iFogColorR;
int iFogColorG;
int iFogColorB;
float flFogStart;
float flFogEnd;
float flFogDensity;
};
EditorViewSettings settings;
void Setup(const CViewSetup &view, CSimpleVCallbackView::EditorViewSettings settings,
const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t& info)
{
this->settings = settings;
BaseClass::Setup(view);
m_ClearFlags = (settings.bClearColor ? VIEW_CLEAR_COLOR : 0) |
(settings.bClearDepth ? VIEW_CLEAR_DEPTH : 0) |
(settings.bClearStencil ? VIEW_CLEAR_STENCIL : 0) |
(settings.bClearObeyStencil ? VIEW_CLEAR_OBEY_STENCIL : 0);
m_DrawFlags = (settings.bDrawPlayers || settings.bDrawStaticProps ||
settings.bDrawTranslucents || settings.bDrawWeapons ||
settings.bDrawMisc) ? DF_DRAW_ENTITITES : 0;
//if ( settings.bDrawWorld )
{
if (!info.m_bOpaqueWater)
{
m_DrawFlags |= DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER;
}
else
{
bool bViewIntersectsWater = DoesViewPlaneIntersectWater(fogInfo.m_flWaterHeight, fogInfo.m_nVisibleFogVolume);
if (bViewIntersectsWater)
{
// have to draw both sides if we can see both.
m_DrawFlags |= DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER;
}
else if (fogInfo.m_bEyeInFogVolume)
{
m_DrawFlags |= DF_RENDER_UNDERWATER;
}
else
{
m_DrawFlags |= DF_RENDER_ABOVEWATER;
}
}
}
if (info.m_bDrawWaterSurface && settings.bDrawWater)
{
m_DrawFlags |= DF_RENDER_WATER;
}
if (!fogInfo.m_bEyeInFogVolume && settings.bDrawSkybox)
{
m_DrawFlags |= DF_DRAWSKYBOX;
}
if (settings.bClipSkybox)
m_DrawFlags |= DF_CLIP_SKYBOX;
m_pCustomVisibility = NULL;
m_fogInfo = fogInfo;
};
void Draw()
{
DrawSetup(0, m_DrawFlags, 0);
CMatRenderContextPtr pRenderContext(materials);
pRenderContext->ClearColor4ub((unsigned char)settings.iClearColorR,
(unsigned char)settings.iClearColorG,
(unsigned char)settings.iClearColorB,
(unsigned char)settings.iClearColorA);
if (settings.bFogOverride)
{
if (!settings.bFogEnabled)
pRenderContext->FogMode(MATERIAL_FOG_NONE);
else
{
pRenderContext->FogMode(MATERIAL_FOG_LINEAR);
pRenderContext->FogColor3ub((unsigned char)settings.iFogColorR,
(unsigned char)settings.iFogColorG,
(unsigned char)settings.iFogColorB);
pRenderContext->FogStart(settings.flFogStart);
pRenderContext->FogEnd(settings.flFogEnd);
pRenderContext->FogMaxDensity(settings.flFogDensity);
}
}
else if (!m_fogInfo.m_bEyeInFogVolume)
{
EnableWorldFog();
}
else
{
m_ClearFlags |= VIEW_CLEAR_COLOR;
SetFogVolumeState(m_fogInfo, false);
pRenderContext.GetFrom(materials);
unsigned char ucFogColor[3];
pRenderContext->GetFogColor(ucFogColor);
pRenderContext->ClearColor4ub(ucFogColor[0], ucFogColor[1], ucFogColor[2], 255);
}
pRenderContext.SafeRelease();
DrawExecute(0, CurrentViewID(), 0);
pRenderContext.GetFrom(materials);
pRenderContext->ClearColor4ub(0, 0, 0, 255);
m_pMainView->DisableFog();
};
virtual void CallbackInitRenderList(int viewId)
{
BaseClass::CallbackInitRenderList(viewId);
if (settings.bDrawPlayers && settings.bDrawStaticProps &&
settings.bDrawTranslucents && settings.bDrawWeapons &&
settings.bDrawMisc)
return;
for (int i = 0; i < RENDER_GROUP_COUNT; i++)
{
#ifndef SWARM_DLL
const bool bStaticProp = i == 0 || i == 2 || i == 4 || i == 6;
#endif
for (int e = 0; e < m_pRenderablesList->m_RenderGroupCounts[i]; e++)
{
CClientRenderablesList::CEntry *pEntry = m_pRenderablesList->m_RenderGroups[i] + e;
if (!pEntry || !pEntry->m_pRenderable)
continue;
#ifdef SWARM_DLL
const bool bStaticProp = pEntry->m_nModelType == RENDERABLE_MODEL_STATIC_PROP;
#endif
bool bRemove = false;
if (bStaticProp)
bRemove = !settings.bDrawStaticProps;
else
{
IClientUnknown *pUnknown = pEntry->m_pRenderable->GetIClientUnknown();
if (!pUnknown || !pUnknown->GetBaseEntity())
continue;
C_BaseEntity *pEntity = pUnknown->GetBaseEntity();
if (pEntity->IsPlayer())
bRemove = !settings.bDrawPlayers;
else if (dynamic_cast< CBaseCombatWeapon* >(pEntity) != NULL)
bRemove = !settings.bDrawWeapons;
#ifdef SWARM_DLL
else if (pEntity->ComputeTranslucencyType() != RENDERABLE_IS_OPAQUE)
#else
else if (pEntry->m_pRenderable->IsTransparent())
#endif
bRemove = !settings.bDrawTranslucents;
else
bRemove = !settings.bDrawMisc;
}
if (bRemove)
{
pEntry->m_pRenderable = NULL;
#ifndef SWARM_DLL
pEntry->m_RenderHandle = NULL;
#endif
}
}
int eLast = -1;
for (int e = 0; e < m_pRenderablesList->m_RenderGroupCounts[i]; e++)
{
CClientRenderablesList::CEntry *pEntry = m_pRenderablesList->m_RenderGroups[i] + e;
if (!pEntry || !pEntry->m_pRenderable
#ifndef SWARM_DLL
|| !pEntry->m_RenderHandle
#endif
)
{
for (int e2 = e + 1; e2 < m_pRenderablesList->m_RenderGroupCounts[i]; e2++)
{
CClientRenderablesList::CEntry *pEntry2 = m_pRenderablesList->m_RenderGroups[i] + e2;
if (pEntry2 && pEntry2->m_pRenderable
#ifndef SWARM_DLL
&& pEntry2->m_RenderHandle
#endif
)
{
CClientRenderablesList::CEntry tmp = *pEntry;
*pEntry = *pEntry2;
*pEntry2 = tmp;
break;
}
}
}
if (pEntry && pEntry->m_pRenderable
#ifndef SWARM_DLL
&& pEntry->m_RenderHandle
#endif
)
eLast = e;
}
m_pRenderablesList->m_RenderGroupCounts[i] = eLast + 1;
}
};
virtual bool ShouldDrawParticles()
{
return settings.bDrawParticles;
};
virtual bool ShouldDrawRopes()
{
return settings.bDrawRopes;
};
virtual bool ShouldDrawWorld()
{
return settings.bDrawWorld;
};
virtual bool ShouldDrawTranslucents()
{
return settings.bDrawTranslucents;
};
virtual bool ShouldDrawTranslucentWorld()
{
return settings.bDrawWorld && settings.bDrawTranslucents;
};
private:
VisibleFogVolumeInfo_t m_fogInfo;
};
#ifdef SWARM_DLL
bool UpdateRefractIfNeededByList(CViewModelRenderablesList::RenderGroups_t &list)
{
int nCount = list.Count();
for (int i = 0; i < nCount; ++i)
{
IClientRenderable *pRenderable = list[i].m_pRenderable;
Assert(pRenderable);
if (pRenderable->GetRenderFlags() & ERENDERFLAGS_NEEDS_POWER_OF_TWO_FB)
{
UpdateRefractTexture();
return true;
}
}
return false;
}
void DrawRenderablesInList(CViewModelRenderablesList::RenderGroups_t &renderGroups, int flags = 0)
{
CViewRender *pCView = assert_cast< CViewRender* >(view);
Assert(pCView->GetCurrentlyDrawingEntity() == NULL);
ASSERT_LOCAL_PLAYER_RESOLVABLE();
#if defined( DBGFLAG_ASSERT )
int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
#endif
Assert(pCView->GetCurrentlyDrawingEntity() == NULL);
int nCount = renderGroups.Count();
for (int i = 0; i < nCount; ++i)
{
IClientRenderable *pRenderable = renderGroups[i].m_pRenderable;
Assert(pRenderable);
// Non-view models wanting to render in view model list...
if (pRenderable->ShouldDraw())
{
Assert(!IsSplitScreenSupported() || pRenderable->ShouldDrawForSplitScreenUser(nSlot));
pCView->SetCurrentlyDrawingEntity(pRenderable->GetIClientUnknown()->GetBaseEntity());
pRenderable->DrawModel(STUDIO_RENDER | flags, renderGroups[i].m_InstanceData);
}
}
pCView->SetCurrentlyDrawingEntity(NULL);
}
#else
static inline bool UpdateRefractIfNeededByList(CUtlVector< IClientRenderable * > &list)
{
int nCount = list.Count();
for (int i = 0; i < nCount; ++i)
{
IClientUnknown *pUnk = list[i]->GetIClientUnknown();
Assert(pUnk);
IClientRenderable *pRenderable = pUnk->GetClientRenderable();
Assert(pRenderable);
if (pRenderable->UsesPowerOfTwoFrameBufferTexture())
{
UpdateRefractTexture();
return true;
}
}
return false;
}
static inline void DrawRenderablesInList(CUtlVector< IClientRenderable * > &list, int flags = 0)
{
CViewRender *pCView = assert_cast< CViewRender* >(view);
Assert(pCView->GetCurrentlyDrawingEntity() == NULL);
int nCount = list.Count();
for (int i = 0; i < nCount; ++i)
{
IClientUnknown *pUnk = list[i]->GetIClientUnknown();
Assert(pUnk);
IClientRenderable *pRenderable = pUnk->GetClientRenderable();
Assert(pRenderable);
// Non-view models wanting to render in view model list...
if (pRenderable->ShouldDraw())
{
pCView->SetCurrentlyDrawingEntity(pUnk->GetBaseEntity());
pRenderable->DrawModel(STUDIO_RENDER | flags);
}
}
pCView->SetCurrentlyDrawingEntity(NULL);
}
#endif
int &ShaderEditorHandler::GetViewIdForModify()
{
Assert(m_piCurrentViewId != NULL);
return *m_piCurrentViewId;
}
const VisibleFogVolumeInfo_t &ShaderEditorHandler::GetFogVolumeInfo()
{
return m_tFogVolumeInfo;
}
const WaterRenderInfo_t &ShaderEditorHandler::GetWaterRenderInfo()
{
return m_tWaterRenderInfo;
}
pFnVrCallback_Declare(VrCallback_General)
{
CViewRender *pCView = assert_cast< CViewRender* >(view);
Assert(pCView->GetViewSetup() != NULL);
const CViewSetup *setup = pCView->GetViewSetup();
CSimpleVCallbackView::EditorViewSettings settings;
settings.bDrawPlayers = pbOptions[0];
settings.bDrawWeapons = pbOptions[1];
settings.bDrawStaticProps = pbOptions[2];
settings.bDrawMisc = pbOptions[3];
settings.bDrawTranslucents = pbOptions[4];
settings.bDrawWater = pbOptions[5];
settings.bDrawWorld = pbOptions[6];
settings.bDrawParticles = pbOptions[7];
settings.bDrawRopes = pbOptions[8];
settings.bDrawSkybox = pbOptions[9];
settings.bClipSkybox = pbOptions[10];
settings.bClearColor = pbOptions[11];
settings.bClearDepth = pbOptions[12];
settings.bClearStencil = pbOptions[13];
settings.bClearObeyStencil = pbOptions[14];
settings.bFogOverride = pbOptions[15];
settings.bFogEnabled = pbOptions[16];
settings.iClearColorR = piOptions[0];
settings.iClearColorG = piOptions[1];
settings.iClearColorB = piOptions[2];
settings.iClearColorA = piOptions[3];
settings.iFogColorR = piOptions[4];
settings.iFogColorG = piOptions[5];
settings.iFogColorB = piOptions[6];
settings.flFogStart = pflOptions[0];
settings.flFogEnd = pflOptions[1];
settings.flFogDensity = pflOptions[2];
if (settings.flFogEnd < 0)
settings.flFogEnd = setup->zFar;
CRefPtr<CSimpleVCallbackView> pGeneralCallbackView = new CSimpleVCallbackView(pCView);
pGeneralCallbackView->Setup(*setup, settings,
g_ShaderEditorSystem->GetFogVolumeInfo(), g_ShaderEditorSystem->GetWaterRenderInfo());
pCView->AddViewToScene(pGeneralCallbackView);
}
pFnVrCallback_Declare(VrCallback_ViewModel)
{
CViewRender *pCView = assert_cast< CViewRender* >(view);
Assert(pCView->GetViewSetup() != NULL);
CMatRenderContextPtr pRenderContext(materials);
static ConVarRef drawVM("r_drawviewmodel");
const bool bHideVM = pbOptions[0];
const bool bFogOverride = pbOptions[5];
const int iClearFlags = (pbOptions[1] ? VIEW_CLEAR_COLOR : 0) |
(pbOptions[2] ? VIEW_CLEAR_DEPTH : 0) |
(pbOptions[3] ? VIEW_CLEAR_STENCIL : 0) |
(pbOptions[4] ? VIEW_CLEAR_OBEY_STENCIL : 0);
drawVM.SetValue(!bHideVM);
if (bFogOverride)
{
if (!pbOptions[6])
pCView->DisableFog();
else
{
pRenderContext->FogMode(MATERIAL_FOG_LINEAR);
pRenderContext->FogColor3ub((unsigned char)piOptions[4],
(unsigned char)piOptions[5],
(unsigned char)piOptions[6]);
pRenderContext->FogStart(pflOptions[0]);
pRenderContext->FogEnd(pflOptions[1]);
pRenderContext->FogMaxDensity(pflOptions[2]);
}
}
int bbx, bby;
materials->GetBackBufferDimensions(bbx, bby);
// Restore the matrices
pRenderContext->MatrixMode(MATERIAL_PROJECTION);
pRenderContext->PushMatrix();
ITexture *pTex = pRenderContext->GetRenderTarget();
const CViewSetup &view = *pCView->GetViewSetup();
CViewSetup viewModelSetup(view);
viewModelSetup.zNear = view.zNearViewmodel;
viewModelSetup.zFar = view.zFarViewmodel;
viewModelSetup.fov = view.fovViewmodel;
#ifdef SWARM_DLL
viewModelSetup.m_flAspectRatio = engine->GetScreenAspectRatio(view.width, view.height);
#else
viewModelSetup.m_flAspectRatio = engine->GetScreenAspectRatio();
#endif
viewModelSetup.width = pTex ? pTex->GetActualWidth() : bbx;
viewModelSetup.height = pTex ? pTex->GetActualHeight() : bby;
if (iClearFlags & VIEW_CLEAR_COLOR)
{
pRenderContext->ClearColor4ub((unsigned char)piOptions[0],
(unsigned char)piOptions[1],
(unsigned char)piOptions[2],
(unsigned char)piOptions[3]);
}
render->Push3DView(viewModelSetup, iClearFlags, pTex, pCView->GetFrustum());
const bool bUseDepthHack = true;
float depthmin = 0.0f;
float depthmax = 1.0f;
// HACK HACK: Munge the depth range to prevent view model from poking into walls, etc.
// Force clipped down range
if (bUseDepthHack)
pRenderContext->DepthRange(0.0f, 0.1f);
#ifdef SWARM_DLL
CViewModelRenderablesList list;
ClientLeafSystem()->CollateViewModelRenderables(&list);
CViewModelRenderablesList::RenderGroups_t &opaqueViewModelList = list.m_RenderGroups[CViewModelRenderablesList::VM_GROUP_OPAQUE];
CViewModelRenderablesList::RenderGroups_t &translucentViewModelList = list.m_RenderGroups[CViewModelRenderablesList::VM_GROUP_TRANSLUCENT];
#else
CUtlVector< IClientRenderable * > opaqueViewModelList(32);
CUtlVector< IClientRenderable * > translucentViewModelList(32);
ClientLeafSystem()->CollateViewModelRenderables(opaqueViewModelList, translucentViewModelList);
#endif
const bool bUpdateRefractForOpaque = UpdateRefractIfNeededByList(opaqueViewModelList);
DrawRenderablesInList(opaqueViewModelList);
if (!bUpdateRefractForOpaque)
UpdateRefractIfNeededByList(translucentViewModelList);
DrawRenderablesInList(translucentViewModelList, STUDIO_TRANSPARENCY);
// Reset the depth range to the original values
if (bUseDepthHack)
pRenderContext->DepthRange(depthmin, depthmax);
render->PopView(pCView->GetFrustum());
// Restore the matrices
pRenderContext->MatrixMode(MATERIAL_PROJECTION);
pRenderContext->PopMatrix();
if (bFogOverride)
pCView->DisableFog();
}
void ShaderEditorHandler::RegisterViewRenderCallbacks()
{
if (!IsReady())
return;
const char *boolNames_generalVrc[] = {
"Draw players",
"Draw weapons",
"Draw static props",
"Draw misc",
"Draw translucents",
"Draw water",
"Draw world",
"Draw particles",
"Draw ropes",
"Draw skybox (2D)",
"Clip skybox",
"Clear color",
"Clear depth",
"Clear stencil",
"Clear obey stencil",
"Fog override",
"Fog force enabled",
};
const bool boolDefaults_generalVrc[] = {
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
false,
true,
true,
false,
false,
false,
true,
};
const char *intNames_generalVrc[] = {
"Clear color R (0-255)",
"Clear color G (0-255)",
"Clear color B (0-255)",
"Clear color A (0-255)",
"Fog color R (0-255)",
"Fog color G (0-255)",
"Fog color B (0-255)",
};
const char *floatNames_generalVrc[] = {
"Fog start (units)",
"Fog end (units)",
"Fog density (0-1)",
};
const float floatDefaults_generalVrc[] = {
0,
2000,
1,
};
const char *boolNames_vmVrc[] = {
"Hide default viewmodel",
"Clear color",
"Clear depth",
"Clear stencil",
"Clear obey stencil",
"Fog override",
"Fog force enabled",
};
const bool boolDefaults_vmVrc[] = {
false,
true,
true,
false,
false,
false,
true,
};
Assert(ARRAYSIZE(boolNames_generalVrc) == ARRAYSIZE(boolDefaults_generalVrc));
Assert(ARRAYSIZE(floatNames_generalVrc) == ARRAYSIZE(floatDefaults_generalVrc));
Assert(ARRAYSIZE(boolNames_vmVrc) == ARRAYSIZE(boolDefaults_vmVrc));
shaderEdit->RegisterViewRenderCallback("General view", VrCallback_General,
boolNames_generalVrc, boolDefaults_generalVrc, ARRAYSIZE(boolNames_generalVrc),
intNames_generalVrc, NULL, ARRAYSIZE(intNames_generalVrc),
floatNames_generalVrc, floatDefaults_generalVrc, ARRAYSIZE(floatNames_generalVrc));
shaderEdit->RegisterViewRenderCallback("Viewmodel view", VrCallback_ViewModel,
boolNames_vmVrc, boolDefaults_vmVrc, ARRAYSIZE(boolNames_vmVrc),
intNames_generalVrc, NULL, ARRAYSIZE(intNames_generalVrc),
floatNames_generalVrc, floatDefaults_generalVrc, ARRAYSIZE(floatNames_generalVrc));
shaderEdit->LockViewRenderCallbacks();
}
#endif