Source code of Windows XP (NT5)
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.

1042 lines
33 KiB

  1. //-----------------------------------------------------------------------------
  2. // File: D3DTextr.cpp
  3. //
  4. // Desc: Functions to manage textures, including creating (loading from a
  5. // file), restoring lost surfaces, invalidating, and destroying.
  6. //
  7. // Note: the implementation of these fucntions maintain an internal list
  8. // of loaded textures. After creation, individual textures are referenced
  9. // via their ASCII names.
  10. //
  11. // Copyright (c) 1996-1999 Microsoft Corporation. All rights reserved
  12. //-----------------------------------------------------------------------------
  13. #include "stdafx.h"
  14. #include "D3DTextr.h"
  15. #include "D3DUtil.h"
  16. //-----------------------------------------------------------------------------
  17. // Macros, function prototypes and static variable
  18. //-----------------------------------------------------------------------------
  19. TCHAR g_strTexturePath[512]; // Path for files
  20. //-----------------------------------------------------------------------------
  21. // Name: TextureContainer
  22. // Desc: Linked list structure to hold info per texture
  23. //-----------------------------------------------------------------------------
  24. struct TextureContainer
  25. {
  26. TextureContainer* m_pNext; // Linked list ptr
  27. TCHAR m_strName[80]; // Name of texture (doubles as image filename)
  28. DWORD m_dwWidth;
  29. DWORD m_dwHeight;
  30. DWORD m_dwStage; // Texture stage (for multitexture devices)
  31. DWORD m_dwBPP;
  32. DWORD m_dwFlags;
  33. BOOL m_bHasAlpha;
  34. LPDIRECTDRAWSURFACE7 m_pddsSurface; // Surface of the texture
  35. HBITMAP m_hbmBitmap; // Bitmap containing texture image
  36. DWORD* m_pRGBAData;
  37. public:
  38. HRESULT LoadImageData();
  39. HRESULT LoadBitmapFile(TCHAR* strPathname);
  40. HRESULT LoadTargaFile(TCHAR* strPathname);
  41. HRESULT Restore(LPDIRECT3DDEVICE7 pd3dDevice);
  42. HRESULT CopyBitmapToSurface();
  43. HRESULT CopyRGBADataToSurface();
  44. TextureContainer(TCHAR* strName, DWORD dwStage, DWORD dwFlags);
  45. ~TextureContainer();
  46. };
  47. // Local list of textures
  48. static TextureContainer* g_ptcTextureList = NULL;
  49. //-----------------------------------------------------------------------------
  50. // Name: CD3DTextureManager
  51. // Desc: Class used to automatically construct and destruct the static
  52. // texture engine class.
  53. //-----------------------------------------------------------------------------
  54. class CD3DTextureManager
  55. {
  56. public:
  57. CD3DTextureManager() {}
  58. ~CD3DTextureManager() { if (g_ptcTextureList) delete g_ptcTextureList; }
  59. };
  60. // Global instance
  61. CD3DTextureManager g_StaticTextureEngine;
  62. //-----------------------------------------------------------------------------
  63. // Name: struct TEXTURESEARCHINFO
  64. // Desc: Structure used to search for texture formats
  65. //-----------------------------------------------------------------------------
  66. struct TEXTURESEARCHINFO
  67. {
  68. DWORD dwDesiredBPP; // Input for texture format search
  69. BOOL bUseAlpha;
  70. BOOL bUsePalette;
  71. BOOL bFoundGoodFormat;
  72. DDPIXELFORMAT* pddpf; // Output of texture format search
  73. };
  74. //-----------------------------------------------------------------------------
  75. // Name: TextureSearchCallback()
  76. // Desc: Enumeration callback routine to find a best-matching texture format.
  77. // The param data is the DDPIXELFORMAT of the best-so-far matching
  78. // texture. Note: the desired BPP is passed in the dwSize field, and the
  79. // default BPP is passed in the dwFlags field.
  80. //-----------------------------------------------------------------------------
  81. static HRESULT CALLBACK TextureSearchCallback(DDPIXELFORMAT* pddpf,
  82. VOID* param)
  83. {
  84. if (NULL==pddpf || NULL==param)
  85. return DDENUMRET_OK;
  86. TEXTURESEARCHINFO* ptsi = (TEXTURESEARCHINFO*)param;
  87. // Skip any funky modes
  88. if (pddpf->dwFlags & (DDPF_LUMINANCE|DDPF_BUMPLUMINANCE|DDPF_BUMPDUDV))
  89. return DDENUMRET_OK;
  90. // Check for palettized formats
  91. if (ptsi->bUsePalette)
  92. {
  93. if (!(pddpf->dwFlags & DDPF_PALETTEINDEXED8))
  94. return DDENUMRET_OK;
  95. // Accept the first 8-bit palettized format we get
  96. memcpy(ptsi->pddpf, pddpf, sizeof(DDPIXELFORMAT));
  97. ptsi->bFoundGoodFormat = TRUE;
  98. return DDENUMRET_CANCEL;
  99. }
  100. // Else, skip any paletized formats (all modes under 16bpp)
  101. if (pddpf->dwRGBBitCount < 16)
  102. return DDENUMRET_OK;
  103. // Skip any FourCC formats
  104. if (pddpf->dwFourCC != 0)
  105. return DDENUMRET_OK;
  106. // Skip any ARGB 4444 formats (which are best used for pre-authored
  107. // content designed speciafically for an ARGB 4444 format).
  108. if (pddpf->dwRGBAlphaBitMask == 0x0000f000)
  109. return DDENUMRET_OK;
  110. // Make sure current alpha format agrees with requested format type
  111. if ((ptsi->bUseAlpha==TRUE) && !(pddpf->dwFlags&DDPF_ALPHAPIXELS))
  112. return DDENUMRET_OK;
  113. if ((ptsi->bUseAlpha==FALSE) && (pddpf->dwFlags&DDPF_ALPHAPIXELS))
  114. return DDENUMRET_OK;
  115. // Check if we found a good match
  116. if (pddpf->dwRGBBitCount == ptsi->dwDesiredBPP)
  117. {
  118. memcpy(ptsi->pddpf, pddpf, sizeof(DDPIXELFORMAT));
  119. ptsi->bFoundGoodFormat = TRUE;
  120. return DDENUMRET_CANCEL;
  121. }
  122. return DDENUMRET_OK;
  123. }
  124. //-----------------------------------------------------------------------------
  125. // Name: FindTexture()
  126. // Desc: Searches the internal list of textures for a texture specified by
  127. // its name. Returns the structure associated with that texture.
  128. //-----------------------------------------------------------------------------
  129. static TextureContainer* FindTexture(TCHAR* strTextureName)
  130. {
  131. TextureContainer* ptcTexture = g_ptcTextureList;
  132. while(ptcTexture)
  133. {
  134. if (!StrCmpI(strTextureName, ptcTexture->m_strName))
  135. return ptcTexture;
  136. ptcTexture = ptcTexture->m_pNext;
  137. }
  138. return NULL;
  139. }
  140. //-----------------------------------------------------------------------------
  141. // Name: TextureContainer()
  142. // Desc: Constructor for a texture object
  143. //-----------------------------------------------------------------------------
  144. TextureContainer::TextureContainer(TCHAR* strName, DWORD dwStage,
  145. DWORD dwFlags)
  146. {
  147. lstrcpy(m_strName, strName);
  148. m_dwWidth = 0;
  149. m_dwHeight = 0;
  150. m_dwStage = dwStage;
  151. m_dwBPP = 0;
  152. m_dwFlags = dwFlags;
  153. m_bHasAlpha = 0;
  154. m_pddsSurface = NULL;
  155. m_hbmBitmap = NULL;
  156. m_pRGBAData = NULL;
  157. // Add the texture to the head of the global texture list
  158. m_pNext = g_ptcTextureList;
  159. g_ptcTextureList = this;
  160. }
  161. //-----------------------------------------------------------------------------
  162. // Name: ~TextureContainer()
  163. // Desc: Destructs the contents of the texture container
  164. //-----------------------------------------------------------------------------
  165. TextureContainer::~TextureContainer()
  166. {
  167. SAFE_RELEASE(m_pddsSurface);
  168. SAFE_DELETE(m_pRGBAData);
  169. DeleteObject(m_hbmBitmap);
  170. // Remove the texture container from the global list
  171. if (g_ptcTextureList == this)
  172. g_ptcTextureList = m_pNext;
  173. else
  174. {
  175. for(TextureContainer* ptc=g_ptcTextureList; ptc; ptc=ptc->m_pNext)
  176. if (ptc->m_pNext == this)
  177. ptc->m_pNext = m_pNext;
  178. }
  179. }
  180. //-----------------------------------------------------------------------------
  181. // Name: LoadImageData()
  182. // Desc: Loads the texture map's image data
  183. //-----------------------------------------------------------------------------
  184. HRESULT TextureContainer::LoadImageData()
  185. {
  186. HRESULT hr = S_OK;
  187. // Check the executable's resource. If it's there, we're done!
  188. m_hbmBitmap = (HBITMAP)LoadImage(GetModuleHandle(NULL), m_strName,
  189. IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
  190. if (!m_hbmBitmap)
  191. {
  192. TCHAR* strExtension;
  193. TCHAR strPathname[256];
  194. // First check if the file exists in the global texture path
  195. lstrcpy(strPathname, g_strTexturePath);
  196. lstrcat(strPathname, m_strName);
  197. if (!PathFileExists(strPathname))
  198. {
  199. // Then check if the file exists in the DirectX SDK media path
  200. lstrcpy(strPathname, D3DUtil_GetDXSDKMediaPath());
  201. lstrcat(strPathname, m_strName);
  202. }
  203. if (PathFileExists(strPathname))
  204. {
  205. // Get the filename extension
  206. if (NULL == (strExtension = StrChr(m_strName, TEXT('.'))))
  207. return DDERR_UNSUPPORTED;
  208. // Load bitmap files
  209. if (!lstrcmpi(strExtension, TEXT(".bmp")))
  210. return LoadBitmapFile(strPathname);
  211. // Load targa files
  212. if (!lstrcmpi(strExtension, TEXT(".tga")))
  213. return LoadTargaFile(strPathname);
  214. }
  215. else
  216. {
  217. hr = DDERR_NOTFOUND;
  218. }
  219. }
  220. // Can add code here to check for other file formats before failing
  221. return DDERR_UNSUPPORTED;
  222. }
  223. //-----------------------------------------------------------------------------
  224. // Name: LoadBitmapFile()
  225. // Desc: Loads data from a .bmp file, and stores it in a bitmap structure.
  226. //-----------------------------------------------------------------------------
  227. HRESULT TextureContainer::LoadBitmapFile(TCHAR* strPathname)
  228. {
  229. // Try to load the bitmap as a file
  230. m_hbmBitmap = (HBITMAP)LoadImage(NULL, strPathname, IMAGE_BITMAP, 0, 0,
  231. LR_LOADFROMFILE|LR_CREATEDIBSECTION);
  232. if (m_hbmBitmap)
  233. return S_OK;
  234. return DDERR_NOTFOUND;
  235. }
  236. BYTE GetFileByte(HANDLE hFile)
  237. {
  238. BYTE byte = 0;
  239. DWORD cbRead;
  240. if (!ReadFile(hFile, &byte, sizeof(byte), &cbRead, NULL) || (sizeof(byte) != cbRead))
  241. {
  242. return 0;
  243. }
  244. return byte;
  245. }
  246. //-----------------------------------------------------------------------------
  247. // Name: LoadTargaFile()
  248. // Desc: Loads RGBA data from a .tga file, and stores it in allocated memory
  249. // for the specified texture container
  250. //-----------------------------------------------------------------------------
  251. HRESULT TextureContainer::LoadTargaFile(TCHAR* strPathname)
  252. {
  253. HANDLE hFile = CreateFile(strPathname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  254. if (INVALID_HANDLE_VALUE == hFile)
  255. return E_FAIL;
  256. struct TargaHeader
  257. {
  258. BYTE IDLength;
  259. BYTE ColormapType;
  260. BYTE ImageType;
  261. BYTE ColormapSpecification[5];
  262. WORD XOrigin;
  263. WORD YOrigin;
  264. WORD ImageWidth;
  265. WORD ImageHeight;
  266. BYTE PixelDepth;
  267. BYTE ImageDescriptor;
  268. } tga;
  269. DWORD cbRead;
  270. if (ReadFile(hFile, &tga, sizeof(tga), &cbRead, NULL))
  271. {
  272. // Only true color, non-mapped images are supported
  273. if ((0 != tga.ColormapType) ||
  274. (tga.ImageType != 10 && tga.ImageType != 2))
  275. {
  276. CloseHandle(hFile);
  277. return E_FAIL;
  278. }
  279. // Skip the ID field. The first byte of the header is the length of this field
  280. if (tga.IDLength)
  281. {
  282. SetFilePointer(hFile, tga.IDLength, 0, FILE_CURRENT);
  283. }
  284. m_dwWidth = tga.ImageWidth;
  285. m_dwHeight = tga.ImageHeight;
  286. m_dwBPP = tga.PixelDepth;
  287. m_pRGBAData = new DWORD[m_dwWidth*m_dwHeight];
  288. if (m_pRGBAData == NULL)
  289. {
  290. CloseHandle(hFile);
  291. return E_FAIL;
  292. }
  293. for(DWORD y=0; y<m_dwHeight; y++)
  294. {
  295. DWORD dwOffset = y*m_dwWidth;
  296. if (0 == (tga.ImageDescriptor & 0x0010))
  297. dwOffset = (m_dwHeight-y-1)*m_dwWidth;
  298. for(DWORD x=0; x<m_dwWidth; x)
  299. {
  300. if (tga.ImageType == 10)
  301. {
  302. BYTE PacketInfo = GetFileByte(hFile);
  303. WORD PacketType = 0x80 & PacketInfo;
  304. WORD PixelCount = (0x007f & PacketInfo) + 1;
  305. if (PacketType)
  306. {
  307. DWORD b = GetFileByte(hFile);
  308. DWORD g = GetFileByte(hFile);
  309. DWORD r = GetFileByte(hFile);
  310. DWORD a = 0xff;
  311. if (m_dwBPP == 32)
  312. a = GetFileByte(hFile);
  313. while(PixelCount--)
  314. {
  315. m_pRGBAData[dwOffset+x] = (r<<24L)+(g<<16L)+(b<<8L)+(a);
  316. x++;
  317. }
  318. }
  319. else
  320. {
  321. while(PixelCount--)
  322. {
  323. BYTE b = GetFileByte(hFile);
  324. BYTE g = GetFileByte(hFile);
  325. BYTE r = GetFileByte(hFile);
  326. BYTE a = 0xff;
  327. if (m_dwBPP == 32)
  328. a = GetFileByte(hFile);
  329. m_pRGBAData[dwOffset+x] = (r<<24L)+(g<<16L)+(b<<8L)+(a);
  330. x++;
  331. }
  332. }
  333. }
  334. else
  335. {
  336. BYTE b = GetFileByte(hFile);
  337. BYTE g = GetFileByte(hFile);
  338. BYTE r = GetFileByte(hFile);
  339. BYTE a = 0xff;
  340. if (m_dwBPP == 32)
  341. a = GetFileByte(hFile);
  342. m_pRGBAData[dwOffset+x] = (r<<24L)+(g<<16L)+(b<<8L)+(a);
  343. x++;
  344. }
  345. }
  346. }
  347. }
  348. CloseHandle(hFile);
  349. // Check for alpha content
  350. for(DWORD i=0; i<(m_dwWidth*m_dwHeight); i++)
  351. {
  352. if ((m_pRGBAData[i] & 0x000000ff) != 0xff)
  353. {
  354. m_bHasAlpha = TRUE;
  355. break;
  356. }
  357. }
  358. return S_OK;
  359. }
  360. //-----------------------------------------------------------------------------
  361. // Name: Restore()
  362. // Desc: Rebuilds the texture surface using the new device.
  363. //-----------------------------------------------------------------------------
  364. HRESULT TextureContainer::Restore(LPDIRECT3DDEVICE7 pd3dDevice)
  365. {
  366. // Release any previously created objects
  367. SAFE_RELEASE(m_pddsSurface);
  368. // Check params
  369. if (NULL == pd3dDevice)
  370. return DDERR_INVALIDPARAMS;
  371. // Get the device caps
  372. D3DDEVICEDESC7 ddDesc;
  373. if (FAILED(pd3dDevice->GetCaps(&ddDesc)))
  374. return E_FAIL;
  375. // Setup the new surface desc
  376. DDSURFACEDESC2 ddsd;
  377. D3DUtil_InitSurfaceDesc(ddsd);
  378. ddsd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|
  379. DDSD_PIXELFORMAT|DDSD_TEXTURESTAGE;
  380. ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
  381. ddsd.dwTextureStage = m_dwStage;
  382. ddsd.dwWidth = m_dwWidth;
  383. ddsd.dwHeight = m_dwHeight;
  384. // Turn on texture management for hardware devices
  385. if (ddDesc.deviceGUID == IID_IDirect3DHALDevice)
  386. ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;
  387. else if (ddDesc.deviceGUID == IID_IDirect3DTnLHalDevice)
  388. ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;
  389. else
  390. ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
  391. // Adjust width and height to be powers of 2, if the device requires it
  392. if (ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2)
  393. {
  394. for(ddsd.dwWidth=1; m_dwWidth>ddsd.dwWidth; ddsd.dwWidth<<=1);
  395. for(ddsd.dwHeight=1; m_dwHeight>ddsd.dwHeight; ddsd.dwHeight<<=1);
  396. }
  397. // Limit max texture sizes, if the driver can't handle large textures
  398. DWORD dwMaxWidth = ddDesc.dwMaxTextureWidth;
  399. DWORD dwMaxHeight = ddDesc.dwMaxTextureHeight;
  400. ddsd.dwWidth = min(ddsd.dwWidth, (dwMaxWidth ? dwMaxWidth : 256));
  401. ddsd.dwHeight = min(ddsd.dwHeight, (dwMaxHeight ? dwMaxHeight : 256));
  402. // Make the texture square, if the driver requires it
  403. if (ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY)
  404. {
  405. if (ddsd.dwWidth > ddsd.dwHeight) ddsd.dwHeight = ddsd.dwWidth;
  406. else ddsd.dwWidth = ddsd.dwHeight;
  407. }
  408. // Setup the structure to be used for texture enumration.
  409. TEXTURESEARCHINFO tsi;
  410. tsi.bFoundGoodFormat = FALSE;
  411. tsi.pddpf = &ddsd.ddpfPixelFormat;
  412. tsi.dwDesiredBPP = m_dwBPP;
  413. tsi.bUsePalette = (m_dwBPP <= 8);
  414. tsi.bUseAlpha = m_bHasAlpha;
  415. if (m_dwFlags & D3DTEXTR_16BITSPERPIXEL)
  416. tsi.dwDesiredBPP = 16;
  417. else if (m_dwFlags & D3DTEXTR_32BITSPERPIXEL)
  418. tsi.dwDesiredBPP = 32;
  419. if (m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK))
  420. {
  421. if (tsi.bUsePalette)
  422. {
  423. if (ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_ALPHAPALETTE)
  424. {
  425. tsi.bUseAlpha = TRUE;
  426. tsi.bUsePalette = TRUE;
  427. }
  428. else
  429. {
  430. tsi.bUseAlpha = TRUE;
  431. tsi.bUsePalette = FALSE;
  432. }
  433. }
  434. }
  435. // Enumerate the texture formats, and find the closest device-supported
  436. // texture pixel format
  437. pd3dDevice->EnumTextureFormats(TextureSearchCallback, &tsi);
  438. // If we couldn't find a format, let's try a default format
  439. if (FALSE == tsi.bFoundGoodFormat)
  440. {
  441. tsi.bUsePalette = FALSE;
  442. tsi.dwDesiredBPP = 16;
  443. pd3dDevice->EnumTextureFormats(TextureSearchCallback, &tsi);
  444. // If we still fail, we cannot create this texture
  445. if (FALSE == tsi.bFoundGoodFormat)
  446. return E_FAIL;
  447. }
  448. // Get the DirectDraw interface for creating surfaces
  449. LPDIRECTDRAW7 pDD;
  450. LPDIRECTDRAWSURFACE7 pddsRender;
  451. pd3dDevice->GetRenderTarget(&pddsRender);
  452. pddsRender->GetDDInterface((VOID**)&pDD);
  453. pddsRender->Release();
  454. // Create a new surface for the texture
  455. HRESULT hr = pDD->CreateSurface(&ddsd, &m_pddsSurface, NULL);
  456. // Done with DDraw
  457. pDD->Release();
  458. if (FAILED(hr))
  459. return hr;
  460. // For bitmap-based textures, copy the bitmap image.
  461. if (m_hbmBitmap)
  462. return CopyBitmapToSurface();
  463. if (m_pRGBAData)
  464. return CopyRGBADataToSurface();
  465. // At this point, code can be added to handle other file formats (such as
  466. // .dds files, .jpg files, etc.).
  467. return S_OK;
  468. }
  469. //-----------------------------------------------------------------------------
  470. // Name: CopyBitmapToSurface()
  471. // Desc: Copies the image of a bitmap into a surface
  472. //-----------------------------------------------------------------------------
  473. HRESULT TextureContainer::CopyBitmapToSurface()
  474. {
  475. // Get a DDraw object to create a temporary surface
  476. LPDIRECTDRAW7 pDD;
  477. m_pddsSurface->GetDDInterface((VOID**)&pDD);
  478. // Get the bitmap structure (to extract width, height, and bpp)
  479. BITMAP bm;
  480. GetObject(m_hbmBitmap, sizeof(BITMAP), &bm);
  481. // Setup the new surface desc
  482. DDSURFACEDESC2 ddsd;
  483. ddsd.dwSize = sizeof(ddsd);
  484. m_pddsSurface->GetSurfaceDesc(&ddsd);
  485. ddsd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|
  486. DDSD_TEXTURESTAGE;
  487. ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE|DDSCAPS_SYSTEMMEMORY;
  488. ddsd.ddsCaps.dwCaps2 = 0L;
  489. ddsd.dwWidth = bm.bmWidth;
  490. ddsd.dwHeight = bm.bmHeight;
  491. // Create a new surface for the texture
  492. LPDIRECTDRAWSURFACE7 pddsTempSurface;
  493. HRESULT hr;
  494. if (FAILED(hr = pDD->CreateSurface(&ddsd, &pddsTempSurface, NULL)))
  495. {
  496. pDD->Release();
  497. return hr;
  498. }
  499. // Get a DC for the bitmap
  500. HDC hdcBitmap = CreateCompatibleDC(NULL);
  501. if (NULL == hdcBitmap)
  502. {
  503. pddsTempSurface->Release();
  504. pDD->Release();
  505. return hr;
  506. }
  507. SelectObject(hdcBitmap, m_hbmBitmap);
  508. // Handle palettized textures. Need to attach a palette
  509. if (ddsd.ddpfPixelFormat.dwRGBBitCount == 8)
  510. {
  511. LPDIRECTDRAWPALETTE pPalette;
  512. DWORD dwPaletteFlags = DDPCAPS_8BIT|DDPCAPS_ALLOW256;
  513. DWORD pe[256];
  514. WORD wNumColors = (WORD) GetDIBColorTable(hdcBitmap, 0, 256, (RGBQUAD*)pe);
  515. // Create the color table
  516. for(WORD i=0; i<wNumColors; i++)
  517. {
  518. pe[i] = RGB(GetBValue(pe[i]), GetGValue(pe[i]), GetRValue(pe[i]));
  519. // Handle textures with transparent pixels
  520. if (m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK))
  521. {
  522. // Set alpha for opaque pixels
  523. if (m_dwFlags & D3DTEXTR_TRANSPARENTBLACK)
  524. {
  525. if (pe[i] != 0x00000000)
  526. pe[i] |= 0xff000000;
  527. }
  528. else if (m_dwFlags & D3DTEXTR_TRANSPARENTWHITE)
  529. {
  530. if (pe[i] != 0x00ffffff)
  531. pe[i] |= 0xff000000;
  532. }
  533. }
  534. }
  535. // Add DDPCAPS_ALPHA flag for textures with transparent pixels
  536. if (m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK))
  537. dwPaletteFlags |= DDPCAPS_ALPHA;
  538. // Create & attach a palette
  539. pDD->CreatePalette(dwPaletteFlags, (PALETTEENTRY*)pe, &pPalette, NULL);
  540. pddsTempSurface->SetPalette(pPalette);
  541. m_pddsSurface->SetPalette(pPalette);
  542. SAFE_RELEASE(pPalette);
  543. }
  544. // Copy the bitmap image to the surface.
  545. HDC hdcSurface;
  546. if (SUCCEEDED(pddsTempSurface->GetDC(&hdcSurface)))
  547. {
  548. BitBlt(hdcSurface, 0, 0, bm.bmWidth, bm.bmHeight, hdcBitmap, 0, 0,
  549. SRCCOPY);
  550. pddsTempSurface->ReleaseDC(hdcSurface);
  551. }
  552. DeleteDC(hdcBitmap);
  553. // Copy the temp surface to the real texture surface
  554. m_pddsSurface->Blt(NULL, pddsTempSurface, NULL, DDBLT_WAIT, NULL);
  555. // Done with the temp surface
  556. pddsTempSurface->Release();
  557. // For textures with real alpha (not palettized), set transparent bits
  558. if (ddsd.ddpfPixelFormat.dwRGBAlphaBitMask)
  559. {
  560. if (m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK))
  561. {
  562. // Lock the texture surface
  563. DDSURFACEDESC2 ddsd;
  564. ddsd.dwSize = sizeof(ddsd);
  565. while(m_pddsSurface->Lock(NULL, &ddsd, 0, NULL) ==
  566. DDERR_WASSTILLDRAWING);
  567. DWORD dwAlphaMask = ddsd.ddpfPixelFormat.dwRGBAlphaBitMask;
  568. DWORD dwRGBMask = (ddsd.ddpfPixelFormat.dwRBitMask |
  569. ddsd.ddpfPixelFormat.dwGBitMask |
  570. ddsd.ddpfPixelFormat.dwBBitMask);
  571. DWORD dwColorkey = 0x00000000; // Colorkey on black
  572. if (m_dwFlags & D3DTEXTR_TRANSPARENTWHITE)
  573. dwColorkey = dwRGBMask; // Colorkey on white
  574. // Add an opaque alpha value to each non-colorkeyed pixel
  575. for(DWORD y=0; y<ddsd.dwHeight; y++)
  576. {
  577. WORD* p16 = (WORD*)((BYTE*)ddsd.lpSurface + y*ddsd.lPitch);
  578. DWORD* p32 = (DWORD*)((BYTE*)ddsd.lpSurface + y*ddsd.lPitch);
  579. for(DWORD x=0; x<ddsd.dwWidth; x++)
  580. {
  581. if (ddsd.ddpfPixelFormat.dwRGBBitCount == 16)
  582. {
  583. if ((*p16 &= dwRGBMask) != dwColorkey)
  584. *p16 |= dwAlphaMask;
  585. p16++;
  586. }
  587. if (ddsd.ddpfPixelFormat.dwRGBBitCount == 32)
  588. {
  589. if ((*p32 &= dwRGBMask) != dwColorkey)
  590. *p32 |= dwAlphaMask;
  591. p32++;
  592. }
  593. }
  594. }
  595. m_pddsSurface->Unlock(NULL);
  596. }
  597. }
  598. pDD->Release();
  599. return S_OK;;
  600. }
  601. //-----------------------------------------------------------------------------
  602. // Name: CopyRGBADataToSurface()
  603. // Desc: Invalidates the current texture objects and rebuilds new ones
  604. // using the new device.
  605. //-----------------------------------------------------------------------------
  606. HRESULT TextureContainer::CopyRGBADataToSurface()
  607. {
  608. // Get a DDraw object to create a temporary surface
  609. LPDIRECTDRAW7 pDD;
  610. m_pddsSurface->GetDDInterface((VOID**)&pDD);
  611. // Setup the new surface desc
  612. DDSURFACEDESC2 ddsd;
  613. ddsd.dwSize = sizeof(ddsd);
  614. m_pddsSurface->GetSurfaceDesc(&ddsd);
  615. ddsd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|
  616. DDSD_TEXTURESTAGE;
  617. ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE|DDSCAPS_SYSTEMMEMORY;
  618. ddsd.ddsCaps.dwCaps2 = 0L;
  619. ddsd.dwWidth = m_dwWidth;
  620. ddsd.dwHeight = m_dwHeight;
  621. // Create a new surface for the texture
  622. LPDIRECTDRAWSURFACE7 pddsTempSurface;
  623. HRESULT hr;
  624. if (FAILED(hr = pDD->CreateSurface(&ddsd, &pddsTempSurface, NULL)))
  625. {
  626. pDD->Release();
  627. return NULL;
  628. }
  629. while(pddsTempSurface->Lock(NULL, &ddsd, 0, 0) == DDERR_WASSTILLDRAWING);
  630. DWORD lPitch = ddsd.lPitch;
  631. BYTE* pBytes = (BYTE*)ddsd.lpSurface;
  632. DWORD dwRMask = ddsd.ddpfPixelFormat.dwRBitMask;
  633. DWORD dwGMask = ddsd.ddpfPixelFormat.dwGBitMask;
  634. DWORD dwBMask = ddsd.ddpfPixelFormat.dwBBitMask;
  635. DWORD dwAMask = ddsd.ddpfPixelFormat.dwRGBAlphaBitMask;
  636. DWORD dwRShiftL = 8, dwRShiftR = 0;
  637. DWORD dwGShiftL = 8, dwGShiftR = 0;
  638. DWORD dwBShiftL = 8, dwBShiftR = 0;
  639. DWORD dwAShiftL = 8, dwAShiftR = 0;
  640. DWORD dwMask;
  641. for(dwMask=dwRMask; dwMask && !(dwMask&0x1); dwMask>>=1) dwRShiftR++;
  642. for(; dwMask; dwMask>>=1) dwRShiftL--;
  643. for(dwMask=dwGMask; dwMask && !(dwMask&0x1); dwMask>>=1) dwGShiftR++;
  644. for(; dwMask; dwMask>>=1) dwGShiftL--;
  645. for(dwMask=dwBMask; dwMask && !(dwMask&0x1); dwMask>>=1) dwBShiftR++;
  646. for(; dwMask; dwMask>>=1) dwBShiftL--;
  647. for(dwMask=dwAMask; dwMask && !(dwMask&0x1); dwMask>>=1) dwAShiftR++;
  648. for(; dwMask; dwMask>>=1) dwAShiftL--;
  649. for(DWORD y=0; y<ddsd.dwHeight; y++)
  650. {
  651. DWORD* pDstData32 = (DWORD*)pBytes;
  652. WORD* pDstData16 = (WORD*)pBytes;
  653. for(DWORD x=0; x<ddsd.dwWidth; x++)
  654. {
  655. DWORD dwPixel = m_pRGBAData[y*ddsd.dwWidth+x];
  656. BYTE r = (BYTE)((dwPixel>>24)&0x000000ff);
  657. BYTE g = (BYTE)((dwPixel>>16)&0x000000ff);
  658. BYTE b = (BYTE)((dwPixel>> 8)&0x000000ff);
  659. BYTE a = (BYTE)((dwPixel>> 0)&0x000000ff);
  660. DWORD dr = ((r>>(dwRShiftL))<<dwRShiftR)&dwRMask;
  661. DWORD dg = ((g>>(dwGShiftL))<<dwGShiftR)&dwGMask;
  662. DWORD db = ((b>>(dwBShiftL))<<dwBShiftR)&dwBMask;
  663. DWORD da = ((a>>(dwAShiftL))<<dwAShiftR)&dwAMask;
  664. if (32 == ddsd.ddpfPixelFormat.dwRGBBitCount)
  665. pDstData32[x] = (DWORD)(dr+dg+db+da);
  666. else
  667. pDstData16[x] = (WORD)(dr+dg+db+da);
  668. }
  669. pBytes += ddsd.lPitch;
  670. }
  671. pddsTempSurface->Unlock(0);
  672. // Copy the temp surface to the real texture surface
  673. m_pddsSurface->Blt(NULL, pddsTempSurface, NULL, DDBLT_WAIT, NULL);
  674. // Done with the temp objects
  675. pddsTempSurface->Release();
  676. pDD->Release();
  677. return S_OK;
  678. }
  679. //-----------------------------------------------------------------------------
  680. // Name: D3DTextr_SetTexturePath()
  681. // Desc: Enumeration callback routine to find a best-matching texture format.
  682. //-----------------------------------------------------------------------------
  683. VOID D3DTextr_SetTexturePath(TCHAR* strTexturePath)
  684. {
  685. if (NULL == strTexturePath)
  686. strTexturePath[0] = 0;
  687. lstrcpy(g_strTexturePath, strTexturePath);
  688. }
  689. //-----------------------------------------------------------------------------
  690. // Name: D3DTextr_CreateTextureFromFile()
  691. // Desc: Is passed a filename and creates a local Bitmap from that file.
  692. // The texture can not be used until it is restored, however.
  693. //-----------------------------------------------------------------------------
  694. HRESULT D3DTextr_CreateTextureFromFile(TCHAR* strName, DWORD dwStage,
  695. DWORD dwFlags)
  696. {
  697. // Check parameters
  698. if (NULL == strName)
  699. return E_INVALIDARG;
  700. // Check first to see if the texture is already loaded
  701. if (NULL != FindTexture(strName))
  702. return S_OK;
  703. // Allocate and add the texture to the linked list of textures;
  704. TextureContainer* ptcTexture = new TextureContainer(strName, dwStage,
  705. dwFlags);
  706. if (NULL == ptcTexture)
  707. return E_OUTOFMEMORY;
  708. // Create a bitmap and load the texture file into it,
  709. if (FAILED(ptcTexture->LoadImageData()))
  710. {
  711. delete ptcTexture;
  712. return E_FAIL;
  713. }
  714. // Save the image's dimensions
  715. if (ptcTexture->m_hbmBitmap)
  716. {
  717. BITMAP bm;
  718. GetObject(ptcTexture->m_hbmBitmap, sizeof(BITMAP), &bm);
  719. ptcTexture->m_dwWidth = (DWORD)bm.bmWidth;
  720. ptcTexture->m_dwHeight = (DWORD)bm.bmHeight;
  721. ptcTexture->m_dwBPP = (DWORD)bm.bmBitsPixel;
  722. }
  723. return S_OK;
  724. }
  725. //-----------------------------------------------------------------------------
  726. // Name: D3DTextr_CreateEmptyTexture()
  727. // Desc: Creates an empty texture.
  728. //-----------------------------------------------------------------------------
  729. HRESULT D3DTextr_CreateEmptyTexture(TCHAR* strName, DWORD dwWidth,
  730. DWORD dwHeight, DWORD dwStage,
  731. DWORD dwFlags)
  732. {
  733. // Check parameters
  734. if (NULL == strName)
  735. return E_INVALIDARG;
  736. // Check first to see if the texture is already loaded
  737. if (NULL != FindTexture(strName))
  738. return E_FAIL;
  739. // Allocate and add the texture to the linked list of textures;
  740. TextureContainer* ptcTexture = new TextureContainer(strName, dwStage,
  741. dwFlags);
  742. if (NULL == ptcTexture)
  743. return E_OUTOFMEMORY;
  744. // Save dimensions
  745. ptcTexture->m_dwWidth = dwWidth;
  746. ptcTexture->m_dwHeight = dwHeight;
  747. ptcTexture->m_dwBPP = 16;
  748. if (ptcTexture->m_dwFlags & D3DTEXTR_32BITSPERPIXEL)
  749. ptcTexture->m_dwBPP = 32;
  750. // Save alpha usage flag
  751. if (dwFlags & D3DTEXTR_CREATEWITHALPHA)
  752. ptcTexture->m_bHasAlpha = TRUE;
  753. return S_OK;
  754. }
  755. //-----------------------------------------------------------------------------
  756. // Name: D3DTextr_Restore()
  757. // Desc: Invalidates the current texture objects and rebuilds new ones
  758. // using the new device.
  759. //-----------------------------------------------------------------------------
  760. HRESULT D3DTextr_Restore(TCHAR* strName, LPDIRECT3DDEVICE7 pd3dDevice)
  761. {
  762. TextureContainer* ptcTexture = FindTexture(strName);
  763. if (NULL == ptcTexture)
  764. return DDERR_NOTFOUND;
  765. // Restore the texture (this recreates the new surface for this device).
  766. return ptcTexture->Restore(pd3dDevice);
  767. }
  768. //-----------------------------------------------------------------------------
  769. // Name: D3DTextr_RestoreAllTextures()
  770. // Desc: This function is called when a mode is changed. It updates all
  771. // texture objects to be valid with the new device.
  772. //-----------------------------------------------------------------------------
  773. HRESULT D3DTextr_RestoreAllTextures(LPDIRECT3DDEVICE7 pd3dDevice)
  774. {
  775. TextureContainer* ptcTexture = g_ptcTextureList;
  776. while(ptcTexture)
  777. {
  778. D3DTextr_Restore(ptcTexture->m_strName, pd3dDevice);
  779. ptcTexture = ptcTexture->m_pNext;
  780. }
  781. return S_OK;
  782. }
  783. //-----------------------------------------------------------------------------
  784. // Name: D3DTextr_Invalidate()
  785. // Desc: Used to bump a texture out of (video) memory, this function
  786. // actually destroys the d3dtexture and ddsurface of the texture
  787. //-----------------------------------------------------------------------------
  788. HRESULT D3DTextr_Invalidate(TCHAR* strName)
  789. {
  790. TextureContainer* ptcTexture = FindTexture(strName);
  791. if (NULL == ptcTexture)
  792. return DDERR_NOTFOUND;
  793. SAFE_RELEASE(ptcTexture->m_pddsSurface);
  794. return S_OK;
  795. }
  796. //-----------------------------------------------------------------------------
  797. // Name: D3DTextr_InvalidateAllTextures()
  798. // Desc: This function is called when a mode is changed. It invalidates
  799. // all texture objects so their device can be safely released.
  800. //-----------------------------------------------------------------------------
  801. HRESULT D3DTextr_InvalidateAllTextures()
  802. {
  803. TextureContainer* ptcTexture = g_ptcTextureList;
  804. while(ptcTexture)
  805. {
  806. SAFE_RELEASE(ptcTexture->m_pddsSurface);
  807. ptcTexture = ptcTexture->m_pNext;
  808. }
  809. return S_OK;
  810. }
  811. //-----------------------------------------------------------------------------
  812. // Name: D3DTextr_DestroyTexture()
  813. // Desc: Frees the resources for the specified texture container
  814. //-----------------------------------------------------------------------------
  815. HRESULT D3DTextr_DestroyTexture(TCHAR* strName)
  816. {
  817. TextureContainer* ptcTexture = FindTexture(strName);
  818. SAFE_DELETE(ptcTexture);
  819. return S_OK;
  820. }
  821. //-----------------------------------------------------------------------------
  822. // Name: D3DTextr_GetSurface()
  823. // Desc: Returns a pointer to a d3dSurface from the name of the texture
  824. //-----------------------------------------------------------------------------
  825. LPDIRECTDRAWSURFACE7 D3DTextr_GetSurface(TCHAR* strName)
  826. {
  827. TextureContainer* ptcTexture = FindTexture(strName);
  828. return ptcTexture ? ptcTexture->m_pddsSurface : NULL;
  829. }