// ****************************************************** // // 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(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(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 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