diff --git a/sp/src/game/client/iviewrender.h b/sp/src/game/client/iviewrender.h index 8d797dea530..dd4b1dd4c1c 100644 --- a/sp/src/game/client/iviewrender.h +++ b/sp/src/game/client/iviewrender.h @@ -145,6 +145,11 @@ abstract_class IViewRender virtual void FreezeFrame( float flFreezeTime ) = 0; virtual IReplayScreenshotSystem *GetReplayScreenshotSystem() = 0; + +#ifdef MAPBASE + virtual bool BSetupSkyBox( const char *pszSkyName ) = 0; + virtual void DrawSkyBox( const CViewSetup &View, bool bNoHeightClip ) = 0; +#endif //MAPBASE }; extern IViewRender *view; diff --git a/sp/src/game/client/view.cpp b/sp/src/game/client/view.cpp index a930c4a75fe..c2cc6be1d61 100644 --- a/sp/src/game/client/view.cpp +++ b/sp/src/game/client/view.cpp @@ -59,6 +59,9 @@ #include "c_prop_portal.h" //portal surface rendering functions #endif +#ifdef MAPBASE +#include "movevars_shared.h" +#endif //MAPBASE // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -344,6 +347,11 @@ void CViewRender::LevelInit( void ) } m_flFreezeFrameUntil = 0; +#ifdef MAPBASE + // Ensure the sky is properly loaded + BSetupSkyBox( sv_skyname.GetString() ); +#endif //MAPBASE + // Clear our overlay materials m_ScreenOverlayMaterial.Init( NULL ); diff --git a/sp/src/game/client/viewrender.cpp b/sp/src/game/client/viewrender.cpp index 6bcff8da90e..e5eb44732fb 100644 --- a/sp/src/game/client/viewrender.cpp +++ b/sp/src/game/client/viewrender.cpp @@ -77,6 +77,7 @@ #ifdef MAPBASE #include "mapbase/c_func_fake_worldportal.h" #include "colorcorrectionmgr.h" +#include "fmtstr.h" #endif // Projective textures @@ -126,6 +127,7 @@ static ConVar r_threaded_renderables( "r_threaded_renderables", "0" ); #ifdef MAPBASE static ConVar r_skybox_use_complex_views( "r_skybox_use_complex_views", "0", FCVAR_CHEAT, "Enable complex views in skyboxes, like reflective glass" ); +static ConVar r_skybox_use_new_renderer( "r_skybox_use_new_renderer", "1", FCVAR_NONE, "Use game client's 2D SkyBox renderer" ); #endif // FIXME: This is not static because we needed to turn it off for TF2 playtests @@ -1994,6 +1996,119 @@ void CViewRender::CleanupMain3DView( const CViewSetup &view ) } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Builds and draws the 2D SkyBox faces +//----------------------------------------------------------------------------- +CViewRender::skyface_t CViewRender::s_rgSkyFaces[ k_ESkyFaceCount ] = +{ + { "LF", {-1.f, 0.f, 0.f }, { 0.f, 1.f, 0.f }, { 0.f, 0.f, 1.f } }, + { "RT", { 1.f, 0.f, 0.f }, { 0.f,-1.f, 0.f }, { 0.f, 0.f, 1.f } }, + { "FT", { 0.f,-1.f, 0.f }, {-1.f, 0.f, 0.f }, { 0.f, 0.f, 1.f } }, + { "BK", { 0.f, 1.f, 0.f }, { 1.f, 0.f, 0.f }, { 0.f, 0.f, 1.f } }, + { "UP", { 0.f, 0.f, 1.f }, { 0.f,-1.f, 0.f }, {-1.f, 0.f, 0.f } }, + { "DN", { 0.f, 0.f,-1.f }, { 0.f,-1.f, 0.f }, { 1.f, 0.f, 0.f } }, +}; + +bool CViewRender::BSetupSkyBox( const char *pszSkyName ) +{ + bool bRetVal = true; + for ( int iFace = k_ESkyFaceFirst; iFace <= k_ESkyFaceLast; iFace++ ) + { + auto &sf = s_rgSkyFaces[ iFace ]; + + sf.pMaterial.Init( CFmtStr( "SkyBox/%s%s", pszSkyName, sf.pszPostfix ), TEXTURE_GROUP_SKYBOX ); + sf.nSamplingResolution = 256; + + if ( IsErrorMaterial( sf.pMaterial ) ) + { + bRetVal = false; // Mark as failed, but try to get rest of the faces.. + continue; + } + + // Get at the texture and it's mapping dimensions, since IMaterial::GetMappingWidth/Height is busted here + bool bFound; + IMaterialVar *pBaseTextureVar = sf.pMaterial->FindVar( "$BaseTexture", &bFound, false ); + if ( bFound ) + { + ITexture *pTexture = NULL; + switch ( pBaseTextureVar->GetType() ) + { + case MATERIAL_VAR_TYPE_STRING: + pTexture = g_pMaterialSystem->FindTexture( pBaseTextureVar->GetStringValue(), TEXTURE_GROUP_SKYBOX, false ); + break; + case MATERIAL_VAR_TYPE_TEXTURE: + pTexture = pBaseTextureVar->GetTextureValue(); + break; + default: + Assert( NULL ); + } + if ( pTexture ) + { + sf.nSamplingResolution = Min( pTexture->GetMappingWidth(), pTexture->GetMappingHeight() ); + } + } + } + return bRetVal; +} + +void CViewRender::DrawSkyBox( const CViewSetup &View, bool bNoHeightClip ) +{ + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + + MaterialHeightClipMode_t ePrevClipMode = pRenderContext->GetHeightClipMode(); + if ( bNoHeightClip ) + { + pRenderContext->SetHeightClipMode( MATERIAL_HEIGHTCLIPMODE_DISABLE ); + } + + float flDist = View.zFar / 2.f; + + // Draw a quad for each face of the sky around the camera + for ( int iFace = k_ESkyFaceFirst; iFace <= k_ESkyFaceLast; iFace++ ) + { + auto &sf = s_rgSkyFaces[ iFace ]; + + Vector vecCenter = flDist * sf.vecNormal + View.origin; + Vector vecRight = flDist * sf.vecRight; + Vector vecUp = flDist * sf.vecUp; + + float flMinUV = .5f / ( float )sf.nSamplingResolution; + float flMaxUV = 1.f - flMinUV; + + IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, sf.pMaterial ); + + CMeshBuilder MeshBuilder; + MeshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); + + MeshBuilder.Position3fv( ( vecCenter - vecRight + vecUp ).Base() ); + MeshBuilder.TexCoord2f( 0, flMinUV, flMinUV ); + MeshBuilder.AdvanceVertexF< VTX_HAVEPOS, 1 >(); + + MeshBuilder.Position3fv( ( vecCenter + vecRight + vecUp ).Base() ); + MeshBuilder.TexCoord2f( 0, flMaxUV, flMinUV ); + MeshBuilder.AdvanceVertexF< VTX_HAVEPOS, 1 >(); + + MeshBuilder.Position3fv( ( vecCenter + vecRight - vecUp ).Base() ); + MeshBuilder.TexCoord2f( 0, flMaxUV, flMaxUV ); + MeshBuilder.AdvanceVertexF< VTX_HAVEPOS, 1 >(); + + MeshBuilder.Position3fv( ( vecCenter - vecRight - vecUp ).Base() ); + MeshBuilder.TexCoord2f( 0, flMinUV, flMaxUV ); + MeshBuilder.AdvanceVertexF< VTX_HAVEPOS, 1 >(); + + MeshBuilder.End(); + pMesh->Draw(); + } + + if ( bNoHeightClip ) + { + pRenderContext->SetHeightClipMode( ePrevClipMode ); + } +} +#endif //MAPBASE + + //----------------------------------------------------------------------------- // Queues up an overlay rendering //----------------------------------------------------------------------------- @@ -4102,7 +4217,25 @@ void CRendering3dView::DrawWorld( float waterZAdjust ) return; } +#ifdef MAPBASE + unsigned long engineFlags; + if ( r_skybox_use_new_renderer.GetBool() ) + { + if ( m_DrawFlags & DF_DRAWSKYBOX ) + { + // Hook up our own 2D sky draw routine + m_pMainView->DrawSkyBox( ( *this ), !( m_DrawFlags & DF_CLIP_SKYBOX ) ); + } + + engineFlags = BuildEngineDrawWorldListFlags( m_DrawFlags & ~DF_DRAWSKYBOX ); + } + else + { + engineFlags = BuildEngineDrawWorldListFlags( m_DrawFlags ); + } +#else unsigned long engineFlags = BuildEngineDrawWorldListFlags( m_DrawFlags ); +#endif //MAPBASE render->DrawWorldLists( m_pWorldRenderList, engineFlags, waterZAdjust ); } diff --git a/sp/src/game/client/viewrender.h b/sp/src/game/client/viewrender.h index 3ba6cd9fc43..4144b7ce5db 100644 --- a/sp/src/game/client/viewrender.h +++ b/sp/src/game/client/viewrender.h @@ -438,6 +438,12 @@ class CViewRender : public IViewRender, { m_UnderWaterOverlayMaterial.Init( pMaterial ); } + +#ifdef MAPBASE + virtual bool BSetupSkyBox( const char *pszSkyName ); + virtual void DrawSkyBox( const CViewSetup &View, bool bNoHeightClip ); +#endif //MAPBASE + private: int m_BuildWorldListsNumber; @@ -559,6 +565,33 @@ class CViewRender : public IViewRender, #if defined( REPLAY_ENABLED ) CReplayScreenshotTaker *m_pReplayScreenshotTaker; #endif + +#ifdef MAPBASE + enum ESkyFace + { + k_ESkyFaceLeft = 0, + k_ESkyFaceRight, + k_ESkyFaceFront, + k_ESkyFaceBack, + k_ESkyFaceUp, + k_ESkyFaceDown, + + k_ESkyFaceCount, + + k_ESkyFaceFirst = k_ESkyFaceLeft, + k_ESkyFaceLast = k_ESkyFaceDown + }; + + struct skyface_t + { + const char *pszPostfix; // Postfix of the texture filename + const Vector vecNormal, vecRight, vecUp; // Face direction and local tangent axes for building quads + CMaterialReference pMaterial; // Material associated with this face + int nSamplingResolution; // Used for UV clamping, smallest of texture width/height + }; + + static skyface_t s_rgSkyFaces[ k_ESkyFaceCount ]; +#endif //MAPBASE }; #endif // VIEWRENDER_H diff --git a/sp/src/game/shared/movevars_shared.cpp b/sp/src/game/shared/movevars_shared.cpp index 563d96e36f9..098c180138d 100644 --- a/sp/src/game/shared/movevars_shared.cpp +++ b/sp/src/game/shared/movevars_shared.cpp @@ -8,6 +8,10 @@ #include "cbase.h" #include "movevars_shared.h" +#if defined( CLIENT_DLL ) && defined( MAPBASE ) +#include "iviewrender.h" +#endif // CLIENT_DLL && MAPBASE + #if defined( TF_CLIENT_DLL ) || defined( TF_DLL ) #include "tf_gamerules.h" #endif @@ -102,7 +106,22 @@ ConVar sv_backspeed ( "sv_backspeed", "0.6", FCVAR_ARCHIVE | FCVAR_REPLICATED | ConVar sv_waterdist ( "sv_waterdist","12", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "Vertical view fixup when eyes are near water plane." ); #endif // CSTRIKE_DLL -ConVar sv_skyname ( "sv_skyname", "sky_urb01", FCVAR_ARCHIVE | FCVAR_REPLICATED, "Current name of the skybox texture" ); +#if defined( CLIENT_DLL ) && defined( MAPBASE ) +static void OnSkyNameChanged( IConVar *pCVar, const char *pszOldValue, float flOldValue ) +{ + // Tell the view renderer that we have swapped skies + if ( !view->BSetupSkyBox( sv_skyname.GetString() ) ) + { + Warning( "Some/all faces of the \"%s\" SkyBox are missing or corrupted.\n", sv_skyname.GetString() ); + } +} +#endif // CLIENT_DLL && MAPBASE + +ConVar sv_skyname ( "sv_skyname", "sky_urb01", FCVAR_ARCHIVE | FCVAR_REPLICATED, "Current name of the skybox texture" +#if defined( CLIENT_DLL ) && defined( MAPBASE ) + , OnSkyNameChanged +#endif // CLIENT_DLL && MAPBASE +); // Vehicle convars ConVar r_VehicleViewDampen( "r_VehicleViewDampen", "1", FCVAR_CHEAT | FCVAR_NOTIFY | FCVAR_REPLICATED );