summaryrefslogtreecommitdiff
path: root/utils/hlfaceposer/matsyswin.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/hlfaceposer/matsyswin.cpp')
-rw-r--r--utils/hlfaceposer/matsyswin.cpp806
1 files changed, 806 insertions, 0 deletions
diff --git a/utils/hlfaceposer/matsyswin.cpp b/utils/hlfaceposer/matsyswin.cpp
new file mode 100644
index 0000000..7675ddf
--- /dev/null
+++ b/utils/hlfaceposer/matsyswin.cpp
@@ -0,0 +1,806 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include <mxtk/mx.h>
+#include <mxtk/mxMessageBox.h>
+#include <mxtk/mxTga.h>
+#include <mxtk/mxPcx.h>
+#include <mxtk/mxBmp.h>
+#include <mxtk/mxMatSysWindow.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include "MatSysWin.h"
+#include "MDLViewer.h"
+#include "StudioModel.h"
+#include "ControlPanel.h"
+#include "ViewerSettings.h"
+#include "materialsystem/imaterialsystem.h"
+#include "materialsystem/imaterialproxyfactory.h"
+#include "filesystem.h"
+#include <keyvalues.h>
+#include "materialsystem/imesh.h"
+#include "expressions.h"
+#include "hlfaceposer.h"
+#include "ifaceposersound.h"
+#include "materialsystem/IMaterialSystemHardwareConfig.h"
+#include "materialsystem/itexture.h"
+#include "materialsystem/MaterialSystem_Config.h"
+#include "istudiorender.h"
+#include "choreowidgetdrawhelper.h"
+#include "faceposer_models.h"
+#include "tier0/icommandline.h"
+#include "mathlib/vmatrix.h"
+#include "vstdlib/cvar.h"
+
+IFileSystem *filesystem = NULL;
+
+extern char g_appTitle[];
+
+// FIXME: move all this to mxMatSysWin
+
+class DummyMaterialProxyFactory : public IMaterialProxyFactory
+{
+public:
+ virtual IMaterialProxy *CreateProxy( const char *proxyName ) {return NULL;}
+ virtual void DeleteProxy( IMaterialProxy *pProxy ) {}
+};
+DummyMaterialProxyFactory g_DummyMaterialProxyFactory;
+
+
+static void ReleaseMaterialSystemObjects()
+{
+ StudioModel::ReleaseStudioModel();
+ models->ReleaseModels();
+}
+
+static void RestoreMaterialSystemObjects( int nChangeFlags )
+{
+ StudioModel::RestoreStudioModel();
+ models->RestoreModels();
+}
+
+void InitMaterialSystemConfig(MaterialSystem_Config_t *pConfig)
+{
+ pConfig->SetFlag( MATSYS_VIDCFG_FLAGS_USING_MULTIPLE_WINDOWS, true );
+}
+
+Vector g_vright( 50, 50, 0 ); // needs to be set to viewer's right in order for chrome to work
+
+IMaterial *g_materialBackground = NULL;
+IMaterial *g_materialWireframe = NULL;
+IMaterial *g_materialWireframeVertexColor = NULL;
+IMaterial *g_materialWireframeVertexColorNoCull = NULL;
+IMaterial *g_materialDebugCopyBaseTexture = NULL;
+IMaterial *g_materialFlatshaded = NULL;
+IMaterial *g_materialSmoothshaded = NULL;
+IMaterial *g_materialBones = NULL;
+IMaterial *g_materialLines = NULL;
+IMaterial *g_materialFloor = NULL;
+IMaterial *g_materialVertexColor = NULL;
+IMaterial *g_materialShadow = NULL;
+
+MatSysWindow *g_pMatSysWindow = 0;
+
+#define MATSYSWIN_NAME "3D View"
+
+MatSysWindow::MatSysWindow (mxWindow *parent, int x, int y, int w, int h, const char *label, int style)
+: IFacePoserToolWindow( "3D View", "3D View" ), mxMatSysWindow ( parent, x, y, w, h, label, style )
+{
+ g_pMaterialSystem->SetMaterialProxyFactory( &g_DummyMaterialProxyFactory );
+
+ SetAutoProcess( true );
+
+ setLabel( MATSYSWIN_NAME );
+
+ m_bSuppressSwap = false;
+
+ m_hWnd = (HWND)getHandle();
+
+ Con_Printf( "Setting material system video mode\n" );
+
+ MaterialSystem_Config_t config;
+ config = g_pMaterialSystem->GetCurrentConfigForVideoCard();
+ InitMaterialSystemConfig(&config);
+ g_pMaterialSystem->OverrideConfig( config, false );
+
+// config.m_VideoMode.m_Width = config.m_VideoMode.m_Height = 0;
+ config.SetFlag( MATSYS_VIDCFG_FLAGS_WINDOWED, true );
+ config.SetFlag( MATSYS_VIDCFG_FLAGS_RESIZING, true );
+
+ if (!g_pMaterialSystem->SetMode( ( void * )m_hWnd, config ) )
+ {
+ return;
+ }
+ g_pMaterialSystem->AddReleaseFunc( ReleaseMaterialSystemObjects );
+ g_pMaterialSystem->AddRestoreFunc( RestoreMaterialSystemObjects );
+
+ Con_Printf( "Loading debug materials\n" );
+
+ ITexture *pCubemapTexture = g_pMaterialSystem->FindTexture( "hlmv/cubemap", NULL, true );
+ pCubemapTexture->IncrementReferenceCount();
+ CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
+ pRenderContext->BindLocalCubemap( pCubemapTexture );
+
+ g_materialBackground = g_pMaterialSystem->FindMaterial("particle/particleapp_background", TEXTURE_GROUP_OTHER, true);
+ g_materialWireframe = g_pMaterialSystem->FindMaterial("debug/debugmrmwireframe", TEXTURE_GROUP_OTHER, true);
+ g_materialWireframeVertexColor = g_pMaterialSystem->FindMaterial("debug/debugwireframevertexcolor", TEXTURE_GROUP_OTHER, true);
+
+ // test: create this from code - you need a vmt to make $nocull 1 happen, can't do it from the render context
+ {
+ KeyValues *pVMTKeyValues = new KeyValues( "Wireframe" );
+ pVMTKeyValues->SetInt("$ignorez", 1);
+ pVMTKeyValues->SetInt("$nocull", 1);
+ pVMTKeyValues->SetInt("$vertexcolor", 1);
+ pVMTKeyValues->SetInt("$decal", 1);
+ g_materialWireframeVertexColorNoCull = g_pMaterialSystem->CreateMaterial( "debug/wireframenocull", pVMTKeyValues );
+ }
+ {
+ KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
+ pVMTKeyValues->SetString("$basetexture", "vgui/white" );
+ g_materialDebugCopyBaseTexture = g_pMaterialSystem->CreateMaterial( "debug/copybasetexture", pVMTKeyValues );
+
+ }
+
+ g_materialFlatshaded = g_pMaterialSystem->FindMaterial("debug/debugdrawflatpolygons", TEXTURE_GROUP_OTHER, true);
+ g_materialSmoothshaded = g_pMaterialSystem->FindMaterial("debug/debugmrmfullbright2", TEXTURE_GROUP_OTHER, true);
+ g_materialBones = g_pMaterialSystem->FindMaterial("debug/debugmrmwireframe", TEXTURE_GROUP_OTHER, true);
+ g_materialLines = g_pMaterialSystem->FindMaterial("debug/debugwireframevertexcolor", TEXTURE_GROUP_OTHER, true);
+ g_materialFloor = g_pMaterialSystem->FindMaterial("hlmv/floor", TEXTURE_GROUP_OTHER, true);
+ g_materialVertexColor = g_pMaterialSystem->FindMaterial("debug/debugvertexcolor", TEXTURE_GROUP_OTHER, true);
+ g_materialShadow = g_pMaterialSystem->FindMaterial("hlmv/shadow", TEXTURE_GROUP_OTHER, true);
+
+ if (!parent)
+ setVisible (true);
+ else
+ mx::setIdleWindow (this);
+
+ m_bSuppressResize = false;
+
+ m_stickyDepth = 0;
+ m_bIsSticky = false;
+ m_snapshotDepth = 0;
+}
+
+
+
+MatSysWindow::~MatSysWindow ()
+{
+ mx::setIdleWindow (0);
+}
+
+void MatSysWindow::redraw()
+{
+ BaseClass::redraw();
+return;
+ if ( IsLocked() )
+ {
+ RECT bounds;
+ GetClientRect( (HWND)getHandle(), &bounds );
+ bounds.bottom = bounds.top + GetCaptionHeight();
+ CChoreoWidgetDrawHelper helper( this, bounds );
+ HandleToolRedraw( helper );
+ }
+}
+
+#define MAX_FPS 250.0f
+#define MIN_TIMESTEP ( 1.0f / MAX_FPS )
+
+double realtime = 0.0f;
+
+void MatSysWindow::Frame( void )
+{
+ static bool recursion_guard = false;
+
+ static double prev = 0.0;
+ double curr = (double) mx::getTickCount () / 1000.0;
+ double dt = ( curr - prev );
+
+ if ( recursion_guard )
+ return;
+
+ recursion_guard = true;
+
+ // clamp to MAX_FPS
+ if ( dt >= 0.0 && dt < MIN_TIMESTEP )
+ {
+ Sleep( max( 0, (int)( ( MIN_TIMESTEP - dt ) * 1000.0f ) ) );
+
+ recursion_guard = false;
+ return;
+ }
+
+ if ( prev != 0.0 )
+ {
+ dt = min( 0.1, dt );
+
+ g_MDLViewer->Think( dt );
+
+ realtime += dt;
+ }
+
+ prev = curr;
+
+ DrawFrame();
+
+ recursion_guard = false;
+}
+
+void MatSysWindow::DrawFrame( void )
+{
+ if (!g_viewerSettings.pause)
+ {
+ redraw ();
+ }
+}
+
+int MatSysWindow::handleEvent (mxEvent *event)
+{
+ MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
+
+ int iret = 0;
+
+ if ( HandleToolEvent( event ) )
+ {
+ return iret;
+ }
+
+ static float oldrx = 0, oldry = 0, oldtz = 50, oldtx = 0, oldty = 0;
+ static float oldlrx = 0, oldlry = 0;
+ static int oldx, oldy;
+
+ switch (event->event)
+ {
+ case mxEvent::Idle:
+ {
+ iret = 1;
+
+ Frame();
+ }
+ break;
+
+ case mxEvent::MouseDown:
+ {
+ StudioModel *pModel = models->GetActiveStudioModel();
+ if (!pModel)
+ break;
+ oldrx = pModel->m_angles[0];
+ oldry = pModel->m_angles[1];
+ oldtx = pModel->m_origin[0];
+ oldty = pModel->m_origin[1];
+ oldtz = pModel->m_origin[2];
+ oldx = (short)event->x;
+ oldy = (short)event->y;
+ oldlrx = g_viewerSettings.lightrot[0];
+ oldlry = g_viewerSettings.lightrot[1];
+ g_viewerSettings.pause = false;
+
+ float r = 1.0/3.0 * min( w(), h() );
+
+ float d = sqrt( ( float )( (event->x - w()/2) * (event->x - w()/2) + (event->y - h()/2) * (event->y - h()/2) ) );
+
+ if (d < r)
+ g_viewerSettings.rotating = false;
+ else
+ g_viewerSettings.rotating = true;
+
+ iret = 1;
+ }
+ break;
+
+ case mxEvent::MouseDrag:
+ {
+ StudioModel *pModel = models->GetActiveStudioModel();
+ if (!pModel)
+ break;
+
+ if (event->buttons & mxEvent::MouseLeftButton)
+ {
+ if (event->modifiers & mxEvent::KeyShift)
+ {
+ pModel->m_origin[1] = oldty - (float) ((short)event->x - oldx) * 0.1;
+ pModel->m_origin[2] = oldtz + (float) ((short)event->y - oldy) * 0.1;
+ }
+ else if (event->modifiers & mxEvent::KeyCtrl)
+ {
+ float ry = (float) (event->y - oldy);
+ float rx = (float) (event->x - oldx);
+ oldx = event->x;
+ oldy = event->y;
+
+ QAngle movement = QAngle( ry, rx, 0 );
+
+ matrix3x4_t tmp1, tmp2, tmp3;
+ AngleMatrix( g_viewerSettings.lightrot, tmp1 );
+ AngleMatrix( movement, tmp2 );
+ ConcatTransforms( tmp2, tmp1, tmp3 );
+ MatrixAngles( tmp3, g_viewerSettings.lightrot );
+ }
+ else
+ {
+ if (!g_viewerSettings.rotating)
+ {
+ float ry = (float) (event->y - oldy);
+ float rx = (float) (event->x - oldx);
+ oldx = event->x;
+ oldy = event->y;
+
+ QAngle movement;
+ matrix3x4_t tmp1, tmp2, tmp3;
+
+ movement = QAngle( 0, rx, 0 );
+ AngleMatrix( pModel->m_angles, tmp1 );
+ AngleMatrix( movement, tmp2 );
+ ConcatTransforms( tmp1, tmp2, tmp3 );
+ MatrixAngles( tmp3, pModel->m_angles );
+
+ movement = QAngle( ry, 0, 0 );
+ AngleMatrix( pModel->m_angles, tmp1 );
+ AngleMatrix( movement, tmp2 );
+ ConcatTransforms( tmp2, tmp1, tmp3 );
+ MatrixAngles( tmp3, pModel->m_angles );
+ }
+ else
+ {
+ float ang1 = (180 / 3.1415) * atan2( oldx - w()/2.0, oldy - h()/2.0 );
+ float ang2 = (180 / 3.1415) * atan2( event->x - w()/2.0, event->y - h()/2.0 );
+ oldx = event->x;
+ oldy = event->y;
+
+ QAngle movement = QAngle( 0, 0, ang2 - ang1 );
+
+ matrix3x4_t tmp1, tmp2, tmp3;
+ AngleMatrix( pModel->m_angles, tmp1 );
+ AngleMatrix( movement, tmp2 );
+ ConcatTransforms( tmp2, tmp1, tmp3 );
+ MatrixAngles( tmp3, pModel->m_angles );
+ }
+ }
+ }
+ else if (event->buttons & mxEvent::MouseRightButton)
+ {
+ pModel->m_origin[0] = oldtx + (float) ((short)event->y - oldy) * 0.1;
+ pModel->m_origin[0] = clamp( pModel->m_origin[0], 8.0f, 1024.0f );
+ }
+ redraw ();
+
+ iret = 1;
+ }
+ break;
+
+ case mxEvent::KeyDown:
+ {
+ iret = 1;
+ switch (event->key)
+ {
+ default:
+ iret = 0;
+ break;
+ case 116: // F5
+ {
+ g_MDLViewer->Refresh();
+ }
+ break;
+ case 32:
+ {
+ int iSeq = models->GetActiveStudioModel()->GetSequence();
+ if (iSeq == models->GetActiveStudioModel()->SetSequence (iSeq + 1))
+ {
+ g_pControlPanel->setSequence( 0 );
+ }
+ else
+ {
+ g_pControlPanel->setSequence( iSeq + 1 );
+ }
+ }
+ break;
+
+ case 27:
+ if (!getParent ()) // fullscreen mode ?
+ mx::quit ();
+ break;
+
+ case 'g':
+ g_viewerSettings.showGround = !g_viewerSettings.showGround;
+ break;
+
+ case 'h':
+ g_viewerSettings.showHitBoxes = !g_viewerSettings.showHitBoxes;
+ break;
+
+ case 'o':
+ g_viewerSettings.showBones = !g_viewerSettings.showBones;
+ break;
+
+ case 'b':
+ g_viewerSettings.showBackground = !g_viewerSettings.showBackground;
+ break;
+
+ case 'm':
+ g_viewerSettings.showMovement = !g_viewerSettings.showMovement;
+ break;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ g_viewerSettings.renderMode = event->key - '1';
+ break;
+
+ case '-':
+ g_viewerSettings.speedScale -= 0.1f;
+ if (g_viewerSettings.speedScale < 0.0f)
+ g_viewerSettings.speedScale = 0.0f;
+ break;
+
+ case '+':
+ g_viewerSettings.speedScale += 0.1f;
+ if (g_viewerSettings.speedScale > 5.0f)
+ g_viewerSettings.speedScale = 5.0f;
+ break;
+ }
+ }
+ break;
+ } // switch (event->event)
+
+ return iret;
+}
+
+
+
+void
+drawFloor ()
+{
+ CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
+ pRenderContext->Bind(g_materialFloor);
+ pRenderContext->MatrixMode(MATERIAL_MODEL);
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadIdentity();
+ pRenderContext->MatrixMode(MATERIAL_VIEW);
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadIdentity();
+ {
+ IMesh* pMesh = pRenderContext->GetDynamicMesh();
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
+
+ float dist=-15000.0f;
+ float tMin=0, tMax=1;
+
+ meshBuilder.Position3f(-dist, dist, dist);
+ meshBuilder.TexCoord2f( 0, tMin,tMax );
+ meshBuilder.Color4ub( 255, 255, 255, 255 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( dist, dist, dist);
+ meshBuilder.TexCoord2f( 0, tMax,tMax );
+ meshBuilder.Color4ub( 255, 255, 255, 255 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( dist,-dist, dist);
+ meshBuilder.TexCoord2f( 0, tMax,tMin );
+ meshBuilder.Color4ub( 255, 255, 255, 255 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f(-dist,-dist, dist);
+ meshBuilder.TexCoord2f( 0, tMin,tMin );
+ meshBuilder.Color4ub( 255, 255, 255, 255 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.End();
+ pMesh->Draw();
+ }
+ pRenderContext->MatrixMode(MATERIAL_MODEL);
+ pRenderContext->PopMatrix();
+ pRenderContext->MatrixMode(MATERIAL_VIEW);
+ pRenderContext->PopMatrix();
+}
+
+
+
+void
+setupRenderMode ()
+{
+}
+
+void MatSysWindow::SuppressBufferSwap( bool bSuppress )
+{
+ m_bSuppressSwap = bSuppress;
+}
+
+void MatSysWindow::draw ()
+{
+ int i;
+
+ g_pMaterialSystem->BeginFrame( 0 );
+ CUtlVector< StudioModel * > modellist;
+
+ modellist.AddToTail( models->GetActiveStudioModel() );
+
+ if ( models->CountVisibleModels() > 0 )
+ {
+ modellist.RemoveAll();
+ for ( i = 0; i < models->Count(); i++ )
+ {
+ if ( models->IsModelShownIn3DView( i ) )
+ {
+ modellist.AddToTail( models->GetStudioModel( i ) );
+ }
+ }
+ }
+
+ CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
+ pRenderContext->ClearBuffers(true, true);
+
+ int captiony = GetCaptionHeight();
+ int viewh = h2() - captiony;
+
+ g_pMaterialSystem->SetView( (HWND)getHandle() );
+
+ pRenderContext->Viewport( 0, captiony, w2(), viewh );
+
+ pRenderContext->MatrixMode( MATERIAL_PROJECTION );
+ pRenderContext->LoadIdentity( );
+ pRenderContext->PerspectiveX(20.0f, (float)w2() / (float)viewh, 1.0f, 20000.0f);
+
+ pRenderContext->MatrixMode( MATERIAL_VIEW );
+ pRenderContext->LoadIdentity( );
+ // FIXME: why is this needed? Doesn't SetView() override this?
+ pRenderContext->Rotate( -90, 1, 0, 0 ); // put Z going up
+ pRenderContext->Rotate( -90, 0, 0, 1 );
+
+ int modelcount = modellist.Count();
+ int countover2 = modelcount / 2;
+ int ydelta = g_pControlPanel->GetModelGap();
+ int yoffset = -countover2 * ydelta;
+ for ( i = 0 ; i < modelcount; i++ )
+ {
+ modellist[ i ]->IncrementFramecounter( );
+
+ Vector oldtrans = modellist[ i ]->m_origin;
+
+ modellist[ i ]->m_origin[ 1 ] = oldtrans[ 1 ] + yoffset;
+ yoffset += ydelta;
+
+ modellist[ i ]->GetStudioRender()->BeginFrame();
+ modellist[ i ]->DrawModel();
+ modellist[ i ]->GetStudioRender()->EndFrame();
+
+ modellist[ i ]->m_origin = oldtrans;
+ }
+
+ //
+ // draw ground
+ //
+ if (g_viewerSettings.showGround)
+ {
+ drawFloor ();
+ }
+
+ if (!m_bSuppressSwap)
+ {
+ g_pMaterialSystem->SwapBuffers();
+ }
+
+ g_pMaterialSystem->EndFrame();
+}
+
+void MatSysWindow::EnableStickySnapshotMode( )
+{
+ m_stickyDepth++;
+}
+
+void MatSysWindow::DisableStickySnapshotMode( )
+{
+ if (--m_stickyDepth == 0)
+ {
+ if (m_bIsSticky)
+ {
+ m_bIsSticky = false;
+
+ HWND wnd = (HWND)getHandle();
+
+ // Move back to original position
+ SetWindowPlacement( wnd, &m_wp );
+
+ SuppressResize( false );
+
+ SetCursor( m_hPrevCursor );
+ }
+ }
+}
+
+
+void MatSysWindow::PushSnapshotMode( int nSnapShotSize )
+{
+ if (m_snapshotDepth++ == 0)
+ {
+ if (m_stickyDepth)
+ {
+ if (m_bIsSticky)
+ return;
+
+ m_bIsSticky = true;
+ m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) );
+ }
+
+ SuppressResize( true );
+
+ RECT rcClient;
+ HWND wnd = (HWND)getHandle();
+
+ GetWindowPlacement( wnd, &m_wp );
+
+ GetClientRect( wnd, &rcClient );
+
+ MoveWindow( wnd, 0, 0, nSnapShotSize + 16, nSnapShotSize + 16, TRUE );
+ }
+}
+
+
+void MatSysWindow::PopSnapshotMode( )
+{
+ if (--m_snapshotDepth == 0)
+ {
+ if (m_stickyDepth == 0)
+ {
+ HWND wnd = (HWND)getHandle();
+
+ // Move back to original position
+ SetWindowPlacement( wnd, &m_wp );
+
+ SuppressResize( false );
+ }
+ }
+}
+
+
+void MatSysWindow::TakeSnapshotRect( const char *pFilename, int x, int y, int w, int h )
+{
+ int i;
+ HANDLE hf;
+ BITMAPFILEHEADER hdr;
+ BITMAPINFOHEADER bi;
+ DWORD dwTmp, imageSize;
+ byte *hp, b, *pBlue, *pRed;
+
+ w = ( w + 3 ) & ~3;
+
+ imageSize = w * h * 3;
+ // Create the file
+ hf = CreateFile( pFilename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
+ if( hf == INVALID_HANDLE_VALUE )
+ {
+ return;
+ }
+
+ // file header
+ hdr.bfType = 0x4d42; // 'BM'
+ hdr.bfSize = (DWORD) ( sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + imageSize );
+ hdr.bfReserved1 = 0;
+ hdr.bfReserved2 = 0;
+ hdr.bfOffBits = (DWORD) ( sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) );
+
+ if( !WriteFile( hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER), (LPDWORD) &dwTmp, NULL ) )
+ Error( "Couldn't write file header to snapshot.\n" );
+
+ // bitmap header
+ bi.biSize = sizeof(BITMAPINFOHEADER);
+ bi.biWidth = w;
+ bi.biHeight = h;
+ bi.biPlanes = 1;
+ bi.biBitCount = 24;
+ bi.biCompression = BI_RGB;
+ bi.biSizeImage = 0; //vid.rowbytes * vid.height;
+ bi.biXPelsPerMeter = 0;
+ bi.biYPelsPerMeter = 0;
+ bi.biClrUsed = 0;
+ bi.biClrImportant = 0;
+
+ if( !WriteFile( hf, (LPVOID) &bi, sizeof(BITMAPINFOHEADER), (LPDWORD) &dwTmp, NULL ) )
+ Error( "Couldn't write bitmap header to snapshot.\n" );
+
+ // bitmap bits
+ hp = (byte *) malloc(imageSize);
+
+ if (hp == NULL)
+ Error( "Couldn't allocate bitmap header to snapshot.\n" );
+
+ // Get Bits from the renderer
+ CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
+ pRenderContext->ReadPixels( x, y, w, h, hp, IMAGE_FORMAT_RGB888 );
+
+ // Invert vertically for BMP format
+ for (i = 0; i < h / 2; i++)
+ {
+ byte *top = hp + i * w * 3;
+ byte *bottom = hp + (h - i - 1) * w * 3;
+ for (int j = 0; j < w * 3; j++)
+ {
+ b = *top;
+ *top = *bottom;
+ *bottom = b;
+ top++;
+ bottom++;
+ }
+ }
+
+ // Reverse Red and Blue
+ pRed = hp;
+ pBlue = pRed + 2;
+ for(i = 0; i < w * h;i++)
+ {
+ b = *pRed;
+ *pRed = *pBlue;
+ *pBlue = b;
+ pBlue += 3;
+ pRed += 3;
+ }
+
+ if( !WriteFile( hf, (LPVOID)hp, imageSize, (LPDWORD) &dwTmp, NULL ) )
+ Error( "Couldn't write bitmap data snapshot.\n" );
+
+ free(hp);
+
+ // clean up
+ if( !CloseHandle( hf ) )
+ Error( "Couldn't close file for snapshot.\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool MatSysWindow::IsSuppressingResize( void )
+{
+ return m_bSuppressResize;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : suppress -
+//-----------------------------------------------------------------------------
+void MatSysWindow::SuppressResize( bool suppress )
+{
+ m_bSuppressResize = suppress;
+}
+
+void
+MatSysWindow::TakeScreenShot (const char *filename)
+{
+ redraw ();
+ int w = w2 ();
+ int h = h2 ();
+
+ mxImage *image = new mxImage ();
+ if (image->create (w, h, 24))
+ {
+#if 0
+ glReadBuffer (GL_FRONT);
+ glReadPixels (0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, image->data);
+#else
+ HDC hdc = GetDC ((HWND) getHandle ());
+ byte *data = (byte *) image->data;
+ int i = 0;
+ for (int y = 0; y < h; y++)
+ {
+ for (int x = 0; x < w; x++)
+ {
+ COLORREF cref = GetPixel (hdc, x, y);
+ data[i++] = (byte) ((cref >> 0)& 0xff);
+ data[i++] = (byte) ((cref >> 8) & 0xff);
+ data[i++] = (byte) ((cref >> 16) & 0xff);
+ }
+ }
+ ReleaseDC ((HWND) getHandle (), hdc);
+#endif
+ if (!mxTgaWrite (filename, image))
+ mxMessageBox (this, "Error writing screenshot.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
+
+ delete image;
+ }
+}