You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
430 lines
12 KiB
430 lines
12 KiB
//====== Copyright © 1996-2005, 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 "tier3/tier3.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;
|
|
|
|
#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 );
|
|
|
|
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();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// 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 );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// 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();
|
|
}
|
|
}
|