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.

719 lines
16 KiB

  1. //========= Copyright � 1996-2005, 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. if (pszName == NULL)
  238. {
  239. pszName = szBuf;
  240. }
  241. if (format == tfWAL)
  242. {
  243. const char *pszCopy = strstr(m_szName, "textures");
  244. if (pszCopy == NULL)
  245. {
  246. pszCopy = m_szName;
  247. }
  248. else
  249. {
  250. pszCopy += strlen("textures\\");
  251. }
  252. strcpy(pszName, pszCopy);
  253. // remove extension
  254. char *psz = strstr(szBuf, ".wal");
  255. if (psz != NULL)
  256. {
  257. *psz = 0;
  258. }
  259. }
  260. else
  261. {
  262. strcpy(pszName, m_szName);
  263. }
  264. return(strlen(pszName));
  265. }
  266. //-----------------------------------------------------------------------------
  267. // Purpose: Resizes a texture to be even powers of 2 in width and height.
  268. // Input : pLoadBuf -
  269. // Output : Returns TRUE on success, FALSE on failure.
  270. //-----------------------------------------------------------------------------
  271. BOOL CWADTexture::AdjustTexture(char *pLoadBuf)
  272. {
  273. // make height/width power of two
  274. int i, i2;
  275. for (i = 0; ; i++)
  276. {
  277. i2 = 1 << i;
  278. if (i2 >= m_nWidth)
  279. {
  280. m_datawidth = i2;
  281. break;
  282. }
  283. }
  284. for (i = 0; ; i++)
  285. {
  286. i2 = 1 << i;
  287. if (i2 >= m_nHeight)
  288. {
  289. m_dataheight = i2;
  290. break;
  291. }
  292. }
  293. // allocate data
  294. m_pData = _GraphicCacheAllocate(m_datawidth * m_dataheight);
  295. if (m_pData == NULL)
  296. {
  297. CString errmsg;
  298. errmsg.Format(IDS_ERRLOADGRAPHIC, m_szName);
  299. AfxMessageBox(errmsg);
  300. return FALSE;
  301. }
  302. // scale up to data
  303. ScaleBitmap(CSize(m_nWidth, m_nHeight), CSize(m_datawidth, m_dataheight), pLoadBuf, (char *)m_pData);
  304. return TRUE;
  305. }
  306. bool CWADTexture::IsLoaded() const
  307. {
  308. return (m_pData != NULL);
  309. }
  310. //-----------------------------------------------------------------------------
  311. // Purpose: Load data from file associated with m_ulFileID.
  312. // Input : fd -
  313. // hFile -
  314. // Output : Returns TRUE on success, FALSE on failure.
  315. //-----------------------------------------------------------------------------
  316. BOOL CWADTexture::Load(int fd, HANDLE hFile)
  317. {
  318. if (m_pData)
  319. {
  320. return TRUE; // already loaded
  321. }
  322. // if fd is -1, get it from base file.. otherwise we've been
  323. // given an fd by caller, so use that in loading
  324. GRAPHICSFILESTRUCT fileInfo;
  325. Q_memset( &fileInfo, 0, sizeof(fileInfo));
  326. if (fd == -1)
  327. {
  328. // find graphics file - different loading based on wad type.
  329. if (!g_Textures.FindGraphicsFile(&fileInfo, m_ulFileID))
  330. {
  331. return(FALSE);
  332. }
  333. // keep fd
  334. fd = fileInfo.fd;
  335. // seek to offset
  336. _lseek(fd, m_ulFileOffset, SEEK_SET);
  337. }
  338. m_bLocalPalette = FALSE;
  339. // dvs: if fd != -1, using FileInfo without initializing it!!
  340. if (!AllocateLoadBuffer(m_nWidth * m_nHeight))
  341. {
  342. AfxMessageBox("Couldn't allocate a texture loading buffer.");
  343. return FALSE;
  344. }
  345. // load bitmap
  346. _read(fd, g_pLoadBuf, m_nWidth * m_nHeight);
  347. //
  348. // If WAD3, read the palette.
  349. //
  350. if (fileInfo.format == tfWAD3)
  351. {
  352. WORD nPal;
  353. _lseek(fd, (m_nWidth / 2 * m_nHeight / 2) + (m_nWidth / 4 * m_nHeight / 4) + (m_nWidth / 8 * m_nHeight / 8), SEEK_CUR);
  354. _read(fd, &nPal, sizeof nPal);
  355. Assert(nPal <= 256);
  356. if ((nPal > 0) && (nPal < 1024))
  357. {
  358. m_bLocalPalette = TRUE;
  359. // setup palette
  360. m_pPalette = (LOGPALETTE *)malloc(sizeof(WORD) * 2 + sizeof(PALETTEENTRY) * nPal);
  361. // fast load - throw into buffer
  362. static unsigned char PalBuf[3 * 1024];
  363. _read(fd, PalBuf, nPal * 3);
  364. // convert to LOGPALETTE
  365. for (int i = 0; i < nPal; i++)
  366. {
  367. m_pPalette->palPalEntry[i].peRed = PalBuf[i*3];
  368. m_pPalette->palPalEntry[i].peGreen = PalBuf[i*3+1];
  369. m_pPalette->palPalEntry[i].peBlue = PalBuf[i*3+2];
  370. m_pPalette->palPalEntry[i].peFlags = D3DRMPALETTE_READONLY | PC_NOCOLLAPSE;
  371. }
  372. m_pPalette->palVersion = 0x300;
  373. m_pPalette->palNumEntries = nPal;
  374. }
  375. }
  376. AdjustTexture(g_pLoadBuf);
  377. return TRUE;
  378. }
  379. //-----------------------------------------------------------------------------
  380. // Purpose: If the buffer pointer passed in is not NULL, copies the image data
  381. // in RGB format to the buffer
  382. // Input : pImageRGB - Pointer to buffer that receives the image data. If the
  383. // pointer is NULL, no data is copied, only the data size is returned.
  384. // Output : Returns a the size of the RGB image in bytes.
  385. //-----------------------------------------------------------------------------
  386. int CWADTexture::GetImageDataRGB( void *pImageRGB )
  387. {
  388. if ( pImageRGB != NULL )
  389. {
  390. Load();
  391. unsigned char *puchImage = ( unsigned char * )m_pData;
  392. unsigned char *pIndex = ( unsigned char * )pImageRGB;
  393. for (int y = 0; y < m_dataheight; y++)
  394. {
  395. for (int x = 0; x < m_datawidth; x++)
  396. {
  397. unsigned char chPaletteEntry = puchImage[y * m_datawidth + x];
  398. *pIndex = m_pPalette->palPalEntry[chPaletteEntry].peRed;
  399. pIndex++;
  400. *pIndex = m_pPalette->palPalEntry[chPaletteEntry].peGreen;
  401. pIndex++;
  402. *pIndex = m_pPalette->palPalEntry[chPaletteEntry].peBlue;
  403. pIndex++;
  404. }
  405. }
  406. }
  407. return( m_datawidth * m_dataheight * 3 );
  408. }
  409. //-----------------------------------------------------------------------------
  410. // Purpose: If the buffer pointer passed in is not NULL, copies the image data
  411. // in RGBA format to the buffer
  412. // Input : pImageRGBA - Pointer to buffer that receives the image data. If the
  413. // pointer is NULL, no data is copied, only the data size is returned.
  414. // Output : Returns a the size of the RGBA image in bytes.
  415. //-----------------------------------------------------------------------------
  416. int CWADTexture::GetImageDataRGBA( void *pImageRGBA )
  417. {
  418. if ( pImageRGBA != NULL )
  419. {
  420. unsigned char *puchImage = (unsigned char *)m_pData;
  421. unsigned char *pIndex = (unsigned char *)pImageRGBA;
  422. for (int y = 0; y < m_dataheight; y++)
  423. {
  424. for (int x = 0; x < m_datawidth; x++)
  425. {
  426. unsigned char chPaletteEntry = puchImage[y * m_datawidth + x];
  427. *pIndex = m_pPalette->palPalEntry[chPaletteEntry].peRed;
  428. pIndex++;
  429. *pIndex = m_pPalette->palPalEntry[chPaletteEntry].peGreen;
  430. pIndex++;
  431. *pIndex = m_pPalette->palPalEntry[chPaletteEntry].peBlue;
  432. pIndex++;
  433. *pIndex = 0;
  434. pIndex++;
  435. }
  436. }
  437. }
  438. return( m_datawidth * m_dataheight * 4 );
  439. }
  440. //-----------------------------------------------------------------------------
  441. // Purpose:
  442. // Input : size -
  443. //-----------------------------------------------------------------------------
  444. void CWADTexture::GetSize(SIZE& size)
  445. {
  446. size.cx = m_nWidth;
  447. size.cy = m_nHeight;
  448. }
  449. //-----------------------------------------------------------------------------
  450. // Purpose: Draws white "No Image" text in a black rectangle.
  451. // Input : pDC -
  452. // rect -
  453. // iFontHeight -
  454. // dwFlags -
  455. //-----------------------------------------------------------------------------
  456. void CWADTexture::DrawNoImage(CDC *pDC, RECT& rect, int iFontHeight)
  457. {
  458. // draw "no data"
  459. CFont *pOldFont = (CFont*) pDC->SelectStockObject(ANSI_VAR_FONT);
  460. COLORREF cr = pDC->SetTextColor(RGB(0xff, 0xff, 0xff));
  461. COLORREF cr2 = pDC->SetBkColor(RGB(0, 0, 0));
  462. // draw black rect first
  463. pDC->FillRect(&rect, CBrush::FromHandle(HBRUSH(GetStockObject(BLACK_BRUSH))));
  464. // then text
  465. pDC->TextOut(rect.left+2, rect.top+2, "No Image", 8);
  466. pDC->SelectObject(pOldFont);
  467. pDC->SetTextColor(cr);
  468. pDC->SetBkColor(cr2);
  469. }
  470. //-----------------------------------------------------------------------------
  471. // Purpose:
  472. // Input : *pDC -
  473. // rect -
  474. // iFontHeight -
  475. // dwFlags -
  476. //-----------------------------------------------------------------------------
  477. void CWADTexture::Draw(CDC *pDC, RECT& rect, int iFontHeight, int iIconHeight, DrawTexData_t &DrawTexData)
  478. {
  479. if (!m_nWidth)
  480. {
  481. DrawNoImage(pDC, rect, iFontHeight);
  482. return;
  483. }
  484. // no data -
  485. if (!m_pData)
  486. {
  487. // try to load -
  488. if (!Load())
  489. {
  490. DrawNoImage(pDC, rect, iFontHeight);
  491. return;
  492. }
  493. }
  494. static struct
  495. {
  496. BITMAPINFOHEADER bmih;
  497. unsigned short colorindex[256];
  498. } bmi;
  499. BITMAPINFOHEADER& bmih = bmi.bmih;
  500. memset(&bmih, 0, sizeof bmih);
  501. bmih.biSize = sizeof(bmih);
  502. bmih.biWidth = m_datawidth;
  503. bmih.biHeight = -m_dataheight; // top-down DIB
  504. bmih.biCompression = BI_RGB;
  505. bmih.biBitCount = 8;
  506. bmih.biPlanes = 1;
  507. static BOOL bInit = FALSE;
  508. if (!bInit)
  509. {
  510. bInit = TRUE;
  511. for (int i = 0; i < 256; i++)
  512. {
  513. bmi.colorindex[i] = i;
  514. }
  515. }
  516. int dest_width = rect.right - rect.left;
  517. int dest_height = rect.bottom - rect.top;
  518. if (DrawTexData.nFlags & drawCaption)
  519. {
  520. dest_height -= iFontHeight + 4;
  521. }
  522. if (!(DrawTexData.nFlags & drawResizeAlways))
  523. {
  524. if (m_nWidth < dest_width)
  525. {
  526. dest_width = m_nWidth;
  527. }
  528. if (m_nHeight < dest_height)
  529. {
  530. dest_height = m_nHeight;
  531. }
  532. }
  533. SetStretchBltMode(pDC->m_hDC, COLORONCOLOR);
  534. 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)
  535. {
  536. Msg(mwError, "CWADTexture::Draw(): StretchDIBits failed.");
  537. }
  538. //
  539. // Caption.
  540. //
  541. if (DrawTexData.nFlags & drawCaption)
  542. {
  543. // draw background for name
  544. CBrush brCaption(RGB(0, 0, 255));
  545. CRect rcCaption(rect);
  546. rcCaption.top = rcCaption.bottom - (iFontHeight + 5);
  547. pDC->FillRect(rcCaption, &brCaption);
  548. // draw name
  549. char szShortName[MAX_PATH];
  550. int iLen = GetShortName(szShortName);
  551. pDC->TextOut(rect.left, rect.bottom - (iFontHeight + 4), szShortName, iLen);
  552. }
  553. }
  554. //-----------------------------------------------------------------------------
  555. // Purpose: Frees the static load buffer.
  556. //-----------------------------------------------------------------------------
  557. bool CWADTexture::Initialize(void)
  558. {
  559. return(AllocateLoadBuffer(g_nLoadSize));
  560. }
  561. //-----------------------------------------------------------------------------
  562. // Purpose: Loads this texture from disk, if it is not already loaded.
  563. // Output : Returns true on success, false on failure.
  564. //-----------------------------------------------------------------------------
  565. bool CWADTexture::Load( void )
  566. {
  567. if (m_pData != NULL)
  568. {
  569. // Already loaded.
  570. return(true);
  571. }
  572. return(Load(-1, NULL) == TRUE);
  573. }
  574. //-----------------------------------------------------------------------------
  575. // Purpose: Frees the static load buffer.
  576. //-----------------------------------------------------------------------------
  577. void CWADTexture::ShutDown(void)
  578. {
  579. if (g_pLoadBuf != NULL)
  580. {
  581. delete[] g_pLoadBuf;
  582. g_pLoadBuf = NULL;
  583. }
  584. }