diff options
Diffstat (limited to 'tools/toolutils/miniviewport.cpp')
| -rw-r--r-- | tools/toolutils/miniviewport.cpp | 457 |
1 files changed, 457 insertions, 0 deletions
diff --git a/tools/toolutils/miniviewport.cpp b/tools/toolutils/miniviewport.cpp new file mode 100644 index 0000000..2b74c35 --- /dev/null +++ b/tools/toolutils/miniviewport.cpp @@ -0,0 +1,457 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "toolutils/miniviewport.h" +#include "tier1/utlstring.h" +#include "vgui/ISurface.h" +#include "materialsystem/imaterialsystemhardwareconfig.h" +#include "materialsystem/imaterialsystem.h" +#include "materialsystem/MaterialSystemUtil.h" +#include "materialsystem/imesh.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/itexture.h" +#include "tier1/KeyValues.h" +#include "toolframework/ienginetool.h" +#include "toolutils/enginetools_int.h" +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "view_shared.h" +#include "texture_group_names.h" +#include "vgui_controls/PropertySheet.h" +#include "tier2/tier2.h" +#include <windows.h> // for MultiByteToWideChar +#include "cdll_int.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +class CMiniViewportEngineRenderArea; + +using namespace vgui; + +extern IMatSystemSurface *g_pMatSystemSurface; + +#define DEFAULT_PREVIEW_WIDTH 1280 + +//----------------------------------------------------------------------------- +// Purpose: This is a "frame" which is used to position the engine +//----------------------------------------------------------------------------- +class CMiniViewportPropertyPage : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CMiniViewportPropertyPage, vgui::EditablePanel ); + +public: + CMiniViewportPropertyPage( Panel *parent, const char *panelName ); + + virtual Color GetBgColor(); + + void GetEngineBounds( int& x, int& y, int& w, int& h ); + + void RenderFrameBegin(); + + CMiniViewportEngineRenderArea *GetViewportArea() { return m_pViewportArea; } + +private: + virtual void PerformLayout(); + + Color m_bgColor; + + CMiniViewportEngineRenderArea *m_pViewportArea; +}; + +//----------------------------------------------------------------------------- +// +// the actual renderable area +// +//----------------------------------------------------------------------------- +class CMiniViewportEngineRenderArea : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CMiniViewportEngineRenderArea, vgui::EditablePanel ); + +public: + CMiniViewportEngineRenderArea( Panel *parent, const char *panelName ); + ~CMiniViewportEngineRenderArea(); + + virtual void PaintBackground(); + virtual void GetEngineBounds( int& x, int& y, int& w, int& h ); + virtual void ApplySchemeSettings( IScheme *pScheme ); + + void RenderFrameBegin(); + void SetOverlayText( const char *pText ); + + // Called when the layoff texture needs to be released + void ReleaseLayoffTexture(); + +protected: + void InitSceneMaterials(); + void ShutdownSceneMaterials(); + + // Paints the black borders around the engine window + void PaintEngineBorders( int x, int y, int w, int h ); + + // Paints the engine window itself + void PaintEngineWindow( int x, int y, int w, int h ); + + // Paints the overlay text + void PaintOverlayText( ); + + int m_nEngineOutputTexture; + vgui::HFont m_OverlayTextFont; + CUtlString m_OverlayText; + + CTextureReference m_ScreenBuffer; + CMaterialReference m_ScreenMaterial; +}; + + +CMiniViewportEngineRenderArea::CMiniViewportEngineRenderArea( Panel *parent, const char *panelName ) + : BaseClass( parent, panelName ) +{ + SetPaintEnabled( false ); + SetPaintBorderEnabled( false ); + SetPaintBackgroundEnabled( true ); + + m_nEngineOutputTexture = vgui::surface()->CreateNewTextureID(); +} + +CMiniViewportEngineRenderArea::~CMiniViewportEngineRenderArea() +{ + ShutdownSceneMaterials(); +} + +void CMiniViewportEngineRenderArea::RenderFrameBegin() +{ + if ( !enginetools->IsInGame() ) + return; + + InitSceneMaterials(); + + CViewSetup playerViewSetup; + int x, y, w, h; + GetEngineBounds( x, y, w, h ); + enginetools->GetPlayerView( playerViewSetup, 0, 0, w, h ); + + // NOTE: This is a workaround to a nasty problem. Vgui uses stencil + // to determing if the panels should occlude each other. The engine + // has now started to use stencil for various random effects. + // To prevent these different stencil uses from clashing, we will + // render the engine prior to vgui painting + cache the result off in + // + // Make the engine draw the scene + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->PushRenderTargetAndViewport( m_ScreenBuffer, 0, 0, w, h ); + + // Tell the engine to tell the client to render the view (sans viewmodel) + enginetools->SetMainView( playerViewSetup.origin, playerViewSetup.angles ); + enginetools->RenderView( playerViewSetup, VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH, RENDERVIEW_DRAWHUD | RENDERVIEW_DRAWVIEWMODEL ); + + // Pop the target + pRenderContext->PopRenderTargetAndViewport(); +} + +void CMiniViewportEngineRenderArea::InitSceneMaterials() +{ + if ( m_ScreenBuffer ) + return; + + if ( g_pMaterialSystem->IsTextureLoaded( "_rt_LayoffResult" ) ) + { + ITexture *pTexture = g_pMaterialSystem->FindTexture( "_rt_LayoffResult", TEXTURE_GROUP_RENDER_TARGET ); + m_ScreenBuffer.Init( pTexture ); + } + else + { + // For now, layoff dimensions match aspect of back buffer + int nBackBufferWidth, nBackBufferHeight; + g_pMaterialSystem->GetBackBufferDimensions( nBackBufferWidth, nBackBufferHeight ); + float flAspect = nBackBufferWidth / (float)nBackBufferHeight; + int nPreviewWidth = min( DEFAULT_PREVIEW_WIDTH, nBackBufferWidth ); + int nPreviewHeight = ( int )( nPreviewWidth / flAspect + 0.5f ); + + g_pMaterialSystem->BeginRenderTargetAllocation(); // Begin allocating RTs which IFM can scribble into + + // LDR final result of either HDR or LDR rendering + m_ScreenBuffer.Init( g_pMaterialSystem->CreateNamedRenderTargetTextureEx2( + "_rt_LayoffResult", nPreviewWidth, nPreviewHeight, RT_SIZE_OFFSCREEN, + g_pMaterialSystem->GetBackBufferFormat(), MATERIAL_RT_DEPTH_SHARED, TEXTUREFLAGS_BORDER ) ); + + g_pMaterialSystem->EndRenderTargetAllocation(); // End allocating RTs which IFM can scribble into + } + + KeyValues *pVMTKeyValues = NULL; + pVMTKeyValues= new KeyValues( "UnlitGeneric" ); + pVMTKeyValues->SetString( "$basetexture", m_ScreenBuffer->GetName() ); + pVMTKeyValues->SetInt( "$nofog", 1 ); + m_ScreenMaterial.Init( "MiniViewportEngineRenderAreaSceneMaterial", pVMTKeyValues ); + m_ScreenMaterial->Refresh(); +} + + +//----------------------------------------------------------------------------- +// Called when the layoff texture needs to be released +//----------------------------------------------------------------------------- +void CMiniViewportEngineRenderArea::ReleaseLayoffTexture() +{ + m_ScreenBuffer.Shutdown(); + m_ScreenMaterial.Shutdown(); +} + + +//----------------------------------------------------------------------------- +// Apply scheme settings +//----------------------------------------------------------------------------- +void CMiniViewportEngineRenderArea::ApplySchemeSettings( IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + m_OverlayTextFont = pScheme->GetFont( "DefaultLargeOutline" ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMiniViewportEngineRenderArea::ShutdownSceneMaterials() +{ + m_ScreenBuffer.Shutdown(); + m_ScreenMaterial.Shutdown(); +} + + +//----------------------------------------------------------------------------- +// Sets text to draw over the window +//----------------------------------------------------------------------------- +void CMiniViewportEngineRenderArea::SetOverlayText( const char *pText ) +{ + m_OverlayText = pText; +} + + +//----------------------------------------------------------------------------- +// Paints the black borders around the engine window +//----------------------------------------------------------------------------- +void CMiniViewportEngineRenderArea::PaintEngineBorders( int x, int y, int w, int h ) +{ + // Draws black borders around the engine window + surface()->DrawSetColor( Color( 0, 0, 0, 255 ) ); + if ( x != 0 ) + { + surface()->DrawFilledRect( 0, 0, x, h ); + surface()->DrawFilledRect( x + w, 0, w + 2 * x, h ); + } + else if ( y != 0 ) + { + surface()->DrawFilledRect( 0, 0, w, y ); + surface()->DrawFilledRect( 0, y + h, w, h + 2 * y ); + } +} + + +//----------------------------------------------------------------------------- +// Paints the overlay text +//----------------------------------------------------------------------------- +void CMiniViewportEngineRenderArea::PaintOverlayText( ) +{ + if ( !m_OverlayText.Length() ) + return; + + int cw, ch; + GetSize( cw, ch ); + + int nTextWidth, nTextHeight; + int nBufLen = m_OverlayText.Length()+1; + wchar_t *pTemp = (wchar_t*)_alloca( nBufLen * sizeof(wchar_t) ); + ::MultiByteToWideChar( CP_UTF8, 0, m_OverlayText.Get(), -1, pTemp, nBufLen ); + + g_pMatSystemSurface->GetTextSize( m_OverlayTextFont, pTemp, nTextWidth, nTextHeight ); + int lx = (cw - nTextWidth) / 2; + if ( lx < 10 ) + { + lx = 10; + } + int ly = ch - 10 - nTextHeight; + g_pMatSystemSurface->DrawColoredTextRect( m_OverlayTextFont, + lx, ly, cw - lx, ch - ly, + 255, 255, 255, 255, "%s", m_OverlayText.Get() ); +} + + +//----------------------------------------------------------------------------- +// Paints the engine window itself +//----------------------------------------------------------------------------- +void CMiniViewportEngineRenderArea::PaintEngineWindow( int x, int y, int w, int h ) +{ + if ( !enginetools->IsInGame() ) + { + surface()->DrawSetColor( Color( 127, 127, 200, 63 ) ); + surface()->DrawFilledRect( x, y, x + w, y + h ); + } + else + { + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + + g_pMatSystemSurface->DrawSetTextureMaterial( m_nEngineOutputTexture, m_ScreenMaterial ); + surface()->DrawSetColor( Color( 0, 0, 0, 255 ) ); + + int nTexWidth = m_ScreenBuffer->GetActualWidth(); + int nTexHeight = m_ScreenBuffer->GetActualHeight(); + float flOOWidth = 1.0f / nTexWidth; + float flOOHeight = 1.0f / nTexHeight; + + float s0, s1, t0, t1; + + s0 = ( 0.5f ) * flOOWidth; + t0 = ( 0.5f ) * flOOHeight; + s1 = ( (float)w - 0.5f ) * flOOWidth; + t1 = ( (float)h - 0.5f ) * flOOHeight; + + vgui::surface()->DrawTexturedSubRect( x, y, x+w, y+h, s0, t0, s1, t1 ); + + PaintOverlayText(); + } +} + +//----------------------------------------------------------------------------- +// Paints the background +//----------------------------------------------------------------------------- +void CMiniViewportEngineRenderArea::PaintBackground() +{ + int x, y, w, h; + GetEngineBounds( x, y, w, h ); + PaintEngineBorders( x, y, w, h ); + PaintEngineWindow( x, y, w, h ); +} + +void CMiniViewportEngineRenderArea::GetEngineBounds( int& x, int& y, int& w, int& h ) +{ + x = 0; + y = 0; + GetSize( w, h ); + + // Check aspect ratio + int sx, sy; + surface()->GetScreenSize( sx, sy ); + + if ( sy > 0 && + h > 0 ) + { + float screenaspect = (float)sx / (float)sy; + float aspect = (float)w / (float)h; + + float ratio = screenaspect / aspect; + + // Screen is wider, need bars at top and bottom + if ( ratio > 1.0f ) + { + int usetall = (float)w / screenaspect; + y = ( h - usetall ) / 2; + h = usetall; + } + // Screen is narrower, need bars at left/right + else + { + int usewide = (float)h * screenaspect; + x = ( w - usewide ) / 2; + w = usewide; + } + } +} + +CMiniViewportPropertyPage::CMiniViewportPropertyPage(Panel *parent, const char *panelName ) : + BaseClass( parent, panelName ) +{ + m_bgColor = Color( 0, 0, 0, 0 ); + + m_pViewportArea = new CMiniViewportEngineRenderArea( this, "Engine" ); +} + +void CMiniViewportPropertyPage::PerformLayout() +{ + BaseClass::PerformLayout(); + + int w, h; + GetSize( w, h ); + m_pViewportArea->SetBounds( 0, 0, w, h ); +} + +Color CMiniViewportPropertyPage::GetBgColor() +{ + return m_bgColor; +} + + +void CMiniViewportPropertyPage::GetEngineBounds( int& x, int& y, int& w, int& h ) +{ + m_pViewportArea->GetEngineBounds( x, y, w, h ); + m_pViewportArea->LocalToScreen( x, y ); +} + +void CMiniViewportPropertyPage::RenderFrameBegin() +{ + m_pViewportArea->RenderFrameBegin(); +} + +CMiniViewport::CMiniViewport( vgui::Panel *parent, bool contextLabel, vgui::IToolWindowFactory *factory /*= 0*/, + vgui::Panel *page /*= NULL*/, char const *title /*= NULL*/, bool contextMenu /*= false*/ ) : + BaseClass( parent, contextLabel, factory, page, title, contextMenu, false ) +{ + SetCloseButtonVisible( false ); + + GetPropertySheet()->SetDraggableTabs( false ); + + // Add the viewport panel + m_hPage = new CMiniViewportPropertyPage( this, "ViewportPage" ); + + AddPage( m_hPage.Get(), "#ToolMiniViewport", false ); +} + +void CMiniViewport::GetViewport( bool& enabled, int& x, int& y, int& w, int& h ) +{ + enabled = false; + x = y = w = h = 0; + + int screenw, screenh; + surface()->GetScreenSize( screenw, screenh ); + + m_hPage->GetEngineBounds( x, y, w, h ); + + y = screenh - ( y + h ); +} + +void CMiniViewport::GetEngineBounds( int& x, int& y, int& w, int& h ) +{ + m_hPage->GetEngineBounds( x, y, w, h ); +} + + +//----------------------------------------------------------------------------- +// Called when the layoff texture needs to be released +//----------------------------------------------------------------------------- +void CMiniViewport::ReleaseLayoffTexture() +{ + if ( m_hPage.Get() ) + { + m_hPage->GetViewportArea()->ReleaseLayoffTexture(); + } +} + + +//----------------------------------------------------------------------------- +// Sets text to draw over the window +//----------------------------------------------------------------------------- +void CMiniViewport::SetOverlayText( const char *pText ) +{ + if ( m_hPage.Get() ) + { + m_hPage->GetViewportArea()->SetOverlayText( pText ); + } +} + +void CMiniViewport::RenderFrameBegin() +{ + if ( m_hPage.Get() ) + { + m_hPage->RenderFrameBegin(); + } +} |