//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #include "stdafx.h" #include "hammer.h" #include "GameConfig.h" #include "OptionProperties.h" #include "OPTTextures.h" #include "Options.h" #include "tier1/strtools.h" #include // memdbgon must be the last include file in a .cpp file!!! #include ///////////////////////////////////////////////////////////////////////////// // COPTTextures property page IMPLEMENT_DYNCREATE(COPTTextures, CPropertyPage) COPTTextures::COPTTextures() : CPropertyPage(COPTTextures::IDD) { //{{AFX_DATA_INIT(COPTTextures) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT m_pMaterialConfig = NULL; m_bDeleted = FALSE; } COPTTextures::~COPTTextures() { // detach the material exclusion list box m_MaterialExcludeList.Detach(); } void COPTTextures::DoDataExchange(CDataExchange* pDX) { CPropertyPage::DoDataExchange(pDX); //{{AFX_DATA_MAP(COPTTextures) DDX_Control(pDX, IDC_TEXTUREFILES, m_TextureFiles); DDX_Control(pDX, IDC_BRIGHTNESS, m_cBrightness); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(COPTTextures, CPropertyPage) //{{AFX_MSG_MAP(COPTTextures) ON_BN_CLICKED(IDC_EXTRACT, OnExtract) ON_BN_CLICKED(IDC_ADDTEXFILE, OnAddtexfile) ON_BN_CLICKED(IDC_REMOVETEXFILE, OnRemovetexfile) ON_WM_HSCROLL() ON_BN_CLICKED(IDC_ADDTEXFILE2, OnAddtexfile2) ON_BN_CLICKED( ID_MATERIALEXCLUDE_ADD, OnMaterialExcludeAdd ) ON_BN_CLICKED( ID_MATERIALEXCLUDE_REM, OnMaterialExcludeRemove ) ON_LBN_SELCHANGE(ID_MATERIALEXCLUDE_LIST, OnMaterialExcludeListSel) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // COPTTextures message handlers BOOL COPTTextures::OnInitDialog() { CPropertyPage::OnInitDialog(); // load texture file list with options int i; for(i = 0; i < Options.textures.nTextureFiles; i++) { m_TextureFiles.AddString(Options.textures.TextureFiles[i]); } // set brightness control & values m_cBrightness.SetRange(1, 50); // 10 is default m_cBrightness.SetPos(int(Options.textures.fBrightness * 10)); // attach the material exclusion list box m_MaterialExcludeList.Attach( GetDlgItem( ID_MATERIALEXCLUDE_LIST )->m_hWnd ); return TRUE; } void COPTTextures::OnExtract() { // redo listbox content m_TextureFiles.ResetContent(); for(int i = 0; i < Options.textures.nTextureFiles; i++) { m_TextureFiles.AddString(Options.textures.TextureFiles[i]); } } //----------------------------------------------------------------------------- // Purpose: // Input : //----------------------------------------------------------------------------- void COPTTextures::OnAddtexfile(void) { static char szInitialDir[MAX_PATH] = "\0"; CFileDialog dlg(TRUE, "wad", NULL, OFN_ALLOWMULTISELECT | OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_FILEMUSTEXIST, "Texture files (*.wad;*.pak)|*.wad; *.pak||"); if (szInitialDir[0] == '\0') { Q_snprintf( szInitialDir, sizeof( szInitialDir ), "%s\\wads\\", g_pGameConfig->m_szModDir ); } dlg.m_ofn.lpstrInitialDir = szInitialDir; if (dlg.DoModal() != IDOK) { return; } // // Get all the filenames from the open file dialog. // POSITION pos = dlg.GetStartPosition(); CString str; while (pos != NULL) { str = dlg.GetNextPathName(pos); str.MakeLower(); m_TextureFiles.AddString(str); SetModified(); } // // Use this directory as the default directory for the next time. // int nBackslash = str.ReverseFind('\\'); if (nBackslash != -1) { lstrcpyn(szInitialDir, str, nBackslash + 1); } } void COPTTextures::OnRemovetexfile() { int i = m_TextureFiles.GetCount(); for (i--; i >= 0; i--) { if (m_TextureFiles.GetSel(i)) m_TextureFiles.DeleteString(i); } m_bDeleted = TRUE; } void COPTTextures::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { if(pScrollBar == (CScrollBar*) &m_cBrightness) SetModified(); CPropertyPage::OnHScroll(nSBCode, nPos, pScrollBar); } BOOL COPTTextures::OnApply() { Options.textures.fBrightness = (float)m_cBrightness.GetPos() / 10.0f; int iSize = m_TextureFiles.GetCount(); CString str; Options.textures.nTextureFiles = iSize; Options.textures.TextureFiles.RemoveAll(); for(int i = 0; i < iSize; i++) { m_TextureFiles.GetText(i, str); Options.textures.TextureFiles.Add(str); } if(m_bDeleted) { // inform them that deleted files will only be reapplied after // they reload the editor MessageBox("You have removed some texture files from the list. " "These texture files will continue to be used during this " "session, but will not be loaded the next time you run " "Hammer.", "A Quick Note"); } Options.PerformChanges(COptions::secTextures); return CPropertyPage::OnApply(); } void GetDirectory(char *pDest, const char *pLongName) { strcpy(pDest, pLongName); int i = strlen(pDest); while (pLongName[i] != '\\' && pLongName[i] != '/' && i > 0) i--; if (i <= 0) i = 0; pDest[i] = 0; return; } void COPTTextures::OnAddtexfile2() { BROWSEINFO bi; char szDisplayName[MAX_PATH]; bi.hwndOwner = m_hWnd; bi.pidlRoot = NULL; bi.pszDisplayName = szDisplayName; bi.lpszTitle = "Select your Quake II directory."; bi.ulFlags = BIF_RETURNONLYFSDIRS; bi.lpfn = NULL; bi.lParam = 0; LPITEMIDLIST pidlNew = SHBrowseForFolder(&bi); if(pidlNew) { // get path from the id list char szPathName[MAX_PATH]; SHGetPathFromIDList(pidlNew, szPathName); if (AfxMessageBox("Add all subdirectories as separate Texture Groups?", MB_YESNO) == IDYES) //if (!strcmpi("\\textures", &szPathName[strlen(szPathName) - strlen("\\textures")])) { char szNewPath[MAX_PATH]; strcpy(szNewPath, szPathName); strcat(szNewPath, "\\*.*"); WIN32_FIND_DATA FindData; HANDLE hFile = FindFirstFile(szNewPath, &FindData); if (hFile != INVALID_HANDLE_VALUE) do { if ((FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&(FindData.cFileName[0] != '.')) { sprintf(szNewPath, "%s\\%s", szPathName, FindData.cFileName); strlwr(szNewPath); if (m_TextureFiles.FindStringExact(-1, szNewPath) == CB_ERR) m_TextureFiles.AddString(szNewPath); } } while (FindNextFile(hFile, &FindData)); } else { strlwr(szPathName); if (m_TextureFiles.FindStringExact(-1, szPathName) == CB_ERR) m_TextureFiles.AddString(strlwr(szPathName)); } SetModified(); // free the previous return value from SHBrowseForFolder CoTaskMemFree(pidlNew); } } static char s_szStartFolder[MAX_PATH]; static int CALLBACK BrowseCallbackProc( HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData ) { switch ( uMsg ) { case BFFM_INITIALIZED: { if ( lpData ) { SendMessage( hwnd, BFFM_SETSELECTION, TRUE, ( LPARAM ) s_szStartFolder ); } break; } default: { break; } } return 0; } //----------------------------------------------------------------------------- // Purpose: // Input : *pszTitle - // *pszDirectory - // Output : Returns TRUE on success, FALSE on failure. //----------------------------------------------------------------------------- BOOL COPTTextures::BrowseForFolder( char *pszTitle, char *pszDirectory ) { USES_CONVERSION; static bool s_bFirst = true; if ( s_bFirst ) { APP()->GetDirectory( DIR_MATERIALS, s_szStartFolder ); s_bFirst = false; } LPITEMIDLIST pidlStartFolder = NULL; IShellFolder *pshDesktop = NULL; SHGetDesktopFolder( &pshDesktop ); if ( pshDesktop ) { ULONG ulEaten; ULONG ulAttributes; pshDesktop->ParseDisplayName( NULL, NULL, A2OLE( s_szStartFolder ), &ulEaten, &pidlStartFolder, &ulAttributes ); } char szTmp[MAX_PATH]; BROWSEINFO bi; memset( &bi, 0, sizeof( bi ) ); bi.hwndOwner = m_hWnd; bi.pszDisplayName = szTmp; bi.lpszTitle = pszTitle; bi.ulFlags = BIF_RETURNONLYFSDIRS /*| BIF_NEWDIALOGSTYLE*/; bi.lpfn = BrowseCallbackProc; bi.lParam = TRUE; LPITEMIDLIST idl = SHBrowseForFolder( &bi ); if ( idl == NULL ) { return FALSE; } SHGetPathFromIDList( idl, pszDirectory ); // Start in this folder next time. Q_strncpy( s_szStartFolder, pszDirectory, sizeof( s_szStartFolder ) ); CoTaskMemFree( pidlStartFolder ); CoTaskMemFree( idl ); return TRUE; } //----------------------------------------------------------------------------- // Purpose: intercept this call and update the "material" configuration pointer // if it is out of sync with the game configuration "parent" (on the // "Options Configs" page) // Output: returns TRUE on success, FALSE on failure //----------------------------------------------------------------------------- BOOL COPTTextures::OnSetActive( void ) { // // get the current game configuration from the "Options Configs" page // COptionProperties *pOptProps = ( COptionProperties* )GetParent(); if( !pOptProps ) return FALSE; CGameConfig *pConfig = pOptProps->Configs.GetCurrentConfig(); if( !pConfig ) return FALSE; // compare for a change if( m_pMaterialConfig != pConfig ) { // update the material config m_pMaterialConfig = pConfig; // update the all config specific material data on this page MaterialExcludeUpdate(); // update the last material config m_pMaterialConfig = pConfig; } return CPropertyPage::OnSetActive(); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void COPTTextures::MaterialExcludeUpdate( void ) { // remove all of the data in the current "material exclude" list box m_MaterialExcludeList.ResetContent(); // // add the data from the current material config // for( int i = 0; i < m_pMaterialConfig->m_MaterialExcludeCount; i++ ) { int result = m_MaterialExcludeList.AddString( m_pMaterialConfig->m_MaterialExclusions[i].szDirectory ); m_MaterialExcludeList.SetItemData( result, 1 ); if( ( result == LB_ERR ) || ( result == LB_ERRSPACE ) ) return; } if (pGD != NULL) { for( int i = 0; i < pGD->m_FGDMaterialExclusions.Count(); i++ ) { char szFolder[MAX_PATH]; strcpy( szFolder, pGD->m_FGDMaterialExclusions[i].szDirectory ); strcat( szFolder, " (default)" ); int result = m_MaterialExcludeList.AddString( szFolder ); m_MaterialExcludeList.SetItemData( result, 0 ); if( ( result == LB_ERR ) || ( result == LB_ERRSPACE ) ) return; } } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void StripOffMaterialDirectory( const char *pszDirectoryName, char *pszName ) { // clear name pszName[0] = '\0'; // create a lower case version of the string char *pLowerCase = _strlwr( _strdup( pszDirectoryName ) ); char *pAtMat = strstr( pLowerCase, "materials" ); if( !pAtMat ) return; // move the pointer ahead 10 spaces = "materials\" pAtMat += 10; // copy the rest to the name string strcpy( pszName, pAtMat ); // free duplicated string's memory free( pLowerCase ); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void COPTTextures::OnMaterialExcludeAdd( void ) { // // get the directory path to exclude // char szTmp[MAX_PATH]; if( !BrowseForFolder( "Select Game Executable Directory", szTmp ) ) return; // strip off the material directory char szSubDirName[MAX_PATH]; StripOffMaterialDirectory( szTmp, &szSubDirName[0] ); if( szSubDirName[0] == '\0' ) return; // // add directory to list box // int result = m_MaterialExcludeList.AddString( szSubDirName ); m_MaterialExcludeList.SetItemData( result, 1 ); if( ( result == LB_ERR ) || ( result == LB_ERRSPACE ) ) return; // // add name of directory to the global exclusion list // int ndx = m_pMaterialConfig->m_MaterialExcludeCount; if( ndx >= MAX_DIRECTORY_SIZE ) return; m_pMaterialConfig->m_MaterialExcludeCount++; int index = m_pMaterialConfig->m_MaterialExclusions.AddToTail(); Q_strncpy( m_pMaterialConfig->m_MaterialExclusions[index].szDirectory, szSubDirName, sizeof ( m_pMaterialConfig->m_MaterialExclusions[index].szDirectory ) ); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void COPTTextures::OnMaterialExcludeRemove( void ) { // // get the directory to remove // int ndxSel = m_MaterialExcludeList.GetCurSel(); if( ndxSel == LB_ERR ) return; char szTmp[MAX_PATH]; m_MaterialExcludeList.GetText( ndxSel, &szTmp[0] ); // // remove directory from the list box // int result = m_MaterialExcludeList.DeleteString( ndxSel ); if( result == LB_ERR ) return; // // remove the name of the directory from the global exclusion list // for( int i = 0; i < m_pMaterialConfig->m_MaterialExcludeCount; i++ ) { if( !strcmp( szTmp, m_pMaterialConfig->m_MaterialExclusions[i].szDirectory ) ) { // remove the directory if( i != ( m_pMaterialConfig->m_MaterialExcludeCount - 1 ) ) { m_pMaterialConfig->m_MaterialExclusions.Remove( i ); } // decrement count m_pMaterialConfig->m_MaterialExcludeCount--; } } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void COPTTextures::OnMaterialExcludeListSel( void ) { int ndxSel = m_MaterialExcludeList.GetCurSel(); if( ndxSel == LB_ERR ) return; char szTmp[MAX_PATH]; m_MaterialExcludeList.GetText( ndxSel, &szTmp[0] ); // Item data of 0 = FGD exclusion, 1 = user-created exclusion DWORD dwData = m_MaterialExcludeList.GetItemData( ndxSel ); GetDlgItem( ID_MATERIALEXCLUDE_REM )->EnableWindow( dwData ? TRUE : FALSE ); }