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