1 //**************************************************************************
2 //**
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
9 //**
10 //** $Id: d3d_tex.cpp 4341 2010-12-15 22:20:42Z dj_jl $
11 //**
12 //** Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //** This program is free software; you can redistribute it and/or
15 //** modify it under the terms of the GNU General Public License
16 //** as published by the Free Software Foundation; either version 2
17 //** of the License, or (at your option) any later version.
18 //**
19 //** This program is distributed in the hope that it will be useful,
20 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 //** GNU General Public License for more details.
23 //**
24 //**************************************************************************
25
26 // HEADER FILES ------------------------------------------------------------
27
28 #include "d3d_local.h"
29
30 // MACROS ------------------------------------------------------------------
31
32 #define SAFE_RELEASE_TEXTURE(iface) \
33 if (iface) \
34 { \
35 ((LPDIRECT3DTEXTURE9)iface)->Release(); \
36 iface = NULL; \
37 }
38
39 // TYPES -------------------------------------------------------------------
40
41 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
42
43 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
44
45 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
46
47 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
48
49 // PUBLIC DATA DEFINITIONS -------------------------------------------------
50
51 // PRIVATE DATA DEFINITIONS ------------------------------------------------
52
53 // CODE --------------------------------------------------------------------
54
55 //==========================================================================
56 //
57 // VDirect3DDrawer::CreateSurface
58 //
59 //==========================================================================
60
CreateSurface(int w,int h,int bpp,bool mipmaps)61 LPDIRECT3DTEXTURE9 VDirect3DDrawer::CreateSurface(int w, int h, int bpp, bool mipmaps)
62 {
63 guard(VDirect3DDrawer::CreateSurface);
64 LPDIRECT3DTEXTURE9 surf = NULL;
65
66 HRESULT res = RenderDevice->CreateTexture(w, h, mipmaps ? 0 : 1, 0,
67 bpp == 32 ? D3DFMT_A8R8G8B8 : D3DFMT_A1R5G5B5,
68 D3DPOOL_MANAGED, &surf, NULL);
69 if (res != D3D_OK)
70 {
71 switch(res)
72 {
73 case D3DERR_INVALIDCALL:
74 {
75 GCon->Log("Invalid call");
76 break;
77 }
78 case D3DERR_OUTOFVIDEOMEMORY:
79 {
80 GCon->Log("Out of vid mem");
81 break;
82 }
83 case E_OUTOFMEMORY:
84 {
85 GCon->Log("Out of mem");
86 break;
87 }
88 default:
89 {
90 GCon->Logf("Unknown error %d", res);
91 }
92 }
93 Sys_Error("Create texture failed\n");
94 }
95 return surf;
96 unguard;
97 }
98
99 //==========================================================================
100 //
101 // VDirect3DDrawer::FlushTextures
102 //
103 //==========================================================================
104
FlushTextures()105 void VDirect3DDrawer::FlushTextures()
106 {
107 guard(VDirect3DDrawer::FlushTextures);
108 for (int i = 0; i < GTextureManager.GetNumTextures(); i++)
109 {
110 FlushTexture(GTextureManager[i]);
111 }
112 unguard;
113 }
114
115 //==========================================================================
116 //
117 // VDirect3DDrawer::ReleaseTextures
118 //
119 //==========================================================================
120
ReleaseTextures()121 void VDirect3DDrawer::ReleaseTextures()
122 {
123 guard(VDirect3DDrawer::ReleaseTextures);
124 FlushTextures();
125 for (int i = 0; i < NUM_BLOCK_SURFS; i++)
126 {
127 SAFE_RELEASE(light_surf[i]);
128 SAFE_RELEASE(add_surf[i]);
129 }
130 SAFE_RELEASE(particle_texture);
131 unguard;
132 }
133
134 //==========================================================================
135 //
136 // VDirect3DDrawer::FlushTexture
137 //
138 //==========================================================================
139
FlushTexture(VTexture * Tex)140 void VDirect3DDrawer::FlushTexture(VTexture* Tex)
141 {
142 guard(VDirect3DDrawer::FlushTexture);
143 SAFE_RELEASE_TEXTURE(Tex->DriverData);
144 for (int j = 0; j < Tex->DriverTranslated.Num(); j++)
145 {
146 SAFE_RELEASE_TEXTURE(Tex->DriverTranslated[j].Data);
147 }
148 Tex->DriverTranslated.Clear();
149 unguard;
150 }
151
152 //==========================================================================
153 //
154 // VDirect3DDrawer::PrecacheTexture
155 //
156 //==========================================================================
157
PrecacheTexture(VTexture * Tex)158 void VDirect3DDrawer::PrecacheTexture(VTexture* Tex)
159 {
160 guard(VDirect3DDrawer::PrecacheTexture);
161 SetTexture(Tex, 0);
162 unguard;
163 }
164
165 //==========================================================================
166 //
167 // VDirect3DDrawer::SetTexture
168 //
169 //==========================================================================
170
SetTexture(VTexture * Tex,int CMap)171 void VDirect3DDrawer::SetTexture(VTexture* Tex, int CMap)
172 {
173 guard(VDirect3DDrawer::SetTexture);
174 SetSpriteLump(Tex, NULL, CMap);
175 if (RenderDevice)
176 {
177 RenderDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
178 RenderDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
179 }
180 unguard;
181 }
182
183 //==========================================================================
184 //
185 // VDirect3DDrawer::SetSpriteLump
186 //
187 //==========================================================================
188
SetSpriteLump(VTexture * Tex,VTextureTranslation * Translation,int CMap)189 void VDirect3DDrawer::SetSpriteLump(VTexture* Tex,
190 VTextureTranslation* Translation, int CMap)
191 {
192 guard(VDirect3DDrawer::SetSpriteLump);
193 if (!RenderDevice)
194 {
195 return;
196 }
197
198 if (Tex->CheckModified())
199 {
200 FlushTexture(Tex);
201 }
202
203 if (Translation || CMap)
204 {
205 VTexture::VTransData* TData = Tex->FindDriverTrans(Translation, CMap);
206 if (!TData)
207 {
208 TData = &Tex->DriverTranslated.Alloc();
209 TData->Data = NULL;
210 TData->Trans = Translation;
211 TData->ColourMap = CMap;
212 GenerateTexture(Tex, &TData->Data, Translation, CMap);
213 }
214 RenderDevice->SetTexture(0, (LPDIRECT3DTEXTURE9)TData->Data);
215 }
216 else
217 {
218 if (!Tex->DriverData)
219 {
220 GenerateTexture(Tex, &Tex->DriverData, NULL, 0);
221 }
222 RenderDevice->SetTexture(0, (LPDIRECT3DTEXTURE9)Tex->DriverData);
223 }
224
225 RenderDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
226 RenderDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
227 tex_iw = 1.0 / Tex->GetWidth();
228 tex_ih = 1.0 / Tex->GetHeight();
229 unguard;
230 }
231
232 //==========================================================================
233 //
234 // VDirect3DDrawer::SetPic
235 //
236 //==========================================================================
237
SetPic(VTexture * Tex,VTextureTranslation * Trans,int CMap)238 void VDirect3DDrawer::SetPic(VTexture* Tex, VTextureTranslation* Trans,
239 int CMap)
240 {
241 guard(VDirect3DDrawer::SetPic);
242 SetSpriteLump(Tex, Trans, CMap);
243 unguard;
244 }
245
246 //==========================================================================
247 //
248 // VDirect3DDrawer::GenerateTexture
249 //
250 //==========================================================================
251
GenerateTexture(VTexture * Tex,void ** Data,VTextureTranslation * Translation,int CMap)252 void VDirect3DDrawer::GenerateTexture(VTexture* Tex, void** Data,
253 VTextureTranslation* Translation, int CMap)
254 {
255 guard(VDirect3DDrawer::GenerateTexture);
256 // Try to load high resolution version.
257 VTexture* SrcTex = Tex->GetHighResolutionTexture();
258 if (!SrcTex)
259 {
260 SrcTex = Tex;
261 }
262
263 SAFE_RELEASE_TEXTURE(*Data);
264 if (Translation && CMap)
265 {
266 rgba_t TmpPal[256];
267 const vuint8* TrTab = Translation->GetTable();
268 const rgba_t* CMPal = ColourMaps[CMap].GetPalette();
269 for (int i = 0; i < 256; i++)
270 {
271 TmpPal[i] = CMPal[TrTab[i]];
272 }
273 *Data = UploadTexture8(SrcTex->GetWidth(), SrcTex->GetHeight(),
274 SrcTex->GetPixels8(), TmpPal);
275 }
276 else if (Translation)
277 {
278 *Data = UploadTexture8(SrcTex->GetWidth(), SrcTex->GetHeight(),
279 SrcTex->GetPixels8(), Translation->GetPalette());
280 }
281 else if (CMap)
282 {
283 *Data = UploadTexture8(SrcTex->GetWidth(), SrcTex->GetHeight(),
284 SrcTex->GetPixels8(), ColourMaps[CMap].GetPalette());
285 }
286 else
287 {
288 vuint8* block = SrcTex->GetPixels();
289 if (SrcTex->Format == TEXFMT_8 || SrcTex->Format == TEXFMT_8Pal)
290 {
291 *Data = UploadTexture8(SrcTex->GetWidth(),
292 SrcTex->GetHeight(), block, SrcTex->GetPalette());
293 }
294 else
295 {
296 *Data = UploadTexture(SrcTex->GetWidth(),
297 SrcTex->GetHeight(), (rgba_t*)block);
298 }
299 }
300 unguard;
301 }
302
303 //==========================================================================
304 //
305 // VDirect3DDrawer::UploadTextureImage
306 //
307 //==========================================================================
308
UploadTextureImage(LPDIRECT3DTEXTURE9 tex,int level,int width,int height,const rgba_t * data)309 void VDirect3DDrawer::UploadTextureImage(LPDIRECT3DTEXTURE9 tex, int level,
310 int width, int height, const rgba_t* data)
311 {
312 guard(VDirect3DDrawer::UploadTextureImage);
313 LPDIRECT3DSURFACE9 surf;
314 tex->GetSurfaceLevel(level, &surf);
315
316 D3DLOCKED_RECT lrect;
317 if (FAILED(surf->LockRect(&lrect, NULL, 0)))
318 {
319 GCon->Logf(NAME_Dev, "Failed to lock surface");
320 return;
321 }
322
323 D3DSURFACE_DESC desc;
324 surf->GetDesc(&desc);
325
326 const rgba_t *in = data;
327 if (desc.Format == D3DFMT_A1R5G5B5)
328 {
329 word *out = (word*)lrect.pBits;
330 for (int i = 0; i < width * height; i++, in++, out++)
331 {
332 *out = MakeCol16(in->r, in->g, in->b, in->a);
333 }
334 }
335 else if (desc.Format == D3DFMT_A8R8G8B8)
336 {
337 vuint32* out = (vuint32*)lrect.pBits;
338 for (int i = 0; i < width * height; i++, in++, out++)
339 {
340 *out = MakeCol32(in->r, in->g, in->b, in->a);
341 }
342 }
343 surf->UnlockRect();
344 surf->Release();
345 unguard;
346 }
347
348 //==========================================================================
349 //
350 // VDirect3DDrawer::UploadTexture8
351 //
352 //==========================================================================
353
UploadTexture8(int Width,int Height,const vuint8 * Data,const rgba_t * Pal)354 LPDIRECT3DTEXTURE9 VDirect3DDrawer::UploadTexture8(int Width, int Height,
355 const vuint8* Data, const rgba_t* Pal)
356 {
357 rgba_t* NewData = (rgba_t*)Z_Calloc(Width * Height * 4);
358 for (int i = 0; i < Width * Height; i++)
359 {
360 if (Data[i])
361 NewData[i] = Pal[Data[i]];
362 }
363 LPDIRECT3DTEXTURE9 Ret;
364 Ret = UploadTexture(Width, Height, NewData);
365 Z_Free(NewData);
366 return Ret;
367 }
368
369 //==========================================================================
370 //
371 // VDirect3DDrawer::UploadTexture
372 //
373 //==========================================================================
374
UploadTexture(int width,int height,const rgba_t * data)375 LPDIRECT3DTEXTURE9 VDirect3DDrawer::UploadTexture(int width, int height, const rgba_t *data)
376 {
377 guard(VDirect3DDrawer::UploadTexture);
378 int w, h;
379 vuint8 *image;
380 vuint8 stackbuf[256 * 128 * 4];
381 LPDIRECT3DTEXTURE9 surf;
382 UINT level;
383
384 w = ToPowerOf2(width);
385 if (w > maxTexSize)
386 {
387 w = maxTexSize;
388 }
389 h = ToPowerOf2(height);
390 if (h > maxTexSize)
391 {
392 h = maxTexSize;
393 }
394 if (square_textures)
395 {
396 w = h = MAX(w, h);
397 }
398
399 if (w * h * 4 <= int(sizeof(stackbuf)))
400 {
401 image = stackbuf;
402 }
403 else
404 {
405 image = (vuint8*)Z_Malloc(w * h * 4);
406 }
407 if (w != width || h != height)
408 {
409 // Smooth transparent edges
410 VTexture::SmoothEdges((vuint8*)data, width, height, (vuint8*)data);
411 // Must rescale image to get "top" mipmap texture image
412 VTexture::ResampleTexture(width, height, (vuint8*)data, w, h, image);
413 }
414 else
415 {
416 memcpy(image, data, w * h * 4);
417 }
418 VTexture::AdjustGamma((rgba_t*)image, w * h);
419 surf = CreateSurface(w, h, 16, true);
420 UploadTextureImage(surf, 0, w, h, (rgba_t*)image);
421
422 for (level = 1; level < surf->GetLevelCount(); level++)
423 {
424 VTexture::MipMap(w, h, image);
425 if (w > 1)
426 w >>= 1;
427 if (h > 1)
428 h >>= 1;
429 UploadTextureImage(surf, level, w, h, (rgba_t*)image);
430 }
431
432 if (image != stackbuf)
433 {
434 Z_Free(image);
435 }
436 return surf;
437 unguard;
438 }
439