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.

720 lines
16 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Implementation of the IEditorTexture interface for WAD textures.
  4. //
  5. //=============================================================================//
  6. #include "stdafx.h"
  7. #include <process.h>
  8. #include <afxtempl.h>
  9. #include <io.h>
  10. #include <sys\stat.h>
  11. #include <fcntl.h>
  12. #include "hammer.h"
  13. #include "MapDoc.h"
  14. #include "Options.h"
  15. #include "MainFrm.h"
  16. #include "GlobalFunctions.h"
  17. #include "WADTypes.h"
  18. #include "BSPFile.h"
  19. #include "bitmap/imageformat.h" // hack : don't want to include this just for ImageFormat
  20. #include "TextureSystem.h"
  21. #include "WADTexture.h"
  22. // memdbgon must be the last include file in a .cpp file!!!
  23. #include <tier0/memdbgon.h>
  24. #pragma warning(disable:4244)
  25. #define _GraphicCacheAllocate(n) malloc(n)
  26. //-----------------------------------------------------------------------------
  27. // Stuff for loading WAD3 files.
  28. //-----------------------------------------------------------------------------
  29. typedef struct WAD3miptex_s
  30. {
  31. char name[16];
  32. unsigned width, height;
  33. unsigned offsets[4]; // four mip maps stored
  34. } WAD3miptex_t;
  35. //-----------------------------------------------------------------------------
  36. // Stuff for loading WAL files.
  37. //-----------------------------------------------------------------------------
  38. typedef struct // Mip Graphic
  39. {
  40. char name[32]; // Name of the Graphic.
  41. DWORD width; // width of picture, must be a multiple of 8
  42. DWORD height; // height of picture, must be a multiple of 8
  43. DWORD offset1; // offset to u_char Pix[width * height]
  44. DWORD offset2; // offset to u_char Pix[width/2 * height/2]
  45. DWORD offset4; // offset to u_char Pix[width/4 * height/4]
  46. DWORD offset8; // offset to u_char Pix[width/8 * height/8]
  47. char animname[32];
  48. DWORD surface;
  49. DWORD contents;
  50. DWORD value;
  51. } walhdr_t;
  52. static char *g_pLoadBuf = NULL;
  53. static int g_nLoadSize = 128 * 1024;
  54. extern void ScaleBitmap(CSize sizeSrc, CSize sizeDest, char *src, char *dest);
  55. //-----------------------------------------------------------------------------
  56. // Purpose:
  57. // Input : nSize -
  58. // Output : Returns true on success, false on failure.
  59. //-----------------------------------------------------------------------------
  60. static bool AllocateLoadBuffer(int nSize)
  61. {
  62. if (nSize > g_nLoadSize)
  63. {
  64. g_nLoadSize = nSize;
  65. if (g_pLoadBuf != NULL)
  66. {
  67. delete[] g_pLoadBuf;
  68. g_pLoadBuf = NULL;
  69. }
  70. }
  71. if (g_pLoadBuf == NULL)
  72. {
  73. g_pLoadBuf = new char[g_nLoadSize];
  74. }
  75. if (g_pLoadBuf == NULL)
  76. {
  77. return(false);
  78. }
  79. return(true);
  80. }
  81. //-----------------------------------------------------------------------------
  82. // Purpose: Constructor. Initializes data members.
  83. //-----------------------------------------------------------------------------
  84. CWADTexture::CWADTexture(void)
  85. {
  86. memset(m_szName, 0, sizeof(m_szName));
  87. memset(m_szFileName, 0, sizeof(m_szFileName));
  88. m_datawidth = 0;
  89. m_dataheight = 0;
  90. m_WALsurface = 0;
  91. m_WALvalue = 0;
  92. m_WALcontents = 0;
  93. m_ulFileOffset = 0;
  94. m_ulFileID = 0;
  95. memset(&format, 0, sizeof(format));
  96. m_pPalette = NULL;
  97. m_bLocalPalette = false;
  98. m_nWidth = 0;
  99. m_nHeight = 0;
  100. m_pData = NULL;
  101. }
  102. //-----------------------------------------------------------------------------
  103. // Purpose: Destructor. Frees texture image data and palette.
  104. //-----------------------------------------------------------------------------
  105. CWADTexture::~CWADTexture(void)
  106. {
  107. //
  108. // Free image data.
  109. //
  110. if (m_pData != NULL)
  111. {
  112. free(m_pData);
  113. m_pData = NULL;
  114. }
  115. //
  116. // Free palette.
  117. //
  118. if (m_pPalette != NULL)
  119. {
  120. free(m_pPalette);
  121. m_pPalette = NULL;
  122. }
  123. }
  124. //-----------------------------------------------------------------------------
  125. // Purpose: Returns the full path of the file (WAD, PAK, or WAL) from which this
  126. // texture was loaded.
  127. //-----------------------------------------------------------------------------
  128. const char *CWADTexture::GetFileName( void ) const
  129. {
  130. return(m_szFileName);
  131. }
  132. //-----------------------------------------------------------------------------
  133. // Purpose:
  134. // Input : fd -
  135. // ulFileID -
  136. // bLoad -
  137. // pszName -
  138. // Output : Returns TRUE on success, FALSE on failure.
  139. //-----------------------------------------------------------------------------
  140. BOOL CWADTexture::Init(int fd, DWORD ulFileID, BOOL bLoad, LPCTSTR pszName)
  141. {
  142. //
  143. // Load header and copy needed data into members variables.
  144. //
  145. GRAPHICSFILESTRUCT FileInfo;
  146. bool bFound = g_Textures.FindGraphicsFile(&FileInfo, ulFileID);
  147. if (!bFound)
  148. {
  149. miptex_t hdr;
  150. _read(fd, (char *)&hdr, sizeof(hdr));
  151. m_nWidth = hdr.width;
  152. m_nHeight = hdr.height;
  153. }
  154. else if (FileInfo.format == tfWAD3)
  155. {
  156. WAD3miptex_t hdr;
  157. _read(fd, (char *)&hdr, sizeof(hdr));
  158. m_nWidth = hdr.width;
  159. m_nHeight = hdr.height;
  160. if (m_nHeight < 0)
  161. {
  162. return(FALSE);
  163. }
  164. }
  165. else
  166. {
  167. return(FALSE);
  168. }
  169. m_ulFileID = ulFileID;
  170. strcpy(m_szName, pszName);
  171. if (bFound)
  172. {
  173. strcpy(m_szFileName, FileInfo.filename);
  174. }
  175. if (m_nWidth * m_nHeight > MAX_TEXTURESIZE)
  176. {
  177. return(FALSE);
  178. }
  179. if (!m_szName[0])
  180. {
  181. return(FALSE);
  182. }
  183. // set offset
  184. m_ulFileOffset = _tell(fd);
  185. if (bLoad)
  186. {
  187. return(Load());
  188. }
  189. return(TRUE);
  190. }
  191. //-----------------------------------------------------------------------------
  192. // Purpose:
  193. // Input :
  194. // Output : CPalette *
  195. //-----------------------------------------------------------------------------
  196. CPalette *CWADTexture::GetPalette(void) const
  197. {
  198. static CPalette pal;
  199. pal.DeleteObject();
  200. pal.CreatePalette(m_pPalette);
  201. return &pal;
  202. }
  203. //-----------------------------------------------------------------------------
  204. // Purpose: Returns a string of comma delimited keywords associated with this
  205. // material.
  206. // Input : pszKeywords - Buffer to receive keywords, NULL to query string length.
  207. // Output : Returns the number of characters in the keyword string.
  208. //-----------------------------------------------------------------------------
  209. int CWADTexture::GetKeywords(char *pszKeywords) const
  210. {
  211. //
  212. // Set the keywords to the WAD file name.
  213. //
  214. if (pszKeywords != NULL)
  215. {
  216. const char *pszLastSlash = strrchr(m_szFileName, '\\');
  217. if (pszLastSlash != NULL)
  218. {
  219. pszLastSlash++;
  220. strcpy(pszKeywords, pszLastSlash);
  221. }
  222. else
  223. {
  224. strcpy(pszKeywords, m_szFileName);
  225. }
  226. }
  227. return(strlen(m_szFileName));
  228. }
  229. //-----------------------------------------------------------------------------
  230. // Purpose:
  231. // Input : *pszName -
  232. // Output : Returns the length of the short name in characters.
  233. //-----------------------------------------------------------------------------
  234. int CWADTexture::GetShortName(char *pszName) const
  235. {
  236. char szBuf[MAX_PATH];
  237. szBuf[0] = '\0';
  238. if (pszName == NULL)
  239. {
  240. pszName = szBuf;
  241. }
  242. if (format == tfWAL)
  243. {
  244. const char *pszCopy = strstr(m_szName, "textures");
  245. if (pszCopy == NULL)
  246. {
  247. pszCopy = m_szName;
  248. }
  249. else
  250. {
  251. pszCopy += strlen("textures\\");
  252. }
  253. strcpy(pszName, pszCopy);
  254. // remove extension
  255. char *psz = strstr(szBuf, ".wal");
  256. if (psz != NULL)
  257. {
  258. *psz = 0;
  259. }
  260. }
  261. else
  262. {
  263. strcpy(pszName, m_szName);
  264. }
  265. return(strlen(pszName));
  266. }
  267. //-----------------------------------------------------------------------------
  268. // Purpose: Resizes a texture to be even powers of 2 in width and height.
  269. // Input : pLoadBuf -
  270. // Output : Returns TRUE on success, FALSE on failure.
  271. //-----------------------------------------------------------------------------
  272. BOOL CWADTexture::AdjustTexture(char *pLoadBuf)
  273. {
  274. // make height/width power of two
  275. int i, i2;
  276. for (i = 0; ; i++)
  277. {
  278. i2 = 1 << i;
  279. if (i2 >= m_nWidth)
  280. {
  281. m_datawidth = i2;
  282. break;
  283. }
  284. }
  285. for (i = 0; ; i++)
  286. {
  287. i2 = 1 << i;
  288. if (i2 >= m_nHeight)
  289. {
  290. m_dataheight = i2;
  291. break;
  292. }
  293. }
  294. // allocate data
  295. m_pData = _GraphicCacheAllocate(m_datawidth * m_dataheight);
  296. if (m_pData == NULL)
  297. {
  298. CString errmsg;
  299. errmsg.Format(IDS_ERRLOADGRAPHIC, m_szName);
  300. AfxMessageBox(errmsg);
  301. return FALSE;
  302. }
  303. // scale up to data
  304. ScaleBitmap(CSize(m_nWidth, m_nHeight), CSize(m_datawidth, m_dataheight), pLoadBuf, (char *)m_pData);
  305. return TRUE;
  306. }
  307. bool CWADTexture::IsLoaded() const
  308. {
  309. return (m_pData != NULL);
  310. }
  311. //-----------------------------------------------------------------------------
  312. // Purpose: Load data from file associated with m_ulFileID.
  313. // Input : fd -
  314. // hFile -
  315. // Output : Returns TRUE on success, FALSE on failure.
  316. //-----------------------------------------------------------------------------
  317. BOOL CWADTexture::Load(int fd, HANDLE hFile)
  318. {
  319. if (m_pData)
  320. {
  321. return TRUE; // already loaded
  322. }
  323. // if fd is -1, get it from base file.. otherwise we've been
  324. // given an fd by caller, so use that in loading
  325. GRAPHICSFILESTRUCT fileInfo;
  326. Q_memset( &fileInfo, 0, sizeof(fileInfo));
  327. if (fd == -1)
  328. {
  329. // find graphics file - different loading based on wad type.
  330. if (!g_Textures.FindGraphicsFile(&fileInfo, m_ulFileID))
  331. {
  332. return(FALSE);
  333. }
  334. // keep fd
  335. fd = fileInfo.fd;
  336. // seek to offset
  337. _lseek(fd, m_ulFileOffset, SEEK_SET);
  338. }
  339. m_bLocalPalette = FALSE;
  340. // dvs: if fd != -1, using FileInfo without initializing it!!
  341. if (!AllocateLoadBuffer(m_nWidth * m_nHeight))
  342. {
  343. AfxMessageBox("Couldn't allocate a texture loading buffer.");
  344. return FALSE;
  345. }
  346. // load bitmap
  347. _read(fd, g_pLoadBuf, m_nWidth * m_nHeight);
  348. //
  349. // If WAD3, read the palette.
  350. //
  351. if (fileInfo.format == tfWAD3)
  352. {
  353. WORD nPal;
  354. _lseek(fd, (m_nWidth / 2 * m_nHeight / 2) + (m_nWidth / 4 * m_nHeight / 4) + (m_nWidth / 8 * m_nHeight / 8), SEEK_CUR);
  355. _read(fd, &nPal, sizeof nPal);
  356. Assert(nPal <= 256);
  357. if ((nPal > 0) && (nPal < 1024))
  358. {
  359. m_bLocalPalette = TRUE;
  360. // setup palette
  361. m_pPalette = (LOGPALETTE *)malloc(sizeof(WORD) * 2 + sizeof(PALETTEENTRY) * nPal);
  362. // fast load - throw into buffer
  363. static unsigned char PalBuf[3 * 1024];
  364. _read(fd, PalBuf, nPal * 3);
  365. // convert to LOGPALETTE
  366. for (int i = 0; i < nPal; i++)
  367. {
  368. m_pPalette->palPalEntry[i].peRed = PalBuf[i*3];
  369. m_pPalette->palPalEntry[i].peGreen = PalBuf[i*3+1];
  370. m_pPalette->palPalEntry[i].peBlue = PalBuf[i*3+2];
  371. m_pPalette->palPalEntry[i].peFlags = D3DRMPALETTE_READONLY | PC_NOCOLLAPSE;
  372. }
  373. m_pPalette->palVersion = 0x300;
  374. m_pPalette->palNumEntries = nPal;
  375. }
  376. }
  377. AdjustTexture(g_pLoadBuf);
  378. return TRUE;
  379. }
  380. //-----------------------------------------------------------------------------
  381. // Purpose: If the buffer pointer passed in is not NULL, copies the image data
  382. // in RGB format to the buffer
  383. // Input : pImageRGB - Pointer to buffer that receives the image data. If the
  384. // pointer is NULL, no data is copied, only the data size is returned.
  385. // Output : Returns a the size of the RGB image in bytes.
  386. //-----------------------------------------------------------------------------
  387. int CWADTexture::GetImageDataRGB( void *pImageRGB )
  388. {
  389. if ( pImageRGB != NULL )
  390. {
  391. Load();
  392. unsigned char *puchImage = ( unsigned char * )m_pData;
  393. unsigned char *pIndex = ( unsigned char * )pImageRGB;
  394. for (int y = 0; y < m_dataheight; y++)
  395. {
  396. for (int x = 0; x < m_datawidth; x++)
  397. {
  398. unsigned char chPaletteEntry = puchImage[y * m_datawidth + x];
  399. *pIndex = m_pPalette->palPalEntry[chPaletteEntry].peRed;
  400. pIndex++;
  401. *pIndex = m_pPalette->palPalEntry[chPaletteEntry].peGreen;
  402. pIndex++;
  403. *pIndex = m_pPalette->palPalEntry[chPaletteEntry].peBlue;
  404. pIndex++;
  405. }
  406. }
  407. }
  408. return( m_datawidth * m_dataheight * 3 );
  409. }
  410. //-----------------------------------------------------------------------------
  411. // Purpose: If the buffer pointer passed in is not NULL, copies the image data
  412. // in RGBA format to the buffer
  413. // Input : pImageRGBA - Pointer to buffer that receives the image data. If the
  414. // pointer is NULL, no data is copied, only the data size is returned.
  415. // Output : Returns a the size of the RGBA image in bytes.
  416. //-----------------------------------------------------------------------------
  417. int CWADTexture::GetImageDataRGBA( void *pImageRGBA )
  418. {
  419. if ( pImageRGBA != NULL )
  420. {
  421. unsigned char *puchImage = (unsigned char *)m_pData;
  422. unsigned char *pIndex = (unsigned char *)pImageRGBA;
  423. for (int y = 0; y < m_dataheight; y++)
  424. {
  425. for (int x = 0; x < m_datawidth; x++)
  426. {
  427. unsigned char chPaletteEntry = puchImage[y * m_datawidth + x];
  428. *pIndex = m_pPalette->palPalEntry[chPaletteEntry].peRed;
  429. pIndex++;
  430. *pIndex = m_pPalette->palPalEntry[chPaletteEntry].peGreen;
  431. pIndex++;
  432. *pIndex = m_pPalette->palPalEntry[chPaletteEntry].peBlue;
  433. pIndex++;
  434. *pIndex = 0;
  435. pIndex++;
  436. }
  437. }
  438. }
  439. return( m_datawidth * m_dataheight * 4 );
  440. }
  441. //-----------------------------------------------------------------------------
  442. // Purpose:
  443. // Input : size -
  444. //-----------------------------------------------------------------------------
  445. void CWADTexture::GetSize(SIZE& size)
  446. {
  447. size.cx = m_nWidth;
  448. size.cy = m_nHeight;
  449. }
  450. //-----------------------------------------------------------------------------
  451. // Purpose: Draws white "No Image" text in a black rectangle.
  452. // Input : pDC -
  453. // rect -
  454. // iFontHeight -
  455. // dwFlags -
  456. //-----------------------------------------------------------------------------
  457. void CWADTexture::DrawNoImage(CDC *pDC, RECT& rect, int iFontHeight)
  458. {
  459. // draw "no data"
  460. CFont *pOldFont = (CFont*) pDC->SelectStockObject(ANSI_VAR_FONT);
  461. COLORREF cr = pDC->SetTextColor(RGB(0xff, 0xff, 0xff));
  462. COLORREF cr2 = pDC->SetBkColor(RGB(0, 0, 0));
  463. // draw black rect first
  464. pDC->FillRect(&rect, CBrush::FromHandle(HBRUSH(GetStockObject(BLACK_BRUSH))));
  465. // then text
  466. pDC->TextOut(rect.left+2, rect.top+2, "No Image", 8);
  467. pDC->SelectObject(pOldFont);
  468. pDC->SetTextColor(cr);
  469. pDC->SetBkColor(cr2);
  470. }
  471. //-----------------------------------------------------------------------------
  472. // Purpose:
  473. // Input : *pDC -
  474. // rect -
  475. // iFontHeight -
  476. // dwFlags -
  477. //-----------------------------------------------------------------------------
  478. void CWADTexture::Draw(CDC *pDC, RECT& rect, int iFontHeight, int iIconHeight, DrawTexData_t &DrawTexData)
  479. {
  480. if (!m_nWidth)
  481. {
  482. DrawNoImage(pDC, rect, iFontHeight);
  483. return;
  484. }
  485. // no data -
  486. if (!m_pData)
  487. {
  488. // try to load -
  489. if (!Load())
  490. {
  491. DrawNoImage(pDC, rect, iFontHeight);
  492. return;
  493. }
  494. }
  495. static struct
  496. {
  497. BITMAPINFOHEADER bmih;
  498. unsigned short colorindex[256];
  499. } bmi;
  500. BITMAPINFOHEADER& bmih = bmi.bmih;
  501. memset(&bmih, 0, sizeof bmih);
  502. bmih.biSize = sizeof(bmih);
  503. bmih.biWidth = m_datawidth;
  504. bmih.biHeight = -m_dataheight; // top-down DIB
  505. bmih.biCompression = BI_RGB;
  506. bmih.biBitCount = 8;
  507. bmih.biPlanes = 1;
  508. static BOOL bInit = FALSE;
  509. if (!bInit)
  510. {
  511. bInit = TRUE;
  512. for (int i = 0; i < 256; i++)
  513. {
  514. bmi.colorindex[i] = i;
  515. }
  516. }
  517. int dest_width = rect.right - rect.left;
  518. int dest_height = rect.bottom - rect.top;
  519. if (DrawTexData.nFlags & drawCaption)
  520. {
  521. dest_height -= iFontHeight + 4;
  522. }
  523. if (!(DrawTexData.nFlags & drawResizeAlways))
  524. {
  525. if (m_nWidth < dest_width)
  526. {
  527. dest_width = m_nWidth;
  528. }
  529. if (m_nHeight < dest_height)
  530. {
  531. dest_height = m_nHeight;
  532. }
  533. }
  534. SetStretchBltMode(pDC->m_hDC, COLORONCOLOR);
  535. if (StretchDIBits(pDC->m_hDC, rect.left, rect.top, dest_width, dest_height, 0, 0, m_datawidth, m_dataheight, m_pData, (BITMAPINFO*)&bmi, DIB_PAL_COLORS, SRCCOPY) == GDI_ERROR)
  536. {
  537. Msg(mwError, "CWADTexture::Draw(): StretchDIBits failed.");
  538. }
  539. //
  540. // Caption.
  541. //
  542. if (DrawTexData.nFlags & drawCaption)
  543. {
  544. // draw background for name
  545. CBrush brCaption(RGB(0, 0, 255));
  546. CRect rcCaption(rect);
  547. rcCaption.top = rcCaption.bottom - (iFontHeight + 5);
  548. pDC->FillRect(rcCaption, &brCaption);
  549. // draw name
  550. char szShortName[MAX_PATH];
  551. int iLen = GetShortName(szShortName);
  552. pDC->TextOut(rect.left, rect.bottom - (iFontHeight + 4), szShortName, iLen);
  553. }
  554. }
  555. //-----------------------------------------------------------------------------
  556. // Purpose: Frees the static load buffer.
  557. //-----------------------------------------------------------------------------
  558. bool CWADTexture::Initialize(void)
  559. {
  560. return(AllocateLoadBuffer(g_nLoadSize));
  561. }
  562. //-----------------------------------------------------------------------------
  563. // Purpose: Loads this texture from disk, if it is not already loaded.
  564. // Output : Returns true on success, false on failure.
  565. //-----------------------------------------------------------------------------
  566. bool CWADTexture::Load( void )
  567. {
  568. if (m_pData != NULL)
  569. {
  570. // Already loaded.
  571. return(true);
  572. }
  573. return(Load(-1, NULL) == TRUE);
  574. }
  575. //-----------------------------------------------------------------------------
  576. // Purpose: Frees the static load buffer.
  577. //-----------------------------------------------------------------------------
  578. void CWADTexture::ShutDown(void)
  579. {
  580. if (g_pLoadBuf != NULL)
  581. {
  582. delete[] g_pLoadBuf;
  583. g_pLoadBuf = NULL;
  584. }
  585. }