2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "DirectXGraphics.h"
25 LPVOID XPhysicalAlloc(SIZE_T s, DWORD ulPhysicalAddress, DWORD ulAlignment, DWORD flProtect)
30 void XPhysicalFree(LPVOID lpAddress)
35 D3DFORMAT GetD3DFormat(XB_D3DFORMAT format)
39 case XB_D3DFMT_A8R8G8B8:
40 case XB_D3DFMT_LIN_A8R8G8B8:
41 return D3DFMT_LIN_A8R8G8B8;
49 return D3DFMT_LIN_A8R8G8B8;
51 return D3DFMT_UNKNOWN;
55 DWORD BytesPerPixelFromFormat(XB_D3DFORMAT format)
59 case XB_D3DFMT_A8R8G8B8:
60 case XB_D3DFMT_LIN_A8R8G8B8:
72 bool IsPalettedFormat(XB_D3DFORMAT format)
74 if (format == XB_D3DFMT_P8)
79 void ParseTextureHeader(D3DTexture *tex, XB_D3DFORMAT &fmt, DWORD &width, DWORD &height, DWORD &pitch, DWORD &offset)
81 fmt = (XB_D3DFORMAT)((tex->Format & 0xff00) >> 8);
85 width = (tex->Size & 0x00000fff) + 1;
86 height = ((tex->Size & 0x00fff000) >> 12) + 1;
87 pitch = (((tex->Size & 0xff000000) >> 24) + 1) << 6;
91 width = 1 << ((tex->Format & 0x00f00000) >> 20);
92 height = 1 << ((tex->Format & 0x0f000000) >> 24);
93 pitch = width * BytesPerPixelFromFormat(fmt);
97 bool IsSwizzledFormat(XB_D3DFORMAT format)
101 case XB_D3DFMT_A8R8G8B8:
117 // Currently only works for 32bit and 8bit textures, with power of 2 width and height
118 void Unswizzle(const void *src, unsigned int depth, unsigned int width, unsigned int height, void *dest)
120 if (height == 0 || width == 0)
123 for (UINT y = 0; y < height; y++)
128 for (int bit = 0; bit < 16; bit++)
129 sy |= ((y >> bit) & 1) << (2*bit);
130 sy <<= 1; // y counts twice
134 UINT y_mask = y % width;
135 for (int bit = 0; bit < 16; bit++)
136 sy |= ((y_mask >> bit) & 1) << (2*bit);
137 sy <<= 1; // y counts twice
138 sy += (y / width) * width * width;
140 BYTE *d = (BYTE *)dest + y * width * depth;
141 for (UINT x = 0; x < width; x++)
146 for (int bit = 0; bit < 16; bit++)
147 sx |= ((x >> bit) & 1) << (2*bit);
151 int x_mask = x % (2*height);
152 for (int bit = 0; bit < 16; bit++)
153 sx |= ((x_mask >> bit) & 1) << (2*bit);
154 sx += (x / (2 * height)) * 2 * height * height;
156 BYTE *s = (BYTE *)src + (sx + sy)*depth;
157 for (unsigned int i = 0; i < depth; ++i)
163 void DXT1toARGB(const void *src, void *dest, unsigned int destWidth)
165 const BYTE *b = (const BYTE *)src;
166 // colour is in R5G6B5 format, convert to R8G8B8
171 for (int i = 0; i < 2; i++)
173 red[i] = b[2*i+1] & 0xf8;
174 green[i] = ((b[2*i+1] & 0x7) << 5) | ((b[2*i] & 0xe0) >> 3);
175 blue[i] = (b[2*i] & 0x1f) << 3;
176 colour[i] = (red[i] << 16) | (green[i] << 8) | blue[i];
178 if (colour[0] > colour[1])
180 red[2] = (2 * red[0] + red[1] + 1) / 3;
181 green[2] = (2 * green[0] + green[1] + 1) / 3;
182 blue[2] = (2 * blue[0] + blue[1] + 1) / 3;
183 red[3] = (red[0] + 2 * red[1] + 1) / 3;
184 green[3] = (green[0] + 2 * green[1] + 1) / 3;
185 blue[3] = (blue[0] + 2 * blue[1] + 1) / 3;
186 for (int i = 0; i < 4; i++)
187 colour[i] = (red[i] << 16) | (green[i] << 8) | blue[i] | 0xFF000000;
191 red[2] = (red[0] + red[1]) / 2;
192 green[2] = (green[0] + green[1]) / 2;
193 blue[2] = (blue[0] + blue[1]) / 2;
194 for (int i = 0; i < 3; i++)
195 colour[i] = (red[i] << 16) | (green[i] << 8) | blue[i] | 0xFF000000;
196 colour[3] = 0; // transparent
198 // ok, now grab the bits
199 for (int y = 0; y < 4; y++)
201 DWORD *d = (DWORD *)dest + destWidth * y;
202 *d++ = colour[(b[4 + y] & 0x03)];
203 *d++ = colour[(b[4 + y] & 0x0c) >> 2];
204 *d++ = colour[(b[4 + y] & 0x30) >> 4];
205 *d++ = colour[(b[4 + y] & 0xc0) >> 6];
209 void DXT4toARGB(const void *src, void *dest, unsigned int destWidth)
211 const BYTE *b = (const BYTE *)src;
215 if (alpha[0] > alpha[1])
217 alpha[2] = (6 * alpha[0] + 1 * alpha[1]+ 3) / 7;
218 alpha[3] = (5 * alpha[0] + 2 * alpha[1] + 3) / 7; // bit code 011
219 alpha[4] = (4 * alpha[0] + 3 * alpha[1] + 3) / 7; // bit code 100
220 alpha[5] = (3 * alpha[0] + 4 * alpha[1] + 3) / 7; // bit code 101
221 alpha[6] = (2 * alpha[0] + 5 * alpha[1] + 3) / 7; // bit code 110
222 alpha[7] = (1 * alpha[0] + 6 * alpha[1] + 3) / 7; // bit code 111
226 alpha[2] = (4 * alpha[0] + 1 * alpha[1] + 2) / 5; // Bit code 010
227 alpha[3] = (3 * alpha[0] + 2 * alpha[1] + 2) / 5; // Bit code 011
228 alpha[4] = (2 * alpha[0] + 3 * alpha[1] + 2) / 5; // Bit code 100
229 alpha[5] = (1 * alpha[0] + 4 * alpha[1] + 2) / 5; // Bit code 101
230 alpha[6] = 0; // Bit code 110
231 alpha[7] = 255; // Bit code 111
233 // ok, now grab the bits
235 a[0][0] = alpha[(b[2] & 0xe0) >> 5];
236 a[0][1] = alpha[(b[2] & 0x1c) >> 2];
237 a[0][2] = alpha[((b[2] & 0x03) << 1) | ((b[3] & 0x80) >> 7)];
238 a[0][3] = alpha[(b[3] & 0x70) >> 4];
239 a[1][0] = alpha[(b[3] & 0x0e) >> 1];
240 a[1][1] = alpha[((b[3] & 0x01) << 2) | ((b[4] & 0xc0) >> 6)];
241 a[1][2] = alpha[(b[4] & 0x38) >> 3];
242 a[1][3] = alpha[(b[4] & 0x07)];
243 a[2][0] = alpha[(b[5] & 0xe0) >> 5];
244 a[2][1] = alpha[(b[5] & 0x1c) >> 2];
245 a[2][2] = alpha[((b[5] & 0x03) << 1) | ((b[6] & 0x80) >> 7)];
246 a[2][3] = alpha[(b[6] & 0x70) >> 4];
247 a[3][0] = alpha[(b[6] & 0x0e) >> 1];
248 a[3][1] = alpha[((b[6] & 0x01) << 2) | ((b[7] & 0xc0) >> 6)];
249 a[3][2] = alpha[(b[7] & 0x38) >> 3];
250 a[3][3] = alpha[(b[7] & 0x07)];
253 // colour is in R5G6B5 format, convert to R8G8B8
258 for (int i = 0; i < 2; i++)
260 red[i] = b[2*i+1] & 0xf8;
261 green[i] = ((b[2*i+1] & 0x7) << 5) | ((b[2*i] & 0xe0) >> 3);
262 blue[i] = (b[2*i] & 0x1f) << 3;
264 red[2] = (2 * red[0] + red[1] + 1) / 3;
265 green[2] = (2 * green[0] + green[1] + 1) / 3;
266 blue[2] = (2 * blue[0] + blue[1] + 1) / 3;
267 red[3] = (red[0] + 2 * red[1] + 1) / 3;
268 green[3] = (green[0] + 2 * green[1] + 1) / 3;
269 blue[3] = (blue[0] + 2 * blue[1] + 1) / 3;
270 for (int i = 0; i < 4; i++)
271 colour[i] = (red[i] << 16) | (green[i] << 8) | blue[i];
272 // and assign them to our texture
273 for (int y = 0; y < 4; y++)
275 DWORD *d = (DWORD *)dest + destWidth * y;
276 *d++ = colour[(b[4 + y] & 0x03)] | (a[y][0] << 24);
277 *d++ = colour[(b[4 + y] & 0x0e) >> 2] | (a[y][1] << 24);
278 *d++ = colour[(b[4 + y] & 0x30) >> 4] | (a[y][2] << 24);
279 *d++ = colour[(b[4 + y] & 0xe0) >> 6] | (a[y][3] << 24);
284 void ConvertDXT1(const void *src, unsigned int width, unsigned int height, void *dest)
286 for (unsigned int y = 0; y < height; y += 4)
288 for (unsigned int x = 0; x < width; x += 4)
290 const BYTE *s = (const BYTE *)src + y * width / 2 + x * 2;
291 DWORD *d = (DWORD *)dest + y * width + x;
292 DXT1toARGB(s, d, width);
297 void ConvertDXT4(const void *src, unsigned int width, unsigned int height, void *dest)
299 // [4 4 4 4][4 4 4 4]
303 for (unsigned int y = 0; y < height; y += 4)
305 for (unsigned int x = 0; x < width; x += 4)
307 const BYTE *s = (const BYTE *)src + y * width + x * 4;
308 DWORD *d = (DWORD *)dest + y * width + x;
309 DXT4toARGB(s, d, width);
314 void GetTextureFromData(D3DTexture *pTex, void *texData, CBaseTexture **ppTexture)
317 DWORD width, height, pitch, offset;
318 ParseTextureHeader(pTex, fmt, width, height, pitch, offset);
320 *ppTexture = new CTexture(width, height, XB_FMT_A8R8G8B8);
324 BYTE *texDataStart = (BYTE *)texData;
325 COLOR *color = (COLOR *)texData;
326 texDataStart += offset;
327 /* DXMERGE - We should really support DXT1,DXT2 and DXT4 in both renderers
328 Perhaps we should extend CTexture::Update() to support a bunch of different texture types
329 Rather than assuming linear 32bits
330 We could just override, as at least then all the loading code from various texture formats
333 BYTE *dstPixels = (BYTE *)lr.pBits;
334 DWORD destPitch = lr.Pitch;
335 if (fmt == XB_D3DFMT_DXT1) // Not sure if these are 100% correct, but they seem to work :P
340 else if (fmt == XB_D3DFMT_DXT2)
344 else if (fmt == XB_D3DFMT_DXT4)
350 if (fmt == XB_D3DFMT_DXT1)
353 BYTE *decoded = new BYTE[pitch * height];
354 ConvertDXT1(texDataStart, width, height, decoded);
355 texDataStart = decoded;
357 else if (fmt == XB_D3DFMT_DXT2 || fmt == XB_D3DFMT_DXT4)
360 BYTE *decoded = new BYTE[pitch * height];
361 ConvertDXT4(texDataStart, width, height, decoded);
362 texDataStart = decoded;
364 if (IsSwizzledFormat(fmt))
365 { // first we unswizzle
366 BYTE *unswizzled = new BYTE[pitch * height];
367 Unswizzle(texDataStart, BytesPerPixelFromFormat(fmt), width, height, unswizzled);
368 texDataStart = unswizzled;
371 if (IsPalettedFormat(fmt))
372 (*ppTexture)->LoadPaletted(width, height, pitch, XB_FMT_A8R8G8B8, texDataStart, color);
374 (*ppTexture)->LoadFromMemory(width, height, pitch, XB_FMT_A8R8G8B8, true, texDataStart);
376 if (IsSwizzledFormat(fmt) || fmt == XB_D3DFMT_DXT1 || fmt == XB_D3DFMT_DXT2 || fmt == XB_D3DFMT_DXT4)
378 delete[] texDataStart;