|
|
//========= 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(); } }
|