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.

1341 lines
35 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Texture management functions. Exposes a list of available textures,
  4. // texture groups, and Most Recently Used textures.
  5. //
  6. // There is one texture context per game configuration in GameCfg.ini.
  7. //
  8. //=============================================================================//
  9. #include "stdafx.h"
  10. #include <process.h>
  11. #include <io.h>
  12. #include <sys\stat.h>
  13. #include <fcntl.h>
  14. #include "DummyTexture.h" // Specific IEditorTexture implementation
  15. #include "GlobalFunctions.h"
  16. #include "MainFrm.h"
  17. #include "MapDoc.h"
  18. #include "Material.h" // Specific IEditorTexture implementation
  19. #include "Options.h"
  20. #include "TextureSystem.h"
  21. #include "WADTexture.h" // Specific IEditorTexture implementation
  22. #include "WADTypes.h"
  23. #include "hammer.h"
  24. #include "filesystem.h"
  25. #include "materialsystem/ITexture.h"
  26. #include "tier1/utldict.h"
  27. #include "FaceEditSheet.h"
  28. // memdbgon must be the last include file in a .cpp file!!!
  29. #include <tier0/memdbgon.h>
  30. #pragma warning(disable:4244)
  31. #define _GraphicCacheAllocate(n) malloc(n)
  32. #define IsSortChr(ch) ((ch == '-') || (ch == '+'))
  33. //-----------------------------------------------------------------------------
  34. // Stuff for loading WAD3 files.
  35. //-----------------------------------------------------------------------------
  36. typedef struct
  37. {
  38. int filepos;
  39. int disksize;
  40. int size; // uncompressed
  41. char type;
  42. char compression;
  43. char pad1, pad2;
  44. char name[16]; // must be null terminated
  45. } WAD3lumpinfo_t;
  46. //-----------------------------------------------------------------------------
  47. // List of global graphics
  48. //-----------------------------------------------------------------------------
  49. CTextureSystem g_Textures;
  50. //-----------------------------------------------------------------------------
  51. // CMaterialFileChangeWatcher implementation.
  52. //-----------------------------------------------------------------------------
  53. void CMaterialFileChangeWatcher::Init( CTextureSystem *pSystem, int context )
  54. {
  55. m_pTextureSystem = pSystem;
  56. m_Context = context;
  57. m_Watcher.Init( this );
  58. char searchPaths[1024 * 16];
  59. if ( g_pFullFileSystem->GetSearchPath( "GAME", false, searchPaths, sizeof( searchPaths ) ) > 0 )
  60. {
  61. CSplitString searchPathList( searchPaths, ";" );
  62. for ( int i=0; i < searchPathList.Count(); i++ )
  63. {
  64. m_Watcher.AddDirectory( searchPathList[i], "materials", true );
  65. }
  66. }
  67. else
  68. {
  69. Warning( "Error in GetSearchPath. Dynamic material list updating will not be available." );
  70. }
  71. }
  72. void CMaterialFileChangeWatcher::OnFileChange( const char *pRelativeFilename, const char *pFullFilename )
  73. {
  74. //Msg( "OnNewFile: %s\n", pRelativeFilename );
  75. CTextureSystem::EFileType eFileType;
  76. if ( CTextureSystem::GetFileTypeFromFilename( pRelativeFilename, &eFileType ) )
  77. m_pTextureSystem->OnFileChange( pRelativeFilename, m_Context, eFileType );
  78. }
  79. void CMaterialFileChangeWatcher::Update()
  80. {
  81. m_Watcher.Update();
  82. }
  83. //-----------------------------------------------------------------------------
  84. // Purpose: Constructor. Creates the "All" group and sets it as the active group.
  85. //-----------------------------------------------------------------------------
  86. CTextureSystem::CTextureSystem(void)
  87. {
  88. m_pLastTex = NULL;
  89. m_nLastIndex = 0;
  90. m_pActiveContext = NULL;
  91. m_pActiveGroup = NULL;
  92. m_pCubemapTexture = NULL;
  93. m_pNoDrawTexture = NULL;
  94. }
  95. //-----------------------------------------------------------------------------
  96. // Purpose: Destructor. Frees the list of groups and dummy textures.
  97. //-----------------------------------------------------------------------------
  98. CTextureSystem::~CTextureSystem(void)
  99. {
  100. }
  101. //-----------------------------------------------------------------------------
  102. // Purpose:
  103. //-----------------------------------------------------------------------------
  104. void CTextureSystem::FreeAllTextures()
  105. {
  106. if ( m_pCubemapTexture )
  107. {
  108. m_pCubemapTexture->DecrementReferenceCount();
  109. m_pCubemapTexture = NULL;
  110. }
  111. int nContextCount = m_TextureContexts.Count();
  112. for (int nContext = 0; nContext < nContextCount; nContext++)
  113. {
  114. TextureContext_t *pContext = &m_TextureContexts.Element(nContext);
  115. //
  116. // Delete all the texture groups for this context.
  117. //
  118. int nGroupCount = pContext->Groups.Count();
  119. for (int nGroup = 0; nGroup < nGroupCount; nGroup++)
  120. {
  121. delete pContext->Groups.Element(nGroup);
  122. }
  123. //
  124. // Delete dummy textures.
  125. //
  126. int nDummyCount = pContext->Dummies.Count();
  127. for (int nDummy = 0; nDummy < nDummyCount; nDummy++)
  128. {
  129. IEditorTexture *pTex = pContext->Dummies.Element(nDummy);
  130. delete pTex;
  131. }
  132. }
  133. //
  134. // Delete all the textures from the master list.
  135. //
  136. for (int i = 0; i < m_Textures.Count(); i++)
  137. {
  138. IEditorTexture *pTex = m_Textures[i];
  139. delete pTex;
  140. }
  141. m_Textures.RemoveAll();
  142. m_pLastTex = NULL;
  143. m_nLastIndex = -1;
  144. // Delete the keywords.
  145. m_Keywords.PurgeAndDeleteElements();
  146. m_ChangeWatchers.PurgeAndDeleteElements();
  147. }
  148. //-----------------------------------------------------------------------------
  149. // Purpose: Adds a texture to the master list of textures.
  150. // Input : pTexture - Pointer to texture to add.
  151. // Output : Returns the index of the texture in the master texture list.
  152. //-----------------------------------------------------------------------------
  153. int CTextureSystem::AddTexture(IEditorTexture *pTexture)
  154. {
  155. return m_Textures.AddToTail(pTexture);
  156. }
  157. //-----------------------------------------------------------------------------
  158. // Purpose: Begins iterating the list of texture/material keywords.
  159. //-----------------------------------------------------------------------------
  160. int CTextureSystem::GetNumKeywords(void)
  161. {
  162. return(m_Keywords.Count());
  163. }
  164. //-----------------------------------------------------------------------------
  165. // Purpose: Continues iterating the list of texture/material keywords.
  166. //-----------------------------------------------------------------------------
  167. const char *CTextureSystem::GetKeyword(int pos)
  168. {
  169. return(m_Keywords.Element(pos));
  170. }
  171. //-----------------------------------------------------------------------------
  172. // Purpose:
  173. // Input : *piIndex -
  174. // bUseMRU -
  175. // Output :
  176. //-----------------------------------------------------------------------------
  177. IEditorTexture *CTextureSystem::EnumActiveTextures(int *piIndex, TEXTUREFORMAT eDesiredFormat) const
  178. {
  179. Assert(piIndex != NULL);
  180. if (piIndex != NULL)
  181. {
  182. if (m_pActiveGroup != NULL)
  183. {
  184. IEditorTexture *pTex = NULL;
  185. do
  186. {
  187. pTex = m_pActiveGroup->GetTexture(*piIndex);
  188. if (pTex != NULL)
  189. {
  190. (*piIndex)++;
  191. if ((eDesiredFormat == tfNone) || (pTex->GetTextureFormat() == eDesiredFormat))
  192. {
  193. return(pTex);
  194. }
  195. }
  196. } while (pTex != NULL);
  197. }
  198. }
  199. return(NULL);
  200. }
  201. //-----------------------------------------------------------------------------
  202. // Purpose: Initializes the texture system.
  203. // Output : Returns true on success, false on failure.
  204. //-----------------------------------------------------------------------------
  205. bool CTextureSystem::Initialize(HWND hwnd)
  206. {
  207. bool bWAD = CWADTexture::Initialize();
  208. bool bMaterial = CMaterial::Initialize(hwnd);
  209. return(bWAD && bMaterial);
  210. }
  211. //-----------------------------------------------------------------------------
  212. // Purpose: Shuts down the texture system.
  213. //-----------------------------------------------------------------------------
  214. void CTextureSystem::ShutDown(void)
  215. {
  216. CWADTexture::ShutDown();
  217. CMaterial::ShutDown();
  218. FreeAllTextures();
  219. }
  220. //-----------------------------------------------------------------------------
  221. // Purpose:
  222. // Input : pszName -
  223. // piIndex -
  224. // bDummy -
  225. // Output :
  226. //-----------------------------------------------------------------------------
  227. IEditorTexture *CTextureSystem::FindActiveTexture(LPCSTR pszInputName, int *piIndex, BOOL bDummy)
  228. {
  229. // The .vmf file format gets confused if there are backslashes in material names,
  230. // so make sure they're all using forward slashes here.
  231. char szName[MAX_PATH];
  232. Q_StrSubst( pszInputName, "\\", "/", szName, sizeof( szName ) );
  233. const char *pszName = szName;
  234. IEditorTexture *pTex = NULL;
  235. //
  236. // Check the cache first.
  237. //
  238. if (m_pLastTex && !stricmp(pszName, m_pLastTex->GetName()))
  239. {
  240. if (piIndex)
  241. {
  242. *piIndex = m_nLastIndex;
  243. }
  244. return m_pLastTex;
  245. }
  246. int iIndex = 0;
  247. // We're finding by name, so we don't care what the format is as long as the name matches.
  248. if ( m_pActiveGroup )
  249. {
  250. pTex = m_pActiveGroup->FindTextureByName( pszName, &iIndex, tfNone );
  251. if ( pTex )
  252. {
  253. if ( piIndex )
  254. *piIndex = iIndex;
  255. m_pLastTex = pTex;
  256. m_nLastIndex = iIndex;
  257. return pTex;
  258. }
  259. }
  260. //
  261. // Let's try again, this time with \textures\ decoration
  262. // TODO: remove this?
  263. //
  264. {
  265. iIndex = 0;
  266. char szBuf[512];
  267. sprintf(szBuf, "textures\\%s", pszName);
  268. for (int i = strlen(szBuf) -1; i >= 0; i--)
  269. {
  270. if (szBuf[i] == '/')
  271. szBuf[i] = '\\';
  272. }
  273. strlwr(szBuf);
  274. if ( m_pActiveGroup )
  275. {
  276. pTex = m_pActiveGroup->FindTextureByName( szBuf, &iIndex, tfNone );
  277. if ( pTex )
  278. {
  279. if ( piIndex )
  280. *piIndex = iIndex;
  281. m_pLastTex = pTex;
  282. m_nLastIndex = iIndex;
  283. return pTex;
  284. }
  285. }
  286. }
  287. //
  288. // Caller doesn't want dummies.
  289. //
  290. if (!bDummy)
  291. {
  292. return(NULL);
  293. }
  294. Assert(!piIndex);
  295. //
  296. // Check the list of dummies for a texture with the same name and texture format.
  297. //
  298. if (m_pActiveContext)
  299. {
  300. int nDummyCount = m_pActiveContext->Dummies.Count();
  301. for (int nDummy = 0; nDummy < nDummyCount; nDummy++)
  302. {
  303. IEditorTexture *pTex = m_pActiveContext->Dummies.Element(nDummy);
  304. if (!strcmpi(pszName, pTex->GetName()))
  305. {
  306. m_pLastTex = pTex;
  307. m_nLastIndex = -1;
  308. return(pTex);
  309. }
  310. }
  311. //
  312. // Not found; add a dummy as a placeholder for the missing texture.
  313. //
  314. pTex = AddDummy(pszName, g_pGameConfig->GetTextureFormat());
  315. }
  316. if (pTex != NULL)
  317. {
  318. m_pLastTex = pTex;
  319. m_nLastIndex = -1;
  320. }
  321. return(pTex);
  322. }
  323. //-----------------------------------------------------------------------------
  324. // Purpose:
  325. // Input : *pTex -
  326. //-----------------------------------------------------------------------------
  327. void CTextureSystem::AddMRU(IEditorTexture *pTex)
  328. {
  329. if (!m_pActiveContext)
  330. return;
  331. int nIndex = m_pActiveContext->MRU.Find(pTex);
  332. if (nIndex != -1)
  333. {
  334. m_pActiveContext->MRU.Remove(nIndex);
  335. }
  336. else if (m_pActiveContext->MRU.Count() == 8)
  337. {
  338. m_pActiveContext->MRU.Remove(7);
  339. }
  340. m_pActiveContext->MRU.AddToHead(pTex);
  341. }
  342. //-----------------------------------------------------------------------------
  343. // Purpose: Change palette on all textures.
  344. // Input :
  345. // dvs: need to handle a palette change for Quake support
  346. //-----------------------------------------------------------------------------
  347. void CTextureSystem::InformPaletteChanged()
  348. {
  349. // int nGraphics = GetCount();
  350. //
  351. // for (int i = 0; i < nGraphics; i++)
  352. // {
  353. // IEditorTexture *pTex = &GetAt(i);
  354. // }
  355. }
  356. //-----------------------------------------------------------------------------
  357. // Purpose: Returns the texture context that corresponds to the given game config.
  358. //-----------------------------------------------------------------------------
  359. TextureContext_t *CTextureSystem::FindTextureContextForConfig(CGameConfig *pConfig)
  360. {
  361. for (int i = 0; i < m_TextureContexts.Count(); i++)
  362. {
  363. if (m_TextureContexts.Element(i).pConfig == pConfig)
  364. {
  365. return &m_TextureContexts.Element(i);
  366. }
  367. }
  368. return NULL;
  369. }
  370. //-----------------------------------------------------------------------------
  371. // Purpose:
  372. //-----------------------------------------------------------------------------
  373. void CTextureSystem::SetActiveConfig(CGameConfig *pConfig)
  374. {
  375. TextureContext_t *pContext = FindTextureContextForConfig(pConfig);
  376. if (pContext)
  377. {
  378. m_pActiveContext = pContext;
  379. m_pActiveGroup = m_pActiveContext->pAllGroup;
  380. }
  381. else
  382. {
  383. m_pActiveContext = NULL;
  384. }
  385. }
  386. //-----------------------------------------------------------------------------
  387. // Purpose:
  388. // Input : char *pcszName -
  389. //-----------------------------------------------------------------------------
  390. void CTextureSystem::SetActiveGroup(const char *pcszName)
  391. {
  392. if (!m_pActiveContext)
  393. return;
  394. char szBuf[MAX_PATH];
  395. sprintf(szBuf, "textures\\%s", pcszName);
  396. int iCount = m_pActiveContext->Groups.Count();
  397. for (int i = 0; i < iCount; i++)
  398. {
  399. CTextureGroup *pGroup = m_pActiveContext->Groups.Element(i);
  400. if (!strcmpi(pGroup->GetName(), pcszName))
  401. {
  402. m_pActiveGroup = pGroup;
  403. return;
  404. }
  405. if (strstr(pGroup->GetName(), pcszName))
  406. {
  407. m_pActiveGroup = pGroup;
  408. return;
  409. }
  410. }
  411. TRACE0("No Group Found!");
  412. }
  413. //-----------------------------------------------------------------------------
  414. // Purpose: Loads textures from all texture files.
  415. //-----------------------------------------------------------------------------
  416. void CTextureSystem::LoadAllGraphicsFiles(void)
  417. {
  418. FreeAllTextures();
  419. // For each game config...
  420. // dvs: Disabled for single-config running.
  421. //for (int nConfig = 0; nConfig < Options.configs.GetGameConfigCount(); nConfig++)
  422. {
  423. //CGameConfig *pConfig = Options.configs.GetGameConfig(nConfig);
  424. CGameConfig *pConfig = g_pGameConfig;
  425. // Create a new texture context with the WADs and materials for that config.
  426. TextureContext_t *pContext = AddTextureContext();
  427. // Bind it to this config.
  428. pContext->pConfig = pConfig;
  429. // Create a group to hold all the textures for this context.
  430. pContext->pAllGroup = new CTextureGroup("All Textures");
  431. pContext->Groups.AddToTail(pContext->pAllGroup);
  432. // Set the new context as the active context.
  433. m_pActiveContext = pContext;
  434. // Load the textures for all WAD files set in this config.
  435. // Only do this for configs that use WAD textures.
  436. if (pConfig->GetTextureFormat() == tfWAD3)
  437. {
  438. LoadWADFiles(pConfig);
  439. }
  440. // Load the materials for this config.
  441. // Do this unconditionally so that we get necessary editor materials.
  442. LoadMaterials(pConfig);
  443. m_pActiveContext->pAllGroup->Sort();
  444. }
  445. }
  446. //-----------------------------------------------------------------------------
  447. // Purpose: Loads all WAD files for the given game config.
  448. //-----------------------------------------------------------------------------
  449. void CTextureSystem::LoadWADFiles(CGameConfig *pConfig)
  450. {
  451. // dvs: FIXME: WADs are not currently per-config
  452. for (int i = 0; i < Options.textures.nTextureFiles; i++)
  453. {
  454. LoadGraphicsFile(Options.textures.TextureFiles[i]);
  455. }
  456. }
  457. //-----------------------------------------------------------------------------
  458. // Purpose: Loads all the materials for the given game config.
  459. //-----------------------------------------------------------------------------
  460. void CTextureSystem::LoadMaterials(CGameConfig *pConfig)
  461. {
  462. CTextureGroup *pGroup = new CTextureGroup("Materials");
  463. pGroup->SetTextureFormat(tfVMT);
  464. m_pActiveContext->Groups.AddToTail(pGroup);
  465. // Add all the materials to the group.
  466. CMaterial::EnumerateMaterials( this, "materials", (int)pGroup, INCLUDE_WORLD_MATERIALS );
  467. // Watch the materials directory recursively...
  468. CMaterialFileChangeWatcher *pWatcher = new CMaterialFileChangeWatcher;
  469. pWatcher->Init( this, (int)pGroup );
  470. m_ChangeWatchers.AddToTail( pWatcher );
  471. Assert( m_pCubemapTexture == NULL );
  472. m_pCubemapTexture = MaterialSystemInterface()->FindTexture( "editor/cubemap", NULL, true );
  473. if ( m_pCubemapTexture )
  474. {
  475. m_pCubemapTexture->IncrementReferenceCount();
  476. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  477. pRenderContext->BindLocalCubemap( m_pCubemapTexture );
  478. }
  479. // Get the nodraw texture.
  480. m_pNoDrawTexture = NULL;
  481. for ( int i=0; i < m_Textures.Count(); i++ )
  482. {
  483. if ( V_stricmp( m_Textures[i]->GetName(), "tools/toolsnodraw" ) == 0 || V_stricmp( m_Textures[i]->GetName(), "tools/toolsnodraw" ) == 0 )
  484. {
  485. m_pNoDrawTexture = m_Textures[i];
  486. break;
  487. }
  488. }
  489. if ( !m_pNoDrawTexture )
  490. m_pNoDrawTexture = CMaterial::CreateMaterial( "tools/toolsnodraw", true );
  491. }
  492. void CTextureSystem::RebindDefaultCubeMap()
  493. {
  494. // rebind with the default cubemap
  495. if ( m_pCubemapTexture )
  496. {
  497. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  498. pRenderContext->BindLocalCubemap( m_pCubemapTexture );
  499. }
  500. }
  501. void CTextureSystem::UpdateFileChangeWatchers()
  502. {
  503. for ( int i=0; i < m_ChangeWatchers.Count(); i++ )
  504. m_ChangeWatchers[i]->Update();
  505. }
  506. void CTextureSystem::OnFileChange( const char *pFilename, int context, CTextureSystem::EFileType eFileType )
  507. {
  508. // It requires the forward slashes later...
  509. char fixedSlashes[MAX_PATH];
  510. V_StrSubst( pFilename, "\\", "/", fixedSlashes, sizeof( fixedSlashes ) );
  511. // Get rid of the extension.
  512. if ( V_strlen( fixedSlashes ) < 5 )
  513. {
  514. Assert( false );
  515. return;
  516. }
  517. fixedSlashes[ V_strlen( fixedSlashes ) - 4 ] = 0;
  518. // Handle it based on what type of file we've got.
  519. if ( eFileType == k_eFileTypeVMT )
  520. {
  521. IEditorTexture *pTex = FindActiveTexture( fixedSlashes, NULL, FALSE );
  522. if ( pTex )
  523. {
  524. pTex->Reload( true );
  525. }
  526. else
  527. {
  528. EnumMaterial( fixedSlashes, context );
  529. IEditorTexture *pTex = FindActiveTexture( fixedSlashes, NULL, FALSE );
  530. if ( pTex )
  531. {
  532. GetMainWnd()->m_TextureBar.NotifyNewMaterial( pTex );
  533. GetMainWnd()->GetFaceEditSheet()->NotifyNewMaterial( pTex );
  534. }
  535. }
  536. }
  537. else if ( eFileType == k_eFileTypeVTF )
  538. {
  539. // Whether a VTF was added, removed, or modified, we do the same thing.. refresh it and any materials that reference it.
  540. ITexture *pTexture = materials->FindTexture( fixedSlashes, TEXTURE_GROUP_UNACCOUNTED, false );
  541. if ( pTexture )
  542. {
  543. pTexture->Download( NULL );
  544. ReloadMaterialsUsingTexture( pTexture );
  545. }
  546. }
  547. }
  548. //-----------------------------------------------------------------------------
  549. // Purpose: Load any materials that reference this texture. Used so we can refresh a
  550. // material's preview image if a relevant .vtf changes.
  551. //-----------------------------------------------------------------------------
  552. void CTextureSystem::ReloadMaterialsUsingTexture( ITexture *pTestTexture )
  553. {
  554. for ( int i=0; i < m_Textures.Count(); i++ )
  555. {
  556. IEditorTexture *pEditorTex = m_Textures[i];
  557. IMaterial *pMat = pEditorTex->GetMaterial( false );
  558. if ( !pMat )
  559. continue;
  560. IMaterialVar **pParams = pMat->GetShaderParams();
  561. int nParams = pMat->ShaderParamCount();
  562. for ( int iParam=0; iParam < nParams; iParam++ )
  563. {
  564. if ( pParams[iParam]->GetType() != MATERIAL_VAR_TYPE_TEXTURE )
  565. continue;
  566. ITexture *pTex = pParams[iParam]->GetTextureValue();
  567. if ( !pTex )
  568. continue;
  569. if ( pTex == pTestTexture )
  570. {
  571. pEditorTex->Reload( true );
  572. break;
  573. }
  574. }
  575. }
  576. }
  577. //-----------------------------------------------------------------------------
  578. // Purpose: Figure out the file type from its extension. Returns false if we don't have an enum for that extension.
  579. //-----------------------------------------------------------------------------
  580. bool CTextureSystem::GetFileTypeFromFilename( const char *pFilename, CTextureSystem::EFileType *pFileType )
  581. {
  582. char strRight[16];
  583. V_StrRight( pFilename, 4, strRight, sizeof( strRight ) );
  584. if ( V_stricmp( strRight, ".vmt" ) == 0 )
  585. {
  586. *pFileType = CTextureSystem::k_eFileTypeVMT;
  587. return true;
  588. }
  589. else if ( V_stricmp( strRight, ".vtf" ) == 0 )
  590. {
  591. *pFileType = CTextureSystem::k_eFileTypeVTF;
  592. return true;
  593. }
  594. return false;
  595. }
  596. //-----------------------------------------------------------------------------
  597. // Purpose: Loads textures from all texture files.
  598. //-----------------------------------------------------------------------------
  599. void CTextureSystem::ReloadTextures( const char *pFilterName )
  600. {
  601. MaterialSystemInterface()->ReloadMaterials( pFilterName );
  602. for ( int i = 0; i < m_Textures.Count(); i++ )
  603. {
  604. if ( !Q_stristr( pFilterName, m_Textures[i]->GetName() ) )
  605. continue;
  606. m_Textures[i]->Reload( false );
  607. }
  608. }
  609. //-----------------------------------------------------------------------------
  610. // Purpose: Adds a placeholder texture for a texture that exists in the map, but
  611. // was not found on disk.
  612. // Input : pszName - Name of missing texture.
  613. // Output : Returns a pointer to the new dummy texture.
  614. //-----------------------------------------------------------------------------
  615. IEditorTexture *CTextureSystem::AddDummy(LPCTSTR pszName, TEXTUREFORMAT eFormat)
  616. {
  617. if (!m_pActiveContext)
  618. return NULL;
  619. IEditorTexture *pTex = new CDummyTexture(pszName, eFormat);
  620. m_pActiveContext->Dummies.AddToTail(pTex);
  621. return(pTex);
  622. }
  623. //-----------------------------------------------------------------------------
  624. // Purpose:
  625. // Input : elem1 -
  626. // elem2 -
  627. // Output : static int __cdecl
  628. //-----------------------------------------------------------------------------
  629. static int __cdecl SortTexturesProc(IEditorTexture * const *elem1, IEditorTexture * const *elem2)
  630. {
  631. IEditorTexture *pElem1 = *((IEditorTexture **)elem1);
  632. IEditorTexture *pElem2 = *((IEditorTexture **)elem2);
  633. Assert((pElem1 != NULL) && (pElem2 != NULL));
  634. if ((pElem1 == NULL) || (pElem2 == NULL))
  635. {
  636. return(0);
  637. }
  638. const char *pszName1 = pElem1->GetName();
  639. const char *pszName2 = pElem2->GetName();
  640. char ch1 = pszName1[0];
  641. char ch2 = pszName2[0];
  642. if (IsSortChr(ch1) && !IsSortChr(ch2))
  643. {
  644. int iFamilyLen = strlen(pszName1+2);
  645. int iFamily = strnicmp(pszName1+2, pszName2, iFamilyLen);
  646. if (!iFamily)
  647. {
  648. return(-1); // same family - put elem1 before elem2
  649. }
  650. return(iFamily); // sort normally
  651. }
  652. else if (!IsSortChr(ch1) && IsSortChr(ch2))
  653. {
  654. int iFamilyLen = strlen(pszName2+2);
  655. int iFamily = strnicmp(pszName1, pszName2+2, iFamilyLen);
  656. if (!iFamily)
  657. {
  658. return(1); // same family - put elem2 before elem1
  659. }
  660. return(iFamily); // sort normally
  661. }
  662. else if (IsSortChr(ch1) && IsSortChr(ch2))
  663. {
  664. // do family name sorting
  665. int iFamily = strcmpi(pszName1+2, pszName2+2);
  666. if (!iFamily)
  667. {
  668. // same family - sort by number
  669. return pszName1[1] - pszName2[1];
  670. }
  671. // different family
  672. return(iFamily);
  673. }
  674. return(strcmpi(pszName1, pszName2));
  675. }
  676. //-----------------------------------------------------------------------------
  677. // Purpose:
  678. // Input : sizeSrc -
  679. // sizeDest -
  680. // *src -
  681. // *dest -
  682. //-----------------------------------------------------------------------------
  683. void ScaleBitmap(CSize sizeSrc, CSize sizeDest, char *src, char *dest)
  684. {
  685. int i;
  686. int e_y = (sizeSrc.cy << 1) - sizeDest.cy;
  687. int sizeDest2_y = (sizeDest.cy << 1);
  688. int sizeSrc2_y = sizeSrc.cy << 1;
  689. int srcline = 0, destline = 0;
  690. char *srclinep, *destlinep;
  691. int e_x = (sizeSrc.cx << 1) - sizeDest.cx;
  692. int sizeDest2_x = (sizeDest.cx << 1);
  693. int sizeSrc2_x = sizeSrc.cx << 1;
  694. for( i = 0; i < sizeDest.cy; i++ )
  695. {
  696. // scale by X
  697. {
  698. srclinep = src + (srcline * sizeSrc.cx);
  699. destlinep = dest + (destline * sizeDest.cx);
  700. int i;
  701. for( i = 0; i < sizeDest.cx; i++ )
  702. {
  703. *destlinep = *srclinep;
  704. while( e_x >= 0 )
  705. {
  706. ++srclinep;
  707. e_x -= sizeDest2_x;
  708. }
  709. ++destlinep;
  710. e_x += sizeSrc2_x;
  711. }
  712. }
  713. while( e_y >= 0 )
  714. {
  715. ++srcline;
  716. e_y -= sizeDest2_y;
  717. }
  718. ++destline;
  719. e_y += sizeSrc2_y;
  720. }
  721. }
  722. //-----------------------------------------------------------------------------
  723. // Purpose:
  724. // Input : id -
  725. // *piIndex -
  726. // Output : GRAPHICSFILESTRUCT *
  727. //-----------------------------------------------------------------------------
  728. bool CTextureSystem::FindGraphicsFile(GRAPHICSFILESTRUCT *pFileInfo, DWORD id, int *piIndex)
  729. {
  730. for (int i = 0; i < m_GraphicsFiles.Count(); i++)
  731. {
  732. if (m_GraphicsFiles[i].id == id)
  733. {
  734. if (piIndex)
  735. {
  736. piIndex[0] = i;
  737. }
  738. if (pFileInfo != NULL)
  739. {
  740. *pFileInfo = m_GraphicsFiles[i];
  741. }
  742. return(true);
  743. }
  744. }
  745. return(false);
  746. }
  747. //-----------------------------------------------------------------------------
  748. // Purpose:
  749. // Input : pFile -
  750. // fd -
  751. // pGroup -
  752. //-----------------------------------------------------------------------------
  753. void CTextureSystem::LoadGraphicsFileWAD3(GRAPHICSFILESTRUCT *pFile, int fd, CTextureGroup *pGroup)
  754. {
  755. // read wad header
  756. wadinfo_t hdr;
  757. _lseek(fd, 0, SEEK_SET);
  758. _read(fd, (char*)&hdr, sizeof hdr);
  759. _lseek(fd, hdr.infotableofs, SEEK_SET);
  760. // allocate directory memory.
  761. WAD3lumpinfo_t *dir = new WAD3lumpinfo_t[hdr.numlumps];
  762. // read entries.
  763. _read(fd, dir, sizeof(WAD3lumpinfo_t) * hdr.numlumps);
  764. // load graphics!
  765. for (int i = 0; i < hdr.numlumps; i++)
  766. {
  767. if (dir[i].type == TYP_MIPTEX)
  768. {
  769. _lseek(fd, dir[i].filepos, SEEK_SET);
  770. CWADTexture *pNew = new CWADTexture;
  771. if (pNew != NULL)
  772. {
  773. if (pNew->Init(fd, pFile->id, FALSE, dir[i].name))
  774. {
  775. pNew->SetTextureFormat(pFile->format);
  776. //
  777. // Add the texture to master list of textures.
  778. //
  779. AddTexture(pNew);
  780. //
  781. // Add the texture's index to the given group and to the "All" group.
  782. //
  783. pGroup->AddTexture(pNew);
  784. if (pGroup != m_pActiveContext->pAllGroup)
  785. {
  786. m_pActiveContext->pAllGroup->AddTexture(pNew);
  787. }
  788. }
  789. else
  790. {
  791. delete pNew;
  792. }
  793. }
  794. }
  795. }
  796. // free memory
  797. delete[] dir;
  798. }
  799. //-----------------------------------------------------------------------------
  800. // Purpose: Loads all textures in a given graphics file and returns an ID for
  801. // the file.
  802. // Input : filename - Full path of graphics file to load.
  803. // Output : Returns the file ID.
  804. //-----------------------------------------------------------------------------
  805. DWORD CTextureSystem::LoadGraphicsFile(const char *pFilename)
  806. {
  807. static DWORD __GraphFileID = 1; // must start at 1.
  808. //
  809. // Make sure it's not already there.
  810. //
  811. int i = m_GraphicsFiles.Count() - 1;
  812. while (i > -1)
  813. {
  814. if (!strcmp(m_GraphicsFiles[i].filename, pFilename))
  815. {
  816. return(m_GraphicsFiles[i].id);
  817. }
  818. i--;
  819. }
  820. //
  821. // Is this a WAD file?
  822. //
  823. DWORD dwAttrib = GetFileAttributes(pFilename);
  824. if (dwAttrib == 0xFFFFFFFF)
  825. {
  826. return(0);
  827. }
  828. GRAPHICSFILESTRUCT gf;
  829. if (!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY))
  830. {
  831. // open the file, and add it to the GraphicFileList array
  832. gf.fd = _open(pFilename, _O_BINARY | _O_RDONLY);
  833. if (gf.fd == -1)
  834. {
  835. // todo: if errno is "out of handles", close some other
  836. // graphics files.
  837. // StatusMsg(IDS_ERROPENGRAPHFILE, errno);
  838. return 0; // could not open
  839. }
  840. char buf[4];
  841. _read(gf.fd, buf, 4);
  842. //
  843. // Make sure the file is in a format that we can read.
  844. //
  845. if (!memcmp(buf, "WAD3", 4))
  846. {
  847. gf.format = tfWAD3;
  848. }
  849. else
  850. {
  851. char str[MAX_PATH*2];
  852. Q_snprintf( str, sizeof(str), "The file \"%s\" is not a valid WAD3 file and will not be used.", pFilename);
  853. AfxMessageBox(str, MB_ICONEXCLAMATION | MB_OK);
  854. _close(gf.fd);
  855. return(0);
  856. }
  857. }
  858. // got it -- setup the rest of the gf structure
  859. gf.id = __GraphFileID++;
  860. Q_strncpy( gf.filename, pFilename, sizeof(gf.filename) );
  861. gf.bLoaded = FALSE;
  862. //
  863. // Add file to list of texture files.
  864. //
  865. m_GraphicsFiles.AddToTail(gf);
  866. //
  867. // Create a new texture group for the file.
  868. //
  869. CTextureGroup *pGroup = new CTextureGroup(pFilename);
  870. pGroup->SetTextureFormat(gf.format);
  871. m_pActiveContext->Groups.AddToTail(pGroup);
  872. //
  873. // Load the textures from the file and place them in the texture group.
  874. //
  875. LoadGraphicsFileWAD3(&gf, gf.fd, pGroup);
  876. gf.bLoaded = TRUE;
  877. //
  878. // Sort this group's list
  879. //
  880. pGroup->Sort();
  881. return(gf.id);
  882. }
  883. //-----------------------------------------------------------------------------
  884. // Purpose: Determines whether or not there is at least one available texture
  885. // group for a given texture format.
  886. // Input : format - Texture format to look for.
  887. // Output : Returns TRUE if textures of a given format are available, FALSE if not.
  888. //-----------------------------------------------------------------------------
  889. bool CTextureSystem::HasTexturesForConfig(CGameConfig *pConfig)
  890. {
  891. if (!pConfig)
  892. return false;
  893. TextureContext_t *pContext = FindTextureContextForConfig(pConfig);
  894. if (!pContext)
  895. return false;
  896. int nCount = pContext->Groups.Count();
  897. for (int i = 0; i < nCount; i++)
  898. {
  899. CTextureGroup *pGroup = pContext->Groups.Element(i);
  900. if (pGroup->GetTextureFormat() == pConfig->GetTextureFormat())
  901. {
  902. return true;
  903. }
  904. }
  905. return false;
  906. }
  907. //-----------------------------------------------------------------------------
  908. // Used to add all the world materials into the material list
  909. //-----------------------------------------------------------------------------
  910. bool CTextureSystem::EnumMaterial( const char *pMaterialName, int nContext )
  911. {
  912. CTextureGroup *pGroup = (CTextureGroup *)nContext;
  913. CMaterial *pMaterial = CMaterial::CreateMaterial(pMaterialName, false);
  914. if (pMaterial != NULL)
  915. {
  916. // Add it to the master list of textures.
  917. AddTexture(pMaterial);
  918. // Add the texture's index to the given group and to the "All" group.
  919. pGroup->AddTexture(pMaterial);
  920. if (pGroup != m_pActiveContext->pAllGroup)
  921. {
  922. m_pActiveContext->pAllGroup->AddTexture(pMaterial);
  923. }
  924. }
  925. return true;
  926. }
  927. //-----------------------------------------------------------------------------
  928. // Registers the keywords as existing in a particular material
  929. //-----------------------------------------------------------------------------
  930. void CTextureSystem::RegisterTextureKeywords( IEditorTexture *pTexture )
  931. {
  932. //
  933. // Add any new keywords from this material to the list of keywords.
  934. //
  935. char szKeywords[MAX_PATH];
  936. pTexture->GetKeywords(szKeywords);
  937. if (szKeywords[0] != '\0')
  938. {
  939. char *pch = strtok(szKeywords, " ,;");
  940. while (pch != NULL)
  941. {
  942. // dvs: hide in a Find function
  943. bool bFound = false;
  944. for( int pos=0; pos < m_Keywords.Count(); pos++ )
  945. {
  946. const char *pszTest = m_Keywords.Element(pos);
  947. if (!stricmp(pszTest, pch))
  948. {
  949. bFound = true;
  950. break;
  951. }
  952. }
  953. if (!bFound)
  954. {
  955. char *pszKeyword = new char[strlen(pch) + 1];
  956. strcpy(pszKeyword, pch);
  957. m_Keywords.AddToTail(pszKeyword);
  958. }
  959. pch = strtok(NULL, " ,;");
  960. }
  961. }
  962. }
  963. //-----------------------------------------------------------------------------
  964. // Used to lazily load in all the textures
  965. //-----------------------------------------------------------------------------
  966. void CTextureSystem::LazyLoadTextures()
  967. {
  968. if ( m_pActiveContext && m_pActiveContext->pAllGroup && !IsRunningInEngine() )
  969. {
  970. m_pActiveContext->pAllGroup->LazyLoadTextures();
  971. }
  972. }
  973. //-----------------------------------------------------------------------------
  974. // Purpose:
  975. // Output : TextureContext_t
  976. //-----------------------------------------------------------------------------
  977. TextureContext_t *CTextureSystem::AddTextureContext()
  978. {
  979. // Allocate a new texture context.
  980. int nIndex = m_TextureContexts.AddToTail();
  981. // Add the group to this config's list of texture groups.
  982. TextureContext_t *pContext = &m_TextureContexts.Element(nIndex);
  983. return pContext;
  984. }
  985. //-----------------------------------------------------------------------------
  986. // Opens the source file associated with a material
  987. //-----------------------------------------------------------------------------
  988. void CTextureSystem::OpenSource( const char *pMaterialName )
  989. {
  990. if ( !pMaterialName )
  991. return;
  992. char pRelativePath[MAX_PATH];
  993. Q_snprintf( pRelativePath, MAX_PATH, "materials/%s.vmt", pMaterialName );
  994. char pFullPath[MAX_PATH];
  995. if ( g_pFullFileSystem->GetLocalPath( pRelativePath, pFullPath, MAX_PATH ) )
  996. {
  997. ShellExecute( NULL, "open", pFullPath, NULL, NULL, SW_SHOWNORMAL );
  998. }
  999. }
  1000. //-----------------------------------------------------------------------------
  1001. // Opens explorer dialog and selects the source file
  1002. //-----------------------------------------------------------------------------
  1003. void CTextureSystem::ExploreToSource( const char *pMaterialName )
  1004. {
  1005. if ( !pMaterialName )
  1006. return;
  1007. char pRelativePath[MAX_PATH];
  1008. Q_snprintf( pRelativePath, MAX_PATH, "materials/%s.vmt", pMaterialName );
  1009. char pFullPath[MAX_PATH];
  1010. if ( g_pFullFileSystem->GetLocalPath( pRelativePath, pFullPath, MAX_PATH ) )
  1011. {
  1012. CString strSel = "/select, ";
  1013. strSel += pFullPath;
  1014. ShellExecute(NULL, "open", "explorer", strSel, NULL, SW_SHOWNORMAL );
  1015. }
  1016. }
  1017. //-----------------------------------------------------------------------------
  1018. // Purpose: Constructor.
  1019. // Input : pszName - Name of group, ie "Materials" or "u:\hl\tfc\tfc.wad".
  1020. //-----------------------------------------------------------------------------
  1021. CTextureGroup::CTextureGroup(const char *pszName)
  1022. {
  1023. strcpy(m_szName, pszName);
  1024. m_eTextureFormat = tfNone;
  1025. m_nTextureToLoad = 0;
  1026. }
  1027. //-----------------------------------------------------------------------------
  1028. // Purpose: Adds a texture to this group.
  1029. // Input : pTexture - Texture to add.
  1030. //-----------------------------------------------------------------------------
  1031. void CTextureGroup::AddTexture(IEditorTexture *pTexture)
  1032. {
  1033. int index = m_Textures.AddToTail(pTexture);
  1034. m_TextureNameMap.Insert( pTexture->GetName(), index );
  1035. }
  1036. //-----------------------------------------------------------------------------
  1037. // Purpose: Sorts the group.
  1038. //-----------------------------------------------------------------------------
  1039. void CTextureGroup::Sort(void)
  1040. {
  1041. m_Textures.Sort(SortTexturesProc);
  1042. // Redo the name map.
  1043. m_TextureNameMap.RemoveAll();
  1044. for ( int i=0; i < m_Textures.Count(); i++ )
  1045. {
  1046. IEditorTexture *pTex = m_Textures[i];
  1047. m_TextureNameMap.Insert( pTex->GetName(), i );
  1048. }
  1049. // Changing the order means we don't know where we should be loading from
  1050. m_nTextureToLoad = 0;
  1051. }
  1052. //-----------------------------------------------------------------------------
  1053. // Purpose: Retrieves a texture by index.
  1054. // Input : nIndex - Index of the texture in this group.
  1055. //-----------------------------------------------------------------------------
  1056. IEditorTexture *CTextureGroup::GetTexture(int nIndex)
  1057. {
  1058. if ((nIndex >= m_Textures.Count()) || (nIndex < 0))
  1059. {
  1060. return(NULL);
  1061. }
  1062. return(m_Textures[nIndex]);
  1063. }
  1064. //-----------------------------------------------------------------------------
  1065. // finds a texture by name
  1066. //-----------------------------------------------------------------------------
  1067. IEditorTexture *CTextureGroup::GetTexture( char const* pName )
  1068. {
  1069. for (int i = 0; i < m_Textures.Count(); i++)
  1070. {
  1071. if (!strcmp(pName, m_Textures[i]->GetName()))
  1072. return m_Textures[i];
  1073. }
  1074. return NULL;
  1075. }
  1076. //-----------------------------------------------------------------------------
  1077. // Quickly find a texture by name.
  1078. //-----------------------------------------------------------------------------
  1079. IEditorTexture* CTextureGroup::FindTextureByName( const char *pName, int *piIndex, TEXTUREFORMAT eDesiredFormat )
  1080. {
  1081. int iMapEntry = m_TextureNameMap.Find( pName );
  1082. if ( iMapEntry == m_TextureNameMap.InvalidIndex() )
  1083. {
  1084. return NULL;
  1085. }
  1086. else
  1087. {
  1088. IEditorTexture *pTex = m_Textures[ m_TextureNameMap[iMapEntry] ];
  1089. if ((eDesiredFormat == tfNone) || (pTex->GetTextureFormat() == eDesiredFormat))
  1090. return pTex;
  1091. else
  1092. return NULL;
  1093. }
  1094. }
  1095. //-----------------------------------------------------------------------------
  1096. // Used to lazily load in all the textures
  1097. //-----------------------------------------------------------------------------
  1098. void CTextureGroup::LazyLoadTextures()
  1099. {
  1100. // Load at most once per call
  1101. while (m_nTextureToLoad < m_Textures.Count())
  1102. {
  1103. if (!m_Textures[m_nTextureToLoad]->IsLoaded())
  1104. {
  1105. m_Textures[m_nTextureToLoad]->Load();
  1106. ++m_nTextureToLoad;
  1107. return;
  1108. }
  1109. // This one was already loaded; skip it
  1110. ++m_nTextureToLoad;
  1111. }
  1112. }