Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2064 lines
55 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. //
  9. // Half-Life Model Viewer (c) 1999 by Mete Ciragan
  10. //
  11. // file: mdlviewer.cpp
  12. // last modified: Jun 03 1999, Mete Ciragan
  13. // copyright: The programs and associated files contained in this
  14. // distribution were developed by Mete Ciragan. The programs
  15. // are not in the public domain, but they are freely
  16. // distributable without licensing fees. These programs are
  17. // provided without guarantee or warrantee expressed or
  18. // implied.
  19. //
  20. // version: 1.2
  21. //
  22. // email: [email protected]
  23. // web: http://www.swissquake.ch/chumbalum-soft/
  24. //
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <mxtk/mx.h>
  29. #include <mxtk/mxTga.h>
  30. #include <mxtk/mxEvent.h>
  31. #include "mdlviewer.h"
  32. #include "ViewerSettings.h"
  33. #include "MatSysWin.h"
  34. #include "ControlPanel.h"
  35. #include "StudioModel.h"
  36. #include "FileAssociation.h"
  37. #include "tier1/strtools.h"
  38. #include "tier0/icommandline.h"
  39. #include "filesystem.h"
  40. #include "ifilesystemopendialog.h"
  41. #include "appframework/tier3app.h"
  42. #include "istudiorender.h"
  43. #include "materialsystem/imaterialsystem.h"
  44. #include "vphysics_interface.h"
  45. #include "Datacache/imdlcache.h"
  46. #include "datacache/idatacache.h"
  47. #include "filesystem_init.h"
  48. #include "materialsystem/imaterialsystemhardwareconfig.h"
  49. #include "SoundEmitterSystem/isoundemittersystembase.h"
  50. #include "soundsystem/isoundsystem.h"
  51. #include "tier2/tier2.h"
  52. #include "tier3/tier3.h"
  53. #include "p4lib/ip4.h"
  54. #include "tier2/p4helpers.h"
  55. #include "datamodel/idatamodel.h"
  56. #include "dmserializers/idmserializers.h"
  57. #include "utlvector.h"
  58. #include "utlbuffer.h"
  59. #include "valve_ipc_win32.h"
  60. #include "threadtools.h"
  61. #include "ConfigManager.h"
  62. #include "materialsystem/imaterialvar.h"
  63. bool g_bOldFileDialogs = false;
  64. MDLViewer *g_MDLViewer = 0;
  65. char g_appTitle[] = "Half-Life Model Viewer v1.22";
  66. static char recentFiles[8][256] = { "", "", "", "", "", "", "", "" };
  67. extern int g_dxlevel;
  68. bool g_bInError = false;
  69. //-----------------------------------------------------------------------------
  70. // Singleton interfaces
  71. //-----------------------------------------------------------------------------
  72. IPhysicsSurfaceProps *physprop;
  73. IPhysicsCollision *physcollision;
  74. IFileSystem *g_pFileSystem;
  75. IStudioDataCache *g_pStudioDataCache;
  76. ISoundEmitterSystemBase *g_pSoundEmitterBase;
  77. CreateInterfaceFn g_Factory;
  78. // Filesystem dialog module wrappers.
  79. CSysModule *g_pFSDialogModule = 0;
  80. CreateInterfaceFn g_FSDialogFactory = 0;
  81. class CHlmvIpcServer : public CValveIpcServerUtl
  82. {
  83. public:
  84. CHlmvIpcServer() : CValveIpcServerUtl( "HLMV_IPC_SERVER" ) {}
  85. ~CHlmvIpcServer();
  86. public:
  87. bool HasCommands();
  88. void AppendCommand( char *pszCommand );
  89. char *GetCommand();
  90. void PopCommand();
  91. protected:
  92. virtual BOOL ExecuteCommand( CUtlBuffer &cmd, CUtlBuffer &res );
  93. protected:
  94. CThreadFastMutex m_mtx;
  95. CUtlVector< char * > m_lstCommands;
  96. }
  97. g_HlmvIpcServer;
  98. CValveIpcClientUtl g_HlmvIpcClient( "HLMV_IPC_SERVER" );
  99. bool g_bHlmvMaster = false; // This hlmv is controlling a controlled hlmv instance
  100. bool g_bHlmvControlled = false; // This hlmv is being controlled by a master hlmv instance
  101. void LoadFileSystemDialogModule()
  102. {
  103. Assert( !g_pFSDialogModule );
  104. // Load the module with the file system open dialog.
  105. const char *pDLLName = "FileSystemOpenDialog.dll";
  106. g_pFSDialogModule = Sys_LoadModule( pDLLName );
  107. if ( g_pFSDialogModule )
  108. {
  109. g_FSDialogFactory = Sys_GetFactory( g_pFSDialogModule );
  110. }
  111. if ( !g_pFSDialogModule || !g_FSDialogFactory )
  112. {
  113. if ( g_pFSDialogModule )
  114. {
  115. Sys_UnloadModule( g_pFSDialogModule );
  116. g_pFSDialogModule = NULL;
  117. }
  118. }
  119. }
  120. void UnloadFileSystemDialogModule()
  121. {
  122. if ( g_pFSDialogModule )
  123. {
  124. Sys_UnloadModule( g_pFSDialogModule );
  125. g_pFSDialogModule = 0;
  126. }
  127. }
  128. void
  129. MDLViewer::initRecentFiles ()
  130. {
  131. for (int i = 0; i < 8; i++)
  132. {
  133. if (strlen (recentFiles[i]))
  134. {
  135. mb->modify (IDC_FILE_RECENTMODELS1 + i, IDC_FILE_RECENTMODELS1 + i, recentFiles[i]);
  136. }
  137. else
  138. {
  139. mb->modify (IDC_FILE_RECENTMODELS1 + i, IDC_FILE_RECENTMODELS1 + i, "(empty)");
  140. mb->setEnabled (IDC_FILE_RECENTMODELS1 + i, false);
  141. }
  142. }
  143. }
  144. void
  145. MDLViewer::loadRecentFiles ()
  146. {
  147. char path[256];
  148. strcpy (path, mx::getApplicationPath ());
  149. strcat (path, "/hlmv.rf");
  150. FILE *file = fopen (path, "rb");
  151. if (file)
  152. {
  153. fread (recentFiles, sizeof recentFiles, 1, file);
  154. fclose (file);
  155. }
  156. }
  157. void
  158. MDLViewer::saveRecentFiles ()
  159. {
  160. char path[256];
  161. strcpy (path, mx::getApplicationPath ());
  162. strcat (path, "/hlmv.rf");
  163. FILE *file = fopen (path, "wb");
  164. if (file)
  165. {
  166. fwrite (recentFiles, sizeof recentFiles, 1, file);
  167. fclose (file);
  168. }
  169. }
  170. struct AccelTableEntry_t
  171. {
  172. unsigned short key;
  173. unsigned short command;
  174. unsigned char flags;
  175. };
  176. #define NUM_ACCELERATORS 25
  177. AccelTableEntry_t accelTable[NUM_ACCELERATORS] = { {VK_F5, IDC_FILE_REFRESH, mx::ACCEL_VIRTKEY },
  178. {VK_UP, IDC_ACCEL_TESSELLATION_INC, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  179. {VK_DOWN, IDC_ACCEL_TESSELLATION_DEC, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  180. {'w', IDC_ACCEL_WIREFRAME, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  181. {'W', IDC_ACCEL_WIREFRAME, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  182. {'a', IDC_ACCEL_ATTACHMENTS, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  183. {'A', IDC_ACCEL_ATTACHMENTS, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  184. {'g', IDC_ACCEL_GROUND, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  185. {'G', IDC_ACCEL_GROUND, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  186. {'h', IDC_ACCEL_HITBOXES, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  187. {'H', IDC_ACCEL_HITBOXES, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  188. {'o', IDC_ACCEL_BONES, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  189. {'O', IDC_ACCEL_BONES, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  190. {'b', IDC_ACCEL_BACKGROUND, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  191. {'B', IDC_ACCEL_BACKGROUND, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  192. {'m', IDC_ACCEL_MOVEMENT, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  193. {'M', IDC_ACCEL_MOVEMENT, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  194. {'n', IDC_ACCEL_NORMALS, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  195. {'N', IDC_ACCEL_NORMALS, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  196. {'d', IDC_ACCEL_DISPLACEMENT, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  197. {'D', IDC_ACCEL_DISPLACEMENT, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  198. {'t', IDC_ACCEL_TANGENTS, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  199. {'T', IDC_ACCEL_TANGENTS, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  200. {'s', IDC_ACCEL_SHADOW, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY},
  201. {'S', IDC_ACCEL_SHADOW, mx::ACCEL_CONTROL | mx::ACCEL_VIRTKEY}};
  202. MDLViewer::MDLViewer ()
  203. : mxWindow (0, 0, 0, 0, 0, g_appTitle, mxWindow::Normal)
  204. {
  205. d_MatSysWindow = 0;
  206. d_cpl = 0;
  207. // create menu stuff
  208. mb = new mxMenuBar (this);
  209. mxMenu *menuFile = new mxMenu ();
  210. menuOptions = new mxMenu ();
  211. menuView = new mxMenu ();
  212. mxMenu *menuHelp = new mxMenu ();
  213. mb->addMenu ("File", menuFile);
  214. mb->addMenu ("Options", menuOptions);
  215. mb->addMenu ("View", menuView);
  216. mb->addMenu ("Help", menuHelp);
  217. mxMenu *menuRecentModels = new mxMenu ();
  218. menuRecentModels->add ("(empty)", IDC_FILE_RECENTMODELS1);
  219. menuRecentModels->add ("(empty)", IDC_FILE_RECENTMODELS2);
  220. menuRecentModels->add ("(empty)", IDC_FILE_RECENTMODELS3);
  221. menuRecentModels->add ("(empty)", IDC_FILE_RECENTMODELS4);
  222. menuRecentModels->add ("(empty)", IDC_FILE_RECENTMODELS5);
  223. menuRecentModels->add ("(empty)", IDC_FILE_RECENTMODELS6);
  224. menuRecentModels->add ("(empty)", IDC_FILE_RECENTMODELS7);
  225. menuRecentModels->add ("(empty)", IDC_FILE_RECENTMODELS8);
  226. if ( g_bOldFileDialogs )
  227. {
  228. menuFile->add ("Load Model...", IDC_FILE_LOADMODEL);
  229. menuFile->add ("(Steam) Load Model...", IDC_FILE_LOADMODEL_STEAM);
  230. }
  231. else
  232. {
  233. menuFile->add ("Load Model...", IDC_FILE_LOADMODEL_STEAM);
  234. }
  235. menuFile->add( "Refresh (F5)", IDC_FILE_REFRESH );
  236. menuFile->addSeparator ();
  237. menuFile->add( "Recompile", IDC_FILE_RECOMPILE );
  238. menuFile->addSeparator ();
  239. menuFile->add ("Run .mvscript...", IDC_OPTIONS_RUNMVSCRIPT );
  240. menuFile->add ("Save session as .mvscript...", IDC_OPTIONS_SAVEMVSCRIPT );
  241. menuFile->addSeparator ();
  242. menuFile->add ("Load Background Texture...", IDC_FILE_LOADBACKGROUNDTEX);
  243. menuFile->add ("Load Ground Texture...", IDC_FILE_LOADGROUNDTEX);
  244. menuFile->addSeparator ();
  245. menuFile->add ("Unload Ground Texture", IDC_FILE_UNLOADGROUNDTEX);
  246. menuFile->addSeparator ();
  247. menuFile->addMenu ("Recent Models", menuRecentModels);
  248. menuFile->addSeparator ();
  249. menuFile->add ("Exit", IDC_FILE_EXIT);
  250. menuFile->setEnabled(IDC_FILE_LOADBACKGROUNDTEX, false);
  251. menuFile->setEnabled(IDC_FILE_LOADGROUNDTEX, false);
  252. menuFile->setEnabled(IDC_FILE_UNLOADGROUNDTEX, false);
  253. menuOptions->add ("Background Color...", IDC_OPTIONS_COLORBACKGROUND);
  254. menuOptions->add ("Ground Color...", IDC_OPTIONS_COLORGROUND);
  255. menuOptions->add ("Light Color...", IDC_OPTIONS_COLORLIGHT);
  256. menuOptions->add ("Ambient Color...", IDC_OPTIONS_COLORAMBIENT);
  257. menuOptions->add ("Secondary Lights", IDC_OPTIONS_SECONDARYLIGHTS );
  258. menuOptions->addSeparator ();
  259. menuOptions->add ("Center View", IDC_OPTIONS_CENTERVIEW);
  260. menuOptions->add ("Center Verts", IDC_OPTIONS_CENTERVERTS);
  261. menuOptions->add ("Viewmodel Mode", IDC_OPTIONS_VIEWMODEL);
  262. #ifdef WIN32
  263. menuOptions->addSeparator ();
  264. menuOptions->add ("Make Screenshot...", IDC_OPTIONS_MAKESCREENSHOT);
  265. //menuOptions->add ("Dump Model Info", IDC_OPTIONS_DUMP);
  266. #endif
  267. menuView->add ("File Associations...", IDC_VIEW_FILEASSOCIATIONS);
  268. menuView->setEnabled( IDC_VIEW_FILEASSOCIATIONS, false );
  269. menuView->addSeparator ();
  270. menuView->add ("Show Activities", IDC_VIEW_ACTIVITIES);
  271. menuView->add ("Show hidden", IDC_VIEW_HIDDEN );
  272. menuView->add( "Show sequence numbers", IDC_VIEW_SEQUENCE_INDICES );
  273. menuView->add( "Sort sequences", IDC_VIEW_SORT_SEQUENCES );
  274. menuView->add ("Show orbit circle", IDC_VIEW_ORBIT_CIRCLE );
  275. menuView->setChecked( IDC_VIEW_ORBIT_CIRCLE, false );
  276. menuView->add ("Enable orbit yaw", IDC_VIEW_ORBIT_YAW );
  277. menuView->setChecked( IDC_VIEW_ORBIT_YAW, false );
  278. // Don't show Dota mode in the SDK
  279. if ( CGameConfigManager::IsSDKDeployment() == false )
  280. {
  281. menuView->addSeparator ();
  282. menuView->add ("DotA View Mode", IDC_VIEW_DOTA);
  283. }
  284. #ifdef WIN32
  285. menuHelp->add ("Goto Homepage...", IDC_HELP_GOTOHOMEPAGE);
  286. menuHelp->addSeparator ();
  287. #endif
  288. menuHelp->add ("About...", IDC_HELP_ABOUT);
  289. d_MatSysWindow = new MatSysWindow (this, 0, 0, 100, 100, "", mxWindow::Normal);
  290. #ifdef WIN32
  291. SetWindowLong ((HWND) d_MatSysWindow->getHandle (), GWL_EXSTYLE, WS_EX_ACCEPTFILES );
  292. #endif
  293. d_cpl = new ControlPanel (this);
  294. d_cpl->setMatSysWindow (d_MatSysWindow);
  295. g_MatSysWindow = d_MatSysWindow;
  296. g_FileAssociation = new FileAssociation ();
  297. loadRecentFiles ();
  298. initRecentFiles ();
  299. LoadViewerRootSettings( );
  300. LoadCompileQCPathSettings();
  301. g_ControlPanel->UpdateQCPathPanel();
  302. // FIXME: where do I actually find the domain size of the viewport, especially for multi-monitor
  303. // try to catch weird initialization error
  304. if (g_viewerSettings.xpos < -16384)
  305. g_viewerSettings.xpos = 20;
  306. if (g_viewerSettings.ypos < -16384)
  307. g_viewerSettings.ypos = 20;
  308. g_viewerSettings.ypos = max( 0, g_viewerSettings.ypos );
  309. g_viewerSettings.width = max( 640, g_viewerSettings.width );
  310. g_viewerSettings.height = max( 700, g_viewerSettings.height );
  311. menuView->setChecked( IDC_VIEW_ACTIVITIES, g_viewerSettings.showActivities );
  312. menuView->setChecked( IDC_VIEW_HIDDEN, g_viewerSettings.showHidden );
  313. menuView->setChecked( IDC_VIEW_SEQUENCE_INDICES, g_viewerSettings.showSequenceIndices );
  314. menuView->setChecked( IDC_VIEW_SORT_SEQUENCES, g_viewerSettings.sortSequences );
  315. if ( CGameConfigManager::IsSDKDeployment() == false )
  316. {
  317. menuView->setChecked( IDC_VIEW_DOTA, g_viewerSettings.dotaMode );
  318. }
  319. setBounds( g_viewerSettings.xpos, g_viewerSettings.ypos, g_viewerSettings.width, g_viewerSettings.height );
  320. setVisible (true);
  321. setTimer( 200 );
  322. CUtlVector< mx::Accel_t > accelerators;
  323. mx::Accel_t accel;
  324. for (int i=0; i < NUM_ACCELERATORS; i++)
  325. {
  326. accel.flags = accelTable[i].flags ;
  327. accel.key = accelTable[i].key;
  328. accel.command = accelTable[i].command;
  329. accelerators.AddToTail( accel );
  330. }
  331. mx::createAccleratorTable( accelerators.Count(), accelerators.Base() );
  332. g_HlmvIpcServer.EnsureRegisteredAndRunning();
  333. if ( !g_HlmvIpcServer.IsRunning() )
  334. {
  335. menuOptions->addSeparator();
  336. menuOptions->add ( "Link HLMV", IDC_OPTIONS_LINKHLMV );
  337. menuOptions->add ( "Unlink HLMV", IDC_OPTIONS_UNLINKHLMV );
  338. menuOptions->setChecked( IDC_OPTIONS_UNLINKHLMV, true );
  339. menuOptions->setEnabled( IDC_OPTIONS_UNLINKHLMV, false );
  340. }
  341. }
  342. MDLViewer::~MDLViewer ()
  343. {
  344. g_HlmvIpcServer.EnsureStoppedAndUnregistered();
  345. saveRecentFiles ();
  346. SaveViewerSettings( g_pStudioModel->GetFileName(), g_pStudioModel );
  347. SaveViewerRootSettings( );
  348. #ifdef WIN32
  349. DeleteFile ("hlmv.cfg");
  350. DeleteFile ("midump.txt");
  351. #endif
  352. }
  353. //-----------------------------------------------------------------------------
  354. // Purpose: Reloads the currently loaded model file.
  355. //-----------------------------------------------------------------------------
  356. void MDLViewer::Refresh( void )
  357. {
  358. g_pStudioModel->ReleaseStudioModel( );
  359. g_pMDLCache->Flush( );
  360. delete g_pWidgetControl;
  361. g_pWidgetControl = NULL;
  362. if ( recentFiles[0][0] != '\0' )
  363. {
  364. char szFile[MAX_PATH];
  365. strcpy( szFile, recentFiles[0] );
  366. g_pMaterialSystem->ReloadMaterials( );
  367. d_cpl->loadModel( szFile );
  368. }
  369. // Also reload shaders (will only work if dynamic shader compile is enabled)
  370. static ConVarRef mat_flushshaders_async( "mat_flushshaders_async" );
  371. mat_flushshaders_async.SetValue( true );
  372. }
  373. //-----------------------------------------------------------------------------
  374. // Purpose: Loads the file and updates the MRU list.
  375. // Input : pszFile - File to load.
  376. //-----------------------------------------------------------------------------
  377. void MDLViewer::LoadModelFile( const char *pszFile, int slot )
  378. {
  379. // copy off name, pszFile may be point into recentFiles array
  380. char filename[1024];
  381. strcpy( filename, pszFile );
  382. LoadModelResult_t eLoaded = d_cpl->loadModel( filename, slot );
  383. if ( eLoaded != LoadModel_Success )
  384. {
  385. switch (eLoaded)
  386. {
  387. case LoadModel_LoadFail:
  388. {
  389. mxMessageBox (this, "Error loading model.", g_appTitle, MX_MB_ERROR | MX_MB_OK);
  390. break;
  391. }
  392. case LoadModel_PostLoadFail:
  393. {
  394. mxMessageBox (this, "Error post-loading model.", g_appTitle, MX_MB_ERROR | MX_MB_OK);
  395. break;
  396. }
  397. case LoadModel_NoModel:
  398. {
  399. mxMessageBox (this, "Error loading model. The model has no vertices.", g_appTitle, MX_MB_ERROR | MX_MB_OK);
  400. break;
  401. }
  402. }
  403. return;
  404. }
  405. if (slot == -1)
  406. {
  407. int i;
  408. for (i = 0; i < 8; i++)
  409. {
  410. if (!mx_strcasecmp( recentFiles[i], filename ))
  411. break;
  412. }
  413. // shift down existing recent files
  414. for (i = ((i > 7) ? 7 : i); i > 0; i--)
  415. {
  416. strcpy (recentFiles[i], recentFiles[i-1]);
  417. }
  418. strcpy( recentFiles[0], filename );
  419. initRecentFiles ();
  420. setLabel( "%s", filename );
  421. }
  422. // Init the dota view if we have that checked
  423. if ( g_viewerSettings.dotaMode )
  424. d_cpl->dotaView();
  425. d_cpl->UpdateSubmodelWindow();
  426. }
  427. static ConVar mat_tessellationlevel( "mat_tessellationlevel", "12", FCVAR_CHEAT );
  428. //-----------------------------------------------------------------------------
  429. // Purpose: Opens a script file and runs commands in sequence. Useful for batching automatic screenshots, etc
  430. // Input : p_szScriptPath - script to parse and execute.
  431. //-----------------------------------------------------------------------------
  432. void MDLViewer::ExecuteMVScript( const char* p_szScriptPath )
  433. {
  434. KeyValues *pMvScriptKeyValues = new KeyValues("ModelViewerScript");
  435. KeyValues::AutoDelete autodelete_pMvScriptKeyValues(pMvScriptKeyValues);
  436. if (pMvScriptKeyValues->LoadFromFile(g_pFullFileSystem, p_szScriptPath))
  437. {
  438. Msg("Executing mvscript: %s\n", p_szScriptPath);
  439. for (KeyValues *kvSub = pMvScriptKeyValues->GetFirstSubKey(); kvSub; kvSub = kvSub->GetNextKey())
  440. {
  441. // parse and execute each command in order
  442. if (!Q_stricmp(kvSub->GetName(), "LoadModel"))
  443. {
  444. char const *szVal = kvSub->GetString();
  445. Msg("mvscript command: LoadModel %s\n", szVal);
  446. if ( Q_stristr( szVal, "models" ) )
  447. szVal = Q_stristr( szVal, "models" );
  448. g_MDLViewer->LoadModelFile(szVal);
  449. }
  450. else if (!Q_stricmp(kvSub->GetName(), "SetAppWindowSize"))
  451. {
  452. char const *szVal = kvSub->GetString();
  453. Msg("mvscript command: SetAppWindowSize %s\n", szVal);
  454. int nWidth = g_viewerSettings.width;
  455. int nHeight = g_viewerSettings.height;
  456. sscanf(szVal, "%i %i", &nWidth, &nHeight);
  457. g_MDLViewer->setBounds(g_viewerSettings.xpos, g_viewerSettings.ypos, max(128, nWidth), max(128, nHeight));
  458. }
  459. else if (!Q_stricmp(kvSub->GetName(), "SetCameraOrigin"))
  460. {
  461. char const *szVal = kvSub->GetString();
  462. Msg("mvscript command: SetCameraOrigin %s\n", szVal);
  463. float flX = 0.0f;
  464. float flY = 0.0f;
  465. float flZ = 0.0f;
  466. sscanf(szVal, "%f %f %f", &flX, &flY, &flZ);
  467. d_cpl->setCameraOrigin(flX, flY, flZ);
  468. }
  469. else if (!Q_stricmp(kvSub->GetName(), "SetCameraAngles"))
  470. {
  471. char const *szVal = kvSub->GetString();
  472. Msg("mvscript command: SetCameraAngles %s\n", szVal);
  473. float flX = 0.0f;
  474. float flY = 0.0f;
  475. float flZ = 0.0f;
  476. sscanf(szVal, "%f %f %f", &flX, &flY, &flZ);
  477. d_cpl->setCameraAngles(flX, flY, flZ);
  478. }
  479. else if (!Q_stricmp(kvSub->GetName(), "SetLightAngles"))
  480. {
  481. char const *szVal = kvSub->GetString();
  482. Msg("mvscript command: SetLightAngles %s\n", szVal);
  483. float flX = 0.0f;
  484. float flY = 0.0f;
  485. float flZ = 0.0f;
  486. sscanf(szVal, "%f %f %f", &flX, &flY, &flZ);
  487. d_cpl->setLightAngles(flX, flY, flZ);
  488. }
  489. else if (!Q_stricmp(kvSub->GetName(), "SetBGColor"))
  490. {
  491. char const *szVal = kvSub->GetString();
  492. Msg("mvscript command: SetBGColor %s\n", szVal);
  493. float flR = 63.0f;
  494. float flG = 63.0f;
  495. float flB = 63.0f;
  496. sscanf(szVal, "%f %f %f", &flR, &flG, &flB);
  497. g_viewerSettings.bgColor[0] = flR / 255.0f;
  498. g_viewerSettings.bgColor[1] = flG / 255.0f;
  499. g_viewerSettings.bgColor[2] = flB / 255.0f;
  500. d_cpl->redrawMatSysWin();
  501. }
  502. else if (!Q_stricmp(kvSub->GetName(), "SetLightColor"))
  503. {
  504. char const *szVal = kvSub->GetString();
  505. Msg("mvscript command: SetLightColor %s\n", szVal);
  506. float flR = 63.0f;
  507. float flG = 63.0f;
  508. float flB = 63.0f;
  509. sscanf(szVal, "%f %f %f", &flR, &flG, &flB);
  510. g_viewerSettings.lColor[0] = flR / 255.0f;
  511. g_viewerSettings.lColor[1] = flG / 255.0f;
  512. g_viewerSettings.lColor[2] = flB / 255.0f;
  513. d_cpl->redrawMatSysWin();
  514. }
  515. else if (!Q_stricmp(kvSub->GetName(), "SetAmbientColor"))
  516. {
  517. char const *szVal = kvSub->GetString();
  518. Msg("mvscript command: SetAmbientColor %s\n", szVal);
  519. float flR = 63.0f;
  520. float flG = 63.0f;
  521. float flB = 63.0f;
  522. sscanf(szVal, "%f %f %f", &flR, &flG, &flB);
  523. g_viewerSettings.aColor[0] = flR / 255.0f;
  524. g_viewerSettings.aColor[1] = flG / 255.0f;
  525. g_viewerSettings.aColor[2] = flB / 255.0f;
  526. d_cpl->redrawMatSysWin();
  527. }
  528. else if (!Q_stricmp(kvSub->GetName(), "Screenshot"))
  529. {
  530. char const *szVal = kvSub->GetString();
  531. Msg("mvscript command: Screenshot %s\n", szVal);
  532. d_MatSysWindow->dumpViewport( szVal );
  533. }
  534. else if (!Q_stricmp(kvSub->GetName(), "SetMatVars"))
  535. {
  536. for (KeyValues *kvSubMatParamChanges = kvSub->GetFirstSubKey(); kvSubMatParamChanges; kvSubMatParamChanges = kvSubMatParamChanges->GetNextKey())
  537. {
  538. char const *szParam = kvSubMatParamChanges->GetName();
  539. char const *szVal = kvSubMatParamChanges->GetString();
  540. Msg("mvscript command: SetMatVar %s to %s\n", szParam, szVal);
  541. d_cpl->setMaterialVar( szParam, szVal );
  542. }
  543. }
  544. else if (!Q_stricmp(kvSub->GetName(), "RunExternalCmd"))
  545. {
  546. char const *szVal = kvSub->GetString();
  547. Msg("mvscript command: RunExternalCmd %s\n", szVal);
  548. char absPath[MAX_PATH];
  549. Q_MakeAbsolutePath(absPath, sizeof(absPath), szVal);
  550. system( absPath );
  551. }
  552. else if (!Q_stricmp(kvSub->GetName(), "LoadMergeModel"))
  553. {
  554. char const *szVal = kvSub->GetString();
  555. Msg("mvscript command: LoadMergeModel %s\n", szVal);
  556. int iChosenSlot = 0;
  557. for (int i = 0; i < HLMV_MAX_MERGED_MODELS; i++)
  558. {
  559. if (g_viewerSettings.mergeModelFile[i][0] == 0)
  560. {
  561. iChosenSlot = i;
  562. break;
  563. }
  564. }
  565. strcpy(g_viewerSettings.mergeModelFile[iChosenSlot], szVal);
  566. LoadModelFile(szVal, iChosenSlot);
  567. }
  568. else if (!Q_stricmp(kvSub->GetName(), "ReplaceMaterials"))
  569. {
  570. studiohdr_t* pStudioR = g_pStudioModel->GetStudioRenderHdr();
  571. if (!pStudioR)
  572. continue;
  573. for (KeyValues *kvSubReplaceMats = kvSub->GetFirstSubKey(); kvSubReplaceMats; kvSubReplaceMats = kvSubReplaceMats->GetNextKey())
  574. {
  575. char const *szParam = kvSubReplaceMats->GetName();
  576. char const *szVal = kvSubReplaceMats->GetString();
  577. if ( Q_stristr( szVal, "materials" ) )
  578. szVal = Q_stristr( szVal, "materials" );
  579. IMaterial *pMaterials[128];
  580. int nNumMaterials = g_pStudioRender->GetMaterialList(pStudioR, ARRAYSIZE(pMaterials), &pMaterials[0]);
  581. for ( int i=0; i<nNumMaterials; i++ )
  582. {
  583. IMaterial *pSelectedMaterial = pMaterials[i];
  584. if ( pSelectedMaterial->IsErrorMaterial() )
  585. continue;
  586. Msg("Material name: %s\n", V_GetFileName(pSelectedMaterial->GetName()));
  587. if ( !Q_stricmp( V_GetFileName(pSelectedMaterial->GetName()), szParam ) )
  588. {
  589. Msg("mvscript command: ReplaceMaterial %s to %s\n", szParam, szVal);
  590. KeyValues *kvLoadedFromFile = new KeyValues(pSelectedMaterial->GetShaderName());
  591. if (kvLoadedFromFile->LoadFromFile(g_pFullFileSystem, szVal))
  592. {
  593. KeyValues *kv = new KeyValues(pSelectedMaterial->GetShaderName());
  594. IMaterialVar **pMatVars = pSelectedMaterial->GetShaderParams();
  595. for (int n = 0; n < pSelectedMaterial->ShaderParamCount(); n++)
  596. {
  597. IMaterialVar *pThisVar = pMatVars[n];
  598. if (pThisVar->IsDefined())
  599. kv->SetString(pThisVar->GetName(), pThisVar->GetStringValue());
  600. }
  601. kv->MergeFrom(kvLoadedFromFile, KeyValues::MERGE_KV_UPDATE);
  602. pSelectedMaterial->SetShaderAndParams(kv);
  603. pSelectedMaterial->Refresh();
  604. if (kv)
  605. delete kv;
  606. }
  607. if (kvLoadedFromFile)
  608. delete kvLoadedFromFile;
  609. }
  610. }
  611. }
  612. }
  613. else if (!Q_stricmp(kvSub->GetName(), "NormalMapping"))
  614. {
  615. g_viewerSettings.enableNormalMapping = kvSub->GetBool();
  616. Msg("mvscript command: NormalMapping %s\n", g_viewerSettings.enableNormalMapping ? "enabled" : "disabled" );
  617. }
  618. else if (!Q_stricmp(kvSub->GetName(), "Close"))
  619. {
  620. Msg("mvscript command: Quit\n");
  621. redraw();
  622. mx::quit();
  623. }
  624. }
  625. }
  626. autodelete_pMvScriptKeyValues.Detach();
  627. }
  628. //-----------------------------------------------------------------------------
  629. // Purpose: Takes a TGA screenshot of the given filename and exits.
  630. // Input : pszFile - File to load.
  631. //-----------------------------------------------------------------------------
  632. void MDLViewer::SaveScreenShot( const char *pszFile )
  633. {
  634. char filename[1024];
  635. strcpy( filename, pszFile );
  636. LoadModelResult_t eLoaded = d_cpl->loadModel( filename );
  637. //
  638. // Screenshot mode. Write a screenshot file and exit.
  639. //
  640. if ( eLoaded == LoadModel_Success )
  641. {
  642. //unload all merged models
  643. for (int i=0; i<HLMV_MAX_MERGED_MODELS; i++)
  644. {
  645. if (g_pStudioExtraModel[i])
  646. {
  647. strcpy( g_viewerSettings.mergeModelFile[i], "" );
  648. g_pStudioExtraModel[i]->FreeModel( false );
  649. delete g_pStudioExtraModel[i];
  650. g_pStudioExtraModel[i] = NULL;
  651. }
  652. }
  653. g_viewerSettings.bgColor[0] = 0.2353f; //117.0f / 255.0f;
  654. g_viewerSettings.bgColor[1] = 0.2353f; //196.0f / 255.0f;
  655. g_viewerSettings.bgColor[2] = 0.2353f; //219.0f / 255.0f;
  656. // Build the name of the TGA to write.
  657. char szScreenShot[1024];
  658. V_ExtractFilePath( filename, szScreenShot, sizeof(szScreenShot) );
  659. strcat(szScreenShot, "screenshots\\" );
  660. if ( CreateDirectory(szScreenShot, NULL) || ERROR_ALREADY_EXISTS == GetLastError() )
  661. {
  662. strcat(szScreenShot, V_GetFileName(filename) );
  663. char *pchDot = strrchr(szScreenShot, '.');
  664. if (pchDot)
  665. {
  666. strcpy(pchDot, ".bmp");
  667. }
  668. else
  669. {
  670. strcat(szScreenShot, ".bmp");
  671. }
  672. d_cpl->setSequence( 0 );
  673. g_pStudioModel->ClearAnimationLayers();
  674. d_cpl->centerView();
  675. d_cpl->cs_gunsidemodelView();
  676. d_cpl->cs_gunsidemodelView();
  677. bool bFoundPaintNameParam = false;
  678. bool bFoundPaintStyleParam = false;
  679. char szPaintName[256];
  680. studiohdr_t* pStudioR = g_pStudioModel->GetStudioRenderHdr();
  681. if ( pStudioR )
  682. {
  683. IMaterial *pMaterials[128];
  684. int nMaterials = g_pStudioRender->GetMaterialList( pStudioR, ARRAYSIZE( pMaterials ), &pMaterials[0] );
  685. for ( int i=0; i<nMaterials; i++ )
  686. {
  687. if ( !pMaterials[i]->IsErrorMaterial() )
  688. {
  689. IMaterialVar *pThisVar = pMaterials[i]->FindVar( "$paintname", &bFoundPaintNameParam, false );
  690. if (bFoundPaintNameParam)
  691. {
  692. V_strcpy( szPaintName, pThisVar->GetStringValue() );
  693. break;
  694. }
  695. else
  696. {
  697. pMaterials[i]->FindVar( "$paintstyle", &bFoundPaintStyleParam, false );
  698. }
  699. }
  700. }
  701. }
  702. if ( bFoundPaintNameParam )
  703. {
  704. //create a version of the paint name with underscores
  705. char szPaintNameWithUnderscores[256];
  706. V_StrSubst( szPaintName, " ", "_", szPaintNameWithUnderscores, sizeof(szPaintNameWithUnderscores) );
  707. strcat(szPaintNameWithUnderscores, ".bmp");
  708. //update the output path
  709. char szNewOputputPath[1024];
  710. V_StrSubst( szScreenShot, ".bmp", szPaintNameWithUnderscores, szNewOputputPath, sizeof(szNewOputputPath) );
  711. d_MatSysWindow->dumpViewportWithLabel( szNewOputputPath, szPaintName );
  712. }
  713. else
  714. {
  715. if (bFoundPaintStyleParam)
  716. mxMessageBox (this, "WARNING: Paint has no $paintname set, can't stamp unknown paint name on screenshot.", g_appTitle, MX_MB_ERROR | MX_MB_OK);
  717. else
  718. d_MatSysWindow->dumpViewport( szScreenShot );
  719. }
  720. }
  721. // Shut down.
  722. mx::quit();
  723. }
  724. else
  725. {
  726. mxMessageBox (this, "Error loading model for commandline screenshot.", g_appTitle, MX_MB_ERROR | MX_MB_OK);
  727. }
  728. return;
  729. }
  730. void MDLViewer::DumpText( const char *pszFile )
  731. {
  732. char filename[1024];
  733. strcpy( filename, pszFile );
  734. LoadModelResult_t eLoaded = d_cpl->loadModel( filename );
  735. //
  736. // Screenshot mode. Write a screenshot file and exit.
  737. //
  738. if ( eLoaded == LoadModel_Success )
  739. {
  740. if ( g_pStudioModel->m_bIsTransparent )
  741. {
  742. Msg("%s is transparent\n", filename );
  743. }
  744. if ( g_pStudioModel->m_bHasProxy )
  745. {
  746. Msg("%s has material proxies\n", filename );
  747. }
  748. }
  749. // Shut down.
  750. mx::quit();
  751. }
  752. const char* MDLViewer::SteamGetOpenFilename()
  753. {
  754. if ( !g_FSDialogFactory )
  755. return NULL;
  756. static char filename[MAX_PATH];
  757. IFileSystemOpenDialog *pDlg;
  758. pDlg = (IFileSystemOpenDialog*)g_FSDialogFactory( FILESYSTEMOPENDIALOG_VERSION, NULL );
  759. if ( !pDlg )
  760. {
  761. char str[512];
  762. Q_snprintf( str, sizeof( str ), "Can't create %s interface.", FILESYSTEMOPENDIALOG_VERSION );
  763. MessageBox( NULL, str, "Error", MB_OK );
  764. return NULL;
  765. }
  766. pDlg->Init( g_Factory, NULL );
  767. pDlg->AddFileMask( "*.jpg" );
  768. pDlg->AddFileMask( "*.mdl" );
  769. pDlg->SetInitialDir( "models", "game" );
  770. pDlg->SetFilterMdlAndJpgFiles( true );
  771. if (pDlg->DoModal() == IDOK)
  772. {
  773. pDlg->GetFilename( filename, sizeof( filename ) );
  774. pDlg->Release();
  775. return filename;
  776. }
  777. else
  778. {
  779. pDlg->Release();
  780. return NULL;
  781. }
  782. }
  783. int
  784. MDLViewer::handleEvent (mxEvent *event)
  785. {
  786. MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
  787. switch (event->event)
  788. {
  789. case mxEvent::Action:
  790. {
  791. Msg("%2.2f %2.2f %2.2f\n", g_pStudioModel->m_angles[0], g_pStudioModel->m_angles[1], g_pStudioModel->m_angles[2]);
  792. switch (event->action)
  793. {
  794. case IDC_FILE_LOADMODEL:
  795. {
  796. const char *ptr = mxGetOpenFileName (this, 0, "*.mdl");
  797. if (ptr)
  798. {
  799. LoadModelFile( ptr );
  800. }
  801. }
  802. break;
  803. case IDC_FILE_LOADMODEL_STEAM:
  804. {
  805. const char *pFilename = SteamGetOpenFilename();
  806. if ( pFilename )
  807. {
  808. LoadModelFile( pFilename );
  809. }
  810. }
  811. break;
  812. case IDC_FILE_REFRESH:
  813. {
  814. Refresh();
  815. break;
  816. }
  817. case IDC_FILE_RECOMPILE:
  818. {
  819. //g_pStudioModel->Key
  820. CStudioHdr *pStudioHdr = g_pStudioModel->GetStudioHdr();
  821. if ( pStudioHdr )
  822. {
  823. studiohdr_t* pStudioR = g_pStudioModel->GetStudioRenderHdr();
  824. KeyValues *tempKeyValues = new KeyValues("qc_path");
  825. if ( tempKeyValues->LoadFromBuffer( NULL, pStudioR->KeyValueText() ) )
  826. {
  827. KeyValues *qc_path = tempKeyValues->FindKey( "qc_path", false );
  828. if (qc_path)
  829. {
  830. char szQCPath[1024];
  831. V_sprintf_safe( szQCPath, "%s\\%s\\%s", getenv("VCONTENT"), getenv("VMOD"), qc_path->GetFirstValue()->GetString() );
  832. g_ControlPanel->AddQCRecordPath( szQCPath, true );
  833. }
  834. else
  835. {
  836. mxMessageBox (this, "MDL has no qc_path defined, and needs to be compiled once manually to learn where its QC is. Then HLMV will be able to recompile it from that point on.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  837. }
  838. }
  839. }
  840. break;
  841. }
  842. case IDC_FILE_LOADBACKGROUNDTEX:
  843. case IDC_FILE_LOADGROUNDTEX:
  844. {
  845. const char *ptr = mxGetOpenFileName (this, 0, "*.*");
  846. if (ptr)
  847. {
  848. if (0 /* d_MatSysWindow->loadTexture (ptr, event->action - IDC_FILE_LOADBACKGROUNDTEX) */)
  849. {
  850. if (event->action == IDC_FILE_LOADBACKGROUNDTEX)
  851. d_cpl->setShowBackground (true);
  852. else
  853. d_cpl->setShowGround (true);
  854. }
  855. else
  856. mxMessageBox (this, "Error loading texture.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  857. }
  858. }
  859. break;
  860. case IDC_FILE_UNLOADGROUNDTEX:
  861. {
  862. // d_MatSysWindow->loadTexture (0, 1);
  863. d_cpl->setShowGround (false);
  864. }
  865. break;
  866. case IDC_FILE_RECENTMODELS1:
  867. case IDC_FILE_RECENTMODELS2:
  868. case IDC_FILE_RECENTMODELS3:
  869. case IDC_FILE_RECENTMODELS4:
  870. case IDC_FILE_RECENTMODELS5:
  871. case IDC_FILE_RECENTMODELS6:
  872. case IDC_FILE_RECENTMODELS7:
  873. case IDC_FILE_RECENTMODELS8:
  874. {
  875. int i = event->action - IDC_FILE_RECENTMODELS1;
  876. LoadModelFile( recentFiles[i] );
  877. }
  878. break;
  879. case IDC_FILE_EXIT:
  880. {
  881. redraw ();
  882. mx::quit ();
  883. }
  884. break;
  885. case IDC_OPTIONS_COLORBACKGROUND:
  886. case IDC_OPTIONS_COLORGROUND:
  887. case IDC_OPTIONS_COLORLIGHT:
  888. case IDC_OPTIONS_COLORAMBIENT:
  889. {
  890. float *cols[4] = { g_viewerSettings.bgColor, g_viewerSettings.gColor, g_viewerSettings.lColor, g_viewerSettings.aColor };
  891. float *col = cols[event->action - IDC_OPTIONS_COLORBACKGROUND];
  892. int r = (int) (col[0] * 255.0f);
  893. int g = (int) (col[1] * 255.0f);
  894. int b = (int) (col[2] * 255.0f);
  895. if (mxChooseColor (this, &r, &g, &b))
  896. {
  897. col[0] = (float) r / 255.0f;
  898. col[1] = (float) g / 255.0f;
  899. col[2] = (float) b / 255.0f;
  900. }
  901. }
  902. break;
  903. case IDC_OPTIONS_SECONDARYLIGHTS:
  904. g_viewerSettings.secondaryLights = !g_viewerSettings.secondaryLights;
  905. menuOptions->setChecked( IDC_OPTIONS_SECONDARYLIGHTS, g_viewerSettings.secondaryLights );
  906. break;
  907. case IDC_OPTIONS_CENTERVIEW:
  908. if ( g_viewerSettings.dotaMode )
  909. break;
  910. d_cpl->centerView ();
  911. if ( g_bHlmvMaster )
  912. {
  913. SendModelTransformToLinkedHlmv();
  914. }
  915. break;
  916. case IDC_OPTIONS_CENTERVERTS:
  917. if ( g_viewerSettings.dotaMode )
  918. break;
  919. d_cpl->centerVerts( );
  920. if ( g_bHlmvMaster )
  921. {
  922. SendModelTransformToLinkedHlmv();
  923. }
  924. break;
  925. case IDC_OPTIONS_VIEWMODEL:
  926. {
  927. if ( g_viewerSettings.dotaMode )
  928. break;
  929. d_cpl->viewmodelView();
  930. if ( g_bHlmvMaster )
  931. {
  932. SendModelTransformToLinkedHlmv();
  933. }
  934. }
  935. break;
  936. case IDC_VIEW_DOTA:
  937. {
  938. g_viewerSettings.dotaMode = !g_viewerSettings.dotaMode;
  939. menuView->setChecked( IDC_VIEW_DOTA, g_viewerSettings.dotaMode );
  940. if ( g_viewerSettings.dotaMode )
  941. {
  942. d_cpl->dotaView();
  943. }
  944. if ( g_bHlmvMaster )
  945. {
  946. SendModelTransformToLinkedHlmv();
  947. }
  948. }
  949. break;
  950. case IDC_OPTIONS_MAKESCREENSHOT:
  951. {
  952. char *ptr = (char *) mxGetSaveFileName (this, "", "*.bmp");
  953. if (ptr)
  954. {
  955. if (!strstr (ptr, ".bmp"))
  956. strcat (ptr, ".bmp");
  957. d_MatSysWindow->dumpViewport (ptr);
  958. }
  959. }
  960. break;
  961. case IDC_OPTIONS_RUNMVSCRIPT:
  962. {
  963. char *ptr = (char *)mxGetOpenFileName(this, "", "*.mvscript");
  964. if (ptr)
  965. {
  966. if (!strstr(ptr, ".mvscript"))
  967. strcat(ptr, ".mvscript");
  968. g_MDLViewer->ExecuteMVScript(ptr);
  969. }
  970. }
  971. break;
  972. case IDC_OPTIONS_SAVEMVSCRIPT:
  973. {
  974. if ( !g_pStudioModel->GetStudioRenderHdr() )
  975. {
  976. mxMessageBox (this, "No model loaded!", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  977. break;
  978. }
  979. //save a mvscript with the current model, camera orientation and light positions
  980. char *ptr = (char *)mxGetSaveFileName(this, "", "*.mvscript");
  981. if (ptr)
  982. {
  983. if (!strstr(ptr, ".mvscript"))
  984. strcat(ptr, ".mvscript");
  985. KeyValues *kv = new KeyValues( "ModelViewerScript" );
  986. const char *szModelPath = g_pStudioModel->GetFileName();
  987. if ( Q_stristr( szModelPath, "models" ) )
  988. szModelPath = Q_stristr( szModelPath, "models" );
  989. kv->SetString( "LoadModel", szModelPath );
  990. char szTemp[64];
  991. V_snprintf( szTemp, 64, "%i %i", g_viewerSettings.width, g_viewerSettings.height );
  992. kv->SetString( "SetAppWindowSize", szTemp );
  993. V_snprintf( szTemp, 64, "%f %f %f", g_pStudioModel->m_origin[0], g_pStudioModel->m_origin[1], g_pStudioModel->m_origin[2] );
  994. kv->SetString( "SetCameraOrigin", szTemp );
  995. V_snprintf(szTemp, 64, "%f %f %f", g_pStudioModel->m_angles[0], g_pStudioModel->m_angles[1], g_pStudioModel->m_angles[2]);
  996. kv->SetString("SetCameraAngles", szTemp);
  997. V_snprintf(szTemp, 64, "%f %f %f", g_viewerSettings.lightrot[YAW], g_viewerSettings.lightrot[PITCH], g_viewerSettings.lightrot[ROLL]);
  998. kv->SetString("SetLightAngles", szTemp);
  999. if ( !kv->SaveToFile( g_pFullFileSystem, ptr ) )
  1000. {
  1001. mxMessageBox (this, "Error saving script file.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  1002. }
  1003. if ( kv )
  1004. delete kv;
  1005. }
  1006. }
  1007. break;
  1008. case IDC_OPTIONS_DUMP:
  1009. d_cpl->dumpModelInfo ();
  1010. break;
  1011. case IDC_OPTIONS_SYNCHLMVCAMERA:
  1012. SendModelTransformToLinkedHlmv();
  1013. break;
  1014. case IDC_OPTIONS_LINKHLMV:
  1015. if ( !g_bHlmvMaster && !g_HlmvIpcServer.IsRunning() && g_HlmvIpcClient.Connect() )
  1016. {
  1017. CUtlBuffer cmd;
  1018. CUtlBuffer res;
  1019. // Make connection to other hlmv
  1020. cmd.PutString( "hlmvLink" );
  1021. cmd.PutChar( '\0' );
  1022. if ( g_HlmvIpcClient.ExecuteCommand( cmd, res ) )
  1023. {
  1024. g_bHlmvMaster = true;
  1025. }
  1026. g_HlmvIpcClient.Disconnect();
  1027. menuOptions->setChecked( IDC_OPTIONS_LINKHLMV, true );
  1028. menuOptions->setEnabled( IDC_OPTIONS_LINKHLMV, false );
  1029. menuOptions->setChecked( IDC_OPTIONS_UNLINKHLMV, false );
  1030. menuOptions->setEnabled( IDC_OPTIONS_UNLINKHLMV, true );
  1031. }
  1032. break;
  1033. case IDC_OPTIONS_UNLINKHLMV:
  1034. if ( g_bHlmvMaster && g_HlmvIpcClient.Connect() )
  1035. {
  1036. CUtlBuffer cmd;
  1037. CUtlBuffer res;
  1038. // Break connection to linked hlmv
  1039. cmd.PutString( "hlmvUnlink" );
  1040. cmd.PutChar( '\0' );
  1041. g_HlmvIpcClient.ExecuteCommand( cmd, res );
  1042. g_bHlmvMaster = false;
  1043. g_HlmvIpcClient.Disconnect();
  1044. menuOptions->setChecked( IDC_OPTIONS_LINKHLMV, false );
  1045. menuOptions->setEnabled( IDC_OPTIONS_LINKHLMV, true );
  1046. menuOptions->setChecked( IDC_OPTIONS_UNLINKHLMV, true );
  1047. menuOptions->setEnabled( IDC_OPTIONS_UNLINKHLMV, false );
  1048. }
  1049. break;
  1050. case IDC_VIEW_FILEASSOCIATIONS:
  1051. g_FileAssociation->setAssociation (0);
  1052. g_FileAssociation->setVisible (true);
  1053. break;
  1054. case IDC_VIEW_ACTIVITIES:
  1055. d_cpl->SaveSelectedSequences();
  1056. g_viewerSettings.showActivities = !g_viewerSettings.showActivities;
  1057. menuView->setChecked( event->action, g_viewerSettings.showActivities );
  1058. d_cpl->initSequenceChoices();
  1059. d_cpl->resetControlPanel();
  1060. d_cpl->RestoreSelectedSequences();
  1061. break;
  1062. case IDC_VIEW_HIDDEN:
  1063. d_cpl->SaveSelectedSequences();
  1064. g_viewerSettings.showHidden = !g_viewerSettings.showHidden;
  1065. menuView->setChecked( event->action, g_viewerSettings.showHidden );
  1066. d_cpl->initSequenceChoices();
  1067. d_cpl->resetControlPanel();
  1068. d_cpl->RestoreSelectedSequences();
  1069. break;
  1070. case IDC_VIEW_SEQUENCE_INDICES:
  1071. d_cpl->SaveSelectedSequences();
  1072. g_viewerSettings.showSequenceIndices = !g_viewerSettings.showSequenceIndices;
  1073. menuView->setChecked( event->action, g_viewerSettings.showSequenceIndices );
  1074. d_cpl->initSequenceChoices();
  1075. d_cpl->resetControlPanel();
  1076. d_cpl->RestoreSelectedSequences();
  1077. break;
  1078. case IDC_VIEW_SORT_SEQUENCES:
  1079. d_cpl->SaveSelectedSequences();
  1080. g_viewerSettings.sortSequences = !g_viewerSettings.sortSequences;
  1081. menuView->setChecked( event->action, g_viewerSettings.sortSequences );
  1082. d_cpl->initSequenceChoices();
  1083. d_cpl->resetControlPanel();
  1084. d_cpl->RestoreSelectedSequences();
  1085. break;
  1086. case IDC_VIEW_ORBIT_CIRCLE:
  1087. g_viewerSettings.showOrbitCircle = !g_viewerSettings.showOrbitCircle;
  1088. menuView->setChecked( event->action, g_viewerSettings.showOrbitCircle );
  1089. break;
  1090. case IDC_VIEW_ORBIT_YAW:
  1091. g_viewerSettings.allowOrbitYaw = !g_viewerSettings.allowOrbitYaw;
  1092. menuView->setChecked( event->action, g_viewerSettings.allowOrbitYaw );
  1093. break;
  1094. #ifdef WIN32
  1095. case IDC_HELP_GOTOHOMEPAGE:
  1096. ShellExecute (0, "open", "http://www.swissquake.ch/chumbalum-soft/index.html", 0, 0, SW_SHOW);
  1097. break;
  1098. #endif
  1099. case IDC_HELP_ABOUT:
  1100. mxMessageBox (this,
  1101. "Half-Life Model Viewer v2.0 (c) 2004 Valve Corp.\n"
  1102. "Portions (c) 1999 by Mete Ciragan\n\n"
  1103. "Left-drag inside circle to spin.\n"
  1104. "Left-drag outside circle to rotate.\n"
  1105. "Right-drag to zoom.\n"
  1106. "Shift-left-drag to x-y-pan.\n"
  1107. "Shift-right-drag to z-pan.\n"
  1108. "Ctrl-left-drag to move light.\n\n"
  1109. "Build:\t" __DATE__ ".\n"
  1110. "Email:\t[email protected]\n"
  1111. "Web:\thttp://www.swissquake.ch/chumbalum-soft/", "About Half-Life Model Viewer",
  1112. MX_MB_OK | MX_MB_INFORMATION);
  1113. break;
  1114. case IDC_ACCEL_WIREFRAME:
  1115. d_cpl->setOverlayWireframe( !g_viewerSettings.overlayWireframe );
  1116. break;
  1117. case IDC_ACCEL_ATTACHMENTS:
  1118. d_cpl->setShowAttachments( !g_viewerSettings.showAttachments );
  1119. break;
  1120. case IDC_ACCEL_GROUND:
  1121. d_cpl->setShowGround( !g_viewerSettings.showGround );
  1122. break;
  1123. case IDC_ACCEL_HITBOXES:
  1124. d_cpl->setShowHitBoxes( !g_viewerSettings.showHitBoxes );
  1125. break;
  1126. case IDC_ACCEL_BONES:
  1127. d_cpl->setShowBones( !g_viewerSettings.showBones );
  1128. break;
  1129. case IDC_ACCEL_BACKGROUND:
  1130. d_cpl->setShowBackground( !g_viewerSettings.showBackground );
  1131. break;
  1132. case IDC_ACCEL_MOVEMENT:
  1133. d_cpl->setShowMovement( !g_viewerSettings.showMovement );
  1134. break;
  1135. case IDC_ACCEL_NORMALS:
  1136. d_cpl->setShowNormals( !g_viewerSettings.showNormals );
  1137. break;
  1138. case IDC_ACCEL_DISPLACEMENT:
  1139. d_cpl->setDisplacementMapping( !g_viewerSettings.enableDisplacementMapping );
  1140. break;
  1141. case IDC_ACCEL_TESSELLATION_INC:
  1142. mat_tessellationlevel.SetValue( mat_tessellationlevel.GetInt() + 1 );
  1143. break;
  1144. case IDC_ACCEL_TESSELLATION_DEC:
  1145. mat_tessellationlevel.SetValue( mat_tessellationlevel.GetInt() - 1 );
  1146. break;
  1147. case IDC_ACCEL_TANGENTS:
  1148. d_cpl->setShowTangentFrame( !g_viewerSettings.showTangentFrame );
  1149. break;
  1150. case IDC_ACCEL_SHADOW:
  1151. d_cpl->setShowShadow( !g_viewerSettings.showShadow );
  1152. break;
  1153. } //switch (event->action)
  1154. } // mxEvent::Action
  1155. break;
  1156. case mxEvent::Size:
  1157. {
  1158. g_viewerSettings.xpos = x();
  1159. g_viewerSettings.ypos = y();
  1160. g_viewerSettings.width = w();
  1161. g_viewerSettings.height = h();
  1162. int w = event->width;
  1163. int h = event->height;
  1164. int y = mb->getHeight ();
  1165. #ifdef WIN32
  1166. #define HEIGHT 240
  1167. #else
  1168. #define HEIGHT 140
  1169. h -= 40;
  1170. #endif
  1171. d_MatSysWindow->setBounds (0, y, w, h - HEIGHT); // !!
  1172. d_cpl->setBounds (0, y + h - HEIGHT, w, HEIGHT);
  1173. }
  1174. break;
  1175. case mxEvent::PosChanged:
  1176. {
  1177. g_viewerSettings.xpos = x();
  1178. g_viewerSettings.ypos = y();
  1179. }
  1180. break;
  1181. case KeyDown:
  1182. d_MatSysWindow->handleEvent(event);
  1183. d_cpl->handleEvent(event);
  1184. break;
  1185. case mxEvent::Activate:
  1186. {
  1187. if (event->action)
  1188. {
  1189. mx::setIdleWindow( getMatSysWindow() );
  1190. }
  1191. else
  1192. {
  1193. mx::setIdleWindow( 0 );
  1194. }
  1195. }
  1196. break;
  1197. case mxEvent::Timer:
  1198. {
  1199. if ( g_HlmvIpcServer.HasCommands() )
  1200. {
  1201. // Execute next command at next msg pump, ~ 1/60th s (60Hz) if controlled, 0.1s if not
  1202. if ( g_bHlmvControlled )
  1203. {
  1204. // Clear up to 10 pending commands if controlled
  1205. for ( int nCmdCount = 0; nCmdCount < 10 && g_HlmvIpcServer.HasCommands(); ++nCmdCount )
  1206. {
  1207. handleIpcCommand( g_HlmvIpcServer.GetCommand() );
  1208. g_HlmvIpcServer.PopCommand();
  1209. }
  1210. setTimer( 17 );
  1211. }
  1212. else
  1213. {
  1214. handleIpcCommand( g_HlmvIpcServer.GetCommand() );
  1215. g_HlmvIpcServer.PopCommand();
  1216. setTimer( 100 );
  1217. }
  1218. }
  1219. else if ( !g_HlmvIpcServer.IsRunning() )
  1220. {
  1221. // Keep trying to establish our server slot if another instance quits
  1222. BOOL bIsRunning = g_HlmvIpcServer.IsRunning();
  1223. g_HlmvIpcServer.EnsureRegisteredAndRunning();
  1224. if ( !bIsRunning && g_HlmvIpcServer.IsRunning() )
  1225. {
  1226. g_bHlmvMaster = false;
  1227. menuOptions->setEnabled( IDC_OPTIONS_LINKHLMV, false );
  1228. menuOptions->setChecked( IDC_OPTIONS_LINKHLMV, false );
  1229. menuOptions->setEnabled( IDC_OPTIONS_UNLINKHLMV, false );
  1230. menuOptions->setChecked( IDC_OPTIONS_LINKHLMV, false );
  1231. }
  1232. // Attempt every 1.0 s
  1233. setTimer( 1000 );
  1234. }
  1235. else
  1236. {
  1237. // Idling, poll command queue @ ~60Hz if controlled, 0.5s ( 2Hz ) otherwise
  1238. if ( g_bHlmvControlled )
  1239. {
  1240. setTimer( 17 );
  1241. }
  1242. else
  1243. {
  1244. setTimer( 500 );
  1245. }
  1246. }
  1247. g_ControlPanel->CompileTimerUpdate();
  1248. g_ControlPanel->UpdateBoneWeightInspect();
  1249. }
  1250. break;
  1251. } // event->event
  1252. return 1;
  1253. }
  1254. void TranslateMayaToHLMVCoordinates( const Vector &vMayaPos, const QAngle &vMayaRot, Vector &vHLMVPos, QAngle &vHLMVAngles )
  1255. {
  1256. vHLMVPos.Init( vMayaPos.z, vMayaPos.x, vMayaPos.y );
  1257. vHLMVAngles[PITCH] = -vMayaRot[0];
  1258. vHLMVAngles[YAW] = vMayaRot[1] + 180;
  1259. vHLMVAngles[ROLL] = -vMayaRot[2];
  1260. }
  1261. void
  1262. MDLViewer::handleIpcCommand( char *szCommand )
  1263. {
  1264. MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
  1265. if ( !strcmp( "reload", szCommand ) )
  1266. {
  1267. Refresh();
  1268. if ( HWND hWnd = (HWND) getHandle() )
  1269. {
  1270. if ( ::IsIconic( hWnd ) )
  1271. ::ShowWindow( hWnd, SW_RESTORE );
  1272. ::BringWindowToTop( hWnd );
  1273. ::SetForegroundWindow( hWnd );
  1274. ::SetFocus( hWnd );
  1275. }
  1276. }
  1277. else if ( V_strncasecmp( "cameraTo", szCommand, 8 ) == 0 )
  1278. {
  1279. // Read the camera position and angles from Maya.
  1280. Vector vMayaPos;
  1281. QAngle vMayaRot;
  1282. char szFirstPart[32];
  1283. sscanf( szCommand, "%s %f %f %f %f %f %f",
  1284. szFirstPart,
  1285. &vMayaPos.x, &vMayaPos.y, &vMayaPos.z,
  1286. &vMayaRot.x, &vMayaRot.y, &vMayaRot.z );
  1287. //
  1288. // Obviously, this could all be simplified, but it's nice to make it easy to see what it's doing here.
  1289. //
  1290. // Translate the camera position/angles from Maya space to model space.
  1291. // In model space, +X=forward, +Y=left, and +Z=up
  1292. // (i.e. the model faces forward along +X)
  1293. Vector vCameraPos;
  1294. QAngle vCameraAngles;
  1295. TranslateMayaToHLMVCoordinates( vMayaPos, vMayaRot, vCameraPos, vCameraAngles );
  1296. // Now, build a matrix from model space to camera space. The way we're defining camera space,
  1297. // the axes point the same way as in model space (+X=forward, +Y=left, +Z=up).
  1298. // This is a standard put-stuff-in-camera-space matrix (backtranslate and then backrotate).
  1299. matrix3x4_t mModelToCameraRot, mModelToCameraTrans, mModelToCameraFull;
  1300. // Backtranslate..
  1301. SetIdentityMatrix( mModelToCameraTrans );
  1302. MatrixSetColumn( -vCameraPos, 3, mModelToCameraTrans );
  1303. // Backrotate..
  1304. AngleMatrix( vCameraAngles, mModelToCameraRot );
  1305. MatrixTranspose( mModelToCameraRot );
  1306. // Concatenate.
  1307. MatrixMultiply( mModelToCameraRot, mModelToCameraTrans, mModelToCameraFull );
  1308. // Now we need to convert the camera space from above to HLMV's specific camera space. This just means negating
  1309. // the X and Y axes because HLMV's camera space is (+X=back, +Y=left, +Z=up).
  1310. matrix3x4_t mCameraToWorld(
  1311. -1, 0, 0, 0,
  1312. 0, -1, 0, 0,
  1313. 0, 0, 1, 0 );
  1314. // Blat all these matrices together.
  1315. matrix3x4_t mFinal;
  1316. MatrixMultiply( mCameraToWorld, mModelToCameraFull, mFinal );
  1317. // Tell HLMV our new fancy transform to use, and then we'll see the model from the same place Maya did.
  1318. g_pStudioModel->SetModelTransform( mFinal );
  1319. // Redraw.
  1320. d_MatSysWindow->redraw();
  1321. }
  1322. else if ( StringHasPrefixCaseSensitive( szCommand, "hlmvModelTransform" ) )
  1323. {
  1324. matrix3x4_t m;
  1325. sscanf( szCommand, "%*s %f %f %f %f %f %f %f %f %f %f %f %f",
  1326. &m.m_flMatVal[0][0], &m.m_flMatVal[0][1], &m.m_flMatVal[0][2], &m.m_flMatVal[0][3],
  1327. &m.m_flMatVal[1][0], &m.m_flMatVal[1][1], &m.m_flMatVal[1][2], &m.m_flMatVal[1][3],
  1328. &m.m_flMatVal[2][0], &m.m_flMatVal[2][1], &m.m_flMatVal[2][2], &m.m_flMatVal[2][3] );
  1329. // Tell HLMV our new fancy transform to use, and then we'll see the model from the same place Maya did.
  1330. g_pStudioModel->SetModelTransform( m );
  1331. // Redraw.
  1332. d_MatSysWindow->redraw();
  1333. }
  1334. else if ( StringHasPrefixCaseSensitive( szCommand, "hlmvForceFrame" ) )
  1335. {
  1336. float flFrame = 0.0f;
  1337. sscanf( szCommand, "%*s %f", &flFrame );
  1338. d_cpl->SetFrameSlider( flFrame );
  1339. d_cpl->setFrame( flFrame );
  1340. d_cpl->setSpeedScale( 0 );
  1341. // Redraw.
  1342. d_MatSysWindow->redraw();
  1343. }
  1344. else if ( StringHasPrefixCaseSensitive( szCommand, "hlmvLink" ) )
  1345. {
  1346. if ( !g_bHlmvControlled )
  1347. {
  1348. g_bHlmvControlled = true;
  1349. CUtlString label( "LINKED: " );
  1350. label += getLabel();
  1351. setLabel( label.Get() );
  1352. }
  1353. }
  1354. else if ( StringHasPrefixCaseSensitive( szCommand, "hlmvUnlink" ) )
  1355. {
  1356. g_bHlmvControlled = false;
  1357. const char *pszLabel = getLabel();
  1358. if ( StringHasPrefixCaseSensitive( pszLabel, "LINKED: " ) )
  1359. {
  1360. setLabel( pszLabel + 8 ); // Skip past "LINKED: "
  1361. }
  1362. }
  1363. }
  1364. void
  1365. MDLViewer::redraw ()
  1366. {
  1367. /*
  1368. mxEvent event;
  1369. event.event = mxEvent::Size;
  1370. event.width = w2 ();
  1371. event.height = h2 ();
  1372. handleEvent (&event);
  1373. */
  1374. }
  1375. //-----------------------------------------------------------------------------
  1376. // Purpose:
  1377. // Output : int
  1378. //-----------------------------------------------------------------------------
  1379. int MDLViewer::GetCurrentHitboxSet( void )
  1380. {
  1381. return d_cpl ? d_cpl->GetCurrentHitboxSet() : 0;
  1382. }
  1383. //-----------------------------------------------------------------------------
  1384. // Sends the model transform to the controlled hlmv instance
  1385. //-----------------------------------------------------------------------------
  1386. void MDLViewer::SendModelTransformToLinkedHlmv()
  1387. {
  1388. if ( g_HlmvIpcClient.Connect() )
  1389. {
  1390. matrix3x4_t m;
  1391. g_pStudioModel->GetModelTransform( m );
  1392. CUtlBuffer cmd;
  1393. CUtlBuffer res;
  1394. cmd.Printf( "%s %f %f %f %f %f %f %f %f %f %f %f %f",
  1395. "hlmvModelTransform",
  1396. m.m_flMatVal[0][0], m.m_flMatVal[0][1], m.m_flMatVal[0][2], m.m_flMatVal[0][3],
  1397. m.m_flMatVal[1][0], m.m_flMatVal[1][1], m.m_flMatVal[1][2], m.m_flMatVal[1][3],
  1398. m.m_flMatVal[2][0], m.m_flMatVal[2][1], m.m_flMatVal[2][2], m.m_flMatVal[2][3] );
  1399. g_HlmvIpcClient.ExecuteCommand( cmd, res );
  1400. g_HlmvIpcClient.Disconnect();
  1401. }
  1402. }
  1403. static CSimpleWindowsLoggingListener s_SimpleWindowsLoggingListener;
  1404. //-----------------------------------------------------------------------------
  1405. // The application object
  1406. //-----------------------------------------------------------------------------
  1407. class CHLModelViewerApp : public CTier3DmSteamApp
  1408. {
  1409. typedef CTier3DmSteamApp BaseClass;
  1410. public:
  1411. // Methods of IApplication
  1412. virtual bool Create();
  1413. virtual bool PreInit();
  1414. virtual int Main();
  1415. virtual void PostShutdown();
  1416. virtual void Destroy();
  1417. };
  1418. //-----------------------------------------------------------------------------
  1419. // Create all singleton systems
  1420. //-----------------------------------------------------------------------------
  1421. bool CHLModelViewerApp::Create()
  1422. {
  1423. LoggingSystem_PushLoggingState();
  1424. LoggingSystem_RegisterLoggingListener( &s_SimpleWindowsLoggingListener );
  1425. g_dxlevel = CommandLine()->ParmValue( "-dx", 0 );
  1426. g_bOldFileDialogs = ( CommandLine()->FindParm( "-olddialogs" ) != 0 );
  1427. AppSystemInfo_t appSystems[] =
  1428. {
  1429. { "materialsystem.dll", MATERIAL_SYSTEM_INTERFACE_VERSION },
  1430. { "studiorender.dll", STUDIO_RENDER_INTERFACE_VERSION },
  1431. { "vphysics.dll", VPHYSICS_INTERFACE_VERSION },
  1432. { "datacache.dll", DATACACHE_INTERFACE_VERSION },
  1433. { "datacache.dll", MDLCACHE_INTERFACE_VERSION },
  1434. { "datacache.dll", STUDIO_DATA_CACHE_INTERFACE_VERSION },
  1435. { "soundemittersystem.dll", SOUNDEMITTERSYSTEM_INTERFACE_VERSION },
  1436. { "soundsystem.dll", SOUNDSYSTEM_INTERFACE_VERSION },
  1437. { "", "" } // Required to terminate the list
  1438. };
  1439. if ( !AddSystems( appSystems ) )
  1440. return false;
  1441. AddSystem( g_pDataModel, VDATAMODEL_INTERFACE_VERSION );
  1442. AddSystem( g_pDmSerializers, DMSERIALIZERS_INTERFACE_VERSION );
  1443. // Add the P4 module separately so that if it is absent
  1444. // (say in the SDK) then the other system will initialize properly
  1445. if ( CGameConfigManager::IsSDKDeployment() == false )
  1446. {
  1447. AppModule_t p4Module = LoadModule( "p4lib.dll" );
  1448. AddSystem( p4Module, P4_INTERFACE_VERSION );
  1449. }
  1450. g_pFileSystem = (IFileSystem*)FindSystem( FILESYSTEM_INTERFACE_VERSION );
  1451. g_pStudioDataCache = (IStudioDataCache*)FindSystem( STUDIO_DATA_CACHE_INTERFACE_VERSION );
  1452. physcollision = (IPhysicsCollision *)FindSystem( VPHYSICS_COLLISION_INTERFACE_VERSION );
  1453. physprop = (IPhysicsSurfaceProps *)FindSystem( VPHYSICS_SURFACEPROPS_INTERFACE_VERSION );
  1454. g_pSoundEmitterBase = (ISoundEmitterSystemBase *)FindSystem( SOUNDEMITTERSYSTEM_INTERFACE_VERSION );
  1455. g_pSoundSystem = (ISoundSystem *)FindSystem( SOUNDSYSTEM_INTERFACE_VERSION );
  1456. IMaterialSystem *pMaterialSystem = (IMaterialSystem*)FindSystem( MATERIAL_SYSTEM_INTERFACE_VERSION );
  1457. if ( !pMaterialSystem )
  1458. {
  1459. Error( "Unable to connect to necessary interface!\n" );
  1460. return false;
  1461. }
  1462. const char *pShaderDLL = CommandLine()->ParmValue("-shaderdll");
  1463. const char *pArg;
  1464. if ( CommandLine()->CheckParm( "-shaderapi", &pArg ))
  1465. {
  1466. pShaderDLL = pArg;
  1467. }
  1468. if(!pShaderDLL)
  1469. {
  1470. pShaderDLL = "shaderapidx9.dll";
  1471. }
  1472. pMaterialSystem->SetShaderAPI( pShaderDLL );
  1473. g_Factory = GetFactory();
  1474. return true;
  1475. }
  1476. void CHLModelViewerApp::Destroy()
  1477. {
  1478. LoggingSystem_PopLoggingState();
  1479. g_pFileSystem = NULL;
  1480. g_pStudioDataCache = NULL;
  1481. physcollision = NULL;
  1482. physprop = NULL;
  1483. }
  1484. //-----------------------------------------------------------------------------
  1485. // Init, shutdown
  1486. //-----------------------------------------------------------------------------
  1487. bool CHLModelViewerApp::PreInit( )
  1488. {
  1489. if ( !BaseClass::PreInit() )
  1490. return false;
  1491. if ( !g_pFileSystem || !physprop || !physcollision || !g_pMaterialSystem ||
  1492. !g_pStudioRender || !g_pMDLCache || !g_pDataCache )
  1493. {
  1494. Error("Unable to load required library interface!\n");
  1495. }
  1496. MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false );
  1497. // Add paths...
  1498. if ( !SetupSearchPaths( NULL, false, true ) )
  1499. return false;
  1500. // Get the adapter from the command line....
  1501. const char *pAdapterString;
  1502. int nAdapter = 0;
  1503. if (CommandLine()->CheckParm( "-adapter", &pAdapterString ))
  1504. {
  1505. nAdapter = atoi( pAdapterString );
  1506. }
  1507. int nAdapterFlags = 0;
  1508. if ( CommandLine()->CheckParm( "-ref" ) )
  1509. {
  1510. nAdapterFlags |= MATERIAL_INIT_REFERENCE_RASTERIZER;
  1511. }
  1512. g_pMaterialSystem->SetAdapter( nAdapter, nAdapterFlags );
  1513. if ( !CGameConfigManager::IsSDKDeployment() || CommandLine()->FindParm( "-OldDialogs" ) )
  1514. {
  1515. g_bOldFileDialogs = true;
  1516. }
  1517. LoadFileSystemDialogModule();
  1518. return true;
  1519. }
  1520. void CHLModelViewerApp::PostShutdown()
  1521. {
  1522. UnloadFileSystemDialogModule();
  1523. BaseClass::PostShutdown();
  1524. }
  1525. //-----------------------------------------------------------------------------
  1526. // main application
  1527. //-----------------------------------------------------------------------------
  1528. int CHLModelViewerApp::Main()
  1529. {
  1530. g_pMaterialSystem->ModInit();
  1531. g_pDataCache->SetSize( 64 * 1024 * 1024 );
  1532. // No p4 mode if specified on the command line or no p4lib.dll found
  1533. const bool bP4DLLExists = g_pFullFileSystem->FileExists( "p4lib.dll", "EXECUTABLE_PATH" );
  1534. if ( ( CommandLine()->FindParm( "-nop4" ) ) || ( !bP4DLLExists ) || CGameConfigManager::IsSDKDeployment() )
  1535. {
  1536. g_p4factory->SetDummyMode( true );
  1537. }
  1538. // Set the named changelist
  1539. g_p4factory->SetOpenFileChangeList( "HLMV Auto Checkout" );
  1540. //mx::setDisplayMode (0, 0, 0);
  1541. g_MDLViewer = new MDLViewer();
  1542. g_MDLViewer->setMenuBar (g_MDLViewer->getMenuBar ());
  1543. g_pStudioModel->Init();
  1544. g_pStudioModel->ModelInit();
  1545. g_pStudioModel->ClearLookTargets( );
  1546. g_pDataModel->SetUndoEnabled( false );
  1547. // Load up the initial model
  1548. const char *pMdlName = NULL;
  1549. int nParmCount = CommandLine()->ParmCount();
  1550. if ( nParmCount > 1 )
  1551. {
  1552. pMdlName = CommandLine()->GetParm( nParmCount - 1 );
  1553. }
  1554. if ( pMdlName && Q_stristr( pMdlName, ".mdl" ) )
  1555. {
  1556. char absPath[MAX_PATH];
  1557. Q_MakeAbsolutePath( absPath, sizeof( absPath ), pMdlName );
  1558. if ( CommandLine()->FindParm( "-screenshot" ) )
  1559. {
  1560. g_MDLViewer->SaveScreenShot( absPath );
  1561. }
  1562. else if ( CommandLine()->FindParm( "-dump" ) )
  1563. {
  1564. g_MDLViewer->DumpText( absPath );
  1565. }
  1566. else
  1567. {
  1568. g_MDLViewer->LoadModelFile( absPath );
  1569. }
  1570. }
  1571. if ( pMdlName && Q_stristr( pMdlName, ".mvscript" ) )
  1572. {
  1573. char absPath[MAX_PATH];
  1574. Q_MakeAbsolutePath(absPath, sizeof(absPath), pMdlName);
  1575. #ifdef DEBUG
  1576. Q_StripExtension( absPath, absPath, sizeof(absPath) );
  1577. Q_strcat(absPath, ".mvscript", sizeof(absPath) );
  1578. //mxMessageBox (NULL, absPath, g_appTitle, MX_MB_OK | MX_MB_ERROR);
  1579. #endif
  1580. g_MDLViewer->ExecuteMVScript(absPath);
  1581. }
  1582. int nRetVal = mx::run ();
  1583. g_pStudioModel->Shutdown();
  1584. g_pMaterialSystem->ModShutdown();
  1585. return nRetVal;
  1586. }
  1587. static bool CHLModelViewerApp_SuggestGameInfoDirFn( CFSSteamSetupInfo const *pFsSteamSetupInfo, char *pchPathBuffer, int nBufferLength, bool *pbBubbleDirectories )
  1588. {
  1589. const char *pMdlName = NULL;
  1590. int nParmCount = CommandLine()->ParmCount();
  1591. if ( nParmCount > 1 )
  1592. {
  1593. pMdlName = CommandLine()->GetParm( nParmCount - 1 );
  1594. }
  1595. if ( pMdlName && Q_stristr( pMdlName, ".mdl" ) )
  1596. {
  1597. Q_MakeAbsolutePath( pchPathBuffer, nBufferLength, pMdlName );
  1598. if ( pbBubbleDirectories )
  1599. *pbBubbleDirectories = true;
  1600. return true;
  1601. }
  1602. return false;
  1603. }
  1604. //-----------------------------------------------------------------------------
  1605. // Main entry point
  1606. //-----------------------------------------------------------------------------
  1607. int main (int argc, char *argv[])
  1608. {
  1609. CommandLine()->CreateCmdLine( argc, argv );
  1610. mx::init( argc, argv );
  1611. // make sure we start in the right directory
  1612. char szName[256];
  1613. strcpy( szName, mx::getApplicationPath() );
  1614. // mx_setcwd (szName);
  1615. // Set game info directory suggestion callback
  1616. SetSuggestGameInfoDirFn( CHLModelViewerApp_SuggestGameInfoDirFn );
  1617. CHLModelViewerApp hlmodelviewerApp;
  1618. CSteamApplication steamApplication( &hlmodelviewerApp );
  1619. return steamApplication.Run();
  1620. }
  1621. //
  1622. // Implementation of IPC server
  1623. //
  1624. CHlmvIpcServer::~CHlmvIpcServer()
  1625. {
  1626. for ( int k = 0; k < m_lstCommands.Count(); ++ k )
  1627. {
  1628. delete [] m_lstCommands[k];
  1629. }
  1630. m_lstCommands.Purge();
  1631. }
  1632. bool CHlmvIpcServer::HasCommands()
  1633. {
  1634. AUTO_LOCK_FM( m_mtx );
  1635. return m_lstCommands.Count() > 0;
  1636. }
  1637. void CHlmvIpcServer::AppendCommand( char *pszCommand )
  1638. {
  1639. AUTO_LOCK_FM( m_mtx );
  1640. m_lstCommands.AddToTail( pszCommand );
  1641. }
  1642. char * CHlmvIpcServer::GetCommand()
  1643. {
  1644. AUTO_LOCK_FM( m_mtx );
  1645. return m_lstCommands.Count() ? m_lstCommands[0] : "";
  1646. }
  1647. void CHlmvIpcServer::PopCommand()
  1648. {
  1649. AUTO_LOCK_FM( m_mtx );
  1650. if ( m_lstCommands.Count() )
  1651. {
  1652. delete [] m_lstCommands[0];
  1653. m_lstCommands.Remove( 0 );
  1654. }
  1655. }
  1656. BOOL CHlmvIpcServer::ExecuteCommand(CUtlBuffer &cmd, CUtlBuffer &res)
  1657. {
  1658. char *szCommand = ( char * ) cmd.Base();
  1659. int nLen = strlen( szCommand );
  1660. while ( nLen > 0 && V_isspace( szCommand[ nLen - 1 ] ) )
  1661. -- nLen;
  1662. if ( nLen <= 0 )
  1663. return FALSE;
  1664. char *pchCopy = new char[ nLen + 1 ];
  1665. memcpy( pchCopy, szCommand, nLen );
  1666. pchCopy[ nLen ] = 0;
  1667. AppendCommand( pchCopy );
  1668. res.PutInt( 0 );
  1669. return TRUE;
  1670. }