Counter Strike : Global Offensive Source Code
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.

820 lines
20 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include <mxtk/mx.h>
  7. #include <mxtk/mxMessageBox.h>
  8. #include <mxtk/mxTga.h>
  9. #include <mxtk/mxPcx.h>
  10. #include <mxtk/mxBmp.h>
  11. #include <mxtk/mxMatSysWindow.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <time.h>
  15. #include <string.h>
  16. #include "MatSysWin.h"
  17. #include "MDLViewer.h"
  18. #include "StudioModel.h"
  19. #include "ControlPanel.h"
  20. #include "ViewerSettings.h"
  21. #include "materialsystem/imaterialsystem.h"
  22. #include "materialsystem/imaterialproxyfactory.h"
  23. #include "FileSystem.h"
  24. #include <KeyValues.h>
  25. #include "materialsystem/IMesh.h"
  26. #include "expressions.h"
  27. #include "hlfaceposer.h"
  28. #include "ifaceposersound.h"
  29. #include "materialsystem/IMaterialSystemHardwareConfig.h"
  30. #include "materialsystem/ITexture.h"
  31. #include "materialsystem/MaterialSystem_Config.h"
  32. #include "istudiorender.h"
  33. #include "choreowidgetdrawhelper.h"
  34. #include "faceposer_models.h"
  35. #include "tier0/icommandline.h"
  36. #include "mathlib/vmatrix.h"
  37. #include "vstdlib/cvar.h"
  38. IFileSystem *filesystem = NULL;
  39. extern char g_appTitle[];
  40. // FIXME: move all this to mxMatSysWin
  41. class DummyMaterialProxyFactory : public IMaterialProxyFactory
  42. {
  43. public:
  44. virtual IMaterialProxy *CreateProxy( const char *proxyName ) {return NULL;}
  45. virtual void DeleteProxy( IMaterialProxy *pProxy ) {}
  46. virtual CreateInterfaceFn GetFactory() {return NULL;}
  47. };
  48. DummyMaterialProxyFactory g_DummyMaterialProxyFactory;
  49. static void ReleaseMaterialSystemObjects( int nChangeFlags )
  50. {
  51. StudioModel::ReleaseStudioModel();
  52. models->ReleaseModels();
  53. }
  54. static void RestoreMaterialSystemObjects( int nChangeFlags )
  55. {
  56. StudioModel::RestoreStudioModel();
  57. models->RestoreModels();
  58. }
  59. void InitMaterialSystemConfig(MaterialSystem_Config_t *pConfig)
  60. {
  61. pConfig->SetFlag( MATSYS_VIDCFG_FLAGS_USING_MULTIPLE_WINDOWS, true );
  62. }
  63. Vector g_vright( 50, 50, 0 ); // needs to be set to viewer's right in order for chrome to work
  64. IMaterial *g_materialBackground = NULL;
  65. IMaterial *g_materialWireframe = NULL;
  66. IMaterial *g_materialWireframeVertexColor = NULL;
  67. IMaterial *g_materialWireframeVertexColorNoCull = NULL;
  68. IMaterial *g_materialDebugCopyBaseTexture = NULL;
  69. IMaterial *g_materialFlatshaded = NULL;
  70. IMaterial *g_materialSmoothshaded = NULL;
  71. IMaterial *g_materialBones = NULL;
  72. IMaterial *g_materialLines = NULL;
  73. IMaterial *g_materialFloor = NULL;
  74. IMaterial *g_materialVertexColor = NULL;
  75. IMaterial *g_materialShadow = NULL;
  76. IMaterial *g_materialArcActive = NULL;
  77. IMaterial *g_materialArcInActive = NULL;
  78. IMaterial *g_materialDebugText = NULL;
  79. MatSysWindow *g_pMatSysWindow = 0;
  80. #define MATSYSWIN_NAME "3D View"
  81. MatSysWindow::MatSysWindow (mxWindow *parent, int x, int y, int w, int h, const char *label, int style)
  82. : IFacePoserToolWindow( "3D View", "3D View" ), mxMatSysWindow ( parent, x, y, w, h, label, style )
  83. {
  84. g_pMaterialSystem->SetMaterialProxyFactory( &g_DummyMaterialProxyFactory );
  85. SetAutoProcess( true );
  86. setLabel( MATSYSWIN_NAME );
  87. m_bSuppressSwap = false;
  88. m_hWnd = (HWND)getHandle();
  89. Con_Printf( "Setting material system video mode\n" );
  90. MaterialSystem_Config_t config;
  91. config = g_pMaterialSystem->GetCurrentConfigForVideoCard();
  92. InitMaterialSystemConfig(&config);
  93. g_pMaterialSystem->OverrideConfig( config, false );
  94. // config.m_VideoMode.m_Width = config.m_VideoMode.m_Height = 0;
  95. config.SetFlag( MATSYS_VIDCFG_FLAGS_WINDOWED, true );
  96. config.SetFlag( MATSYS_VIDCFG_FLAGS_RESIZING, true );
  97. if (!g_pMaterialSystem->SetMode( ( void * )m_hWnd, config ) )
  98. {
  99. return;
  100. }
  101. g_pMaterialSystem->AddReleaseFunc( ReleaseMaterialSystemObjects );
  102. g_pMaterialSystem->AddRestoreFunc( RestoreMaterialSystemObjects );
  103. Con_Printf( "Loading debug materials\n" );
  104. ITexture *pCubemapTexture = g_pMaterialSystem->FindTexture( "hlmv/cubemap", NULL, true );
  105. pCubemapTexture->IncrementReferenceCount();
  106. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  107. pRenderContext->BindLocalCubemap( pCubemapTexture );
  108. g_materialBackground = g_pMaterialSystem->FindMaterial("particle/particleapp_background", TEXTURE_GROUP_OTHER, true);
  109. g_materialWireframe = g_pMaterialSystem->FindMaterial("debug/debugmrmwireframe", TEXTURE_GROUP_OTHER, true);
  110. g_materialWireframeVertexColor = g_pMaterialSystem->FindMaterial("debug/debugwireframevertexcolor", TEXTURE_GROUP_OTHER, true);
  111. // test: create this from code - you need a vmt to make $nocull 1 happen, can't do it from the render context
  112. {
  113. KeyValues *pVMTKeyValues = new KeyValues( "Wireframe" );
  114. pVMTKeyValues->SetInt("$ignorez", 1);
  115. pVMTKeyValues->SetInt("$nocull", 1);
  116. pVMTKeyValues->SetInt("$vertexcolor", 1);
  117. pVMTKeyValues->SetInt("$decal", 1);
  118. g_materialWireframeVertexColorNoCull = g_pMaterialSystem->CreateMaterial( "debug/wireframenocull", pVMTKeyValues );
  119. }
  120. {
  121. KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
  122. pVMTKeyValues->SetString("$basetexture", "vgui/white" );
  123. g_materialDebugCopyBaseTexture = g_pMaterialSystem->CreateMaterial( "debug/copybasetexture", pVMTKeyValues );
  124. }
  125. g_materialFlatshaded = g_pMaterialSystem->FindMaterial("debug/debugdrawflatpolygons", TEXTURE_GROUP_OTHER, true);
  126. g_materialSmoothshaded = g_pMaterialSystem->FindMaterial("debug/debugmrmfullbright2", TEXTURE_GROUP_OTHER, true);
  127. g_materialBones = g_pMaterialSystem->FindMaterial("debug/debugmrmwireframe", TEXTURE_GROUP_OTHER, true);
  128. g_materialLines = g_pMaterialSystem->FindMaterial("debug/debugwireframevertexcolor", TEXTURE_GROUP_OTHER, true);
  129. g_materialFloor = g_pMaterialSystem->FindMaterial("hlmv/floor", TEXTURE_GROUP_OTHER, true);
  130. g_materialVertexColor = g_pMaterialSystem->FindMaterial("debug/debugvertexcolor", TEXTURE_GROUP_OTHER, true);
  131. g_materialShadow = g_pMaterialSystem->FindMaterial("hlmv/shadow", TEXTURE_GROUP_OTHER, true);
  132. if (!parent)
  133. setVisible (true);
  134. else
  135. mx::setIdleWindow (this);
  136. m_bSuppressResize = false;
  137. m_stickyDepth = 0;
  138. m_bIsSticky = false;
  139. m_snapshotDepth = 0;
  140. }
  141. MatSysWindow::~MatSysWindow ()
  142. {
  143. mx::setIdleWindow (0);
  144. }
  145. void MatSysWindow::redraw()
  146. {
  147. // this gets called recursivly when an Assert dialogue pops up!
  148. static bool bInRedraw;
  149. if (!bInRedraw)
  150. {
  151. bInRedraw = true;
  152. BaseClass::redraw();
  153. bInRedraw = false;
  154. }
  155. return;
  156. if ( IsLocked() )
  157. {
  158. RECT bounds;
  159. GetClientRect( (HWND)getHandle(), &bounds );
  160. bounds.bottom = bounds.top + GetCaptionHeight();
  161. CChoreoWidgetDrawHelper helper( this, bounds );
  162. HandleToolRedraw( helper );
  163. }
  164. }
  165. #define MAX_FPS 250.0f
  166. #define MIN_TIMESTEP ( 1.0f / MAX_FPS )
  167. double realtime = 0.0f;
  168. void MatSysWindow::Frame( void )
  169. {
  170. static bool recursion_guard = false;
  171. static double prev = 0.0;
  172. double curr = (double) mx::getTickCount () / 1000.0;
  173. double dt = ( curr - prev );
  174. if ( recursion_guard )
  175. return;
  176. recursion_guard = true;
  177. // clamp to MAX_FPS
  178. if ( dt >= 0.0 && dt < MIN_TIMESTEP )
  179. {
  180. Sleep( max( 0, (int)( ( MIN_TIMESTEP - dt ) * 1000.0f ) ) );
  181. recursion_guard = false;
  182. return;
  183. }
  184. if ( prev != 0.0 )
  185. {
  186. dt = min( 0.1, dt );
  187. g_MDLViewer->Think( dt );
  188. realtime += dt;
  189. }
  190. prev = curr;
  191. DrawFrame();
  192. recursion_guard = false;
  193. }
  194. void MatSysWindow::DrawFrame( void )
  195. {
  196. if (!g_viewerSettings.pause)
  197. {
  198. redraw ();
  199. }
  200. }
  201. int MatSysWindow::handleEvent (mxEvent *event)
  202. {
  203. MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
  204. int iret = 0;
  205. if ( HandleToolEvent( event ) )
  206. {
  207. return iret;
  208. }
  209. static float oldrx = 0, oldry = 0, oldtz = 50, oldtx = 0, oldty = 0;
  210. static float oldlrx = 0, oldlry = 0;
  211. static int oldx, oldy;
  212. switch (event->event)
  213. {
  214. case mxEvent::Idle:
  215. {
  216. iret = 1;
  217. Frame();
  218. }
  219. break;
  220. case mxEvent::MouseDown:
  221. {
  222. StudioModel *pModel = models->GetActiveStudioModel();
  223. if (!pModel)
  224. break;
  225. oldrx = pModel->m_angles[0];
  226. oldry = pModel->m_angles[1];
  227. oldtx = pModel->m_origin[0];
  228. oldty = pModel->m_origin[1];
  229. oldtz = pModel->m_origin[2];
  230. oldx = (short)event->x;
  231. oldy = (short)event->y;
  232. oldlrx = g_viewerSettings.lightrot[0];
  233. oldlry = g_viewerSettings.lightrot[1];
  234. g_viewerSettings.pause = false;
  235. float r = 1.0/3.0 * min( w(), h() );
  236. float d = sqrt( ( float )( (event->x - w()/2) * (event->x - w()/2) + (event->y - h()/2) * (event->y - h()/2) ) );
  237. if (d < r)
  238. g_viewerSettings.rotating = false;
  239. else
  240. g_viewerSettings.rotating = true;
  241. iret = 1;
  242. }
  243. break;
  244. case mxEvent::MouseDrag:
  245. {
  246. StudioModel *pModel = models->GetActiveStudioModel();
  247. if (!pModel)
  248. break;
  249. if (event->buttons & mxEvent::MouseLeftButton)
  250. {
  251. if (event->modifiers & mxEvent::KeyShift)
  252. {
  253. pModel->m_origin[1] = oldty - (float) ((short)event->x - oldx) * 0.1;
  254. pModel->m_origin[2] = oldtz + (float) ((short)event->y - oldy) * 0.1;
  255. }
  256. else if (event->modifiers & mxEvent::KeyCtrl)
  257. {
  258. float ry = (float) (event->y - oldy);
  259. float rx = (float) (event->x - oldx);
  260. oldx = event->x;
  261. oldy = event->y;
  262. QAngle movement = QAngle( ry, rx, 0 );
  263. matrix3x4_t tmp1, tmp2, tmp3;
  264. AngleMatrix( g_viewerSettings.lightrot, tmp1 );
  265. AngleMatrix( movement, tmp2 );
  266. ConcatTransforms( tmp2, tmp1, tmp3 );
  267. MatrixAngles( tmp3, g_viewerSettings.lightrot );
  268. }
  269. else
  270. {
  271. if (!g_viewerSettings.rotating)
  272. {
  273. float ry = (float) (event->y - oldy);
  274. float rx = (float) (event->x - oldx);
  275. oldx = event->x;
  276. oldy = event->y;
  277. QAngle movement;
  278. matrix3x4_t tmp1, tmp2, tmp3;
  279. movement = QAngle( 0, rx, 0 );
  280. AngleMatrix( pModel->m_angles, tmp1 );
  281. AngleMatrix( movement, tmp2 );
  282. ConcatTransforms( tmp1, tmp2, tmp3 );
  283. MatrixAngles( tmp3, pModel->m_angles );
  284. movement = QAngle( ry, 0, 0 );
  285. AngleMatrix( pModel->m_angles, tmp1 );
  286. AngleMatrix( movement, tmp2 );
  287. ConcatTransforms( tmp2, tmp1, tmp3 );
  288. MatrixAngles( tmp3, pModel->m_angles );
  289. }
  290. else
  291. {
  292. float ang1 = (180 / 3.1415) * atan2( oldx - w()/2.0, oldy - h()/2.0 );
  293. float ang2 = (180 / 3.1415) * atan2( event->x - w()/2.0, event->y - h()/2.0 );
  294. oldx = event->x;
  295. oldy = event->y;
  296. QAngle movement = QAngle( 0, 0, ang2 - ang1 );
  297. matrix3x4_t tmp1, tmp2, tmp3;
  298. AngleMatrix( pModel->m_angles, tmp1 );
  299. AngleMatrix( movement, tmp2 );
  300. ConcatTransforms( tmp2, tmp1, tmp3 );
  301. MatrixAngles( tmp3, pModel->m_angles );
  302. }
  303. }
  304. }
  305. else if (event->buttons & mxEvent::MouseRightButton)
  306. {
  307. pModel->m_origin[0] = oldtx + (float) ((short)event->y - oldy) * 0.1;
  308. pModel->m_origin[0] = clamp( pModel->m_origin[0], 8.0f, 2048.0f );
  309. }
  310. redraw ();
  311. iret = 1;
  312. }
  313. break;
  314. case mxEvent::KeyDown:
  315. {
  316. iret = 1;
  317. switch (event->key)
  318. {
  319. default:
  320. iret = 0;
  321. break;
  322. case 116: // F5
  323. {
  324. g_MDLViewer->Refresh();
  325. }
  326. break;
  327. case 32:
  328. {
  329. int iSeq = models->GetActiveStudioModel()->GetSequence();
  330. if (iSeq == models->GetActiveStudioModel()->SetSequence (iSeq + 1))
  331. {
  332. g_pControlPanel->setSequence( 0 );
  333. }
  334. else
  335. {
  336. g_pControlPanel->setSequence( iSeq + 1 );
  337. }
  338. }
  339. break;
  340. case 27:
  341. if (!getParent ()) // fullscreen mode ?
  342. mx::quit ();
  343. break;
  344. case 'g':
  345. g_viewerSettings.showGround = !g_viewerSettings.showGround;
  346. break;
  347. case 'h':
  348. g_viewerSettings.showHitBoxes = !g_viewerSettings.showHitBoxes;
  349. break;
  350. case 'o':
  351. g_viewerSettings.showBones = !g_viewerSettings.showBones;
  352. break;
  353. case 'b':
  354. g_viewerSettings.showBackground = !g_viewerSettings.showBackground;
  355. break;
  356. case 'm':
  357. g_viewerSettings.showMovement = !g_viewerSettings.showMovement;
  358. break;
  359. case '1':
  360. case '2':
  361. case '3':
  362. case '4':
  363. g_viewerSettings.renderMode = event->key - '1';
  364. break;
  365. case '-':
  366. g_viewerSettings.speedScale -= 0.1f;
  367. if (g_viewerSettings.speedScale < 0.0f)
  368. g_viewerSettings.speedScale = 0.0f;
  369. break;
  370. case '+':
  371. g_viewerSettings.speedScale += 0.1f;
  372. if (g_viewerSettings.speedScale > 5.0f)
  373. g_viewerSettings.speedScale = 5.0f;
  374. break;
  375. }
  376. }
  377. break;
  378. } // switch (event->event)
  379. return iret;
  380. }
  381. void
  382. drawFloor ()
  383. {
  384. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  385. pRenderContext->Bind(g_materialFloor);
  386. pRenderContext->MatrixMode(MATERIAL_MODEL);
  387. pRenderContext->PushMatrix();
  388. pRenderContext->LoadIdentity();
  389. pRenderContext->MatrixMode(MATERIAL_VIEW);
  390. pRenderContext->PushMatrix();
  391. pRenderContext->LoadIdentity();
  392. {
  393. IMesh* pMesh = pRenderContext->GetDynamicMesh();
  394. CMeshBuilder meshBuilder;
  395. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  396. float dist=-15000.0f;
  397. float tMin=0, tMax=1;
  398. meshBuilder.Position3f(-dist, dist, dist);
  399. meshBuilder.TexCoord2f( 0, tMin,tMax );
  400. meshBuilder.Color4ub( 255, 255, 255, 255 );
  401. meshBuilder.AdvanceVertex();
  402. meshBuilder.Position3f( dist, dist, dist);
  403. meshBuilder.TexCoord2f( 0, tMax,tMax );
  404. meshBuilder.Color4ub( 255, 255, 255, 255 );
  405. meshBuilder.AdvanceVertex();
  406. meshBuilder.Position3f( dist,-dist, dist);
  407. meshBuilder.TexCoord2f( 0, tMax,tMin );
  408. meshBuilder.Color4ub( 255, 255, 255, 255 );
  409. meshBuilder.AdvanceVertex();
  410. meshBuilder.Position3f(-dist,-dist, dist);
  411. meshBuilder.TexCoord2f( 0, tMin,tMin );
  412. meshBuilder.Color4ub( 255, 255, 255, 255 );
  413. meshBuilder.AdvanceVertex();
  414. meshBuilder.End();
  415. pMesh->Draw();
  416. }
  417. pRenderContext->MatrixMode(MATERIAL_MODEL);
  418. pRenderContext->PopMatrix();
  419. pRenderContext->MatrixMode(MATERIAL_VIEW);
  420. pRenderContext->PopMatrix();
  421. }
  422. void
  423. setupRenderMode ()
  424. {
  425. }
  426. void MatSysWindow::SuppressBufferSwap( bool bSuppress )
  427. {
  428. m_bSuppressSwap = bSuppress;
  429. }
  430. void MatSysWindow::draw ()
  431. {
  432. if ( CommandLine()->FindParm( "-noshaderapi" ) )
  433. return;
  434. int i;
  435. g_pMaterialSystem->BeginFrame( 0 );
  436. CUtlVector< StudioModel * > modellist;
  437. modellist.AddToTail( models->GetActiveStudioModel() );
  438. if ( models->CountVisibleModels() > 0 )
  439. {
  440. modellist.RemoveAll();
  441. for ( i = 0; i < models->Count(); i++ )
  442. {
  443. if ( models->IsModelShownIn3DView( i ) )
  444. {
  445. modellist.AddToTail( models->GetStudioModel( i ) );
  446. }
  447. }
  448. }
  449. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  450. pRenderContext->ClearBuffers(true, true);
  451. int captiony = GetCaptionHeight();
  452. int viewh = h2() - captiony;
  453. g_pMaterialSystem->SetView( (HWND)getHandle() );
  454. pRenderContext->Viewport( 0, captiony, w2(), viewh );
  455. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  456. pRenderContext->LoadIdentity( );
  457. pRenderContext->PerspectiveX(20.0f, (float)w2() / (float)viewh, 1.0f, 20000.0f);
  458. pRenderContext->MatrixMode( MATERIAL_VIEW );
  459. pRenderContext->LoadIdentity( );
  460. // FIXME: why is this needed? Doesn't SetView() override this?
  461. pRenderContext->Rotate( -90, 1, 0, 0 ); // put Z going up
  462. pRenderContext->Rotate( -90, 0, 0, 1 );
  463. int modelcount = modellist.Count();
  464. int countover2 = modelcount / 2;
  465. int ydelta = g_pControlPanel->GetModelGap();
  466. int yoffset = -countover2 * ydelta;
  467. for ( i = 0 ; i < modelcount; i++ )
  468. {
  469. modellist[ i ]->IncrementFramecounter( );
  470. Vector oldtrans = modellist[ i ]->m_origin;
  471. modellist[ i ]->m_origin[ 1 ] = oldtrans[ 1 ] + yoffset;
  472. yoffset += ydelta;
  473. modellist[ i ]->GetStudioRender()->BeginFrame();
  474. modellist[ i ]->DrawModel();
  475. modellist[ i ]->GetStudioRender()->EndFrame();
  476. modellist[ i ]->m_origin = oldtrans;
  477. }
  478. //
  479. // draw ground
  480. //
  481. if (g_viewerSettings.showGround)
  482. {
  483. drawFloor ();
  484. }
  485. if (!m_bSuppressSwap)
  486. {
  487. g_pMaterialSystem->SwapBuffers();
  488. }
  489. g_pMaterialSystem->EndFrame();
  490. }
  491. void MatSysWindow::EnableStickySnapshotMode( )
  492. {
  493. m_stickyDepth++;
  494. }
  495. void MatSysWindow::DisableStickySnapshotMode( )
  496. {
  497. if (--m_stickyDepth == 0)
  498. {
  499. if (m_bIsSticky)
  500. {
  501. m_bIsSticky = false;
  502. HWND wnd = (HWND)getHandle();
  503. // Move back to original position
  504. SetWindowPlacement( wnd, &m_wp );
  505. SuppressResize( false );
  506. SetCursor( m_hPrevCursor );
  507. }
  508. }
  509. }
  510. void MatSysWindow::PushSnapshotMode( int nSnapShotSize )
  511. {
  512. if (m_snapshotDepth++ == 0)
  513. {
  514. if (m_stickyDepth)
  515. {
  516. if (m_bIsSticky)
  517. return;
  518. m_bIsSticky = true;
  519. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) );
  520. }
  521. SuppressResize( true );
  522. RECT rcClient;
  523. HWND wnd = (HWND)getHandle();
  524. GetWindowPlacement( wnd, &m_wp );
  525. GetClientRect( wnd, &rcClient );
  526. MoveWindow( wnd, 0, 0, nSnapShotSize + 16, nSnapShotSize + 16, TRUE );
  527. }
  528. }
  529. void MatSysWindow::PopSnapshotMode( )
  530. {
  531. if (--m_snapshotDepth == 0)
  532. {
  533. if (m_stickyDepth == 0)
  534. {
  535. HWND wnd = (HWND)getHandle();
  536. // Move back to original position
  537. SetWindowPlacement( wnd, &m_wp );
  538. SuppressResize( false );
  539. }
  540. }
  541. }
  542. void MatSysWindow::TakeSnapshotRect( const char *pFilename, int x, int y, int w, int h )
  543. {
  544. int i;
  545. HANDLE hf;
  546. BITMAPFILEHEADER hdr;
  547. BITMAPINFOHEADER bi;
  548. DWORD dwTmp, imageSize;
  549. byte *hp, b, *pBlue, *pRed;
  550. w = ( w + 3 ) & ~3;
  551. imageSize = w * h * 3;
  552. // Create the file
  553. hf = CreateFile( pFilename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
  554. if( hf == INVALID_HANDLE_VALUE )
  555. {
  556. return;
  557. }
  558. // file header
  559. hdr.bfType = 0x4d42; // 'BM'
  560. hdr.bfSize = (DWORD) ( sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + imageSize );
  561. hdr.bfReserved1 = 0;
  562. hdr.bfReserved2 = 0;
  563. hdr.bfOffBits = (DWORD) ( sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) );
  564. if( !WriteFile( hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER), (LPDWORD) &dwTmp, NULL ) )
  565. Error( "Couldn't write file header to snapshot.\n" );
  566. // bitmap header
  567. bi.biSize = sizeof(BITMAPINFOHEADER);
  568. bi.biWidth = w;
  569. bi.biHeight = h;
  570. bi.biPlanes = 1;
  571. bi.biBitCount = 24;
  572. bi.biCompression = BI_RGB;
  573. bi.biSizeImage = 0; //vid.rowbytes * vid.height;
  574. bi.biXPelsPerMeter = 0;
  575. bi.biYPelsPerMeter = 0;
  576. bi.biClrUsed = 0;
  577. bi.biClrImportant = 0;
  578. if( !WriteFile( hf, (LPVOID) &bi, sizeof(BITMAPINFOHEADER), (LPDWORD) &dwTmp, NULL ) )
  579. Error( "Couldn't write bitmap header to snapshot.\n" );
  580. // bitmap bits
  581. hp = (byte *) malloc(imageSize);
  582. if (hp == NULL)
  583. Error( "Couldn't allocate bitmap header to snapshot.\n" );
  584. // Get Bits from the renderer
  585. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  586. pRenderContext->ReadPixels( x, y, w, h, hp, IMAGE_FORMAT_RGB888 );
  587. // Invert vertically for BMP format
  588. for (i = 0; i < h / 2; i++)
  589. {
  590. byte *top = hp + i * w * 3;
  591. byte *bottom = hp + (h - i - 1) * w * 3;
  592. for (int j = 0; j < w * 3; j++)
  593. {
  594. b = *top;
  595. *top = *bottom;
  596. *bottom = b;
  597. top++;
  598. bottom++;
  599. }
  600. }
  601. // Reverse Red and Blue
  602. pRed = hp;
  603. pBlue = pRed + 2;
  604. for(i = 0; i < w * h;i++)
  605. {
  606. b = *pRed;
  607. *pRed = *pBlue;
  608. *pBlue = b;
  609. pBlue += 3;
  610. pRed += 3;
  611. }
  612. if( !WriteFile( hf, (LPVOID)hp, imageSize, (LPDWORD) &dwTmp, NULL ) )
  613. Error( "Couldn't write bitmap data snapshot.\n" );
  614. free(hp);
  615. // clean up
  616. if( !CloseHandle( hf ) )
  617. Error( "Couldn't close file for snapshot.\n" );
  618. }
  619. //-----------------------------------------------------------------------------
  620. // Purpose:
  621. // Output : Returns true on success, false on failure.
  622. //-----------------------------------------------------------------------------
  623. bool MatSysWindow::IsSuppressingResize( void )
  624. {
  625. return m_bSuppressResize;
  626. }
  627. //-----------------------------------------------------------------------------
  628. // Purpose:
  629. // Input : suppress -
  630. //-----------------------------------------------------------------------------
  631. void MatSysWindow::SuppressResize( bool suppress )
  632. {
  633. m_bSuppressResize = suppress;
  634. }
  635. void
  636. MatSysWindow::TakeScreenShot (const char *filename)
  637. {
  638. redraw ();
  639. int w = w2 ();
  640. int h = h2 ();
  641. mxImage *image = new mxImage ();
  642. if (image->create (w, h, 24))
  643. {
  644. #if 0
  645. glReadBuffer (GL_FRONT);
  646. glReadPixels (0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, image->data);
  647. #else
  648. HDC hdc = GetDC ((HWND) getHandle ());
  649. byte *data = (byte *) image->data;
  650. int i = 0;
  651. for (int y = 0; y < h; y++)
  652. {
  653. for (int x = 0; x < w; x++)
  654. {
  655. Color cref = RGBToColor( GetPixel (hdc, x, y) );
  656. data[i++] = (byte)cref.r();
  657. data[i++] = (byte)cref.g();
  658. data[i++] = (byte)cref.b();
  659. }
  660. }
  661. ReleaseDC ((HWND) getHandle (), hdc);
  662. #endif
  663. if (!mxTgaWrite (filename, image))
  664. mxMessageBox (this, "Error writing screenshot.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  665. delete image;
  666. }
  667. }