summaryrefslogtreecommitdiff
path: root/utils/hlmv/mdlviewer.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/hlmv/mdlviewer.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'utils/hlmv/mdlviewer.cpp')
-rw-r--r--utils/hlmv/mdlviewer.cpp1631
1 files changed, 1631 insertions, 0 deletions
diff --git a/utils/hlmv/mdlviewer.cpp b/utils/hlmv/mdlviewer.cpp
new file mode 100644
index 0000000..aae97d6
--- /dev/null
+++ b/utils/hlmv/mdlviewer.cpp
@@ -0,0 +1,1631 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+//
+// Half-Life Model Viewer (c) 1999 by Mete Ciragan
+//
+// file: mdlviewer.cpp
+// last modified: Jun 03 1999, Mete Ciragan
+// copyright: The programs and associated files contained in this
+// distribution were developed by Mete Ciragan. The programs
+// are not in the public domain, but they are freely
+// distributable without licensing fees. These programs are
+// provided without guarantee or warrantee expressed or
+// implied.
+//
+// version: 1.2
+//
+// web: http://www.swissquake.ch/chumbalum-soft/
+//
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mxtk/mx.h>
+#include <mxtk/mxTga.h>
+#include <mxtk/mxEvent.h>
+#include "mdlviewer.h"
+#include "ViewerSettings.h"
+#include "MatSysWin.h"
+#include "ControlPanel.h"
+#include "StudioModel.h"
+#include "FileAssociation.h"
+#include "tier1/strtools.h"
+#include "tier0/icommandline.h"
+#include "filesystem.h"
+#include "ifilesystemopendialog.h"
+#include "appframework/appframework.h"
+#include "istudiorender.h"
+#include "materialsystem/imaterialsystem.h"
+#include "vphysics_interface.h"
+#include "Datacache/imdlcache.h"
+#include "datacache/idatacache.h"
+#include "filesystem_init.h"
+#include "materialsystem/imaterialsystemhardwareconfig.h"
+#include "SoundEmitterSystem/isoundemittersystembase.h"
+#include "soundsystem/isoundsystem.h"
+#include "tier1/tier1.h"
+#include "valve_ipc_win32.h"
+#include "threadtools.h"
+#include "vstdlib/IKeyValuesSystem.h"
+
+bool g_bOldFileDialogs = false;
+
+MDLViewer *g_MDLViewer = 0;
+char g_appTitle[] = "Half-Life Model Viewer v1.22";
+static char recentFiles[8][256] = { "", "", "", "", "", "", "", "" };
+extern int g_dxlevel;
+bool g_bInError = false;
+
+
+//-----------------------------------------------------------------------------
+// Singleton interfaces
+//-----------------------------------------------------------------------------
+IStudioRender *g_pStudioRender;
+IMDLCache *g_pMDLCache;
+IPhysicsSurfaceProps *physprop;
+IPhysicsCollision *physcollision;
+IFileSystem *g_pFileSystem;
+IMaterialSystem *g_pMaterialSystem;
+IMaterialSystemHardwareConfig *g_pMaterialSystemHardwareConfig;
+IStudioDataCache *g_pStudioDataCache;
+IDataCache *g_pDataCache;
+ISoundEmitterSystemBase *g_pSoundEmitterBase;
+ISoundSystem *g_pSoundSystem;
+CreateInterfaceFn g_Factory;
+
+// Filesystem dialog module wrappers.
+CSysModule *g_pFSDialogModule = 0;
+CreateInterfaceFn g_FSDialogFactory = 0;
+
+
+class CHlmvIpcServer : public CValveIpcServerUtl
+{
+public:
+ CHlmvIpcServer() : CValveIpcServerUtl( "HLMV_IPC_SERVER" ) {}
+ ~CHlmvIpcServer();
+
+public:
+ bool HasCommands();
+ void AppendCommand( char *pszCommand );
+ char *GetCommand();
+ void PopCommand();
+
+protected:
+ virtual BOOL ExecuteCommand( CUtlBuffer &cmd, CUtlBuffer &res );
+
+protected:
+ CThreadFastMutex m_mtx;
+ CUtlVector< char * > m_lstCommands;
+}
+g_HlmvIpcServer;
+
+CValveIpcClientUtl g_HlmvIpcClient( "HLMV_IPC_SERVER" );
+bool g_bHlmvMaster = false; // This hlmv is controlling a controlled hlmv instance
+bool g_bHlmvControlled = false; // This hlmv is being controlled by a master hlmv instance
+
+void LoadFileSystemDialogModule()
+{
+ Assert( !g_pFSDialogModule );
+
+ // Load the module with the file system open dialog.
+ const char *pDLLName = "FileSystemOpenDialog.dll";
+ g_pFSDialogModule = Sys_LoadModule( pDLLName );
+ if ( g_pFSDialogModule )
+ {
+ g_FSDialogFactory = Sys_GetFactory( g_pFSDialogModule );
+ }
+
+ if ( !g_pFSDialogModule || !g_FSDialogFactory )
+ {
+ if ( g_pFSDialogModule )
+ {
+ Sys_UnloadModule( g_pFSDialogModule );
+ g_pFSDialogModule = NULL;
+ }
+ }
+}
+
+void UnloadFileSystemDialogModule()
+{
+ if ( g_pFSDialogModule )
+ {
+ Sys_UnloadModule( g_pFSDialogModule );
+ g_pFSDialogModule = 0;
+ }
+}
+
+
+
+void
+MDLViewer::initRecentFiles ()
+{
+ for (int i = 0; i < 8; i++)
+ {
+ if (strlen (recentFiles[i]))
+ {
+ mb->modify (IDC_FILE_RECENTMODELS1 + i, IDC_FILE_RECENTMODELS1 + i, recentFiles[i]);
+ }
+ else
+ {
+ mb->modify (IDC_FILE_RECENTMODELS1 + i, IDC_FILE_RECENTMODELS1 + i, "(empty)");
+ mb->setEnabled (IDC_FILE_RECENTMODELS1 + i, false);
+ }
+ }
+}
+
+
+
+void
+MDLViewer::loadRecentFiles ()
+{
+ char path[256];
+ strcpy (path, mx::getApplicationPath ());
+ strcat (path, "/hlmv.rf");
+ FILE *file = fopen (path, "rb");
+ if (file)
+ {
+ fread (recentFiles, sizeof recentFiles, 1, file);
+ fclose (file);
+ }
+}
+
+
+
+void
+MDLViewer::saveRecentFiles ()
+{
+ char path[256];
+
+ strcpy (path, mx::getApplicationPath ());
+ strcat (path, "/hlmv.rf");
+
+ FILE *file = fopen (path, "wb");
+ if (file)
+ {
+ fwrite (recentFiles, sizeof recentFiles, 1, file);
+ fclose (file);
+ }
+}
+
+struct AccelTableEntry_t
+{
+ unsigned short key;
+ unsigned short command;
+ unsigned char flags;
+};
+
+AccelTableEntry_t accelTable[] = {{VK_F1, IDC_FLUSH_SHADERS, mx::ACCEL_VIRTKEY},
+ {VK_F5, IDC_FILE_REFRESH, mx::ACCEL_VIRTKEY},
+ {'u', IDC_FILE_UNLOADALLMERGEDMODELS, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
+ {'U', IDC_FILE_UNLOADALLMERGEDMODELS, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
+ {'w', IDC_ACCEL_WIREFRAME, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
+ {'W', IDC_ACCEL_WIREFRAME, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
+ {'a', IDC_ACCEL_ATTACHMENTS, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
+ {'A', IDC_ACCEL_ATTACHMENTS, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
+ {'g', IDC_ACCEL_GROUND, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
+ {'G', IDC_ACCEL_GROUND, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
+ {'h', IDC_ACCEL_HITBOXES, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
+ {'H', IDC_ACCEL_HITBOXES, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
+ {'o', IDC_ACCEL_BONES, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
+ {'O', IDC_ACCEL_BONES, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
+ {'b', IDC_ACCEL_BACKGROUND, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
+ {'B', IDC_ACCEL_BACKGROUND, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
+ {'m', IDC_ACCEL_MOVEMENT, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
+ {'M', IDC_ACCEL_MOVEMENT, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
+ {'n', IDC_ACCEL_NORMALS, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
+ {'N', IDC_ACCEL_NORMALS, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
+ {'t', IDC_ACCEL_TANGENTS, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
+ {'T', IDC_ACCEL_TANGENTS, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
+ {'s', IDC_ACCEL_SHADOW, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
+ {'S', IDC_ACCEL_SHADOW, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY}};
+#define NUM_ACCELERATORS ARRAYSIZE( accelTable )
+
+
+MDLViewer::MDLViewer ()
+: mxWindow (0, 0, 0, 0, 0, g_appTitle, mxWindow::Normal)
+{
+ d_MatSysWindow = 0;
+ d_cpl = 0;
+
+ // create menu stuff
+ mb = new mxMenuBar (this);
+ mxMenu *menuFile = new mxMenu ();
+ menuOptions = new mxMenu ();
+ menuView = new mxMenu ();
+ mxMenu *menuHelp = new mxMenu ();
+
+ mb->addMenu ("File", menuFile);
+ mb->addMenu ("Options", menuOptions);
+ mb->addMenu ("View", menuView);
+ mb->addMenu ("Help", menuHelp);
+
+ mxMenu *menuRecentModels = new mxMenu ();
+ menuRecentModels->add ("(empty)", IDC_FILE_RECENTMODELS1);
+ menuRecentModels->add ("(empty)", IDC_FILE_RECENTMODELS2);
+ menuRecentModels->add ("(empty)", IDC_FILE_RECENTMODELS3);
+ menuRecentModels->add ("(empty)", IDC_FILE_RECENTMODELS4);
+ menuRecentModels->add ("(empty)", IDC_FILE_RECENTMODELS5);
+ menuRecentModels->add ("(empty)", IDC_FILE_RECENTMODELS6);
+ menuRecentModels->add ("(empty)", IDC_FILE_RECENTMODELS7);
+ menuRecentModels->add ("(empty)", IDC_FILE_RECENTMODELS8);
+
+ if ( g_bOldFileDialogs )
+ {
+ menuFile->add ("Load Model...", IDC_FILE_LOADMODEL);
+ menuFile->add ("(Steam) Load Model...", IDC_FILE_LOADMODEL_STEAM);
+ }
+ else
+ {
+ menuFile->add ("Load Model...", IDC_FILE_LOADMODEL_STEAM);
+ }
+
+ menuFile->add( "Refresh (F5)", IDC_FILE_REFRESH );
+ menuFile->addSeparator ();
+
+ if ( g_bOldFileDialogs )
+ {
+ menuFile->add ("Load Weapon...", IDC_FILE_LOADMERGEDMODEL);
+ menuFile->add ("(Steam) Load Weapon...", IDC_FILE_LOADMERGEDMODEL_STEAM);
+ }
+ else
+ {
+ menuFile->add ("Load Weapon...", IDC_FILE_LOADMERGEDMODEL_STEAM);
+ }
+
+ mxMenu *menuUnloadWeapon = new mxMenu ();
+ menuUnloadWeapon->add ("Unload All Merged Models (Ctrl-U)", IDC_FILE_UNLOADALLMERGEDMODELS);
+ menuUnloadWeapon->add ("(empty)", IDC_FILE_UNLOADMERGEDMODEL1);
+ menuUnloadWeapon->add ("(empty)", IDC_FILE_UNLOADMERGEDMODEL2);
+ menuUnloadWeapon->add ("(empty)", IDC_FILE_UNLOADMERGEDMODEL3);
+ menuUnloadWeapon->add ("(empty)", IDC_FILE_UNLOADMERGEDMODEL4);
+ menuUnloadWeapon->add ("(empty)", IDC_FILE_UNLOADMERGEDMODEL5);
+ menuUnloadWeapon->add ("(empty)", IDC_FILE_UNLOADMERGEDMODEL6);
+ menuUnloadWeapon->add ("(empty)", IDC_FILE_UNLOADMERGEDMODEL7);
+ menuUnloadWeapon->add ("(empty)", IDC_FILE_UNLOADMERGEDMODEL8);
+ menuUnloadWeapon->add ("(empty)", IDC_FILE_UNLOADMERGEDMODEL9);
+ menuUnloadWeapon->add ("(empty)", IDC_FILE_UNLOADMERGEDMODEL10);
+ menuUnloadWeapon->add ("(empty)", IDC_FILE_UNLOADMERGEDMODEL11);
+ menuUnloadWeapon->add ("(empty)", IDC_FILE_UNLOADMERGEDMODEL12);
+ for ( int i = IDC_FILE_UNLOADMERGEDMODEL1; i <= IDC_FILE_UNLOADMERGEDMODEL12; i++ )
+ {
+ menuUnloadWeapon->setEnabled( i, false );
+ }
+ menuFile->addMenu ("Unload Weapon", menuUnloadWeapon);
+
+ menuFile->addSeparator ();
+ menuFile->add ("Load Background Texture...", IDC_FILE_LOADBACKGROUNDTEX);
+ menuFile->add ("Load Ground Texture...", IDC_FILE_LOADGROUNDTEX);
+ menuFile->addSeparator ();
+ menuFile->add ("Unload Ground Texture", IDC_FILE_UNLOADGROUNDTEX);
+ menuFile->addSeparator ();
+ menuFile->addMenu ("Recent Models", menuRecentModels);
+ menuFile->addSeparator ();
+ menuFile->add ("Exit", IDC_FILE_EXIT);
+
+ menuFile->setEnabled(IDC_FILE_LOADBACKGROUNDTEX, false);
+ menuFile->setEnabled(IDC_FILE_LOADGROUNDTEX, false);
+ menuFile->setEnabled(IDC_FILE_UNLOADGROUNDTEX, false);
+
+ menuOptions->add ("Background Color...", IDC_OPTIONS_COLORBACKGROUND);
+ menuOptions->add ("Ground Color...", IDC_OPTIONS_COLORGROUND);
+ menuOptions->add ("Light Color...", IDC_OPTIONS_COLORLIGHT);
+ menuOptions->add ("Ambient Color...", IDC_OPTIONS_COLORAMBIENT);
+ menuOptions->addSeparator ();
+ menuOptions->add ("Center View", IDC_OPTIONS_CENTERVIEW);
+ menuOptions->add ("Viewmodel Mode", IDC_OPTIONS_VIEWMODEL);
+#ifdef WIN32
+ menuOptions->addSeparator ();
+ menuOptions->add ("Make Screenshot...", IDC_OPTIONS_MAKESCREENSHOT);
+ //menuOptions->add ("Dump Model Info", IDC_OPTIONS_DUMP);
+#endif
+
+ menuView->add ("File Associations...", IDC_VIEW_FILEASSOCIATIONS);
+ menuView->setEnabled( IDC_VIEW_FILEASSOCIATIONS, false );
+
+ menuView->addSeparator ();
+ menuView->add ("Show Activities", IDC_VIEW_ACTIVITIES);
+ menuView->add ("Show hidden", IDC_VIEW_HIDDEN );
+
+#ifdef WIN32
+ menuHelp->add ("Goto Homepage...", IDC_HELP_GOTOHOMEPAGE);
+ menuHelp->addSeparator ();
+#endif
+ menuHelp->add ("About...", IDC_HELP_ABOUT);
+
+
+ d_MatSysWindow = new MatSysWindow (this, 0, 0, 100, 100, "", mxWindow::Normal);
+#ifdef WIN32
+ // SetWindowLong ((HWND) d_MatSysWindow->getHandle (), GWL_EXSTYLE, WS_EX_CLIENTEDGE);
+#endif
+
+ d_cpl = new ControlPanel (this);
+ d_cpl->setMatSysWindow (d_MatSysWindow);
+ g_MatSysWindow = d_MatSysWindow;
+
+ g_FileAssociation = new FileAssociation ();
+
+ loadRecentFiles ();
+ initRecentFiles ();
+
+ LoadViewerRootSettings( );
+
+ // FIXME: where do I actually find the domain size of the viewport, especially for multi-monitor
+ // try to catch weird initialization error
+ if (g_viewerSettings.xpos < -16384)
+ g_viewerSettings.xpos = 20;
+ if (g_viewerSettings.ypos < -16384)
+ g_viewerSettings.ypos = 20;
+ g_viewerSettings.ypos = max( 0, g_viewerSettings.ypos );
+ g_viewerSettings.width = max( 640, g_viewerSettings.width );
+ g_viewerSettings.height = max( 700, g_viewerSettings.height );
+
+ setBounds( g_viewerSettings.xpos, g_viewerSettings.ypos, g_viewerSettings.width, g_viewerSettings.height );
+ setVisible (true);
+ setTimer( 200 );
+
+ CUtlVector< mx::Accel_t > accelerators;
+ mx::Accel_t accel;
+
+ for (int i=0; i < NUM_ACCELERATORS; i++)
+ {
+ accel.flags = accelTable[i].flags ;
+ accel.key = accelTable[i].key;
+ accel.command = accelTable[i].command;
+ accelerators.AddToTail( accel );
+ }
+
+ mx::createAccleratorTable( accelerators.Count(), accelerators.Base() );
+
+ g_HlmvIpcServer.EnsureRegisteredAndRunning();
+
+ if ( !g_HlmvIpcServer.IsRunning() )
+ {
+ menuOptions->addSeparator();
+ menuOptions->add ( "Link HLMV", IDC_OPTIONS_LINKHLMV );
+ menuOptions->add ( "Unlink HLMV", IDC_OPTIONS_UNLINKHLMV );
+ menuOptions->setChecked( IDC_OPTIONS_UNLINKHLMV, true );
+ menuOptions->setEnabled( IDC_OPTIONS_UNLINKHLMV, false );
+ }
+}
+
+
+
+MDLViewer::~MDLViewer ()
+{
+ g_HlmvIpcServer.EnsureStoppedAndUnregistered();
+
+ saveRecentFiles ();
+ SaveViewerSettings( g_pStudioModel->GetFileName(), g_pStudioModel );
+ SaveViewerRootSettings( );
+
+#ifdef WIN32
+ DeleteFile ("hlmv.cfg");
+ DeleteFile ("midump.txt");
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Reloads the currently loaded model file.
+//-----------------------------------------------------------------------------
+void MDLViewer::Refresh( void )
+{
+ KeyValuesSystem()->InvalidateCache();
+
+ g_pStudioModel->ReleaseStudioModel();
+ g_pMDLCache->Flush();
+ if ( recentFiles[0][0] != '\0' )
+ {
+ char szFile[MAX_PATH];
+ strcpy( szFile, recentFiles[0] );
+ g_pMaterialSystem->ReloadMaterials();
+ d_cpl->loadModel( szFile );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Loads the file and updates the MRU list.
+// Input : pszFile - File to load.
+//-----------------------------------------------------------------------------
+void MDLViewer::LoadModelFile( const char *pszFile, int slot )
+{
+ // copy off name, pszFile may be point into recentFiles array
+ char filename[1024];
+ strcpy( filename, pszFile );
+
+ LoadModelResult_t eLoaded = d_cpl->loadModel( filename, slot );
+
+ if ( eLoaded != LoadModel_Success )
+ {
+ switch (eLoaded)
+ {
+ case LoadModel_LoadFail:
+ {
+ mxMessageBox (this, "Error loading model.", g_appTitle, MX_MB_ERROR | MX_MB_OK);
+ break;
+ }
+
+ case LoadModel_PostLoadFail:
+ {
+ mxMessageBox (this, "Error post-loading model.", g_appTitle, MX_MB_ERROR | MX_MB_OK);
+ break;
+ }
+
+ case LoadModel_NoModel:
+ {
+ mxMessageBox (this, "Error loading model. The model has no vertices.", g_appTitle, MX_MB_ERROR | MX_MB_OK);
+ break;
+ }
+ }
+
+ return;
+ }
+
+ if (slot == -1)
+ {
+ int i;
+ for (i = 0; i < 8; i++)
+ {
+ if (!mx_strcasecmp( recentFiles[i], filename ))
+ break;
+ }
+
+ // shift down existing recent files
+ for (i = ((i > 7) ? 7 : i); i > 0; i--)
+ {
+ strcpy (recentFiles[i], recentFiles[i-1]);
+ }
+
+ strcpy( recentFiles[0], filename );
+
+ initRecentFiles ();
+
+ setLabel( "%s", filename );
+ }
+ else
+ {
+ mb->modify (IDC_FILE_UNLOADMERGEDMODEL1 + slot, IDC_FILE_UNLOADMERGEDMODEL1 + slot, pszFile);
+ mb->setEnabled (IDC_FILE_UNLOADMERGEDMODEL1 + slot, true);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Takes a TGA screenshot of the given filename and exits.
+// Input : pszFile - File to load.
+//-----------------------------------------------------------------------------
+void MDLViewer::SaveScreenShot( const char *pszFile )
+{
+ char filename[1024];
+ strcpy( filename, pszFile );
+ LoadModelResult_t eLoaded = d_cpl->loadModel( filename );
+
+ //
+ // Screenshot mode. Write a screenshot file and exit.
+ //
+ if ( eLoaded == LoadModel_Success )
+ {
+ g_viewerSettings.bgColor[0] = 117.0f / 255.0f;
+ g_viewerSettings.bgColor[1] = 196.0f / 255.0f;
+ g_viewerSettings.bgColor[2] = 219.0f / 255.0f;
+
+ // Build the name of the TGA to write.
+ char szScreenShot[256];
+ strcpy(szScreenShot, filename);
+ char *pchDot = strrchr(szScreenShot, '.');
+ if (pchDot)
+ {
+ strcpy(pchDot, ".tga");
+ }
+ else
+ {
+ strcat(szScreenShot, ".tga");
+ }
+
+ // Center the view and write the TGA.
+ d_cpl->centerView();
+ d_MatSysWindow->dumpViewport(szScreenShot);
+ }
+
+ // Shut down.
+ mx::quit();
+ return;
+}
+
+
+void MDLViewer::DumpText( const char *pszFile )
+{
+ char filename[1024];
+ strcpy( filename, pszFile );
+ LoadModelResult_t eLoaded = d_cpl->loadModel( filename );
+
+ //
+ // Screenshot mode. Write a screenshot file and exit.
+ //
+ if ( eLoaded == LoadModel_Success )
+ {
+ if ( g_pStudioModel->m_bIsTransparent )
+ {
+ Msg("%s is transparent\n", filename );
+ }
+ if ( g_pStudioModel->m_bHasProxy )
+ {
+ Msg("%s has material proxies\n", filename );
+ }
+ }
+
+ // Shut down.
+ mx::quit();
+}
+
+
+const char* MDLViewer::SteamGetOpenFilename()
+{
+ if ( !g_FSDialogFactory )
+ return NULL;
+
+ static char filename[MAX_PATH];
+
+ IFileSystemOpenDialog *pDlg;
+ pDlg = (IFileSystemOpenDialog*)g_FSDialogFactory( FILESYSTEMOPENDIALOG_VERSION, NULL );
+ if ( !pDlg )
+ {
+ char str[512];
+ Q_snprintf( str, sizeof( str ), "Can't create %s interface.", FILESYSTEMOPENDIALOG_VERSION );
+ MessageBox( NULL, str, "Error", MB_OK );
+ return NULL;
+ }
+ pDlg->Init( g_Factory, NULL );
+ pDlg->AddFileMask( "*.jpg" );
+ pDlg->AddFileMask( "*.mdl" );
+ pDlg->SetInitialDir( "models", "game" );
+ pDlg->SetFilterMdlAndJpgFiles( true );
+
+ if (pDlg->DoModal() == IDOK)
+ {
+ pDlg->GetFilename( filename, sizeof( filename ) );
+ pDlg->Release();
+ return filename;
+ }
+ else
+ {
+ pDlg->Release();
+ return NULL;
+ }
+}
+
+
+int
+MDLViewer::handleEvent (mxEvent *event)
+{
+ MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
+
+ switch (event->event)
+ {
+ case mxEvent::Action:
+ {
+ switch (event->action)
+ {
+ case IDC_FILE_LOADMODEL:
+ {
+ const char *ptr = mxGetOpenFileName (this, 0, "*.mdl");
+ if (ptr)
+ {
+ LoadModelFile( ptr );
+ }
+ }
+ break;
+
+ case IDC_FILE_LOADMODEL_STEAM:
+ {
+ const char *pFilename = SteamGetOpenFilename();
+ if ( pFilename )
+ {
+ LoadModelFile( pFilename );
+ }
+ }
+ break;
+
+ case IDC_FILE_LOADMERGEDMODEL:
+ {
+ const char *ptr = mxGetOpenFileName (this, 0, "*.mdl");
+ if (ptr)
+ {
+ // find the first free slot
+ int iChosenSlot = 0;
+ for ( int i = 0; i < HLMV_MAX_MERGED_MODELS; i++ )
+ {
+ if ( g_viewerSettings.mergeModelFile[i][0] == 0 )
+ {
+ iChosenSlot = i;
+ break;
+ }
+ }
+ strcpy( g_viewerSettings.mergeModelFile[iChosenSlot], ptr );
+ LoadModelFile( ptr, iChosenSlot );
+ }
+ }
+ break;
+
+ case IDC_FILE_LOADMERGEDMODEL_STEAM:
+ {
+ const char *pFilename = SteamGetOpenFilename();
+ if ( pFilename )
+ {
+ // find the first free slot
+ int iChosenSlot = 0;
+ for ( int i = 0; i < HLMV_MAX_MERGED_MODELS; i++ )
+ {
+ if ( g_viewerSettings.mergeModelFile[i][0] == 0 )
+ {
+ iChosenSlot = i;
+ break;
+ }
+ }
+ strcpy( g_viewerSettings.mergeModelFile[iChosenSlot], pFilename );
+ LoadModelFile( pFilename, iChosenSlot );
+ }
+ }
+ break;
+
+
+ case IDC_FILE_UNLOADMERGEDMODEL1:
+ case IDC_FILE_UNLOADMERGEDMODEL2:
+ case IDC_FILE_UNLOADMERGEDMODEL3:
+ case IDC_FILE_UNLOADMERGEDMODEL4:
+ case IDC_FILE_UNLOADMERGEDMODEL5:
+ case IDC_FILE_UNLOADMERGEDMODEL6:
+ case IDC_FILE_UNLOADMERGEDMODEL7:
+ case IDC_FILE_UNLOADMERGEDMODEL8:
+ case IDC_FILE_UNLOADMERGEDMODEL9:
+ case IDC_FILE_UNLOADMERGEDMODEL10:
+ case IDC_FILE_UNLOADMERGEDMODEL11:
+ case IDC_FILE_UNLOADMERGEDMODEL12:
+ {
+ int i = event->action - IDC_FILE_UNLOADMERGEDMODEL1;
+ // FIXME: move to d_cpl
+ if (g_pStudioExtraModel[i])
+ {
+ V_strcpy_safe( g_viewerSettings.mergeModelFile[i], "" );
+ g_pStudioExtraModel[i]->FreeModel( false );
+ delete g_pStudioExtraModel[i];
+ g_pStudioExtraModel[i] = NULL;
+
+ mb->modify (IDC_FILE_UNLOADMERGEDMODEL1 + i, IDC_FILE_UNLOADMERGEDMODEL1 + i, "(empty)");
+ mb->setEnabled (IDC_FILE_UNLOADMERGEDMODEL1 + i, false);
+ }
+ }
+ break;
+
+ case IDC_FILE_UNLOADALLMERGEDMODELS:
+ d_cpl->UnloadAllMergedModels();
+ break;
+
+ case IDC_FILE_REFRESH:
+ {
+ Refresh();
+ break;
+ }
+
+ case IDC_FLUSH_SHADERS:
+ {
+ CCommand args;
+ args.Tokenize( "mat_flushshaders" );
+
+ ConCommandBase *pCommandBase = g_pCVar->FindCommandBase( args[0] );
+ if ( !pCommandBase )
+ {
+ ConWarning( "Unknown command or convar '%s'!\n", args[0] );
+ break;
+ }
+
+ if ( pCommandBase->IsCommand() )
+ {
+ ConCommand *pCommand = static_cast<ConCommand*>( pCommandBase );
+ pCommand->Dispatch( args );
+ }
+ }
+ break;
+
+ case IDC_FILE_LOADBACKGROUNDTEX:
+ case IDC_FILE_LOADGROUNDTEX:
+ {
+ const char *ptr = mxGetOpenFileName (this, 0, "*.*");
+ if (ptr)
+ {
+ if (0 /* d_MatSysWindow->loadTexture (ptr, event->action - IDC_FILE_LOADBACKGROUNDTEX) */)
+ {
+ if (event->action == IDC_FILE_LOADBACKGROUNDTEX)
+ d_cpl->setShowBackground (true);
+ else
+ d_cpl->setShowGround (true);
+
+ }
+ else
+ mxMessageBox (this, "Error loading texture.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
+ }
+ }
+ break;
+
+ case IDC_FILE_UNLOADGROUNDTEX:
+ {
+ // d_MatSysWindow->loadTexture (0, 1);
+ d_cpl->setShowGround (false);
+ }
+ break;
+
+ case IDC_FILE_RECENTMODELS1:
+ case IDC_FILE_RECENTMODELS2:
+ case IDC_FILE_RECENTMODELS3:
+ case IDC_FILE_RECENTMODELS4:
+ case IDC_FILE_RECENTMODELS5:
+ case IDC_FILE_RECENTMODELS6:
+ case IDC_FILE_RECENTMODELS7:
+ case IDC_FILE_RECENTMODELS8:
+ {
+ int i = event->action - IDC_FILE_RECENTMODELS1;
+ LoadModelFile( recentFiles[i] );
+ }
+ break;
+
+ case IDC_FILE_EXIT:
+ {
+ redraw ();
+ mx::quit ();
+ }
+ break;
+
+ case IDC_OPTIONS_COLORBACKGROUND:
+ case IDC_OPTIONS_COLORGROUND:
+ case IDC_OPTIONS_COLORLIGHT:
+ case IDC_OPTIONS_COLORAMBIENT:
+ {
+ float *cols[4] = { g_viewerSettings.bgColor, g_viewerSettings.gColor, g_viewerSettings.lColor, g_viewerSettings.aColor };
+ float *col = cols[event->action - IDC_OPTIONS_COLORBACKGROUND];
+ int r = (int) (col[0] * 255.0f);
+ int g = (int) (col[1] * 255.0f);
+ int b = (int) (col[2] * 255.0f);
+ if (mxChooseColor (this, &r, &g, &b))
+ {
+ col[0] = (float) r / 255.0f;
+ col[1] = (float) g / 255.0f;
+ col[2] = (float) b / 255.0f;
+ }
+ }
+ break;
+
+ case IDC_OPTIONS_CENTERVIEW:
+ d_cpl->centerView ();
+ if ( g_bHlmvMaster )
+ {
+ SendModelTransformToLinkedHlmv();
+ }
+ break;
+ case IDC_OPTIONS_CENTERVERTS:
+ //d_cpl->centerVerts( );
+ if ( g_bHlmvMaster )
+ {
+ SendModelTransformToLinkedHlmv();
+ }
+ break;
+ case IDC_OPTIONS_VIEWMODEL:
+ {
+ d_cpl->viewmodelView();
+ if ( g_bHlmvMaster )
+ {
+ SendModelTransformToLinkedHlmv();
+ }
+ }
+ break;
+
+ case IDC_OPTIONS_MAKESCREENSHOT:
+ {
+ char *ptr = (char *) mxGetSaveFileName (this, "", "*.tga");
+ if (ptr)
+ {
+ if (!strstr (ptr, ".tga"))
+ strcat (ptr, ".tga");
+ d_MatSysWindow->dumpViewport (ptr);
+ }
+ }
+ break;
+
+ case IDC_OPTIONS_DUMP:
+ d_cpl->dumpModelInfo ();
+ break;
+
+ case IDC_OPTIONS_SYNCHLMVCAMERA:
+ SendModelTransformToLinkedHlmv();
+
+ break;
+
+ case IDC_OPTIONS_LINKHLMV:
+ if ( !g_bHlmvMaster && !g_HlmvIpcServer.IsRunning() && g_HlmvIpcClient.Connect() )
+ {
+ CUtlBuffer cmd;
+ CUtlBuffer res;
+
+ // Make connection to other hlmv
+ cmd.PutString( "hlmvLink" );
+ cmd.PutChar( '\0' );
+
+ if ( g_HlmvIpcClient.ExecuteCommand( cmd, res ) )
+ {
+ g_bHlmvMaster = true;
+ }
+
+ g_HlmvIpcClient.Disconnect();
+
+ SendModelTransformToLinkedHlmv();
+ SendLightRotToLinkedHlmv();
+
+ menuOptions->setChecked( IDC_OPTIONS_LINKHLMV, true );
+ menuOptions->setEnabled( IDC_OPTIONS_LINKHLMV, false );
+
+ menuOptions->setChecked( IDC_OPTIONS_UNLINKHLMV, false );
+ menuOptions->setEnabled( IDC_OPTIONS_UNLINKHLMV, true );
+ }
+ break;
+
+ case IDC_OPTIONS_UNLINKHLMV:
+ if ( g_bHlmvMaster && g_HlmvIpcClient.Connect() )
+ {
+ CUtlBuffer cmd;
+ CUtlBuffer res;
+
+ // Break connection to linked hlmv
+
+ cmd.PutString( "hlmvUnlink" );
+ cmd.PutChar( '\0' );
+
+ g_HlmvIpcClient.ExecuteCommand( cmd, res );
+ g_bHlmvMaster = false;
+
+ g_HlmvIpcClient.Disconnect();
+
+ menuOptions->setChecked( IDC_OPTIONS_LINKHLMV, false );
+ menuOptions->setEnabled( IDC_OPTIONS_LINKHLMV, true );
+
+ menuOptions->setChecked( IDC_OPTIONS_UNLINKHLMV, true );
+ menuOptions->setEnabled( IDC_OPTIONS_UNLINKHLMV, false );
+ }
+ break;
+
+ case IDC_VIEW_FILEASSOCIATIONS:
+ g_FileAssociation->setAssociation (0);
+ g_FileAssociation->setVisible (true);
+ break;
+
+ case IDC_VIEW_ACTIVITIES:
+ g_viewerSettings.showActivities = !g_viewerSettings.showActivities;
+ menuView->setChecked( event->action, g_viewerSettings.showActivities );
+ d_cpl->initSequenceChoices();
+ d_cpl->resetControlPanel();
+ break;
+
+ case IDC_VIEW_HIDDEN:
+ g_viewerSettings.showHidden = !g_viewerSettings.showHidden;
+ menuView->setChecked( event->action, g_viewerSettings.showHidden );
+ d_cpl->initSequenceChoices();
+ d_cpl->resetControlPanel();
+ break;
+
+#ifdef WIN32
+ case IDC_HELP_GOTOHOMEPAGE:
+ ShellExecute (0, "open", "http://www.swissquake.ch/chumbalum-soft/index.html", 0, 0, SW_SHOW);
+ break;
+#endif
+
+ case IDC_HELP_ABOUT:
+ mxMessageBox (this,
+ "Half-Life Model Viewer v2.0 (c) 2004 Valve Corp.\n"
+ "Portions (c) 1999 by Mete Ciragan\n\n"
+ "Left-drag inside circle to spin.\n"
+ "Left-drag outside circle to rotate.\n"
+ "Right-drag to zoom.\n"
+ "Shift-left-drag to x-y-pan.\n"
+ "Shift-right-drag to z-pan.\n"
+ "Ctrl-left-drag to move light.\n\n"
+ "Build:\t" __DATE__ ".\n"
+ "Email:\[email protected]\n"
+ "Web:\thttp://www.swissquake.ch/chumbalum-soft/", "About Half-Life Model Viewer",
+ MX_MB_OK | MX_MB_INFORMATION);
+ break;
+
+ case IDC_ACCEL_WIREFRAME:
+ d_cpl->setOverlayWireframe( !g_viewerSettings.overlayWireframe );
+ break;
+
+ case IDC_ACCEL_ATTACHMENTS:
+ d_cpl->setShowAttachments( !g_viewerSettings.showAttachments );
+ break;
+
+ case IDC_ACCEL_GROUND:
+ d_cpl->setShowGround( !g_viewerSettings.showGround );
+ break;
+
+ case IDC_ACCEL_HITBOXES:
+ d_cpl->setShowHitBoxes( !g_viewerSettings.showHitBoxes );
+ break;
+
+ case IDC_ACCEL_BONES:
+ d_cpl->setShowBones( !g_viewerSettings.showBones );
+ break;
+
+ case IDC_ACCEL_BACKGROUND:
+ d_cpl->setShowBackground( !g_viewerSettings.showBackground );
+ break;
+
+ case IDC_ACCEL_MOVEMENT:
+ d_cpl->setShowMovement( !g_viewerSettings.showMovement );
+ break;
+
+ case IDC_ACCEL_NORMALS:
+ d_cpl->setShowNormals( !g_viewerSettings.showNormals );
+ break;
+
+ case IDC_ACCEL_TANGENTS:
+ d_cpl->setShowTangentFrame( !g_viewerSettings.showTangentFrame );
+ break;
+
+ case IDC_ACCEL_SHADOW:
+ d_cpl->setShowShadow( !g_viewerSettings.showShadow );
+ break;
+
+ } //switch (event->action)
+
+ } // mxEvent::Action
+ break;
+
+ case mxEvent::Size:
+ {
+ g_viewerSettings.xpos = x();
+ g_viewerSettings.ypos = y();
+ g_viewerSettings.width = w();
+ g_viewerSettings.height = h();
+
+ int w = event->width;
+ int h = event->height;
+ int y = mb->getHeight ();
+#ifdef WIN32
+#define HEIGHT 240
+#else
+#define HEIGHT 140
+ h -= 40;
+#endif
+
+ d_MatSysWindow->setBounds (0, y, w, h - HEIGHT); // !!
+ d_cpl->setBounds (0, y + h - HEIGHT, w, HEIGHT);
+ }
+ break;
+
+
+ case mxEvent::PosChanged:
+ {
+ g_viewerSettings.xpos = x();
+ g_viewerSettings.ypos = y();
+ }
+ break;
+
+ case KeyDown:
+ d_MatSysWindow->handleEvent(event);
+ d_cpl->handleEvent(event);
+ break;
+
+ case mxEvent::Activate:
+ {
+ if (event->action)
+ {
+ mx::setIdleWindow( getMatSysWindow() );
+ }
+ else
+ {
+ mx::setIdleWindow( 0 );
+ }
+ }
+ break;
+
+ case mxEvent::Timer:
+ {
+ if ( g_HlmvIpcServer.HasCommands() )
+ {
+ // Execute next command at next msg pump, ~ 1/60th s (60Hz) if controlled, 0.1s if not
+ if ( g_bHlmvControlled )
+ {
+ // Clear up to 10 pending commands if controlled
+ for ( int nCmdCount = 0; nCmdCount < 10 && g_HlmvIpcServer.HasCommands(); ++nCmdCount )
+ {
+ handleIpcCommand( g_HlmvIpcServer.GetCommand() );
+ g_HlmvIpcServer.PopCommand();
+ }
+
+ setTimer( 17 );
+ }
+ else
+ {
+ handleIpcCommand( g_HlmvIpcServer.GetCommand() );
+ g_HlmvIpcServer.PopCommand();
+
+ setTimer( 100 );
+ }
+ }
+ else if ( !g_HlmvIpcServer.IsRunning() )
+ {
+ // Keep trying to establish our server slot if another instance quits
+ BOOL bIsRunning = g_HlmvIpcServer.IsRunning();
+ g_HlmvIpcServer.EnsureRegisteredAndRunning();
+ if ( !bIsRunning && g_HlmvIpcServer.IsRunning() )
+ {
+ g_bHlmvMaster = false;
+ menuOptions->setEnabled( IDC_OPTIONS_LINKHLMV, false );
+ menuOptions->setChecked( IDC_OPTIONS_LINKHLMV, false );
+ menuOptions->setEnabled( IDC_OPTIONS_UNLINKHLMV, false );
+ menuOptions->setChecked( IDC_OPTIONS_LINKHLMV, false );
+ }
+
+ // Attempt every 1.0 s
+ setTimer( 1000 );
+ }
+ else
+ {
+ // Idling, poll command queue @ ~60Hz if controlled, 0.5s ( 2Hz ) otherwise
+ if ( g_bHlmvControlled )
+ {
+ setTimer( 17 );
+ }
+ else
+ {
+ setTimer( 500 );
+ }
+ }
+ }
+ break;
+ } // event->event
+
+ return 1;
+}
+
+
+
+void TranslateMayaToHLMVCoordinates( const Vector &vMayaPos, const QAngle &vMayaRot, Vector &vHLMVPos, QAngle &vHLMVAngles )
+{
+ vHLMVPos.Init( vMayaPos.z, vMayaPos.x, vMayaPos.y );
+
+ vHLMVAngles[PITCH] = -vMayaRot[0];
+ vHLMVAngles[YAW] = vMayaRot[1] + 180;
+ vHLMVAngles[ROLL] = -vMayaRot[2];
+}
+
+
+void MDLViewer::handleIpcCommand( char *szCommand )
+{
+ MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
+
+ if ( !strcmp( "reload", szCommand ) )
+ {
+ Refresh();
+
+ if ( HWND hWnd = (HWND) getHandle() )
+ {
+ if ( ::IsIconic( hWnd ) )
+ ::ShowWindow( hWnd, SW_RESTORE );
+
+ ::BringWindowToTop( hWnd );
+ ::SetForegroundWindow( hWnd );
+ ::SetFocus( hWnd );
+ }
+ }
+ else if ( V_strncasecmp( "cameraTo", szCommand, 8 ) == 0 )
+ {
+ // Read the camera position and angles from Maya.
+ Vector vMayaPos;
+ QAngle vMayaRot;
+
+ char szFirstPart[32];
+ sscanf( szCommand, "%s %f %f %f %f %f %f",
+ szFirstPart,
+ &vMayaPos.x, &vMayaPos.y, &vMayaPos.z,
+ &vMayaRot.x, &vMayaRot.y, &vMayaRot.z );
+
+
+ //
+ // Obviously, this could all be simplified, but it's nice to make it easy to see what it's doing here.
+ //
+
+
+ // Translate the camera position/angles from Maya space to model space.
+ // In model space, +X=forward, +Y=left, and +Z=up
+ // (i.e. the model faces forward along +X)
+ Vector vCameraPos;
+ QAngle vCameraAngles;
+ TranslateMayaToHLMVCoordinates( vMayaPos, vMayaRot, vCameraPos, vCameraAngles );
+
+
+ // Now, build a matrix from model space to camera space. The way we're defining camera space,
+ // the axes point the same way as in model space (+X=forward, +Y=left, +Z=up).
+ // This is a standard put-stuff-in-camera-space matrix (backtranslate and then backrotate).
+ matrix3x4_t mModelToCameraRot, mModelToCameraTrans, mModelToCameraFull;
+
+ // Backtranslate..
+ SetIdentityMatrix( mModelToCameraTrans );
+ MatrixSetColumn( -vCameraPos, 3, mModelToCameraTrans );
+
+ // Backrotate..
+ AngleMatrix( vCameraAngles, mModelToCameraRot );
+ MatrixTranspose( mModelToCameraRot );
+
+ // Concatenate.
+ MatrixMultiply( mModelToCameraRot, mModelToCameraTrans, mModelToCameraFull );
+
+
+ // Now we need to convert the camera space from above to HLMV's specific camera space. This just means negating
+ // the X and Y axes because HLMV's camera space is (+X=back, +Y=left, +Z=up).
+ matrix3x4_t mCameraToWorld(
+ -1, 0, 0, 0,
+ 0, -1, 0, 0,
+ 0, 0, 1, 0 );
+
+ // Blat all these matrices together.
+ matrix3x4_t mFinal;
+ MatrixMultiply( mCameraToWorld, mModelToCameraFull, mFinal );
+
+ // Tell HLMV our new fancy transform to use, and then we'll see the model from the same place Maya did.
+ g_pStudioModel->SetModelTransform( mFinal );
+
+ // Redraw.
+ d_MatSysWindow->redraw();
+ }
+ else if ( StringHasPrefixCaseSensitive( szCommand, "hlmvModelTransform" ) )
+ {
+ matrix3x4_t m;
+
+ sscanf( szCommand, "%*s %f %f %f %f %f %f %f %f %f %f %f %f",
+ &m.m_flMatVal[0][0], &m.m_flMatVal[0][1], &m.m_flMatVal[0][2], &m.m_flMatVal[0][3],
+ &m.m_flMatVal[1][0], &m.m_flMatVal[1][1], &m.m_flMatVal[1][2], &m.m_flMatVal[1][3],
+ &m.m_flMatVal[2][0], &m.m_flMatVal[2][1], &m.m_flMatVal[2][2], &m.m_flMatVal[2][3] );
+
+ // Tell HLMV our new fancy transform to use, and then we'll see the model from the same place Maya did.
+ g_pStudioModel->SetModelTransform( m );
+
+ // Redraw.
+ d_MatSysWindow->redraw();
+ }
+ else if ( StringHasPrefixCaseSensitive( szCommand, "hlmvLightRot" ) )
+ {
+ sscanf( szCommand, "%*s %f %f %f",
+ &g_viewerSettings.lightrot[0], &g_viewerSettings.lightrot[1], &g_viewerSettings.lightrot[2] );
+
+ // Redraw.
+ d_MatSysWindow->redraw();
+ }
+ else if ( StringHasPrefixCaseSensitive( szCommand, "hlmvForceFrame" ) )
+ {
+ float flFrame = 0.0f;
+ sscanf( szCommand, "%*s %f", &flFrame );
+
+ d_cpl->SetFrameSlider( flFrame );
+ d_cpl->setFrame( flFrame );
+ d_cpl->setSpeedScale( 0 );
+
+ // Redraw.
+ d_MatSysWindow->redraw();
+ }
+ else if ( StringHasPrefixCaseSensitive( szCommand, "hlmvLink" ) )
+ {
+ if ( !g_bHlmvControlled )
+ {
+ g_bHlmvControlled = true;
+
+ CUtlString label( "LINKED: " );
+ label += getLabel();
+ setLabel( label.Get() );
+ }
+ }
+ else if ( StringHasPrefixCaseSensitive( szCommand, "hlmvUnlink" ) )
+ {
+ g_bHlmvControlled = false;
+
+ const char *pszLabel = getLabel();
+ if ( StringHasPrefixCaseSensitive( pszLabel, "LINKED: " ) )
+ {
+ setLabel( pszLabel + 8 ); // Skip past "LINKED: "
+ }
+ }
+}
+
+
+void
+MDLViewer::redraw ()
+{
+ /*
+ mxEvent event;
+ event.event = mxEvent::Size;
+ event.width = w2 ();
+ event.height = h2 ();
+ handleEvent (&event);
+ */
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int MDLViewer::GetCurrentHitboxSet( void )
+{
+ return d_cpl ? d_cpl->GetCurrentHitboxSet() : 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Sends the model transform to the controlled hlmv instance
+//-----------------------------------------------------------------------------
+void MDLViewer::SendModelTransformToLinkedHlmv()
+{
+ if ( g_bHlmvMaster && g_HlmvIpcClient.Connect() )
+ {
+ matrix3x4_t m;
+ g_pStudioModel->GetModelTransform( m );
+
+ CUtlBuffer cmd;
+ CUtlBuffer res;
+
+ cmd.Printf( "%s %f %f %f %f %f %f %f %f %f %f %f %f",
+ "hlmvModelTransform",
+ m.m_flMatVal[0][0], m.m_flMatVal[0][1], m.m_flMatVal[0][2], m.m_flMatVal[0][3],
+ m.m_flMatVal[1][0], m.m_flMatVal[1][1], m.m_flMatVal[1][2], m.m_flMatVal[1][3],
+ m.m_flMatVal[2][0], m.m_flMatVal[2][1], m.m_flMatVal[2][2], m.m_flMatVal[2][3] );
+
+ g_HlmvIpcClient.ExecuteCommand( cmd, res );
+
+ g_HlmvIpcClient.Disconnect();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sends the light rotation to the controlled hlmv instance
+//-----------------------------------------------------------------------------
+void MDLViewer::SendLightRotToLinkedHlmv()
+{
+ if ( g_bHlmvMaster && g_HlmvIpcClient.Connect() )
+ {
+ CUtlBuffer cmdLightRot;
+ CUtlBuffer resLightRot;
+
+ cmdLightRot.Printf( "%s %f %f %f",
+ "hlmvLightRot",
+ g_viewerSettings.lightrot[0], g_viewerSettings.lightrot[1], g_viewerSettings.lightrot[2] );
+
+ g_HlmvIpcClient.ExecuteCommand( cmdLightRot, resLightRot );
+
+ g_HlmvIpcClient.Disconnect();
+ }
+}
+
+
+SpewRetval_t HLMVSpewFunc( SpewType_t spewType, char const *pMsg )
+{
+ g_bInError = true;
+ switch (spewType)
+ {
+ case SPEW_ERROR:
+ MessageBox(NULL, pMsg, "FATAL ERROR", MB_OK);
+ g_bInError = false;
+ return SPEW_ABORT;
+
+ default:
+ OutputDebugString(pMsg);
+ g_bInError = false;
+#ifdef _DEBUG
+ return spewType == SPEW_ASSERT ? SPEW_DEBUGGER : SPEW_CONTINUE;
+#else
+ return SPEW_CONTINUE;
+#endif
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// The application object
+//-----------------------------------------------------------------------------
+class CHLModelViewerApp : public CSteamAppSystemGroup
+{
+public:
+ // Methods of IApplication
+ virtual bool Create();
+ virtual bool PreInit();
+ virtual int Main();
+ virtual void PostShutdown();
+ virtual void Destroy();
+};
+
+
+//-----------------------------------------------------------------------------
+// Create all singleton systems
+//-----------------------------------------------------------------------------
+bool CHLModelViewerApp::Create()
+{
+ SpewOutputFunc( HLMVSpewFunc );
+
+ g_dxlevel = CommandLine()->ParmValue( "-dx", 0 );
+ g_bOldFileDialogs = ( CommandLine()->FindParm( "-olddialogs" ) != 0 );
+
+ AppSystemInfo_t appSystems[] =
+ {
+ { "materialsystem.dll", MATERIAL_SYSTEM_INTERFACE_VERSION },
+ { "studiorender.dll", STUDIO_RENDER_INTERFACE_VERSION },
+ { "vphysics.dll", VPHYSICS_INTERFACE_VERSION },
+ { "datacache.dll", DATACACHE_INTERFACE_VERSION },
+ { "datacache.dll", MDLCACHE_INTERFACE_VERSION },
+ { "datacache.dll", STUDIO_DATA_CACHE_INTERFACE_VERSION },
+ { "soundemittersystem.dll", SOUNDEMITTERSYSTEM_INTERFACE_VERSION },
+ { "soundsystem.dll", SOUNDSYSTEM_INTERFACE_VERSION },
+
+ { "", "" } // Required to terminate the list
+ };
+
+ if ( !AddSystems( appSystems ) )
+ return false;
+
+ g_pFileSystem = (IFileSystem*)FindSystem( FILESYSTEM_INTERFACE_VERSION );
+ g_pMaterialSystem = (IMaterialSystem*)FindSystem( MATERIAL_SYSTEM_INTERFACE_VERSION );
+ g_pMaterialSystemHardwareConfig = (IMaterialSystemHardwareConfig*)FindSystem( MATERIALSYSTEM_HARDWARECONFIG_INTERFACE_VERSION );
+ g_pStudioRender = (IStudioRender*)FindSystem( STUDIO_RENDER_INTERFACE_VERSION );
+ g_pDataCache = (IDataCache*)FindSystem( DATACACHE_INTERFACE_VERSION );
+ g_pMDLCache = (IMDLCache*)FindSystem( MDLCACHE_INTERFACE_VERSION );
+ g_pStudioDataCache = (IStudioDataCache*)FindSystem( STUDIO_DATA_CACHE_INTERFACE_VERSION );
+ physcollision = (IPhysicsCollision *)FindSystem( VPHYSICS_COLLISION_INTERFACE_VERSION );
+ physprop = (IPhysicsSurfaceProps *)FindSystem( VPHYSICS_SURFACEPROPS_INTERFACE_VERSION );
+ g_pSoundEmitterBase = (ISoundEmitterSystemBase *)FindSystem( SOUNDEMITTERSYSTEM_INTERFACE_VERSION );
+ g_pSoundSystem = (ISoundSystem *)FindSystem( SOUNDSYSTEM_INTERFACE_VERSION );
+
+ if ( !g_pFileSystem || !physprop || !physcollision || !g_pMaterialSystem || !g_pStudioRender || !g_pMDLCache || !g_pDataCache )
+ {
+ Error("Unable to load required library interface!\n");
+ }
+
+ const char *pShaderDLL = CommandLine()->ParmValue("-shaderdll");
+ const char *pArg;
+ if ( CommandLine()->CheckParm( "-shaderapi", &pArg ))
+ {
+ pShaderDLL = pArg;
+ }
+
+ if(!pShaderDLL)
+ {
+ pShaderDLL = "shaderapidx9.dll";
+ }
+
+ g_pMaterialSystem->SetShaderAPI( pShaderDLL );
+
+ g_Factory = GetFactory();
+
+ return true;
+}
+
+
+void CHLModelViewerApp::Destroy()
+{
+ g_pFileSystem = NULL;
+ g_pMaterialSystem = NULL;
+ g_pMaterialSystemHardwareConfig = NULL;
+ g_pStudioRender = NULL;
+ g_pDataCache = NULL;
+ g_pMDLCache = NULL;
+ g_pStudioDataCache = NULL;
+ physcollision = NULL;
+ physprop = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Init, shutdown
+//-----------------------------------------------------------------------------
+bool CHLModelViewerApp::PreInit( )
+{
+ CreateInterfaceFn factory = GetFactory();
+ ConnectTier1Libraries( &factory, 1 );
+ ConVar_Register( 0 );
+
+ MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false );
+
+ // Add paths...
+ if ( !SetupSearchPaths( NULL, false, true ) )
+ return false;
+
+ // Get the adapter from the command line....
+ const char *pAdapterString;
+ int nAdapter = 0;
+ if (CommandLine()->CheckParm( "-adapter", &pAdapterString ))
+ {
+ nAdapter = atoi( pAdapterString );
+ }
+
+ int nAdapterFlags = 0;
+ if ( CommandLine()->CheckParm( "-ref" ) )
+ {
+ nAdapterFlags |= MATERIAL_INIT_REFERENCE_RASTERIZER;
+ }
+
+ g_pMaterialSystem->SetAdapter( nAdapter, nAdapterFlags );
+
+ g_bOldFileDialogs = true;
+ if ( CommandLine()->FindParm( "-NoSteamdDialog" ) )
+ g_bOldFileDialogs = false;
+
+ LoadFileSystemDialogModule();
+
+ return true;
+}
+
+void CHLModelViewerApp::PostShutdown()
+{
+ UnloadFileSystemDialogModule();
+ DisconnectTier1Libraries();
+}
+
+
+//-----------------------------------------------------------------------------
+// main application
+//-----------------------------------------------------------------------------
+int CHLModelViewerApp::Main()
+{
+ g_pMaterialSystem->ModInit();
+ g_pSoundEmitterBase->ModInit();
+
+ g_pDataCache->SetSize( 64 * 1024 * 1024 );
+
+ //mx::setDisplayMode (0, 0, 0);
+ g_MDLViewer = new MDLViewer ();
+ g_MDLViewer->setMenuBar (g_MDLViewer->getMenuBar ());
+
+ g_pStudioModel->Init();
+ g_pStudioModel->ModelInit();
+ g_pStudioModel->ClearLookTargets( );
+
+ // Load up the initial model
+ const char *pMdlName = NULL;
+ int nParmCount = CommandLine()->ParmCount();
+ if ( nParmCount > 1 )
+ {
+ pMdlName = CommandLine()->GetParm( nParmCount - 1 );
+ }
+
+ if ( pMdlName && Q_stristr( pMdlName, ".mdl" ) )
+ {
+ char absPath[MAX_PATH];
+ Q_MakeAbsolutePath( absPath, sizeof( absPath ), pMdlName );
+
+ if ( CommandLine()->FindParm( "-screenshot" ) )
+ {
+ g_MDLViewer->SaveScreenShot( absPath );
+ }
+ else if ( CommandLine()->FindParm( "-dump" ) )
+ {
+ g_MDLViewer->DumpText( absPath );
+ }
+ else
+ {
+ g_MDLViewer->LoadModelFile( absPath );
+ }
+ }
+
+ int nRetVal = mx::run ();
+
+ g_pStudioModel->Shutdown();
+ g_pMaterialSystem->ModShutdown();
+
+ return nRetVal;
+}
+
+static bool CHLModelViewerApp_SuggestGameInfoDirFn( CFSSteamSetupInfo const *pFsSteamSetupInfo, char *pchPathBuffer, int nBufferLength, bool *pbBubbleDirectories )
+{
+ const char *pMdlName = NULL;
+ int nParmCount = CommandLine()->ParmCount();
+ if ( nParmCount > 1 )
+ {
+ pMdlName = CommandLine()->GetParm( nParmCount - 1 );
+ }
+
+ if ( pMdlName && Q_stristr( pMdlName, ".mdl" ) )
+ {
+ Q_MakeAbsolutePath( pchPathBuffer, nBufferLength, pMdlName );
+
+ if ( pbBubbleDirectories )
+ *pbBubbleDirectories = true;
+
+ return true;
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Main entry point
+//-----------------------------------------------------------------------------
+int main (int argc, char *argv[])
+{
+ CommandLine()->CreateCmdLine( argc, argv );
+ mx::init( argc, argv );
+
+ // make sure we start in the right directory
+ char szName[256];
+ strcpy( szName, mx::getApplicationPath() );
+ // mx_setcwd (szName);
+
+ // Set game info directory suggestion callback
+ SetSuggestGameInfoDirFn( CHLModelViewerApp_SuggestGameInfoDirFn );
+
+ CHLModelViewerApp hlmodelviewerApp;
+ CSteamApplication steamApplication( &hlmodelviewerApp );
+ return steamApplication.Run();
+}
+//
+// Implementation of IPC server
+//
+
+
+CHlmvIpcServer::~CHlmvIpcServer()
+{
+ for ( int k = 0; k < m_lstCommands.Count(); ++ k )
+ {
+ delete [] m_lstCommands[k];
+ }
+ m_lstCommands.Purge();
+}
+
+bool CHlmvIpcServer::HasCommands()
+{
+ AUTO_LOCK( m_mtx );
+ return m_lstCommands.Count() > 0;
+}
+
+void CHlmvIpcServer::AppendCommand( char *pszCommand )
+{
+ AUTO_LOCK( m_mtx );
+ m_lstCommands.AddToTail( pszCommand );
+}
+
+char * CHlmvIpcServer::GetCommand()
+{
+ AUTO_LOCK( m_mtx );
+ return m_lstCommands.Count() ? m_lstCommands[0] : "";
+}
+
+void CHlmvIpcServer::PopCommand()
+{
+ AUTO_LOCK( m_mtx );
+ if ( m_lstCommands.Count() )
+ {
+ delete [] m_lstCommands[0];
+ m_lstCommands.Remove( 0 );
+ }
+}
+
+BOOL CHlmvIpcServer::ExecuteCommand(CUtlBuffer &cmd, CUtlBuffer &res)
+{
+ char *szCommand = ( char * ) cmd.Base();
+ int nLen = strlen( szCommand );
+ while ( nLen > 0 && V_isspace( szCommand[ nLen - 1 ] ) )
+ -- nLen;
+
+ if ( nLen <= 0 )
+ return FALSE;
+
+ char *pchCopy = new char[ nLen + 1 ];
+ memcpy( pchCopy, szCommand, nLen );
+ pchCopy[ nLen ] = 0;
+
+ AppendCommand( pchCopy );
+
+ res.PutInt( 0 );
+ return TRUE;
+}
+