Fix keymap.
[vuplus_xbmc] / xbmc / guilib / DirectXGraphics.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  */
20
21 #include "DirectXGraphics.h"
22 #include "Texture.h"
23 #include "XBTF.h"
24
25 LPVOID XPhysicalAlloc(SIZE_T s, DWORD ulPhysicalAddress, DWORD ulAlignment, DWORD flProtect)
26 {
27   return malloc(s);
28 }
29
30 void XPhysicalFree(LPVOID lpAddress)
31 {
32   free(lpAddress);
33 }
34
35 D3DFORMAT GetD3DFormat(XB_D3DFORMAT format)
36 {
37   switch (format)
38   {
39   case XB_D3DFMT_A8R8G8B8:
40   case XB_D3DFMT_LIN_A8R8G8B8:
41     return D3DFMT_LIN_A8R8G8B8;
42   case XB_D3DFMT_DXT1:
43     return D3DFMT_DXT1;
44   case XB_D3DFMT_DXT2:
45     return D3DFMT_DXT2;
46   case XB_D3DFMT_DXT4:
47     return D3DFMT_DXT4;
48   case XB_D3DFMT_P8:
49     return D3DFMT_LIN_A8R8G8B8;
50   default:
51     return D3DFMT_UNKNOWN;
52   }
53 }
54
55 DWORD BytesPerPixelFromFormat(XB_D3DFORMAT format)
56 {
57   switch (format)
58   {
59   case XB_D3DFMT_A8R8G8B8:
60   case XB_D3DFMT_LIN_A8R8G8B8:
61   case XB_D3DFMT_DXT4:
62     return 4;
63   case XB_D3DFMT_P8:
64   case XB_D3DFMT_DXT1:
65   case XB_D3DFMT_DXT2:
66     return 1;
67   default:
68     return 0;
69   }
70 }
71
72 bool IsPalettedFormat(XB_D3DFORMAT format)
73 {
74   if (format == XB_D3DFMT_P8)
75     return true;
76   return false;
77 }
78
79 void ParseTextureHeader(D3DTexture *tex, XB_D3DFORMAT &fmt, DWORD &width, DWORD &height, DWORD &pitch, DWORD &offset)
80 {
81   fmt = (XB_D3DFORMAT)((tex->Format & 0xff00) >> 8);
82   offset = tex->Data;
83   if (tex->Size)
84   {
85     width = (tex->Size & 0x00000fff) + 1;
86     height = ((tex->Size & 0x00fff000) >> 12) + 1;
87     pitch = (((tex->Size & 0xff000000) >> 24) + 1) << 6;
88   }
89   else
90   {
91     width = 1 << ((tex->Format & 0x00f00000) >> 20);
92     height = 1 << ((tex->Format & 0x0f000000) >> 24);
93     pitch = width * BytesPerPixelFromFormat(fmt);
94   }
95 }
96
97 bool IsSwizzledFormat(XB_D3DFORMAT format)
98 {
99   switch (format)
100   {
101   case XB_D3DFMT_A8R8G8B8:
102   case XB_D3DFMT_P8:
103     return true;
104   default:
105     return false;
106   }
107 }
108
109 // Unswizzle.
110 // Format is:
111
112 // 00 01 04 05
113 // 02 03 06 07
114 // 08 09 12 13
115 // 10 11 14 15 ...
116
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)
119 {
120   if (height == 0 || width == 0)
121     return;
122
123   for (UINT y = 0; y < height; y++)
124   {
125     UINT sy = 0;
126     if (y < width)
127     {
128       for (int bit = 0; bit < 16; bit++)
129         sy |= ((y >> bit) & 1) << (2*bit);
130       sy <<= 1; // y counts twice
131     }
132     else
133     {
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;
139     }
140     BYTE *d = (BYTE *)dest + y * width * depth;
141     for (UINT x = 0; x < width; x++)
142     {
143       UINT sx = 0;
144       if (x < height * 2)
145       {
146         for (int bit = 0; bit < 16; bit++)
147           sx |= ((x >> bit) & 1) << (2*bit);
148       }
149       else
150       {
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;
155       }
156       BYTE *s = (BYTE *)src + (sx + sy)*depth;
157       for (unsigned int i = 0; i < depth; ++i)
158         *d++ = *s++;
159     }
160   }
161 }
162
163 void DXT1toARGB(const void *src, void *dest, unsigned int destWidth)
164 {
165   const BYTE *b = (const BYTE *)src;
166   // colour is in R5G6B5 format, convert to R8G8B8
167   DWORD colour[4];
168   BYTE red[4];
169   BYTE green[4];
170   BYTE blue[4];
171   for (int i = 0; i < 2; i++)
172   {
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];
177   }
178   if (colour[0] > colour[1])
179   {
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;
188   }
189   else
190   {
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
197   }
198   // ok, now grab the bits
199   for (int y = 0; y < 4; y++)
200   {
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];
206   }
207 }
208
209 void DXT4toARGB(const void *src, void *dest, unsigned int destWidth)
210 {
211   const BYTE *b = (const BYTE *)src;
212   BYTE alpha[8];
213   alpha[0] = b[0];
214   alpha[1] = b[1];
215   if (alpha[0] > alpha[1])
216   {
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
223   }
224   else
225   {
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
232   }
233   // ok, now grab the bits
234   BYTE a[4][4];
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)];
251
252   b = (BYTE *)src + 8;
253   // colour is in R5G6B5 format, convert to R8G8B8
254   DWORD colour[4];
255   BYTE red[4];
256   BYTE green[4];
257   BYTE blue[4];
258   for (int i = 0; i < 2; i++)
259   {
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;
263   }
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++)
274   {
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);
280   }
281
282 }
283
284 void ConvertDXT1(const void *src, unsigned int width, unsigned int height, void *dest)
285 {
286   for (unsigned int y = 0; y < height; y += 4)
287   {
288     for (unsigned int x = 0; x < width; x += 4)
289     {
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);
293     }
294   }
295 }
296
297 void ConvertDXT4(const void *src, unsigned int width, unsigned int height, void *dest)
298 {
299   // [4 4 4 4][4 4 4 4]
300   //
301   //
302   //
303   for (unsigned int y = 0; y < height; y += 4)
304   {
305     for (unsigned int x = 0; x < width; x += 4)
306     {
307       const BYTE *s = (const BYTE *)src + y * width + x * 4;
308       DWORD *d = (DWORD *)dest + y * width + x;
309       DXT4toARGB(s, d, width);
310     }
311   }
312 }
313
314 void GetTextureFromData(D3DTexture *pTex, void *texData, CBaseTexture **ppTexture)
315 {
316   XB_D3DFORMAT fmt;
317   DWORD width, height, pitch, offset;
318   ParseTextureHeader(pTex, fmt, width, height, pitch, offset);
319
320   *ppTexture = new CTexture(width, height, XB_FMT_A8R8G8B8);
321
322   if (*ppTexture)
323   {
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
331              will be in one place
332
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
336     {
337       pitch /= 2;
338       destPitch /= 4;
339     }
340     else if (fmt == XB_D3DFMT_DXT2)
341     {
342       destPitch /= 4;
343     }
344     else if (fmt == XB_D3DFMT_DXT4)
345     {
346       pitch /= 4;
347       destPitch /= 4;
348     }
349 */
350     if (fmt == XB_D3DFMT_DXT1)
351     {
352       pitch = width * 4;
353       BYTE *decoded = new BYTE[pitch * height];
354       ConvertDXT1(texDataStart, width, height, decoded);
355       texDataStart = decoded;
356     }
357     else if (fmt == XB_D3DFMT_DXT2 || fmt == XB_D3DFMT_DXT4)
358     {
359       pitch = width * 4;
360       BYTE *decoded = new BYTE[pitch * height];
361       ConvertDXT4(texDataStart, width, height, decoded);
362       texDataStart = decoded;
363     }
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;
369     }
370
371     if (IsPalettedFormat(fmt))
372       (*ppTexture)->LoadPaletted(width, height, pitch, XB_FMT_A8R8G8B8, texDataStart, color);
373     else
374       (*ppTexture)->LoadFromMemory(width, height, pitch, XB_FMT_A8R8G8B8, true, texDataStart);
375
376     if (IsSwizzledFormat(fmt) || fmt == XB_D3DFMT_DXT1 || fmt == XB_D3DFMT_DXT2 || fmt == XB_D3DFMT_DXT4)
377     {
378       delete[] texDataStart;
379     }
380   }
381 }