Team Fortress 2 Source Code as on 22/4/2020
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.

457 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "toolutils/miniviewport.h"
  7. #include "tier1/utlstring.h"
  8. #include "vgui/ISurface.h"
  9. #include "materialsystem/imaterialsystemhardwareconfig.h"
  10. #include "materialsystem/imaterialsystem.h"
  11. #include "materialsystem/MaterialSystemUtil.h"
  12. #include "materialsystem/imesh.h"
  13. #include "materialsystem/imaterial.h"
  14. #include "materialsystem/itexture.h"
  15. #include "tier1/KeyValues.h"
  16. #include "toolframework/ienginetool.h"
  17. #include "toolutils/enginetools_int.h"
  18. #include "VGuiMatSurface/IMatSystemSurface.h"
  19. #include "view_shared.h"
  20. #include "texture_group_names.h"
  21. #include "vgui_controls/PropertySheet.h"
  22. #include "tier2/tier2.h"
  23. #include <windows.h> // for MultiByteToWideChar
  24. #include "cdll_int.h"
  25. // memdbgon must be the last include file in a .cpp file!!!
  26. #include "tier0/memdbgon.h"
  27. class CMiniViewportEngineRenderArea;
  28. using namespace vgui;
  29. extern IMatSystemSurface *g_pMatSystemSurface;
  30. #define DEFAULT_PREVIEW_WIDTH 1280
  31. //-----------------------------------------------------------------------------
  32. // Purpose: This is a "frame" which is used to position the engine
  33. //-----------------------------------------------------------------------------
  34. class CMiniViewportPropertyPage : public vgui::EditablePanel
  35. {
  36. DECLARE_CLASS_SIMPLE( CMiniViewportPropertyPage, vgui::EditablePanel );
  37. public:
  38. CMiniViewportPropertyPage( Panel *parent, const char *panelName );
  39. virtual Color GetBgColor();
  40. void GetEngineBounds( int& x, int& y, int& w, int& h );
  41. void RenderFrameBegin();
  42. CMiniViewportEngineRenderArea *GetViewportArea() { return m_pViewportArea; }
  43. private:
  44. virtual void PerformLayout();
  45. Color m_bgColor;
  46. CMiniViewportEngineRenderArea *m_pViewportArea;
  47. };
  48. //-----------------------------------------------------------------------------
  49. //
  50. // the actual renderable area
  51. //
  52. //-----------------------------------------------------------------------------
  53. class CMiniViewportEngineRenderArea : public vgui::EditablePanel
  54. {
  55. DECLARE_CLASS_SIMPLE( CMiniViewportEngineRenderArea, vgui::EditablePanel );
  56. public:
  57. CMiniViewportEngineRenderArea( Panel *parent, const char *panelName );
  58. ~CMiniViewportEngineRenderArea();
  59. virtual void PaintBackground();
  60. virtual void GetEngineBounds( int& x, int& y, int& w, int& h );
  61. virtual void ApplySchemeSettings( IScheme *pScheme );
  62. void RenderFrameBegin();
  63. void SetOverlayText( const char *pText );
  64. // Called when the layoff texture needs to be released
  65. void ReleaseLayoffTexture();
  66. protected:
  67. void InitSceneMaterials();
  68. void ShutdownSceneMaterials();
  69. // Paints the black borders around the engine window
  70. void PaintEngineBorders( int x, int y, int w, int h );
  71. // Paints the engine window itself
  72. void PaintEngineWindow( int x, int y, int w, int h );
  73. // Paints the overlay text
  74. void PaintOverlayText( );
  75. int m_nEngineOutputTexture;
  76. vgui::HFont m_OverlayTextFont;
  77. CUtlString m_OverlayText;
  78. CTextureReference m_ScreenBuffer;
  79. CMaterialReference m_ScreenMaterial;
  80. };
  81. CMiniViewportEngineRenderArea::CMiniViewportEngineRenderArea( Panel *parent, const char *panelName )
  82. : BaseClass( parent, panelName )
  83. {
  84. SetPaintEnabled( false );
  85. SetPaintBorderEnabled( false );
  86. SetPaintBackgroundEnabled( true );
  87. m_nEngineOutputTexture = vgui::surface()->CreateNewTextureID();
  88. }
  89. CMiniViewportEngineRenderArea::~CMiniViewportEngineRenderArea()
  90. {
  91. ShutdownSceneMaterials();
  92. }
  93. void CMiniViewportEngineRenderArea::RenderFrameBegin()
  94. {
  95. if ( !enginetools->IsInGame() )
  96. return;
  97. InitSceneMaterials();
  98. CViewSetup playerViewSetup;
  99. int x, y, w, h;
  100. GetEngineBounds( x, y, w, h );
  101. enginetools->GetPlayerView( playerViewSetup, 0, 0, w, h );
  102. // NOTE: This is a workaround to a nasty problem. Vgui uses stencil
  103. // to determing if the panels should occlude each other. The engine
  104. // has now started to use stencil for various random effects.
  105. // To prevent these different stencil uses from clashing, we will
  106. // render the engine prior to vgui painting + cache the result off in
  107. //
  108. // Make the engine draw the scene
  109. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  110. pRenderContext->PushRenderTargetAndViewport( m_ScreenBuffer, 0, 0, w, h );
  111. // Tell the engine to tell the client to render the view (sans viewmodel)
  112. enginetools->SetMainView( playerViewSetup.origin, playerViewSetup.angles );
  113. enginetools->RenderView( playerViewSetup, VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH, RENDERVIEW_DRAWHUD | RENDERVIEW_DRAWVIEWMODEL );
  114. // Pop the target
  115. pRenderContext->PopRenderTargetAndViewport();
  116. }
  117. void CMiniViewportEngineRenderArea::InitSceneMaterials()
  118. {
  119. if ( m_ScreenBuffer )
  120. return;
  121. if ( g_pMaterialSystem->IsTextureLoaded( "_rt_LayoffResult" ) )
  122. {
  123. ITexture *pTexture = g_pMaterialSystem->FindTexture( "_rt_LayoffResult", TEXTURE_GROUP_RENDER_TARGET );
  124. m_ScreenBuffer.Init( pTexture );
  125. }
  126. else
  127. {
  128. // For now, layoff dimensions match aspect of back buffer
  129. int nBackBufferWidth, nBackBufferHeight;
  130. g_pMaterialSystem->GetBackBufferDimensions( nBackBufferWidth, nBackBufferHeight );
  131. float flAspect = nBackBufferWidth / (float)nBackBufferHeight;
  132. int nPreviewWidth = min( DEFAULT_PREVIEW_WIDTH, nBackBufferWidth );
  133. int nPreviewHeight = ( int )( nPreviewWidth / flAspect + 0.5f );
  134. g_pMaterialSystem->BeginRenderTargetAllocation(); // Begin allocating RTs which IFM can scribble into
  135. // LDR final result of either HDR or LDR rendering
  136. m_ScreenBuffer.Init( g_pMaterialSystem->CreateNamedRenderTargetTextureEx2(
  137. "_rt_LayoffResult", nPreviewWidth, nPreviewHeight, RT_SIZE_OFFSCREEN,
  138. g_pMaterialSystem->GetBackBufferFormat(), MATERIAL_RT_DEPTH_SHARED, TEXTUREFLAGS_BORDER ) );
  139. g_pMaterialSystem->EndRenderTargetAllocation(); // End allocating RTs which IFM can scribble into
  140. }
  141. KeyValues *pVMTKeyValues = NULL;
  142. pVMTKeyValues= new KeyValues( "UnlitGeneric" );
  143. pVMTKeyValues->SetString( "$basetexture", m_ScreenBuffer->GetName() );
  144. pVMTKeyValues->SetInt( "$nofog", 1 );
  145. m_ScreenMaterial.Init( "MiniViewportEngineRenderAreaSceneMaterial", pVMTKeyValues );
  146. m_ScreenMaterial->Refresh();
  147. }
  148. //-----------------------------------------------------------------------------
  149. // Called when the layoff texture needs to be released
  150. //-----------------------------------------------------------------------------
  151. void CMiniViewportEngineRenderArea::ReleaseLayoffTexture()
  152. {
  153. m_ScreenBuffer.Shutdown();
  154. m_ScreenMaterial.Shutdown();
  155. }
  156. //-----------------------------------------------------------------------------
  157. // Apply scheme settings
  158. //-----------------------------------------------------------------------------
  159. void CMiniViewportEngineRenderArea::ApplySchemeSettings( IScheme *pScheme )
  160. {
  161. BaseClass::ApplySchemeSettings( pScheme );
  162. m_OverlayTextFont = pScheme->GetFont( "DefaultLargeOutline" );
  163. }
  164. //-----------------------------------------------------------------------------
  165. // Purpose:
  166. //-----------------------------------------------------------------------------
  167. void CMiniViewportEngineRenderArea::ShutdownSceneMaterials()
  168. {
  169. m_ScreenBuffer.Shutdown();
  170. m_ScreenMaterial.Shutdown();
  171. }
  172. //-----------------------------------------------------------------------------
  173. // Sets text to draw over the window
  174. //-----------------------------------------------------------------------------
  175. void CMiniViewportEngineRenderArea::SetOverlayText( const char *pText )
  176. {
  177. m_OverlayText = pText;
  178. }
  179. //-----------------------------------------------------------------------------
  180. // Paints the black borders around the engine window
  181. //-----------------------------------------------------------------------------
  182. void CMiniViewportEngineRenderArea::PaintEngineBorders( int x, int y, int w, int h )
  183. {
  184. // Draws black borders around the engine window
  185. surface()->DrawSetColor( Color( 0, 0, 0, 255 ) );
  186. if ( x != 0 )
  187. {
  188. surface()->DrawFilledRect( 0, 0, x, h );
  189. surface()->DrawFilledRect( x + w, 0, w + 2 * x, h );
  190. }
  191. else if ( y != 0 )
  192. {
  193. surface()->DrawFilledRect( 0, 0, w, y );
  194. surface()->DrawFilledRect( 0, y + h, w, h + 2 * y );
  195. }
  196. }
  197. //-----------------------------------------------------------------------------
  198. // Paints the overlay text
  199. //-----------------------------------------------------------------------------
  200. void CMiniViewportEngineRenderArea::PaintOverlayText( )
  201. {
  202. if ( !m_OverlayText.Length() )
  203. return;
  204. int cw, ch;
  205. GetSize( cw, ch );
  206. int nTextWidth, nTextHeight;
  207. int nBufLen = m_OverlayText.Length()+1;
  208. wchar_t *pTemp = (wchar_t*)_alloca( nBufLen * sizeof(wchar_t) );
  209. ::MultiByteToWideChar( CP_UTF8, 0, m_OverlayText.Get(), -1, pTemp, nBufLen );
  210. g_pMatSystemSurface->GetTextSize( m_OverlayTextFont, pTemp, nTextWidth, nTextHeight );
  211. int lx = (cw - nTextWidth) / 2;
  212. if ( lx < 10 )
  213. {
  214. lx = 10;
  215. }
  216. int ly = ch - 10 - nTextHeight;
  217. g_pMatSystemSurface->DrawColoredTextRect( m_OverlayTextFont,
  218. lx, ly, cw - lx, ch - ly,
  219. 255, 255, 255, 255, "%s", m_OverlayText.Get() );
  220. }
  221. //-----------------------------------------------------------------------------
  222. // Paints the engine window itself
  223. //-----------------------------------------------------------------------------
  224. void CMiniViewportEngineRenderArea::PaintEngineWindow( int x, int y, int w, int h )
  225. {
  226. if ( !enginetools->IsInGame() )
  227. {
  228. surface()->DrawSetColor( Color( 127, 127, 200, 63 ) );
  229. surface()->DrawFilledRect( x, y, x + w, y + h );
  230. }
  231. else
  232. {
  233. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  234. g_pMatSystemSurface->DrawSetTextureMaterial( m_nEngineOutputTexture, m_ScreenMaterial );
  235. surface()->DrawSetColor( Color( 0, 0, 0, 255 ) );
  236. int nTexWidth = m_ScreenBuffer->GetActualWidth();
  237. int nTexHeight = m_ScreenBuffer->GetActualHeight();
  238. float flOOWidth = 1.0f / nTexWidth;
  239. float flOOHeight = 1.0f / nTexHeight;
  240. float s0, s1, t0, t1;
  241. s0 = ( 0.5f ) * flOOWidth;
  242. t0 = ( 0.5f ) * flOOHeight;
  243. s1 = ( (float)w - 0.5f ) * flOOWidth;
  244. t1 = ( (float)h - 0.5f ) * flOOHeight;
  245. vgui::surface()->DrawTexturedSubRect( x, y, x+w, y+h, s0, t0, s1, t1 );
  246. PaintOverlayText();
  247. }
  248. }
  249. //-----------------------------------------------------------------------------
  250. // Paints the background
  251. //-----------------------------------------------------------------------------
  252. void CMiniViewportEngineRenderArea::PaintBackground()
  253. {
  254. int x, y, w, h;
  255. GetEngineBounds( x, y, w, h );
  256. PaintEngineBorders( x, y, w, h );
  257. PaintEngineWindow( x, y, w, h );
  258. }
  259. void CMiniViewportEngineRenderArea::GetEngineBounds( int& x, int& y, int& w, int& h )
  260. {
  261. x = 0;
  262. y = 0;
  263. GetSize( w, h );
  264. // Check aspect ratio
  265. int sx, sy;
  266. surface()->GetScreenSize( sx, sy );
  267. if ( sy > 0 &&
  268. h > 0 )
  269. {
  270. float screenaspect = (float)sx / (float)sy;
  271. float aspect = (float)w / (float)h;
  272. float ratio = screenaspect / aspect;
  273. // Screen is wider, need bars at top and bottom
  274. if ( ratio > 1.0f )
  275. {
  276. int usetall = (float)w / screenaspect;
  277. y = ( h - usetall ) / 2;
  278. h = usetall;
  279. }
  280. // Screen is narrower, need bars at left/right
  281. else
  282. {
  283. int usewide = (float)h * screenaspect;
  284. x = ( w - usewide ) / 2;
  285. w = usewide;
  286. }
  287. }
  288. }
  289. CMiniViewportPropertyPage::CMiniViewportPropertyPage(Panel *parent, const char *panelName ) :
  290. BaseClass( parent, panelName )
  291. {
  292. m_bgColor = Color( 0, 0, 0, 0 );
  293. m_pViewportArea = new CMiniViewportEngineRenderArea( this, "Engine" );
  294. }
  295. void CMiniViewportPropertyPage::PerformLayout()
  296. {
  297. BaseClass::PerformLayout();
  298. int w, h;
  299. GetSize( w, h );
  300. m_pViewportArea->SetBounds( 0, 0, w, h );
  301. }
  302. Color CMiniViewportPropertyPage::GetBgColor()
  303. {
  304. return m_bgColor;
  305. }
  306. void CMiniViewportPropertyPage::GetEngineBounds( int& x, int& y, int& w, int& h )
  307. {
  308. m_pViewportArea->GetEngineBounds( x, y, w, h );
  309. m_pViewportArea->LocalToScreen( x, y );
  310. }
  311. void CMiniViewportPropertyPage::RenderFrameBegin()
  312. {
  313. m_pViewportArea->RenderFrameBegin();
  314. }
  315. CMiniViewport::CMiniViewport( vgui::Panel *parent, bool contextLabel, vgui::IToolWindowFactory *factory /*= 0*/,
  316. vgui::Panel *page /*= NULL*/, char const *title /*= NULL*/, bool contextMenu /*= false*/ ) :
  317. BaseClass( parent, contextLabel, factory, page, title, contextMenu, false )
  318. {
  319. SetCloseButtonVisible( false );
  320. GetPropertySheet()->SetDraggableTabs( false );
  321. // Add the viewport panel
  322. m_hPage = new CMiniViewportPropertyPage( this, "ViewportPage" );
  323. AddPage( m_hPage.Get(), "#ToolMiniViewport", false );
  324. }
  325. void CMiniViewport::GetViewport( bool& enabled, int& x, int& y, int& w, int& h )
  326. {
  327. enabled = false;
  328. x = y = w = h = 0;
  329. int screenw, screenh;
  330. surface()->GetScreenSize( screenw, screenh );
  331. m_hPage->GetEngineBounds( x, y, w, h );
  332. y = screenh - ( y + h );
  333. }
  334. void CMiniViewport::GetEngineBounds( int& x, int& y, int& w, int& h )
  335. {
  336. m_hPage->GetEngineBounds( x, y, w, h );
  337. }
  338. //-----------------------------------------------------------------------------
  339. // Called when the layoff texture needs to be released
  340. //-----------------------------------------------------------------------------
  341. void CMiniViewport::ReleaseLayoffTexture()
  342. {
  343. if ( m_hPage.Get() )
  344. {
  345. m_hPage->GetViewportArea()->ReleaseLayoffTexture();
  346. }
  347. }
  348. //-----------------------------------------------------------------------------
  349. // Sets text to draw over the window
  350. //-----------------------------------------------------------------------------
  351. void CMiniViewport::SetOverlayText( const char *pText )
  352. {
  353. if ( m_hPage.Get() )
  354. {
  355. m_hPage->GetViewportArea()->SetOverlayText( pText );
  356. }
  357. }
  358. void CMiniViewport::RenderFrameBegin()
  359. {
  360. if ( m_hPage.Get() )
  361. {
  362. m_hPage->RenderFrameBegin();
  363. }
  364. }