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.

806 lines
20 KiB

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