summaryrefslogtreecommitdiff
path: root/tools/toolutils/miniviewport.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/toolutils/miniviewport.cpp')
-rw-r--r--tools/toolutils/miniviewport.cpp457
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();
+ }
+}