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.

541 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "stdafx.h"
  7. #include "hammer.h"
  8. #include "GameConfig.h"
  9. #include "OptionProperties.h"
  10. #include "OPTTextures.h"
  11. #include "Options.h"
  12. #include "tier1/strtools.h"
  13. #include <shlobj.h>
  14. // memdbgon must be the last include file in a .cpp file!!!
  15. #include <tier0/memdbgon.h>
  16. /////////////////////////////////////////////////////////////////////////////
  17. // COPTTextures property page
  18. IMPLEMENT_DYNCREATE(COPTTextures, CPropertyPage)
  19. COPTTextures::COPTTextures() : CPropertyPage(COPTTextures::IDD)
  20. {
  21. //{{AFX_DATA_INIT(COPTTextures)
  22. // NOTE: the ClassWizard will add member initialization here
  23. //}}AFX_DATA_INIT
  24. m_pMaterialConfig = NULL;
  25. m_bDeleted = FALSE;
  26. }
  27. COPTTextures::~COPTTextures()
  28. {
  29. // detach the material exclusion list box
  30. m_MaterialExcludeList.Detach();
  31. }
  32. void COPTTextures::DoDataExchange(CDataExchange* pDX)
  33. {
  34. CPropertyPage::DoDataExchange(pDX);
  35. //{{AFX_DATA_MAP(COPTTextures)
  36. DDX_Control(pDX, IDC_TEXTUREFILES, m_TextureFiles);
  37. DDX_Control(pDX, IDC_BRIGHTNESS, m_cBrightness);
  38. //}}AFX_DATA_MAP
  39. }
  40. BEGIN_MESSAGE_MAP(COPTTextures, CPropertyPage)
  41. //{{AFX_MSG_MAP(COPTTextures)
  42. ON_BN_CLICKED(IDC_EXTRACT, OnExtract)
  43. ON_BN_CLICKED(IDC_ADDTEXFILE, OnAddtexfile)
  44. ON_BN_CLICKED(IDC_REMOVETEXFILE, OnRemovetexfile)
  45. ON_WM_HSCROLL()
  46. ON_BN_CLICKED(IDC_ADDTEXFILE2, OnAddtexfile2)
  47. ON_BN_CLICKED( ID_MATERIALEXCLUDE_ADD, OnMaterialExcludeAdd )
  48. ON_BN_CLICKED( ID_MATERIALEXCLUDE_REM, OnMaterialExcludeRemove )
  49. ON_LBN_SELCHANGE(ID_MATERIALEXCLUDE_LIST, OnMaterialExcludeListSel)
  50. //}}AFX_MSG_MAP
  51. END_MESSAGE_MAP()
  52. /////////////////////////////////////////////////////////////////////////////
  53. // COPTTextures message handlers
  54. BOOL COPTTextures::OnInitDialog()
  55. {
  56. CPropertyPage::OnInitDialog();
  57. // load texture file list with options
  58. int i;
  59. for(i = 0; i < Options.textures.nTextureFiles; i++)
  60. {
  61. m_TextureFiles.AddString(Options.textures.TextureFiles[i]);
  62. }
  63. // set brightness control & values
  64. m_cBrightness.SetRange(1, 50); // 10 is default
  65. m_cBrightness.SetPos(int(Options.textures.fBrightness * 10));
  66. // attach the material exclusion list box
  67. m_MaterialExcludeList.Attach( GetDlgItem( ID_MATERIALEXCLUDE_LIST )->m_hWnd );
  68. return TRUE;
  69. }
  70. void COPTTextures::OnExtract()
  71. {
  72. // redo listbox content
  73. m_TextureFiles.ResetContent();
  74. for(int i = 0; i < Options.textures.nTextureFiles; i++)
  75. {
  76. m_TextureFiles.AddString(Options.textures.TextureFiles[i]);
  77. }
  78. }
  79. //-----------------------------------------------------------------------------
  80. // Purpose:
  81. // Input :
  82. //-----------------------------------------------------------------------------
  83. void COPTTextures::OnAddtexfile(void)
  84. {
  85. static char szInitialDir[MAX_PATH] = "\0";
  86. CFileDialog dlg(TRUE, "wad", NULL, OFN_ALLOWMULTISELECT | OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_FILEMUSTEXIST, "Texture files (*.wad;*.pak)|*.wad; *.pak||");
  87. if (szInitialDir[0] == '\0')
  88. {
  89. Q_snprintf( szInitialDir, sizeof( szInitialDir ), "%s\\wads\\", g_pGameConfig->m_szModDir );
  90. }
  91. dlg.m_ofn.lpstrInitialDir = szInitialDir;
  92. if (dlg.DoModal() != IDOK)
  93. {
  94. return;
  95. }
  96. //
  97. // Get all the filenames from the open file dialog.
  98. //
  99. POSITION pos = dlg.GetStartPosition();
  100. CString str;
  101. while (pos != NULL)
  102. {
  103. str = dlg.GetNextPathName(pos);
  104. str.MakeLower();
  105. m_TextureFiles.AddString(str);
  106. SetModified();
  107. }
  108. //
  109. // Use this directory as the default directory for the next time.
  110. //
  111. int nBackslash = str.ReverseFind('\\');
  112. if (nBackslash != -1)
  113. {
  114. lstrcpyn(szInitialDir, str, nBackslash + 1);
  115. }
  116. }
  117. void COPTTextures::OnRemovetexfile()
  118. {
  119. int i = m_TextureFiles.GetCount();
  120. for (i--; i >= 0; i--)
  121. {
  122. if (m_TextureFiles.GetSel(i))
  123. m_TextureFiles.DeleteString(i);
  124. }
  125. m_bDeleted = TRUE;
  126. }
  127. void COPTTextures::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
  128. {
  129. if(pScrollBar == (CScrollBar*) &m_cBrightness)
  130. SetModified();
  131. CPropertyPage::OnHScroll(nSBCode, nPos, pScrollBar);
  132. }
  133. BOOL COPTTextures::OnApply()
  134. {
  135. Options.textures.fBrightness = (float)m_cBrightness.GetPos() / 10.0f;
  136. int iSize = m_TextureFiles.GetCount();
  137. CString str;
  138. Options.textures.nTextureFiles = iSize;
  139. Options.textures.TextureFiles.RemoveAll();
  140. for(int i = 0; i < iSize; i++)
  141. {
  142. m_TextureFiles.GetText(i, str);
  143. Options.textures.TextureFiles.Add(str);
  144. }
  145. if(m_bDeleted)
  146. {
  147. // inform them that deleted files will only be reapplied after
  148. // they reload the editor
  149. MessageBox("You have removed some texture files from the list. "
  150. "These texture files will continue to be used during this "
  151. "session, but will not be loaded the next time you run "
  152. "Hammer.", "A Quick Note");
  153. }
  154. Options.PerformChanges(COptions::secTextures);
  155. return CPropertyPage::OnApply();
  156. }
  157. void GetDirectory(char *pDest, const char *pLongName)
  158. {
  159. strcpy(pDest, pLongName);
  160. int i = strlen(pDest);
  161. while (pLongName[i] != '\\' && pLongName[i] != '/' && i > 0)
  162. i--;
  163. if (i <= 0)
  164. i = 0;
  165. pDest[i] = 0;
  166. return;
  167. }
  168. void COPTTextures::OnAddtexfile2()
  169. {
  170. BROWSEINFO bi;
  171. char szDisplayName[MAX_PATH];
  172. bi.hwndOwner = m_hWnd;
  173. bi.pidlRoot = NULL;
  174. bi.pszDisplayName = szDisplayName;
  175. bi.lpszTitle = "Select your Quake II directory.";
  176. bi.ulFlags = BIF_RETURNONLYFSDIRS;
  177. bi.lpfn = NULL;
  178. bi.lParam = 0;
  179. LPITEMIDLIST pidlNew = SHBrowseForFolder(&bi);
  180. if(pidlNew)
  181. {
  182. // get path from the id list
  183. char szPathName[MAX_PATH];
  184. SHGetPathFromIDList(pidlNew, szPathName);
  185. if (AfxMessageBox("Add all subdirectories as separate Texture Groups?", MB_YESNO) == IDYES)
  186. //if (!strcmpi("\\textures", &szPathName[strlen(szPathName) - strlen("\\textures")]))
  187. {
  188. char szNewPath[MAX_PATH];
  189. strcpy(szNewPath, szPathName);
  190. strcat(szNewPath, "\\*.*");
  191. WIN32_FIND_DATA FindData;
  192. HANDLE hFile = FindFirstFile(szNewPath, &FindData);
  193. if (hFile != INVALID_HANDLE_VALUE) do
  194. {
  195. if ((FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  196. &&(FindData.cFileName[0] != '.'))
  197. {
  198. sprintf(szNewPath, "%s\\%s", szPathName, FindData.cFileName);
  199. strlwr(szNewPath);
  200. if (m_TextureFiles.FindStringExact(-1, szNewPath) == CB_ERR)
  201. m_TextureFiles.AddString(szNewPath);
  202. }
  203. } while (FindNextFile(hFile, &FindData));
  204. }
  205. else
  206. {
  207. strlwr(szPathName);
  208. if (m_TextureFiles.FindStringExact(-1, szPathName) == CB_ERR)
  209. m_TextureFiles.AddString(strlwr(szPathName));
  210. }
  211. SetModified();
  212. // free the previous return value from SHBrowseForFolder
  213. CoTaskMemFree(pidlNew);
  214. }
  215. }
  216. static char s_szStartFolder[MAX_PATH];
  217. static int CALLBACK BrowseCallbackProc( HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData )
  218. {
  219. switch ( uMsg )
  220. {
  221. case BFFM_INITIALIZED:
  222. {
  223. if ( lpData )
  224. {
  225. SendMessage( hwnd, BFFM_SETSELECTION, TRUE, ( LPARAM ) s_szStartFolder );
  226. }
  227. break;
  228. }
  229. default:
  230. {
  231. break;
  232. }
  233. }
  234. return 0;
  235. }
  236. //-----------------------------------------------------------------------------
  237. // Purpose:
  238. // Input : *pszTitle -
  239. // *pszDirectory -
  240. // Output : Returns TRUE on success, FALSE on failure.
  241. //-----------------------------------------------------------------------------
  242. BOOL COPTTextures::BrowseForFolder( char *pszTitle, char *pszDirectory )
  243. {
  244. USES_CONVERSION;
  245. static bool s_bFirst = true;
  246. if ( s_bFirst )
  247. {
  248. APP()->GetDirectory( DIR_MATERIALS, s_szStartFolder );
  249. s_bFirst = false;
  250. }
  251. LPITEMIDLIST pidlStartFolder = NULL;
  252. IShellFolder *pshDesktop = NULL;
  253. SHGetDesktopFolder( &pshDesktop );
  254. if ( pshDesktop )
  255. {
  256. ULONG ulEaten;
  257. ULONG ulAttributes;
  258. pshDesktop->ParseDisplayName( NULL, NULL, A2OLE( s_szStartFolder ), &ulEaten, &pidlStartFolder, &ulAttributes );
  259. }
  260. char szTmp[MAX_PATH];
  261. BROWSEINFO bi;
  262. memset( &bi, 0, sizeof( bi ) );
  263. bi.hwndOwner = m_hWnd;
  264. bi.pszDisplayName = szTmp;
  265. bi.lpszTitle = pszTitle;
  266. bi.ulFlags = BIF_RETURNONLYFSDIRS /*| BIF_NEWDIALOGSTYLE*/;
  267. bi.lpfn = BrowseCallbackProc;
  268. bi.lParam = TRUE;
  269. LPITEMIDLIST idl = SHBrowseForFolder( &bi );
  270. if ( idl == NULL )
  271. {
  272. return FALSE;
  273. }
  274. SHGetPathFromIDList( idl, pszDirectory );
  275. // Start in this folder next time.
  276. Q_strncpy( s_szStartFolder, pszDirectory, sizeof( s_szStartFolder ) );
  277. CoTaskMemFree( pidlStartFolder );
  278. CoTaskMemFree( idl );
  279. return TRUE;
  280. }
  281. //-----------------------------------------------------------------------------
  282. // Purpose: intercept this call and update the "material" configuration pointer
  283. // if it is out of sync with the game configuration "parent" (on the
  284. // "Options Configs" page)
  285. // Output: returns TRUE on success, FALSE on failure
  286. //-----------------------------------------------------------------------------
  287. BOOL COPTTextures::OnSetActive( void )
  288. {
  289. //
  290. // get the current game configuration from the "Options Configs" page
  291. //
  292. COptionProperties *pOptProps = ( COptionProperties* )GetParent();
  293. if( !pOptProps )
  294. return FALSE;
  295. CGameConfig *pConfig = pOptProps->Configs.GetCurrentConfig();
  296. if( !pConfig )
  297. return FALSE;
  298. // compare for a change
  299. if( m_pMaterialConfig != pConfig )
  300. {
  301. // update the material config
  302. m_pMaterialConfig = pConfig;
  303. // update the all config specific material data on this page
  304. MaterialExcludeUpdate();
  305. // update the last material config
  306. m_pMaterialConfig = pConfig;
  307. }
  308. return CPropertyPage::OnSetActive();
  309. }
  310. //-----------------------------------------------------------------------------
  311. //-----------------------------------------------------------------------------
  312. void COPTTextures::MaterialExcludeUpdate( void )
  313. {
  314. // remove all of the data in the current "material exclude" list box
  315. m_MaterialExcludeList.ResetContent();
  316. //
  317. // add the data from the current material config
  318. //
  319. for( int i = 0; i < m_pMaterialConfig->m_MaterialExcludeCount; i++ )
  320. {
  321. int result = m_MaterialExcludeList.AddString( m_pMaterialConfig->m_MaterialExclusions[i].szDirectory );
  322. m_MaterialExcludeList.SetItemData( result, 1 );
  323. if( ( result == LB_ERR ) || ( result == LB_ERRSPACE ) )
  324. return;
  325. }
  326. if (pGD != NULL)
  327. {
  328. for( int i = 0; i < pGD->m_FGDMaterialExclusions.Count(); i++ )
  329. {
  330. char szFolder[MAX_PATH];
  331. strcpy( szFolder, pGD->m_FGDMaterialExclusions[i].szDirectory );
  332. strcat( szFolder, " (default)" );
  333. int result = m_MaterialExcludeList.AddString( szFolder );
  334. m_MaterialExcludeList.SetItemData( result, 0 );
  335. if( ( result == LB_ERR ) || ( result == LB_ERRSPACE ) )
  336. return;
  337. }
  338. }
  339. }
  340. //-----------------------------------------------------------------------------
  341. //-----------------------------------------------------------------------------
  342. void StripOffMaterialDirectory( const char *pszDirectoryName, char *pszName )
  343. {
  344. // clear name
  345. pszName[0] = '\0';
  346. // create a lower case version of the string
  347. char *pLowerCase = _strlwr( _strdup( pszDirectoryName ) );
  348. char *pAtMat = strstr( pLowerCase, "materials" );
  349. if( !pAtMat )
  350. return;
  351. // move the pointer ahead 10 spaces = "materials\"
  352. pAtMat += 10;
  353. // copy the rest to the name string
  354. strcpy( pszName, pAtMat );
  355. // free duplicated string's memory
  356. free( pLowerCase );
  357. }
  358. //-----------------------------------------------------------------------------
  359. //-----------------------------------------------------------------------------
  360. void COPTTextures::OnMaterialExcludeAdd( void )
  361. {
  362. //
  363. // get the directory path to exclude
  364. //
  365. char szTmp[MAX_PATH];
  366. if( !BrowseForFolder( "Select Game Executable Directory", szTmp ) )
  367. return;
  368. // strip off the material directory
  369. char szSubDirName[MAX_PATH];
  370. StripOffMaterialDirectory( szTmp, &szSubDirName[0] );
  371. if( szSubDirName[0] == '\0' )
  372. return;
  373. //
  374. // add directory to list box
  375. //
  376. int result = m_MaterialExcludeList.AddString( szSubDirName );
  377. m_MaterialExcludeList.SetItemData( result, 1 );
  378. if( ( result == LB_ERR ) || ( result == LB_ERRSPACE ) )
  379. return;
  380. //
  381. // add name of directory to the global exclusion list
  382. //
  383. int ndx = m_pMaterialConfig->m_MaterialExcludeCount;
  384. if( ndx >= MAX_DIRECTORY_SIZE )
  385. return;
  386. m_pMaterialConfig->m_MaterialExcludeCount++;
  387. int index = m_pMaterialConfig->m_MaterialExclusions.AddToTail();
  388. Q_strncpy( m_pMaterialConfig->m_MaterialExclusions[index].szDirectory, szSubDirName, sizeof ( m_pMaterialConfig->m_MaterialExclusions[index].szDirectory ) );
  389. }
  390. //-----------------------------------------------------------------------------
  391. //-----------------------------------------------------------------------------
  392. void COPTTextures::OnMaterialExcludeRemove( void )
  393. {
  394. //
  395. // get the directory to remove
  396. //
  397. int ndxSel = m_MaterialExcludeList.GetCurSel();
  398. if( ndxSel == LB_ERR )
  399. return;
  400. char szTmp[MAX_PATH];
  401. m_MaterialExcludeList.GetText( ndxSel, &szTmp[0] );
  402. //
  403. // remove directory from the list box
  404. //
  405. int result = m_MaterialExcludeList.DeleteString( ndxSel );
  406. if( result == LB_ERR )
  407. return;
  408. //
  409. // remove the name of the directory from the global exclusion list
  410. //
  411. for( int i = 0; i < m_pMaterialConfig->m_MaterialExcludeCount; i++ )
  412. {
  413. if( !strcmp( szTmp, m_pMaterialConfig->m_MaterialExclusions[i].szDirectory ) )
  414. {
  415. // remove the directory
  416. if( i != ( m_pMaterialConfig->m_MaterialExcludeCount - 1 ) )
  417. {
  418. m_pMaterialConfig->m_MaterialExclusions.Remove( i );
  419. }
  420. // decrement count
  421. m_pMaterialConfig->m_MaterialExcludeCount--;
  422. }
  423. }
  424. }
  425. //-----------------------------------------------------------------------------
  426. //-----------------------------------------------------------------------------
  427. void COPTTextures::OnMaterialExcludeListSel( void )
  428. {
  429. int ndxSel = m_MaterialExcludeList.GetCurSel();
  430. if( ndxSel == LB_ERR )
  431. return;
  432. char szTmp[MAX_PATH];
  433. m_MaterialExcludeList.GetText( ndxSel, &szTmp[0] );
  434. // Item data of 0 = FGD exclusion, 1 = user-created exclusion
  435. DWORD dwData = m_MaterialExcludeList.GetItemData( ndxSel );
  436. GetDlgItem( ID_MATERIALEXCLUDE_REM )->EnableWindow( dwData ? TRUE : FALSE );
  437. }