mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-22 06:06:50 +00:00
807 lines
20 KiB
C++
807 lines
20 KiB
C++
//========= 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;
|
|
}
|
|
}
|