Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

722 lines
22 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #if defined(WIN32) && !defined( _X360 )
  7. #include <windows.h>
  8. #endif
  9. #include "filesystem.h"
  10. #include "filesystem_init.h"
  11. #include "appframework/IAppSystemGroup.h"
  12. #include "appframework/IAppSystem.h"
  13. #include "appframework/AppFramework.h"
  14. #include "filesystem_helpers.h"
  15. #include "matsys_controls/QCGenerator.h"
  16. #include "tier1/KeyValues.h"
  17. #include "tier2/vconfig.h"
  18. #include "vgui_controls/ListPanel.h"
  19. #include "vgui_controls/TextEntry.h"
  20. #include "vgui_controls/Button.h"
  21. #include "vgui_controls/FileOpenDialog.h"
  22. #include "vgui_controls/DirectorySelectDialog.h"
  23. #include "vgui_controls/ComboBox.h"
  24. #include "vgui_controls/CheckButton.h"
  25. #include "vgui_controls/MessageBox.h"
  26. #include "vgui/ISurface.h"
  27. #include "vgui/IInput.h"
  28. #include "vgui/Cursor.h"
  29. #include "vgui_controls/KeyBoardEditorDialog.h"
  30. #if defined( _X360 )
  31. #include "xbox/xbox_win32stubs.h"
  32. #endif
  33. using namespace vgui;
  34. #define MAX_KEYVALUE 1024
  35. //-----------------------------------------------------------------------------
  36. // Purpose: returns a pointer to the 'count' occurence of a character from the end of a string
  37. // returns 0 of there aren't 'count' number of the character in the string
  38. //-----------------------------------------------------------------------------
  39. char *strrchrcount(char *string, int character, int count )
  40. {
  41. int j = count;
  42. int numChars = strlen( string );
  43. for( int i = numChars; i > 0; i-- )
  44. {
  45. if( string[i-1] == character )
  46. {
  47. j--;
  48. }
  49. if( j == 0 )
  50. {
  51. return string + i-1;
  52. }
  53. }
  54. return 0;
  55. }
  56. class CModalPreserveMessageBox : public vgui::MessageBox
  57. {
  58. public:
  59. CModalPreserveMessageBox(const char *title, const char *text, vgui::Panel *parent)
  60. : vgui::MessageBox( title, text, parent )
  61. {
  62. m_PrevAppFocusPanel = vgui::input()->GetAppModalSurface();
  63. }
  64. ~CModalPreserveMessageBox()
  65. {
  66. vgui::input()->SetAppModalSurface( m_PrevAppFocusPanel );
  67. }
  68. public:
  69. vgui::VPANEL m_PrevAppFocusPanel;
  70. };
  71. void VGUIMessageBox( vgui::Panel *pParent, const char *pTitle, const char *pMsg, ... )
  72. {
  73. char msg[4096];
  74. va_list marker;
  75. va_start( marker, pMsg );
  76. Q_vsnprintf( msg, sizeof( msg ), pMsg, marker );
  77. va_end( marker );
  78. vgui::MessageBox *dlg = new CModalPreserveMessageBox( pTitle, msg, pParent );
  79. dlg->DoModal();
  80. dlg->Activate();
  81. dlg->RequestFocus();
  82. }
  83. //-----------------------------------------------------------------------------
  84. // Purpose: Places all the info from the vgui controls into the QCInfo struct
  85. //-----------------------------------------------------------------------------
  86. void QCInfo::SyncFromControls()
  87. {
  88. char tempText[MAX_PATH];
  89. vgui::Panel *pTargetField = pQCGenerator->FindChildByName( "staticPropCheck" );
  90. bStaticProp = ((CheckButton *)pTargetField)->IsSelected();
  91. pTargetField = pQCGenerator->FindChildByName( "mostlyOpaqueCheck" );
  92. bMostlyOpaque = ((CheckButton *)pTargetField)->IsSelected();
  93. pTargetField = pQCGenerator->FindChildByName( "disableCollisionsCheck" );
  94. bDisableCollision = ((CheckButton *)pTargetField)->IsSelected();
  95. pTargetField = pQCGenerator->FindChildByName( "referencePhysicsCheck" );
  96. bReferenceAsPhys = ((CheckButton *)pTargetField)->IsSelected();
  97. pTargetField = pQCGenerator->FindChildByName( "concaveCheck" );
  98. bConcave = ((CheckButton *)pTargetField)->IsSelected();
  99. pTargetField = pQCGenerator->FindChildByName( "automassCheck" );
  100. bAutomass = ((CheckButton *)pTargetField)->IsSelected();
  101. pTargetField = pQCGenerator->FindChildByName( "massField" );
  102. ((TextEntry *)pTargetField)->GetText(tempText, MAX_PATH);
  103. fMass = atof(tempText);
  104. pTargetField = pQCGenerator->FindChildByName( "scaleField" );
  105. ((TextEntry *)pTargetField)->GetText(tempText, MAX_PATH);
  106. fScale = atof(tempText);
  107. pTargetField = pQCGenerator->FindChildByName( "collisionSMDField" );
  108. ((TextEntry *)pTargetField)->GetText( tempText, MAX_PATH );
  109. V_strcpy_safe( pszCollisionPath, tempText );
  110. pTargetField = pQCGenerator->FindChildByName( "surfacePropertyDropDown" );
  111. ((ComboBox *)pTargetField)->GetText( tempText, MAX_PATH );
  112. V_strcpy_safe( pszSurfaceProperty, tempText );
  113. pTargetField = pQCGenerator->FindChildByName( "materialsField" );
  114. ((TextEntry *)pTargetField)->GetText( tempText, MAX_PATH );
  115. V_strcpy_safe( pszMaterialPath, tempText );
  116. LODs.RemoveAll();
  117. pTargetField = pQCGenerator->FindChildByName( "LODList" );
  118. int numLOD = ((ListPanel *)pTargetField)->GetItemCount();
  119. for ( int i = 0; i < numLOD; i++ )
  120. {
  121. KeyValues *key = ((ListPanel *)pTargetField)->GetItem( i );
  122. LODInfo newLOD;
  123. V_strcpy_safe( newLOD.pszFilename, key->GetString( "SMD" ) );
  124. newLOD.iLOD = key->GetInt( "LOD" );
  125. LODs.AddToTail( newLOD );
  126. }
  127. }
  128. //-----------------------------------------------------------------------------
  129. // Purpose: Called during intialization to setup the initial state of the VGUI controls
  130. //-----------------------------------------------------------------------------
  131. void QCInfo::SyncToControls()
  132. {
  133. char tempText[MAX_PATH];
  134. vgui::Panel *pTargetField = pQCGenerator->FindChildByName( "staticPropCheck" );
  135. ((CheckButton *)pTargetField)->SetSelected( bStaticProp );
  136. pTargetField = pQCGenerator->FindChildByName( "mostlyOpaqueCheck" );
  137. ((CheckButton *)pTargetField)->SetSelected( bMostlyOpaque );
  138. pTargetField = pQCGenerator->FindChildByName( "disableCollisionsCheck" );
  139. ((CheckButton *)pTargetField)->SetSelected( bDisableCollision );
  140. pTargetField = pQCGenerator->FindChildByName( "referencePhysicsCheck" );
  141. ((CheckButton *)pTargetField)->SetSelected( bReferenceAsPhys );
  142. pTargetField = pQCGenerator->FindChildByName( "concaveCheck" );
  143. ((CheckButton *)pTargetField)->SetSelected( bConcave );
  144. pTargetField = pQCGenerator->FindChildByName( "automassCheck" );
  145. ((CheckButton *)pTargetField)->SetSelected( bAutomass );
  146. Q_snprintf( tempText, 10, "%d", (int)fMass );
  147. pTargetField = pQCGenerator->FindChildByName( "massField" );
  148. ((TextEntry *)pTargetField)->SetText( tempText );
  149. Q_snprintf( tempText, 10, "%d", (int)fScale );
  150. pTargetField = pQCGenerator->FindChildByName( "scaleField" );
  151. ((TextEntry *)pTargetField)->SetText( tempText );
  152. pTargetField = pQCGenerator->FindChildByName( "collisionSMDField" );
  153. ((TextEntry *)pTargetField)->SetText( pszCollisionPath );
  154. pTargetField = pQCGenerator->FindChildByName( "materialsField" );
  155. ((TextEntry *)pTargetField)->SetText( pszMaterialPath );
  156. pTargetField = pQCGenerator->FindChildByName( "surfacePropertyDropDown" );
  157. int numItems = ((ComboBox *)pTargetField)->GetItemCount();
  158. for( int i = 0; i < numItems; i++ )
  159. {
  160. ((ComboBox *)pTargetField)->GetItemText( i, tempText, MAX_PATH );
  161. if ( !Q_strcmp( tempText, pszSurfaceProperty ) )
  162. {
  163. ((ComboBox *)pTargetField)->SetItemEnabled( i, true );
  164. ((ComboBox *)pTargetField)->SetText( tempText );
  165. break;
  166. }
  167. }
  168. }
  169. CBrowseButton::CBrowseButton( vgui::Panel *pParent ) : BaseClass( pParent, "Browse Button", "...", pParent, "browse" )
  170. {
  171. SetParent( pParent );
  172. pszStartingDirectory = NULL;
  173. pszFileFilter = NULL;
  174. pszTargetField = NULL;
  175. }
  176. CBrowseButton::~CBrowseButton()
  177. {
  178. }
  179. void CBrowseButton::SetCharVar( char **pVar, const char *pszNewText )
  180. {
  181. if ( *pVar && pszNewText && !Q_strcmp( *pVar, pszNewText ) )
  182. {
  183. return;
  184. }
  185. if ( *pVar )
  186. {
  187. delete [] *pVar;
  188. *pVar = NULL;
  189. }
  190. if ( pszNewText )
  191. {
  192. int len = Q_strlen( pszNewText ) + 1;
  193. *pVar = new char[ len ];
  194. Q_strncpy( *pVar, pszNewText, len );
  195. }
  196. }
  197. void CBrowseButton::InitBrowseInfo( int x, int y, const char *pszName, const char *pszDir, const char *pszFilter, const char *pszField )
  198. {
  199. SetSize( 24, 24 );
  200. SetPos( x, y );
  201. SetName( pszName );
  202. SetCharVar( GetStartingDirectory(), pszDir );
  203. SetCharVar( GetFileFilter(), pszFilter );
  204. SetCharVar( GetTargetField(), pszField );
  205. SetActionMessage();
  206. }
  207. void CBrowseButton::SetActionMessage()
  208. {
  209. KeyValues *newActionMessage = new KeyValues( "browse", "directory", pszStartingDirectory, "filter", pszFileFilter);
  210. newActionMessage->SetString( "targetField", pszTargetField );
  211. SetCommand( newActionMessage );
  212. }
  213. const char *ParseKeyvalue( const char *pBuffer, char *key, char *value )
  214. {
  215. char com_token[1024];
  216. pBuffer = (const char *)ParseFile( pBuffer, com_token, NULL );
  217. if ( Q_strlen( com_token ) < MAX_KEYVALUE )
  218. {
  219. Q_strncpy( key, com_token, MAX_KEYVALUE );
  220. Q_strlower( key );
  221. }
  222. // no value on a close brace
  223. if ( !Q_strcmp( key, "}" ) )
  224. {
  225. value[0] = 0;
  226. return pBuffer;
  227. }
  228. pBuffer = (const char *)ParseFile( pBuffer, com_token, NULL );
  229. if ( Q_strlen( com_token ) < MAX_KEYVALUE )
  230. {
  231. Q_strncpy( value, com_token, MAX_KEYVALUE );
  232. Q_strlower( value );
  233. }
  234. return pBuffer;
  235. }
  236. //-----------------------------------------------------------------------------
  237. // Purpose: Constructor
  238. //-----------------------------------------------------------------------------
  239. CQCGenerator::CQCGenerator( vgui::Panel *pParent, const char *pszPath, const char *pszScene ) : BaseClass( pParent, "QCGenerator" )
  240. {
  241. m_QCInfo_t.Init( this );
  242. SetMinimumSize(846, 770);
  243. m_pLODPanel = new ListPanel(this, "LODList");
  244. m_pLODPanel->SetSelectIndividualCells( true );
  245. m_pLODPanel->AddColumnHeader(0, "SMD", "LOD SMD", 450, 0);
  246. m_pLODPanel->AddColumnHeader(1, "LOD", "LOD Distance", 50, 0);
  247. m_pLODPanel->AddActionSignalTarget( this );
  248. m_pLODPanel->SetMouseInputEnabled( true );
  249. LoadControlSettings( "QCGenerator.res" );
  250. m_pCollisionBrowseButton = new CBrowseButton( this );
  251. m_pCollisionBrowseButton->InitBrowseInfo( 808, 158, "collisionBrowseButton", pszPath, "*.smd", "collisionSMDField" );
  252. char szTerminatedPath[1024] = "\0";
  253. sprintf( szTerminatedPath, "%s\\", pszPath );
  254. InitializeSMDPaths( szTerminatedPath, pszScene );
  255. char *pszMaterialsStart = strrchrcount( szTerminatedPath, '\\', 3 ) + 1;
  256. char *pszMaterialsEnd = strrchr( szTerminatedPath, '\\');
  257. Q_strncpy( m_QCInfo_t.pszMaterialPath, pszMaterialsStart, pszMaterialsEnd - pszMaterialsStart + 1 );
  258. SetParent( pParent );
  259. char szGamePath[1024] = "\0";
  260. char szSearchPath[1024] = "\0";
  261. // Get the currently set game configuration
  262. GetVConfigRegistrySetting( GAMEDIR_TOKEN, szGamePath, sizeof( szGamePath ) );
  263. static const char *pSurfacePropFilename = "\\scripts\\surfaceproperties.txt";
  264. sprintf( szSearchPath, "%s%s", szGamePath, pSurfacePropFilename );
  265. FileHandle_t fp = g_pFullFileSystem->Open( szSearchPath, "rb" );
  266. if ( !fp )
  267. {
  268. //the set game configuration didn't have a surfaceproperties file; we are grabbing it from hl2
  269. //TODO: This only works if they are in a subdirectory that is a peer to an hl2 directory
  270. // that contains the file. It potentially needs to search the entire drive or prompt for the location
  271. char *pszEndGamePath = Q_strrchr( szGamePath, '\\' );
  272. pszEndGamePath[0] = 0;
  273. V_strcat_safe( szGamePath, "\\hl2" );
  274. sprintf( szSearchPath, "%s%s", szGamePath, pSurfacePropFilename );
  275. fp = g_pFullFileSystem->Open( szSearchPath, "rb" );
  276. }
  277. int len = g_pFullFileSystem->Size( fp );
  278. const char *szSurfacePropContents = new char[len+1];
  279. g_pFullFileSystem->Read( (void *)szSurfacePropContents, len, fp );
  280. char key[MAX_KEYVALUE], value[MAX_KEYVALUE];
  281. vgui::Panel *pSurfacePropDropDown = FindChildByName( "surfacePropertyDropDown" );
  282. //filling up the surface property dropdown
  283. while ( szSurfacePropContents )
  284. {
  285. szSurfacePropContents = ParseKeyvalue( szSurfacePropContents, key, value );
  286. ((ComboBox *)pSurfacePropDropDown)->AddItem( key, NULL );
  287. while ( szSurfacePropContents )
  288. {
  289. szSurfacePropContents = ParseKeyvalue( szSurfacePropContents, key, value );
  290. if (!stricmp( key, "}" ) )
  291. {
  292. break;
  293. }
  294. }
  295. }
  296. m_QCInfo_t.SyncToControls();
  297. m_pLODEdit = 0;
  298. }
  299. //-----------------------------------------------------------------------------
  300. // Purpose: Destructor
  301. //-----------------------------------------------------------------------------
  302. CQCGenerator::~CQCGenerator()
  303. {
  304. }
  305. void CQCGenerator::OnCommand( const char *command )
  306. {
  307. if ( Q_stricmp( command, "createQC" ) == 0 )
  308. {
  309. m_QCInfo_t.SyncFromControls();
  310. GenerateQCFile();
  311. }
  312. if ( Q_stricmp( command, "deleteSeq" ) == 0 )
  313. {
  314. //delete it
  315. DeleteLOD();
  316. }
  317. if ( Q_stricmp( command, "editSeq" ) == 0 )
  318. {
  319. //edit
  320. EditLOD();
  321. }
  322. BaseClass::OnCommand( command );
  323. }
  324. void CQCGenerator::OnKeyCodeTyped( KeyCode code )
  325. {
  326. switch ( code )
  327. {
  328. case KEY_ENTER:
  329. EditLOD();
  330. }
  331. }
  332. void CQCGenerator::OnBrowse( KeyValues *data )
  333. {
  334. V_strcpy_safe( m_szTargetField, data->GetString( "targetField" ) );
  335. const char *filter = data->GetString( "filter" );
  336. if ( Q_strlen( filter ) == 0 )
  337. {
  338. // BrowseDirectory( data );
  339. }
  340. else
  341. {
  342. BrowseFile( data );
  343. }
  344. }
  345. /*
  346. //This function is no longer used in the current version of the program.
  347. void CQCGenerator::BrowseDirectory( KeyValues *data )
  348. {
  349. DirectorySelectDialog *pDialog = new DirectorySelectDialog( this, "Select Directory" );
  350. pDialog->AddActionSignalTarget( this );
  351. pDialog->DoModal();
  352. pDialog->SetStartDirectory( data->GetString( "directory" ) );
  353. }
  354. */
  355. void CQCGenerator::BrowseFile( KeyValues *data )
  356. {
  357. const char *filter = data->GetString( "filter" );
  358. FileOpenDialog *pDialog = new FileOpenDialog( this, "Select File", true );
  359. pDialog->AddFilter( filter, filter, true );
  360. pDialog->AddActionSignalTarget(this);
  361. pDialog->SetStartDirectory( data->GetString( "directory" ) );
  362. pDialog->DoModal( true );
  363. }
  364. void CQCGenerator::OnFileSelected( KeyValues *data )
  365. {
  366. if ( m_szTargetField )
  367. {
  368. vgui::Panel *pTargetField = FindChildByName( m_szTargetField );
  369. ((TextEntry *)pTargetField)->SetText( data->GetString( "fullpath" ) );
  370. Repaint();
  371. }
  372. }
  373. void CQCGenerator::OnDirectorySelected( KeyValues *data )
  374. {
  375. if ( m_szTargetField )
  376. {
  377. vgui::Panel *pTargetField = FindChildByName( m_szTargetField );
  378. ((TextEntry *)pTargetField)->SetText( data->GetString( "dir" ) );
  379. Repaint();
  380. }
  381. }
  382. bool CQCGenerator::GenerateQCFile()
  383. {
  384. //TODO: clean this up. Consider creating a datatype that includes the string to write out when the QC file is created
  385. char *nameBegin = strrchr( m_QCInfo_t.pszSMDPath, '\\' );
  386. char szPath[MAX_PATH];
  387. char szName[MAX_PATH];
  388. Q_strncpy( szPath, m_QCInfo_t.pszSMDPath, nameBegin - m_QCInfo_t.pszSMDPath + 2 );
  389. V_strcpy_safe( szName, szPath);
  390. V_strcat_safe( szName, m_QCInfo_t.pszSceneName);
  391. V_strcat_safe( szName, ".qc" );
  392. FileHandle_t pSaveFile = g_pFullFileSystem->Open( szName, "wt" );
  393. if (!pSaveFile)
  394. {
  395. char szSaveError[1024] = "";
  396. Q_snprintf( szSaveError, 1024, "Save failed: invalid file name '%s'\n\nDirectory '%s' must exist.", szName, szPath );
  397. VGUIMessageBox( this, "QC Generator error", szSaveError );
  398. return 0;
  399. }
  400. //write qc header
  401. g_pFullFileSystem->FPrintf( pSaveFile, "//\n// .qc file version 1.0\n\n");
  402. //write out modelname info
  403. char szModelName[MAX_PATH];
  404. char *modelStart = strrchrcount( szName, '\\', 2) + 1;
  405. char *modelEnd = strrchr( szName, '.' );
  406. Q_strncpy( szModelName, modelStart, modelEnd - modelStart + 1 );
  407. V_strcat_safe( szModelName, ".mdl" );
  408. g_pFullFileSystem->FPrintf( pSaveFile, "$modelname %s\n\n", szModelName );
  409. //write out scale info
  410. g_pFullFileSystem->FPrintf( pSaveFile, "$scale %f\n", m_QCInfo_t.fScale );
  411. //write out body info
  412. g_pFullFileSystem->FPrintf( pSaveFile, "$body \"Body\" \"%s\"\n", strrchr( m_QCInfo_t.pszSMDPath, '\\' ) + 1 );
  413. if ( m_QCInfo_t.bStaticProp == true )
  414. {
  415. g_pFullFileSystem->FPrintf( pSaveFile, "$staticprop\n" );
  416. }
  417. if ( m_QCInfo_t.bMostlyOpaque == true )
  418. {
  419. g_pFullFileSystem->FPrintf( pSaveFile, "$mostlyopaque\n" );
  420. }
  421. //write out surfaceprop info
  422. g_pFullFileSystem->FPrintf( pSaveFile, "$surfaceprop \"%s\"\n\n", m_QCInfo_t.pszSurfaceProperty );
  423. //write materials
  424. g_pFullFileSystem->FPrintf( pSaveFile, "$cdmaterials %s\n\n", m_QCInfo_t.pszMaterialPath);
  425. if ( m_QCInfo_t.bStaticProp || m_QCInfo_t.bNoAnimation )
  426. {
  427. g_pFullFileSystem->FPrintf( pSaveFile, "// --------- Animation sequences -------\n");
  428. g_pFullFileSystem->FPrintf( pSaveFile, "$sequence \"idle\" \"%s\" fps 30\n\n", strrchr(m_QCInfo_t.pszSMDPath, '\\')+1);
  429. }
  430. //write out lod info
  431. for( int i = 0; i < m_QCInfo_t.LODs.Count(); i++ )
  432. {
  433. LODInfo thisLOD = m_QCInfo_t.LODs.Element( i );
  434. g_pFullFileSystem->FPrintf( pSaveFile, "$lod %d\n{\n\treplacemodel \"%s\" \"%s\"\n}\n\n", thisLOD.iLOD, strrchr(m_QCInfo_t.pszSMDPath, '\\')+1, thisLOD.pszFilename );
  435. }
  436. if ( m_QCInfo_t.bDisableCollision != true )
  437. {
  438. //write out collision header
  439. g_pFullFileSystem->FPrintf( pSaveFile, "\n" );
  440. //write out collision info
  441. if ( m_QCInfo_t.bReferenceAsPhys == true )
  442. {
  443. g_pFullFileSystem->FPrintf( pSaveFile, "$collisionmodel \"%s\"", strrchr( m_QCInfo_t.pszSMDPath, '\\' ) + 1 );
  444. }
  445. else
  446. {
  447. if( Q_strcmp( m_QCInfo_t.pszCollisionPath, "" ) )
  448. {
  449. g_pFullFileSystem->FPrintf( pSaveFile, "$collisionmodel \"%s\"", strrchr( m_QCInfo_t.pszCollisionPath, '\\' ) + 1 );
  450. }
  451. }
  452. g_pFullFileSystem->FPrintf( pSaveFile, " {\n\t// Mass in kilograms\n ");
  453. if ( m_QCInfo_t.bAutomass == true )
  454. {
  455. g_pFullFileSystem->FPrintf( pSaveFile, "\t$automass\n" );
  456. }
  457. else
  458. {
  459. g_pFullFileSystem->FPrintf( pSaveFile, "\t$mass %f\n", m_QCInfo_t.fMass );
  460. }
  461. if ( m_QCInfo_t.bConcave == true )
  462. {
  463. g_pFullFileSystem->FPrintf( pSaveFile, "\t$concave\n" );
  464. }
  465. g_pFullFileSystem->FPrintf( pSaveFile, "}\n\n");
  466. }
  467. g_pFullFileSystem->Close( pSaveFile );
  468. char szCommand[MAX_PATH];
  469. char szGamePath[MAX_PATH];
  470. char studiomdlPath[512];
  471. g_pFullFileSystem->RelativePathToFullPath( "studiomdl.bat", NULL, studiomdlPath, sizeof( studiomdlPath ));
  472. GetVConfigRegistrySetting( GAMEDIR_TOKEN, szGamePath, sizeof( szGamePath ) );
  473. #ifdef WIN32
  474. STARTUPINFO startup;
  475. PROCESS_INFORMATION process;
  476. memset(&startup, 0, sizeof(startup));
  477. startup.cb = sizeof(startup);
  478. sprintf( szCommand, "%s -game %s %s", studiomdlPath, szGamePath, szName);
  479. bool bReturn = CreateProcess( NULL, szCommand, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &startup, &process);
  480. #else
  481. Assert( !"Implement me, why aren't we using a thread tool abstraction?" );
  482. bool bReturn = false;
  483. #endif
  484. return bReturn;
  485. }
  486. void CQCGenerator::InitializeSMDPaths( const char *pszPath, const char *pszScene )
  487. {
  488. V_strcpy_safe( m_QCInfo_t.pszSceneName, pszScene );
  489. FileFindHandle_t *pFileHandle = new FileFindHandle_t();
  490. g_pFullFileSystem->AddSearchPath( pszPath, "SMD_DIR" );
  491. const char *filename = g_pFullFileSystem->FindFirst( "*.smd", pFileHandle );
  492. bool bFoundReference = false;
  493. bool bFoundCollision = false;
  494. bool bFoundLOD = false;
  495. //iterate through .smd files
  496. const char *startName = pszScene;
  497. int nSearchLength = Q_strlen( pszScene );
  498. int currentLOD = 1;
  499. while( filename )
  500. {
  501. if ( !strncmp( startName, filename, nSearchLength ) )
  502. {
  503. const char *filenameEnd = filename + nSearchLength;
  504. if ( !strncmp( filenameEnd, "_ref", 4 ) || !strncmp( filenameEnd, ".smd", 4 ) )
  505. {
  506. bFoundReference = true;
  507. //we have found the reference smd.
  508. V_strcpy_safe( m_QCInfo_t.pszSMDPath, pszPath );
  509. V_strcat_safe( m_QCInfo_t.pszSMDPath, filename );
  510. }
  511. if ( !strncmp( filenameEnd, "_phy", 4) || !strncmp( filenameEnd, "_col", 4 ) )
  512. {
  513. bFoundCollision = true;
  514. //we have found the collision smd.
  515. V_strcpy_safe( m_QCInfo_t.pszCollisionPath, pszPath );
  516. V_strcat_safe( m_QCInfo_t.pszCollisionPath, filename );
  517. }
  518. if ( !strncmp( filenameEnd, "_lod", 4) )
  519. {
  520. bFoundLOD = true;
  521. //we found an LOD smd.
  522. char lodName[255];
  523. Q_snprintf( lodName, Q_strlen( lodName ), "lod%d", currentLOD );
  524. //we found an LOD
  525. KeyValues *newKv = new KeyValues( lodName, "SMD", filename, "LOD", "10" );
  526. m_pLODPanel->AddItem( newKv, currentLOD, false, false );
  527. currentLOD++;
  528. }
  529. }
  530. filename = g_pFullFileSystem->FindNext( *pFileHandle );
  531. }
  532. char pszMessage[2048] = "";
  533. char pszRefMessage[1024] = "";
  534. char pszColMessage[1024] = "";
  535. if (!bFoundReference )
  536. {
  537. V_strcat_safe( m_QCInfo_t.pszSMDPath, pszPath );
  538. V_strcat_safe( m_QCInfo_t.pszSMDPath, pszScene );
  539. V_strcat_safe( m_QCInfo_t.pszSMDPath, ".smd" );
  540. Q_snprintf( pszRefMessage, 1024, "Reference SMD not found.\n\nValid default reference SMDs are %s%s_ref*.smd and %s%s.smd\nUsing default of %s. Model will not compile.\n\n", pszPath, pszScene, pszPath, pszScene, m_QCInfo_t.pszSMDPath );
  541. }
  542. if ( !bFoundCollision )
  543. {
  544. Q_snprintf( pszColMessage, 1024, "Collision SMD not found.\n\nThe valid default collision SMD is %s%s_phy*.smd.\nUsing reference SMD as default.\n", pszPath, pszScene );
  545. V_strcpy_safe( m_QCInfo_t.pszCollisionPath, m_QCInfo_t.pszSMDPath );
  546. m_QCInfo_t.bReferenceAsPhys = true;
  547. }
  548. if ( !bFoundReference || !bFoundCollision)
  549. {
  550. V_strcpy_safe( pszMessage, pszRefMessage );
  551. V_strcat_safe( pszMessage, pszColMessage );
  552. VGUIMessageBox( this, "Error Initializing Paths", pszMessage );
  553. }
  554. }
  555. void CQCGenerator::DeleteLOD()
  556. {
  557. int numSelected = m_pLODPanel->GetSelectedItemsCount();
  558. int selected;
  559. for ( int i = numSelected-1; i >= 0; i-- )
  560. {
  561. selected = m_pLODPanel->GetSelectedItem( i );
  562. m_pLODPanel->RemoveItem( selected );
  563. }
  564. }
  565. void CQCGenerator::EditLOD()
  566. {
  567. int numSelected = m_pLODPanel->GetSelectedItemsCount();
  568. if ( numSelected == 1 && !m_pLODPanel->IsInEditMode() )
  569. {
  570. if ( m_pLODEdit )
  571. {
  572. m_pLODEdit->MarkForDeletion();
  573. m_pLODEdit = NULL;
  574. }
  575. m_pLODEdit = new vgui::TextEntry( this, "Edit" );
  576. m_pLODEdit->SendNewLine( true );
  577. m_nSelectedSequence = m_pLODPanel->GetSelectedItem( 0 );
  578. m_nSelectedColumn = m_pLODPanel->GetSelectedColumn();
  579. m_pLODPanel->EnterEditMode( m_nSelectedSequence, m_nSelectedColumn, m_pLODEdit );
  580. }
  581. }
  582. void CQCGenerator::OnNewLODText()
  583. {
  584. KeyValues *pEditItem = m_pLODPanel->GetItem( m_nSelectedSequence );
  585. KeyValues *pListItem = pEditItem;
  586. wchar_t szEditText[MAX_PATH];
  587. pEditItem = pEditItem->GetFirstValue();
  588. const char *name = pEditItem->GetName();
  589. for( int i = 0; i < m_nSelectedColumn; i++ )
  590. {
  591. pEditItem = pEditItem->GetNextValue();
  592. name = pEditItem->GetName();
  593. }
  594. m_pLODEdit->GetText( szEditText, MAX_PATH );
  595. pListItem->SetWString( name, szEditText );
  596. m_pLODPanel->LeaveEditMode();
  597. m_pLODPanel->InvalidateLayout();
  598. return;
  599. }