landscape fixes, implemented gr_check_mode
[btb/d2x.git] / arch / win32 / texture.cpp
1 #include "pch.h"
2 #include "texture.h"
3
4 #include "d3dframe.h"
5 extern CD3DFramework* g_pFramework;
6
7 ////////////////////////////////////////////////////////////////////////////
8
9 BOOL CTexture::s_bLocked = FALSE;
10 DDSURFACEDESC2 CTexture::s_ddsd;
11
12
13 HRESULT CTexture::Initialize (BYTE *rgbSource, ULONG ulWidth, ULONG ulHeight, ULONG ulPitch)
14 {
15         m_rgbSource = rgbSource;
16         m_ulWidthSource = ulWidth;
17         m_ulHeightSource = ulHeight;
18         m_ulPitchSource = ulPitch;
19
20         return S_OK;
21 }
22
23 HRESULT CTexture::Allocate (CPaletteInfo *ppi)
24 {
25         HRESULT hr;
26
27         ASSERT (m_spddsMemory == NULL);
28
29         if (ppi->IsPow2 ())
30         {
31                 m_ulWidth = 1;
32                 while (m_ulWidth < m_ulWidthSource)
33                         m_ulWidth *= 2;
34                 
35                 m_ulHeight = 1;
36                 while (m_ulHeight < m_ulHeightSource)
37                         m_ulHeight *= 2;
38         }
39         else
40         {
41                 m_ulWidth = m_ulWidthSource;
42                 m_ulHeight = m_ulHeightSource;
43         }
44
45         if (ppi->IsSquare ())
46         {
47                 if (m_ulHeight > m_ulWidth)
48                 {
49                         m_ulWidth = m_ulHeight;
50                 }
51                 else
52                 {
53                         m_ulHeight = m_ulWidth;
54                 }
55         }
56
57         m_flAdjX = (D3DVALUE) m_ulWidthSource / (D3DVALUE) m_ulWidth;
58         m_flAdjY = (D3DVALUE) m_ulHeightSource / (D3DVALUE) m_ulHeight;
59
60         DDSURFACEDESC2 ddsd;
61         ZeroMemory (&ddsd, sizeof (ddsd));
62         ddsd.dwSize = sizeof (ddsd);
63         ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
64         ddsd.dwWidth = m_ulWidth;
65         ddsd.dwHeight = m_ulHeight;
66         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
67         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;
68         ppi->GetPixelFormat (&ddsd.ddpfPixelFormat);
69
70         hr = g_pFramework->GetDirectDraw ()->CreateSurface(&ddsd, &m_spddsMemory, NULL);
71         ASSERT (SUCCEEDED (hr));
72         if (FAILED (hr))
73                 return hr;
74
75         ASSERT (m_spddsMemory != NULL);
76
77         m_spddtMemory = m_spddsMemory;
78
79         DirtyMemory ();
80
81         DDCOLORKEY ddck;
82         if (ppi->IsIndexed ())
83         {
84                 ddck.dwColorSpaceLowValue = 255;
85                 ddck.dwColorSpaceHighValue = 255;
86         }
87         else
88         {
89                 ddck.dwColorSpaceLowValue = 0;
90                 ddck.dwColorSpaceHighValue = 0;
91         }
92         hr = m_spddsMemory->SetColorKey (DDCKEY_SRCBLT, &ddck);
93         ASSERT (SUCCEEDED (hr));
94
95         if (ppi->GetPalette () != NULL)
96         {
97                 hr = m_spddsMemory->SetPalette (ppi->GetPalette ());
98                 ASSERT (SUCCEEDED (hr));
99         }
100
101         return hr;
102 }
103
104 HRESULT CTexture::Free (void)
105 {
106         HRESULT hr = S_OK;
107
108         m_spddtMemory = m_spddsMemory = NULL;
109
110         m_ulWidth = 0;
111         m_ulHeight = 0;
112
113         return hr;
114 }
115
116 HRESULT CTexture::Lock (void)
117 {
118         HRESULT hr;
119         if (!s_bLocked)
120         {
121                 s_bLocked = TRUE;
122
123                 s_ddsd.dwSize = sizeof (s_ddsd);
124                 hr = m_spddsMemory->Lock (
125                         NULL,
126                         &s_ddsd,
127 #ifndef NDEBUG
128                         DDLOCK_NOSYSLOCK |
129 #endif
130                         DDLOCK_WAIT,
131                         NULL);
132                 ASSERT (SUCCEEDED (hr));
133         }
134         else
135         {
136                 // already locked
137                 hr = E_FAIL;
138                 ASSERT (FALSE);
139         }
140         return hr;
141 }
142
143 HRESULT CTexture::Unlock (void)
144 {
145         HRESULT hr;
146         if (s_bLocked)
147         {
148                 hr = m_spddsMemory->Unlock (NULL);
149                 ASSERT (SUCCEEDED (hr));
150
151                 s_bLocked = FALSE;
152         }
153         else
154         {
155                 // not locked
156                 hr = E_FAIL;
157                 ASSERT (FALSE);
158         }
159         return hr;
160 }
161
162 void CTexture::PlotPixel (ULONG ulX, ULONG ulY, BYTE b)
163 {
164         ASSERT (ulX <= m_ulWidth);
165         ASSERT (ulY <= m_ulHeight);
166
167         ASSERT (s_bLocked);
168         ASSERT (s_ddsd.lpSurface != NULL);
169
170         switch (s_ddsd.ddpfPixelFormat.dwRGBBitCount)
171         {
172                 case 8:
173                 {
174                         * (((LPBYTE) s_ddsd.lpSurface) + ulX + ulY * s_ddsd.lPitch) = b;
175
176                         break;
177                 }
178                 case 16:
179                 {
180                         WORD w;
181                         if (!(m_bTransparent && b == 255))
182                         {
183                                 w = m_ppi->Read16 (b);
184                         }
185                         else
186                         {
187                                 w = 0;
188                         }
189                         * (WORD *) (((LPBYTE) s_ddsd.lpSurface) + ulX * 2 + ulY * s_ddsd.lPitch) = w;
190                         break;
191                 }
192                 
193                 default:
194                 {
195                         ASSERT (FALSE);
196                         break;
197                 }
198         }
199 }
200
201 void CTexture::SetBitmapData (BYTE *rgb, BOOL bRle)
202 {
203         m_rgbSource = rgb;
204         m_bRle = bRle;
205         DirtyMemory ();
206 }
207
208 void CTexture::CopyFromSource (void)
209 {
210         if (SUCCEEDED (Lock ()))
211         {
212                 if (m_bRle)
213                 {
214                         PBYTE pbLine = m_rgbSource + m_ulHeightSource + 4;;
215                         for (ULONG y = 0; y < m_ulHeightSource; y ++)
216                         {
217                                 ULONG x = 0;
218                                 PBYTE pbSrc = pbLine;
219
220                                 while (1)
221                                 {
222                                         const BYTE RLE_CODE = 0xE0;
223                                         BYTE b = *pbSrc++;
224                                         if ((b & RLE_CODE) != RLE_CODE)
225                                         {
226                                                 PlotPixel (x++, y, b);
227                                         }
228                                         else
229                                         {
230                                                 BYTE cb = b & (~RLE_CODE);
231                                                 if (cb == 0)
232                                                         break;
233
234                                                 b = *pbSrc++;
235                                                 while (cb--)
236                                                         PlotPixel (x++, y, b);
237                                         }
238                                 }
239                                 ASSERT (x <= m_ulWidthSource);
240
241                                 pbLine += m_rgbSource [y + 4];
242                         }
243                 }
244                 else
245                 {
246                         LPBYTE lpbDest = (LPBYTE) s_ddsd.lpSurface;
247                         LPBYTE lpbSrc = m_rgbSource;
248
249                         switch (s_ddsd.ddpfPixelFormat.dwRGBBitCount)
250                         {
251                                 case 8:
252                                 {
253                                         for (ULONG y = m_ulHeightSource; y != 0; y--)
254                                         {
255                                                 memcpy (lpbDest, lpbSrc, m_ulPitchSource);
256                                                 lpbDest += s_ddsd.lPitch;
257                                                 lpbSrc += m_ulPitchSource;
258                                         }
259                                         break;
260                                 }
261                                 case 16:
262                                 {
263                                         for (ULONG y = m_ulHeightSource; y != 0; y--)
264                                         {
265                                                 LPBYTE lpbLineSrc = lpbSrc;
266                                                 LPWORD lpwLineDest = (LPWORD) lpbDest;
267
268                                                 if (m_bTransparent)
269                                                 {
270                                                         for (ULONG x = m_ulWidthSource; x != 0; x--)
271                                                         {
272                                                                 BYTE b = *lpbLineSrc++;
273                                                                 *lpwLineDest++ = (b == 255) ? 0 : m_ppi->Read16 (b);
274                                                         }
275                                                 }
276                                                 else
277                                                 {
278                                                         for (ULONG x = m_ulWidthSource; x != 0; x--)
279                                                         {
280                                                                 *lpwLineDest++ = m_ppi->Read16 (*lpbLineSrc++);
281                                                         }
282                                                 }
283                                                 lpbDest += s_ddsd.lPitch;
284                                                 lpbSrc += m_ulPitchSource;
285                                         }
286                                         break;
287                                 }
288                                 
289                                 default:
290                                 {
291                                         ASSERT (FALSE);
292                                         break;
293                                 }
294                         }
295                 }
296                 Unlock ();
297         }
298         else
299         {
300                 ASSERT (FALSE);
301         }
302 }
303
304 HRESULT CTexture::CleanMemory (void)
305 {
306         CopyFromSource ();
307         m_bDirtyMemory = FALSE;
308         return S_OK;
309 }
310
311 IDirect3DTexture2 *CTexture::GetTexture ()
312 {
313         if (m_bDirtyMemory)
314         {
315                 CleanMemory ();
316         }
317
318         return m_spddtMemory;
319 }
320
321 ////////////////////////////////////////////////////////////////////////////
322
323 struct FindTextureData
324 {
325     DWORD           bpp;        // we want a texture format of this bpp
326     DDPIXELFORMAT   ddpf;       // place the format here
327 };
328
329
330 HRESULT CALLBACK FindTextureCallback(LPDDPIXELFORMAT pddpf, LPVOID lParam)
331 {
332     FindTextureData * FindData = (FindTextureData *)lParam;
333         
334     //
335     // we use GetDC/BitBlt to init textures so we only
336     // want to use formats that GetDC will support.
337     //
338     if (pddpf->dwFlags & (DDPF_ALPHA|DDPF_ALPHAPIXELS))
339         return DDENUMRET_OK;
340
341 /*
342     if (pddpf->dwRGBBitCount == 16)
343     {
344         FindData->ddpf = ddpf;
345     }
346         
347     return DDENUMRET_OK;
348 */
349
350         
351 //      if (!(pddpf->dwFlags & DDPF_ALPHAPIXELS))
352 //              return DDENUMRET_OK;
353
354     if (pddpf->dwRGBBitCount < 8)
355         return DDENUMRET_OK;
356
357     if (pddpf->dwRGBBitCount == 8 && !(pddpf->dwFlags & DDPF_PALETTEINDEXED8))
358         return DDENUMRET_OK;
359         
360     if (pddpf->dwRGBBitCount > 8 && !(pddpf->dwFlags & DDPF_RGB))
361         return DDENUMRET_OK;
362
363     //
364     // keep the texture format that is nearest to the bitmap we have
365     //
366     if (FindData->ddpf.dwRGBBitCount == 0 ||
367                 (pddpf->dwRGBBitCount >= FindData->bpp && pddpf->dwRGBBitCount <= FindData->ddpf.dwRGBBitCount) //&&
368                 //(pddpf->dwAlphaBitDepth != 0 && pddpf->dwAlphaBitDepth > FindData->ddpf.dwAlphaBitDepth) // ALPHA BIT DEPTHS ARE REVERSED!!!!
369                 )
370     {
371         FindData->ddpf = *pddpf;
372     }
373         
374     return DDENUMRET_OK;
375 }
376
377 void ChooseTextureFormat(LPDIRECT3DDEVICE3 Device, DWORD bpp, DDPIXELFORMAT *pddpf)
378 {
379         HRESULT hr;
380     FindTextureData FindData;
381         ZeroMemory(&FindData, sizeof(FindData));
382     FindData.bpp = bpp;
383         hr = Device->EnumTextureFormats(FindTextureCallback, (LPVOID)&FindData);
384     ASSERT(hr == S_OK);
385     *pddpf = FindData.ddpf;
386 }
387
388 HRESULT CPaletteInfo::Initialize ()
389 {
390         m_spddpPalette = NULL;
391
392         //
393         // find the best texture format to use.
394         //
395         ChooseTextureFormat (g_pFramework->GetD3DDevice (), 8, &m_ddpfPixelFormat);
396         
397         m_cshftR = GetShift (m_mskR = m_ddpfPixelFormat.dwRBitMask);
398         m_cshftG = GetShift (m_mskG = m_ddpfPixelFormat.dwGBitMask);
399         m_cshftB = GetShift (m_mskB = m_ddpfPixelFormat.dwBBitMask);
400
401         HRESULT hr;
402
403         D3DDEVICEDESC descHAL, descHEL;
404         descHAL.dwSize = descHEL.dwSize = sizeof (descHAL);
405         hr = g_pFramework->GetD3DDevice ()->GetCaps (&descHAL, &descHEL);
406         ASSERT (SUCCEEDED (hr));
407
408         if (!descHAL.dwFlags) {
409                 m_bPow2 = (descHEL.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) != 0;
410                 m_bSquare = (descHEL.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY) != 0;
411         } else {
412                 m_bPow2 = (descHAL.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) != 0;
413                 m_bSquare = (descHAL.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY) != 0;
414         }
415
416         if (IsIndexed ())
417         {
418                 hr = g_pFramework->GetDirectDraw ()->CreatePalette (DDPCAPS_8BIT | DDPCAPS_ALLOW256, m_rgpe, &m_spddpPalette, NULL);
419                 ASSERT (SUCCEEDED (hr));
420         }
421
422         return S_OK;
423 }
424
425 HRESULT CPaletteInfo::Uninitialize ()
426 {
427         m_spddpPalette = NULL;  // smart pointer release
428
429         return S_OK;
430 }
431
432 void CPaletteInfo::SetPaletteEntries (PALETTEENTRY rgpe [256])
433 {
434         // okay, we don't really need to cache the palette values
435         // we could implement ReadPalette by individual Getentries calls...
436         memcpy (m_rgpe, rgpe, sizeof (m_rgpe));
437
438         if (m_spddpPalette != NULL)
439         {
440                 HRESULT hr = m_spddpPalette->SetEntries (0, 0, 256,     m_rgpe);
441                 ASSERT (SUCCEEDED (hr));
442         }
443 }
444
445 void CPaletteInfo::GetPaletteEntries (PALETTEENTRY rgpe [256])
446 {
447         if (m_spddpPalette != NULL)
448         {
449                 HRESULT hr = m_spddpPalette->GetEntries (0, 0, 256,     m_rgpe);
450                 ASSERT (SUCCEEDED (hr));
451         }
452 }
453
454 ////////////////////////////////////////////////////////////////
455 CPaletteInfo *CTexture::m_ppi;
456
457 HRESULT CTextureSet::Initialize ()
458 {
459         HRESULT hr;
460                 
461         hr = m_pi.Initialize ();
462         ASSERT (SUCCEEDED (hr));
463
464         CTexture::m_ppi = &m_pi;
465
466         for (TEXTURE_SET::iterator iter = m_setTextures.begin ();
467                 iter != m_setTextures.end ();
468                 iter ++)
469         {
470                 (*iter)->Allocate (&m_pi);
471         }
472
473         return hr;
474 }
475
476 HRESULT CTextureSet::Uninitialize ()
477 {
478         for (TEXTURE_SET::iterator iter = m_setTextures.begin ();
479                 iter != m_setTextures.end ();
480                 iter ++)
481         {
482                 (*iter)->Free ();
483         }
484
485         m_pi.Uninitialize ();
486
487         return S_OK;
488 }
489
490 CTexture *CTextureSet::CreateTexture (BYTE *rgbSource, ULONG dx, ULONG dy, ULONG ulPitch)
491 {
492         CTexture *pTexture = new CTexture;
493
494         pTexture->Initialize (rgbSource, dx, dy, ulPitch);
495         pTexture->Allocate (&m_pi);
496
497         m_setTextures.insert (pTexture);
498
499         return pTexture;
500 }
501
502 void CTextureSet::FreeTexture (CTexture *pTexture)
503 {
504         m_setTextures.erase (pTexture);
505
506         delete pTexture;
507 }
508
509 void CTextureSet::DirtyTextures (void)
510 {
511         for (TEXTURE_SET::iterator iter = m_setTextures.begin ();
512                 iter != m_setTextures.end ();
513                 iter ++)
514         {
515                 (*iter)->DirtyMemory ();
516         }
517 }
518
519
520 void CTextureSet::SetPaletteEntries (PALETTEENTRY rgpe [256])
521 {
522         m_pi.SetPaletteEntries (rgpe);
523
524         if (!m_pi.IsIndexed ())
525         {
526                 DirtyTextures ();
527         }
528 }
529
530 void CTextureSet::GetPaletteEntries (PALETTEENTRY rgpe [256])
531 {
532         m_pi.GetPaletteEntries (rgpe);
533 }