Skip to content

Commit b41487f

Browse files
committed
Add a custom 2D SkyBox renderer to the game client (mapbase-source#534)
1 parent e305c9b commit b41487f

5 files changed

Lines changed: 182 additions & 2 deletions

File tree

src/game/client/iviewrender.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ abstract_class IViewRender
138138
virtual void FreezeFrame( float flFreezeTime ) = 0;
139139

140140
virtual IReplayScreenshotSystem *GetReplayScreenshotSystem() = 0;
141+
142+
virtual bool BSetupSkyBox(const char* pszSkyName) = 0;
143+
virtual void DrawSkyBox(const CViewSetup& View, bool bNoHeightClip) = 0;
141144
};
142145

143146
extern IViewRender *view;

src/game/client/view.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
#include "c_prop_portal.h" //portal surface rendering functions
6060
#endif
6161

62+
#include "movevars_shared.h"
6263

6364
// memdbgon must be the last include file in a .cpp file!!!
6465
#include "tier0/memdbgon.h"
@@ -350,6 +351,9 @@ void CViewRender::LevelInit( void )
350351
}
351352
m_flFreezeFrameUntil = 0;
352353

354+
// Ensure the sky is properly loaded
355+
BSetupSkyBox(sv_skyname.GetString());
356+
353357
// Clear our overlay materials
354358
m_ScreenOverlayMaterial.Init( NULL );
355359

src/game/client/viewrender.cpp

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ static ConVar r_drawtranslucentrenderables( "r_drawtranslucentrenderables", "1",
121121
static ConVar r_drawopaquerenderables( "r_drawopaquerenderables", "1", FCVAR_CHEAT );
122122
static ConVar r_threaded_renderables( "r_threaded_renderables", "0" );
123123

124+
static ConVar r_skybox_use_new_renderer("r_skybox_use_new_renderer", "1", FCVAR_NONE, "Use game client's 2D SkyBox renderer");
125+
124126
// FIXME: This is not static because we needed to turn it off for TF2 playtests
125127
ConVar r_DrawDetailProps( "r_DrawDetailProps", "1", FCVAR_NONE, "0=Off, 1=Normal, 2=Wireframe" );
126128

@@ -2049,6 +2051,115 @@ void CViewRender::CleanupMain3DView( const CViewSetup &viewRender )
20492051
render->PopView( GetFrustum() );
20502052
}
20512053

2054+
//-----------------------------------------------------------------------------
2055+
// Builds and draws the 2D SkyBox faces
2056+
//-----------------------------------------------------------------------------
2057+
CViewRender::skyface_t CViewRender::s_rgSkyFaces[k_ESkyFaceCount] =
2058+
{
2059+
{ "LF", {-1.f, 0.f, 0.f }, { 0.f, 1.f, 0.f }, { 0.f, 0.f, 1.f } },
2060+
{ "RT", { 1.f, 0.f, 0.f }, { 0.f,-1.f, 0.f }, { 0.f, 0.f, 1.f } },
2061+
{ "FT", { 0.f,-1.f, 0.f }, {-1.f, 0.f, 0.f }, { 0.f, 0.f, 1.f } },
2062+
{ "BK", { 0.f, 1.f, 0.f }, { 1.f, 0.f, 0.f }, { 0.f, 0.f, 1.f } },
2063+
{ "UP", { 0.f, 0.f, 1.f }, { 0.f,-1.f, 0.f }, {-1.f, 0.f, 0.f } },
2064+
{ "DN", { 0.f, 0.f,-1.f }, { 0.f,-1.f, 0.f }, { 1.f, 0.f, 0.f } },
2065+
};
2066+
2067+
bool CViewRender::BSetupSkyBox(const char* pszSkyName)
2068+
{
2069+
bool bRetVal = true;
2070+
for (int iFace = k_ESkyFaceFirst; iFace <= k_ESkyFaceLast; iFace++)
2071+
{
2072+
auto& sf = s_rgSkyFaces[iFace];
2073+
2074+
sf.pMaterial.Init(CFmtStr("SkyBox/%s%s", pszSkyName, sf.pszPostfix), TEXTURE_GROUP_SKYBOX);
2075+
sf.nSamplingResolution = 256;
2076+
2077+
if (IsErrorMaterial(sf.pMaterial))
2078+
{
2079+
bRetVal = false; // Mark as failed, but try to get rest of the faces..
2080+
continue;
2081+
}
2082+
2083+
// Get at the texture and it's mapping dimensions, since IMaterial::GetMappingWidth/Height is busted here
2084+
bool bFound;
2085+
IMaterialVar* pBaseTextureVar = sf.pMaterial->FindVar("$BaseTexture", &bFound, false);
2086+
if (bFound)
2087+
{
2088+
ITexture* pTexture = NULL;
2089+
switch (pBaseTextureVar->GetType())
2090+
{
2091+
case MATERIAL_VAR_TYPE_STRING:
2092+
pTexture = g_pMaterialSystem->FindTexture(pBaseTextureVar->GetStringValue(), TEXTURE_GROUP_SKYBOX, false);
2093+
break;
2094+
case MATERIAL_VAR_TYPE_TEXTURE:
2095+
pTexture = pBaseTextureVar->GetTextureValue();
2096+
break;
2097+
default:
2098+
Assert(NULL);
2099+
}
2100+
if (pTexture)
2101+
{
2102+
sf.nSamplingResolution = Min(pTexture->GetMappingWidth(), pTexture->GetMappingHeight());
2103+
}
2104+
}
2105+
}
2106+
return bRetVal;
2107+
}
2108+
2109+
void CViewRender::DrawSkyBox(const CViewSetup& View, bool bNoHeightClip)
2110+
{
2111+
CMatRenderContextPtr pRenderContext(g_pMaterialSystem);
2112+
2113+
MaterialHeightClipMode_t ePrevClipMode = pRenderContext->GetHeightClipMode();
2114+
if (bNoHeightClip)
2115+
{
2116+
pRenderContext->SetHeightClipMode(MATERIAL_HEIGHTCLIPMODE_DISABLE);
2117+
}
2118+
2119+
float flDist = View.zFar / 2.f;
2120+
2121+
// Draw a quad for each face of the sky around the camera
2122+
for (int iFace = k_ESkyFaceFirst; iFace <= k_ESkyFaceLast; iFace++)
2123+
{
2124+
auto& sf = s_rgSkyFaces[iFace];
2125+
2126+
Vector vecCenter = flDist * sf.vecNormal + View.origin;
2127+
Vector vecRight = flDist * sf.vecRight;
2128+
Vector vecUp = flDist * sf.vecUp;
2129+
2130+
float flMinUV = .5f / (float)sf.nSamplingResolution;
2131+
float flMaxUV = 1.f - flMinUV;
2132+
2133+
IMesh* pMesh = pRenderContext->GetDynamicMesh(true, NULL, NULL, sf.pMaterial);
2134+
2135+
CMeshBuilder MeshBuilder;
2136+
MeshBuilder.Begin(pMesh, MATERIAL_QUADS, 1);
2137+
2138+
MeshBuilder.Position3fv((vecCenter - vecRight + vecUp).Base());
2139+
MeshBuilder.TexCoord2f(0, flMinUV, flMinUV);
2140+
MeshBuilder.AdvanceVertexF< VTX_HAVEPOS, 1 >();
2141+
2142+
MeshBuilder.Position3fv((vecCenter + vecRight + vecUp).Base());
2143+
MeshBuilder.TexCoord2f(0, flMaxUV, flMinUV);
2144+
MeshBuilder.AdvanceVertexF< VTX_HAVEPOS, 1 >();
2145+
2146+
MeshBuilder.Position3fv((vecCenter + vecRight - vecUp).Base());
2147+
MeshBuilder.TexCoord2f(0, flMaxUV, flMaxUV);
2148+
MeshBuilder.AdvanceVertexF< VTX_HAVEPOS, 1 >();
2149+
2150+
MeshBuilder.Position3fv((vecCenter - vecRight - vecUp).Base());
2151+
MeshBuilder.TexCoord2f(0, flMinUV, flMaxUV);
2152+
MeshBuilder.AdvanceVertexF< VTX_HAVEPOS, 1 >();
2153+
2154+
MeshBuilder.End();
2155+
pMesh->Draw();
2156+
}
2157+
2158+
if (bNoHeightClip)
2159+
{
2160+
pRenderContext->SetHeightClipMode(ePrevClipMode);
2161+
}
2162+
}
20522163

20532164
//-----------------------------------------------------------------------------
20542165
// Queues up an overlay rendering
@@ -3742,7 +3853,21 @@ void CRendering3dView::DrawWorld( float waterZAdjust )
37423853
return;
37433854
}
37443855

3745-
unsigned long engineFlags = BuildEngineDrawWorldListFlags( m_DrawFlags );
3856+
unsigned long engineFlags;
3857+
if (r_skybox_use_new_renderer.GetBool())
3858+
{
3859+
if (m_DrawFlags & DF_DRAWSKYBOX)
3860+
{
3861+
// Hook up our own 2D sky draw routine
3862+
m_pMainView->DrawSkyBox((*this), !(m_DrawFlags & DF_CLIP_SKYBOX));
3863+
}
3864+
3865+
engineFlags = BuildEngineDrawWorldListFlags(m_DrawFlags & ~DF_DRAWSKYBOX);
3866+
}
3867+
else
3868+
{
3869+
engineFlags = BuildEngineDrawWorldListFlags(m_DrawFlags);
3870+
}
37463871

37473872
render->DrawWorldLists( m_pWorldRenderList, engineFlags, waterZAdjust );
37483873
}

src/game/client/viewrender.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,10 @@ class CViewRender : public IViewRender,
423423
{
424424
m_UnderWaterOverlayMaterial.Init( pMaterial );
425425
}
426+
427+
virtual bool BSetupSkyBox(const char* pszSkyName);
428+
virtual void DrawSkyBox(const CViewSetup& View, bool bNoHeightClip);
429+
426430
private:
427431
int m_BuildWorldListsNumber;
428432

@@ -529,6 +533,31 @@ class CViewRender : public IViewRender,
529533
#if defined( REPLAY_ENABLED )
530534
CReplayScreenshotTaker *m_pReplayScreenshotTaker;
531535
#endif
536+
537+
enum ESkyFace
538+
{
539+
k_ESkyFaceLeft = 0,
540+
k_ESkyFaceRight,
541+
k_ESkyFaceFront,
542+
k_ESkyFaceBack,
543+
k_ESkyFaceUp,
544+
k_ESkyFaceDown,
545+
546+
k_ESkyFaceCount,
547+
548+
k_ESkyFaceFirst = k_ESkyFaceLeft,
549+
k_ESkyFaceLast = k_ESkyFaceDown
550+
};
551+
552+
struct skyface_t
553+
{
554+
const char* pszPostfix; // Postfix of the texture filename
555+
const Vector vecNormal, vecRight, vecUp; // Face direction and local tangent axes for building quads
556+
CMaterialReference pMaterial; // Material associated with this face
557+
int nSamplingResolution; // Used for UV clamping, smallest of texture width/height
558+
};
559+
560+
static skyface_t s_rgSkyFaces[k_ESkyFaceCount];
532561
};
533562

534563
#endif // VIEWRENDER_H

src/game/shared/movevars_shared.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
#include "cbase.h"
99
#include "movevars_shared.h"
1010

11+
#if defined( CLIENT_DLL )
12+
#include "iviewrender.h"
13+
#endif // CLIENT_DLL
14+
1115
#if defined( TF_CLIENT_DLL ) || defined( TF_DLL )
1216
#include "tf_gamerules.h"
1317
#endif
@@ -102,7 +106,22 @@ ConVar sv_backspeed ( "sv_backspeed", "0.6", FCVAR_ARCHIVE | FCVAR_REPLICATED, "
102106
ConVar sv_waterdist ( "sv_waterdist","12", FCVAR_REPLICATED, "Vertical view fixup when eyes are near water plane." );
103107
#endif // CSTRIKE_DLL
104108

105-
ConVar sv_skyname ( "sv_skyname", "sky_urb01", FCVAR_ARCHIVE | FCVAR_REPLICATED, "Current name of the skybox texture" );
109+
#if defined( CLIENT_DLL )
110+
static void OnSkyNameChanged(IConVar* pCVar, const char* pszOldValue, float flOldValue)
111+
{
112+
// Tell the view renderer that we have swapped skies
113+
if (!view->BSetupSkyBox(sv_skyname.GetString()))
114+
{
115+
Warning("Some/all faces of the \"%s\" SkyBox are missing or corrupted.\n", sv_skyname.GetString());
116+
}
117+
}
118+
#endif // CLIENT_DLL && MAPBASE
119+
120+
ConVar sv_skyname("sv_skyname", "sky_urb01", FCVAR_ARCHIVE | FCVAR_REPLICATED, "Current name of the skybox texture"
121+
#if defined( CLIENT_DLL )
122+
, OnSkyNameChanged
123+
#endif // CLIENT_DLL && MAPBASE
124+
);
106125

107126
// Vehicle convars
108127
ConVar r_VehicleViewDampen( "r_VehicleViewDampen", "1", FCVAR_CHEAT | FCVAR_NOTIFY | FCVAR_REPLICATED );

0 commit comments

Comments
 (0)