Bug fix: Change all .desktop files to RDNS style
[geeqie.git] / src / image-load-dds.cc
1 /*
2  * Copyright (C) 2018 The Geeqie Team
3  *
4  * Author: Wolfgang Lieff
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20  * Derived from dds_reader written by:
21  * Copyright (c) 2015 Kenji Sasaki
22  * Released under the MIT license.
23  * https://github.com/npedotnet/DDSReader/blob/master/LICENSE
24
25  */
26
27 #include "main.h"
28
29 #include "image-load.h"
30 #include "image-load-dds.h"
31
32 struct ImageLoaderDDS {
33         ImageLoaderBackendCbAreaUpdated area_updated_cb;
34         ImageLoaderBackendCbSize size_cb;
35         ImageLoaderBackendCbAreaPrepared area_prepared_cb;
36         gpointer data;
37         GdkPixbuf *pixbuf;
38         guint requested_width;
39         guint requested_height;
40         gboolean abort;
41 };
42
43 static void free_buffer(guchar *pixels, gpointer)
44 {
45         g_free(pixels);
46 }
47
48 uint ddsGetHeight(unsigned const char * buffer) {
49         return (buffer[12] & 0xFF) | (buffer[13] & 0xFF) << 8 | (buffer[14] & 0xFF) << 16 | (buffer[15] & 0xFF) << 24;
50 }
51
52 uint ddsGetWidth(unsigned const char * buffer) {
53         return (buffer[16] & 0xFF) | (buffer[17] & 0xFF) << 8 | (buffer[18] & 0xFF) << 16 | (buffer[19] & 0xFF) << 24;
54 }
55
56 #pragma GCC diagnostic push
57 #pragma GCC diagnostic ignored "-Wunused-function"
58 uint ddsGetMipmap_unused(unsigned const char * buffer) {
59         return (buffer[28] & 0xFF) | (buffer[29] & 0xFF) << 8 | (buffer[30] & 0xFF) << 16 | (buffer[31] & 0xFF) << 24;
60 }
61 #pragma GCC diagnostic pop
62
63 uint ddsGetPixelFormatFlags(unsigned const char * buffer) {
64         return (buffer[80] & 0xFF) | (buffer[81] & 0xFF) << 8 | (buffer[82] & 0xFF) << 16 | (buffer[83] & 0xFF) << 24;
65 }
66
67 uint ddsGetFourCC(unsigned const char * buffer) {
68         return (buffer[84] & 0xFF) << 24 | (buffer[85] & 0xFF) << 16 | (buffer[86] & 0xFF) << 8 | (buffer[87] & 0xFF);
69 }
70
71 uint ddsGetBitCount(unsigned const char * buffer) {
72         return (buffer[88] & 0xFF) | (buffer[89] & 0xFF) << 8 | (buffer[90] & 0xFF) << 16 | (buffer[91] & 0xFF) << 24;
73 }
74
75 uint ddsGetRedMask(unsigned const char * buffer) {
76         return (buffer[92] & 0xFF) | (buffer[93] & 0xFF) << 8 | (buffer[94] & 0xFF) << 16 | (buffer[95] & 0xFF) << 24;
77 }
78
79 uint ddsGetGreenMask(unsigned const char * buffer) {
80         return (buffer[96] & 0xFF) | (buffer[97] & 0xFF) << 8 | (buffer[98] & 0xFF) << 16 | (buffer[99] & 0xFF) << 24;
81 }
82
83 uint ddsGetBlueMask(unsigned const char * buffer) {
84         return (buffer[100] & 0xFF) | (buffer[101] & 0xFF) << 8 | (buffer[102] & 0xFF) << 16 | (buffer[103] & 0xFF) << 24;
85 }
86
87 uint ddsGetAlphaMask(unsigned const char * buffer) {
88         return (buffer[104] & 0xFF) | (buffer[105] & 0xFF) << 8 | (buffer[106] & 0xFF) << 16 | (buffer[107] & 0xFF) << 24;
89 }
90
91 // Image Type
92 #define DXT1 (0x44585431)
93 #define DXT2 (0x44585432)
94 #define DXT3 (0x44585433)
95 #define DXT4 (0x44585434)
96 #define DXT5 (0x44585435)
97 #define A1R5G5B5 ((1 << 16) | 2)
98 #define X1R5G5B5 ((2 << 16) | 2)
99 #define A4R4G4B4 ((3 << 16) | 2)
100 #define X4R4G4B4 ((4 << 16) | 2)
101 #define R5G6B5 ((5 << 16) | 2)
102 #define R8G8B8 ((1 << 16) | 3)
103 #define A8B8G8R8 ((1 << 16) | 4)
104 #define X8B8G8R8 ((2 << 16) | 4)
105 #define A8R8G8B8 ((3 << 16) | 4)
106 #define X8R8G8B8 ((4 << 16) | 4)
107
108 // RGBA Masks
109 static const uint A1R5G5B5_MASKS[] = { 0x7C00, 0x03E0, 0x001F, 0x8000 };
110 static const uint X1R5G5B5_MASKS[] = { 0x7C00, 0x03E0, 0x001F, 0x0000 };
111 static const uint A4R4G4B4_MASKS[] = { 0x0F00, 0x00F0, 0x000F, 0xF000 };
112 static const uint X4R4G4B4_MASKS[] = { 0x0F00, 0x00F0, 0x000F, 0x0000 };
113 static const uint R5G6B5_MASKS[] = { 0xF800, 0x07E0, 0x001F, 0x0000 };
114 static const uint R8G8B8_MASKS[] = { 0xFF0000, 0x00FF00, 0x0000FF, 0x000000 };
115 static const uint A8B8G8R8_MASKS[] = { 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 };
116 static const uint X8B8G8R8_MASKS[] = { 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000 };
117 static const uint A8R8G8B8_MASKS[] = { 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000 };
118 static const uint X8R8G8B8_MASKS[] = { 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000 };
119
120 // BIT4 = 17 * index;
121 static const uint BIT5[] = { 0, 8, 16, 25, 33, 41, 49, 58, 66, 74, 82, 90, 99, 107, 115, 123, 132, 140, 148, 156, 165, 173, 181, 189, 197, 206, 214, 222, 230, 239, 247, 255 };
122 static const uint BIT6[] = { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 130, 134, 138, 142, 146, 150, 154, 158, 162, 166, 170, 174, 178, 182, 186, 190, 194, 198, 202, 206, 210, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251, 255 };
123
124 static uint ddsGetType(const unsigned char *buffer) {
125         uint type = 0;
126         uint flags = ddsGetPixelFormatFlags(buffer);
127         if ((flags & 0x04) != 0) {
128                 // DXT
129                 type = ddsGetFourCC(buffer);
130         }
131         else if ((flags & 0x40) != 0) {
132                 // RGB
133                 uint bitCount = ddsGetBitCount(buffer);
134                 uint redMask = ddsGetRedMask(buffer);
135                 uint greenMask = ddsGetGreenMask(buffer);
136                 uint blueMask = ddsGetBlueMask(buffer);
137                 uint alphaMask = ((flags & 0x01) != 0) ? ddsGetAlphaMask(buffer) : 0; // 0x01 alpha
138                 if (bitCount == 16) {
139                         if (redMask == A1R5G5B5_MASKS[0] && greenMask == A1R5G5B5_MASKS[1] && blueMask == A1R5G5B5_MASKS[2] && alphaMask == A1R5G5B5_MASKS[3]) {
140                                 // A1R5G5B5
141                                 type = A1R5G5B5;
142                         }
143                         else if (redMask == X1R5G5B5_MASKS[0] && greenMask == X1R5G5B5_MASKS[1] && blueMask == X1R5G5B5_MASKS[2] && alphaMask == X1R5G5B5_MASKS[3]) {
144                                 // X1R5G5B5
145                                 type = X1R5G5B5;
146                         }
147                         else if (redMask == A4R4G4B4_MASKS[0] && greenMask == A4R4G4B4_MASKS[1] && blueMask == A4R4G4B4_MASKS[2] && alphaMask == A4R4G4B4_MASKS[3]) {
148                                 // A4R4G4B4
149                                 type = A4R4G4B4;
150                         }
151                         else if (redMask == X4R4G4B4_MASKS[0] && greenMask == X4R4G4B4_MASKS[1] && blueMask == X4R4G4B4_MASKS[2] && alphaMask == X4R4G4B4_MASKS[3]) {
152                                 // X4R4G4B4
153                                 type = X4R4G4B4;
154                         }
155                         else if (redMask == R5G6B5_MASKS[0] && greenMask == R5G6B5_MASKS[1] && blueMask == R5G6B5_MASKS[2] && alphaMask == R5G6B5_MASKS[3]) {
156                                 // R5G6B5
157                                 type = R5G6B5;
158                         }
159                         else {
160                                 // Unsupported 16bit RGB image
161                         }
162                 }
163                 else if (bitCount == 24) {
164                         if (redMask == R8G8B8_MASKS[0] && greenMask == R8G8B8_MASKS[1] && blueMask == R8G8B8_MASKS[2] && alphaMask == R8G8B8_MASKS[3]) {
165                                 // R8G8B8
166                                 type = R8G8B8;
167                         }
168                         else {
169                                 // Unsupported 24bit RGB image
170                         }
171                 }
172                 else if (bitCount == 32) {
173                         if (redMask == A8B8G8R8_MASKS[0] && greenMask == A8B8G8R8_MASKS[1] && blueMask == A8B8G8R8_MASKS[2] && alphaMask == A8B8G8R8_MASKS[3]) {
174                                 // A8B8G8R8
175                                 type = A8B8G8R8;
176                         }
177                         else if (redMask == X8B8G8R8_MASKS[0] && greenMask == X8B8G8R8_MASKS[1] && blueMask == X8B8G8R8_MASKS[2] && alphaMask == X8B8G8R8_MASKS[3]) {
178                                 // X8B8G8R8
179                                 type = X8B8G8R8;
180                         }
181                         else if (redMask == A8R8G8B8_MASKS[0] && greenMask == A8R8G8B8_MASKS[1] && blueMask == A8R8G8B8_MASKS[2] && alphaMask == A8R8G8B8_MASKS[3]) {
182                                 // A8R8G8B8
183                                 type = A8R8G8B8;
184                         }
185                         else if (redMask == X8R8G8B8_MASKS[0] && greenMask == X8R8G8B8_MASKS[1] && blueMask == X8R8G8B8_MASKS[2] && alphaMask == X8R8G8B8_MASKS[3]) {
186                                 // X8R8G8B8
187                                 type = X8R8G8B8;
188                         }
189                         else {
190                                 // Unsupported 32bit RGB image
191                         }
192                 }
193         }
194         else {
195                 // YUV or LUMINANCE image
196         }
197         return type;
198 }
199
200 uint ddsGetDXTColor2_1(uint c0, uint c1, uint a) {
201         // 2*c0/3 + c1/3
202         uint r = (2 * BIT5[(c0 & 0xFC00) >> 11] + BIT5[(c1 & 0xFC00) >> 11]) / 3;
203         uint g = (2 * BIT6[(c0 & 0x07E0) >> 5] + BIT6[(c1 & 0x07E0) >> 5]) / 3;
204         uint b = (2 * BIT5[c0 & 0x001F] + BIT5[c1 & 0x001F]) / 3;
205         return (a << 24) | (r << 0) | (g << 8) | (b << 16);
206 }
207
208 uint ddsGetDXTColor1_1(uint c0, uint c1, uint a) {
209         // (c0+c1) / 2
210         uint r = (BIT5[(c0 & 0xFC00) >> 11] + BIT5[(c1 & 0xFC00) >> 11]) / 2;
211         uint g = (BIT6[(c0 & 0x07E0) >> 5] + BIT6[(c1 & 0x07E0) >> 5]) / 2;
212         uint b = (BIT5[c0 & 0x001F] + BIT5[c1 & 0x001F]) / 2;
213         return (a << 24) | (r << 0) | (g << 8) | (b << 16);
214 }
215
216 uint ddsGetDXTColor1(uint c, uint a) {
217         uint r = BIT5[(c & 0xFC00) >> 11];
218         uint g = BIT6[(c & 0x07E0) >> 5];
219         uint b = BIT5[(c & 0x001F)];
220         return (a << 24) | (r << 0) | (g << 8) | (b << 16);
221 }
222
223 uint ddsGetDXTColor(uint c0, uint c1, uint a, uint t) {
224         switch (t) {
225         case 0: return ddsGetDXTColor1(c0, a);
226         case 1: return ddsGetDXTColor1(c1, a);
227         case 2: return (c0 > c1) ? ddsGetDXTColor2_1(c0, c1, a) : ddsGetDXTColor1_1(c0, c1, a);
228         case 3: return (c0 > c1) ? ddsGetDXTColor2_1(c1, c0, a) : 0;
229         }
230         return 0;
231 }
232
233 guchar *ddsDecodeDXT1(uint width, uint height, const unsigned char *buffer) {
234         auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
235         if (pixels == nullptr) return nullptr;
236         uint index = 128;
237         uint w = (width + 3) / 4;
238         uint h = (height + 3) / 4;
239         for (uint i = 0; i<h; i++) {
240                 for (uint j = 0; j<w; j++) {
241                         uint c0 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2;
242                         uint c1 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2;
243                         for (uint k = 0; k<4; k++) {
244                                 if (4 * i + k >= height) break;
245                                 uint t0 = (buffer[index] & 0x03);
246                                 uint t1 = (buffer[index] & 0x0C) >> 2;
247                                 uint t2 = (buffer[index] & 0x30) >> 4;
248                                 uint t3 = (buffer[index++] & 0xC0) >> 6;
249                                 pixels[4 * width*i + 4 * j + width*k + 0] = ddsGetDXTColor(c0, c1, 0xFF, t0);
250                                 if (4 * j + 1 >= width) continue;
251                                 pixels[4 * width*i + 4 * j + width*k + 1] = ddsGetDXTColor(c0, c1, 0xFF, t1);
252                                 if (4 * j + 2 >= width) continue;
253                                 pixels[4 * width*i + 4 * j + width*k + 2] = ddsGetDXTColor(c0, c1, 0xFF, t2);
254                                 if (4 * j + 3 >= width) continue;
255                                 pixels[4 * width*i + 4 * j + width*k + 3] = ddsGetDXTColor(c0, c1, 0xFF, t3);
256                         }
257                 }
258         }
259         return reinterpret_cast<guchar *>(pixels);
260 }
261
262 guchar *ddsDecodeDXT3(uint width, uint height, const unsigned char *buffer) {
263         auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
264         if (pixels == nullptr) return nullptr;
265         uint index = 128;
266         uint w = (width + 3) / 4;
267         uint h = (height + 3) / 4;
268         uint alphaTable[16];
269         for (uint i = 0; i<h; i++) {
270                 for (uint j = 0; j<w; j++) {
271                         // create alpha table(4bit to 8bit)
272                         for (uint k = 0; k<4; k++) {
273                                 uint a0 = (buffer[index++] & 0xFF);
274                                 uint a1 = (buffer[index++] & 0xFF);
275                                 // 4bit alpha to 8bit alpha
276                                 alphaTable[4 * k + 0] = 17 * ((a0 & 0xF0) >> 4);
277                                 alphaTable[4 * k + 1] = 17 * (a0 & 0x0F);
278                                 alphaTable[4 * k + 2] = 17 * ((a1 & 0xF0) >> 4);
279                                 alphaTable[4 * k + 3] = 17 * (a1 & 0x0F);
280                         }
281                         uint c0 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2;
282                         uint c1 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2;
283                         for (uint k = 0; k<4; k++) {
284                                 if (4 * i + k >= height) break;
285                                 uint t0 = (buffer[index] & 0x03);
286                                 uint t1 = (buffer[index] & 0x0C) >> 2;
287                                 uint t2 = (buffer[index] & 0x30) >> 4;
288                                 uint t3 = (buffer[index++] & 0xC0) >> 6;
289                                 pixels[4 * width*i + 4 * j + width*k + 0] = ddsGetDXTColor(c0, c1, alphaTable[4 * k + 0], t0);
290                                 if (4 * j + 1 >= width) continue;
291                                 pixels[4 * width*i + 4 * j + width*k + 1] = ddsGetDXTColor(c0, c1, alphaTable[4 * k + 1], t1);
292                                 if (4 * j + 2 >= width) continue;
293                                 pixels[4 * width*i + 4 * j + width*k + 2] = ddsGetDXTColor(c0, c1, alphaTable[4 * k + 2], t2);
294                                 if (4 * j + 3 >= width) continue;
295                                 pixels[4 * width*i + 4 * j + width*k + 3] = ddsGetDXTColor(c0, c1, alphaTable[4 * k + 3], t3);
296                         }
297                 }
298         }
299         return reinterpret_cast<guchar *>(pixels);
300 }
301
302 guchar *ddsDecodeDXT2(uint width, uint height, const unsigned char *buffer) {
303         return ddsDecodeDXT3(width, height, buffer);
304 }
305
306 int ddsGetDXT5Alpha(uint a0, uint a1, uint t) {
307         if (a0 > a1) switch (t) {
308         case 0: return a0;
309         case 1: return a1;
310         case 2: return (6 * a0 + a1) / 7;
311         case 3: return (5 * a0 + 2 * a1) / 7;
312         case 4: return (4 * a0 + 3 * a1) / 7;
313         case 5: return (3 * a0 + 4 * a1) / 7;
314         case 6: return (2 * a0 + 5 * a1) / 7;
315         case 7: return (a0 + 6 * a1) / 7;
316         }
317         else switch (t) {
318         case 0: return a0;
319         case 1: return a1;
320         case 2: return (4 * a0 + a1) / 5;
321         case 3: return (3 * a0 + 2 * a1) / 5;
322         case 4: return (2 * a0 + 3 * a1) / 5;
323         case 5: return (a0 + 4 * a1) / 5;
324         case 6: return 0;
325         case 7: return 255;
326         }
327         return 0;
328 }
329
330 guchar *ddsDecodeDXT5(uint width, uint height, const unsigned char *buffer) {
331         auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
332         if (pixels == nullptr) return nullptr;
333         uint index = 128;
334         uint w = (width + 3) / 4;
335         uint h = (height + 3) / 4;
336         uint alphaTable[16];
337         for (uint i = 0; i<h; i++) {
338                 for (uint j = 0; j<w; j++) {
339                         // create alpha table
340                         uint a0 = (buffer[index++] & 0xFF);
341                         uint a1 = (buffer[index++] & 0xFF);
342                         uint b0 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8 | (buffer[index + 2] & 0xFF) << 16; index += 3;
343                         uint b1 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8 | (buffer[index + 2] & 0xFF) << 16; index += 3;
344                         alphaTable[0] = b0 & 0x07;
345                         alphaTable[1] = (b0 >> 3) & 0x07;
346                         alphaTable[2] = (b0 >> 6) & 0x07;
347                         alphaTable[3] = (b0 >> 9) & 0x07;
348                         alphaTable[4] = (b0 >> 12) & 0x07;
349                         alphaTable[5] = (b0 >> 15) & 0x07;
350                         alphaTable[6] = (b0 >> 18) & 0x07;
351                         alphaTable[7] = (b0 >> 21) & 0x07;
352                         alphaTable[8] = b1 & 0x07;
353                         alphaTable[9] = (b1 >> 3) & 0x07;
354                         alphaTable[10] = (b1 >> 6) & 0x07;
355                         alphaTable[11] = (b1 >> 9) & 0x07;
356                         alphaTable[12] = (b1 >> 12) & 0x07;
357                         alphaTable[13] = (b1 >> 15) & 0x07;
358                         alphaTable[14] = (b1 >> 18) & 0x07;
359                         alphaTable[15] = (b1 >> 21) & 0x07;
360                         uint c0 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2;
361                         uint c1 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2;
362                         for (uint k = 0; k<4; k++) {
363                                 if (4 * i + k >= height) break;
364                                 uint t0 = (buffer[index] & 0x03);
365                                 uint t1 = (buffer[index] & 0x0C) >> 2;
366                                 uint t2 = (buffer[index] & 0x30) >> 4;
367                                 uint t3 = (buffer[index++] & 0xC0) >> 6;
368                                 pixels[4 * width*i + 4 * j + width*k + 0] = ddsGetDXTColor(c0, c1, ddsGetDXT5Alpha(a0, a1, alphaTable[4 * k + 0]), t0);
369                                 if (4 * j + 1 >= width) continue;
370                                 pixels[4 * width*i + 4 * j + width*k + 1] = ddsGetDXTColor(c0, c1, ddsGetDXT5Alpha(a0, a1, alphaTable[4 * k + 1]), t1);
371                                 if (4 * j + 2 >= width) continue;
372                                 pixels[4 * width*i + 4 * j + width*k + 2] = ddsGetDXTColor(c0, c1, ddsGetDXT5Alpha(a0, a1, alphaTable[4 * k + 2]), t2);
373                                 if (4 * j + 3 >= width) continue;
374                                 pixels[4 * width*i + 4 * j + width*k + 3] = ddsGetDXTColor(c0, c1, ddsGetDXT5Alpha(a0, a1, alphaTable[4 * k + 3]), t3);
375                         }
376                 }
377         }
378         return reinterpret_cast<guchar *>(pixels);
379 }
380
381 guchar *ddsDecodeDXT4(uint width, uint height, const unsigned char *buffer) {
382         return ddsDecodeDXT5(width, height, buffer);
383 }
384
385 guchar *ddsReadA1R5G5B5(uint width, uint height, const unsigned char *buffer) {
386         auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
387         if (pixels == nullptr) return nullptr;
388         uint index = 128;
389         for (uint i = 0; i<height*width; i++) {
390                 uint rgba = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2;
391                 uint r = BIT5[(rgba & A1R5G5B5_MASKS[0]) >> 10];
392                 uint g = BIT5[(rgba & A1R5G5B5_MASKS[1]) >> 5];
393                 uint b = BIT5[(rgba & A1R5G5B5_MASKS[2])];
394                 uint a = 255 * ((rgba & A1R5G5B5_MASKS[3]) >> 15);
395                 pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16);
396         }
397         return reinterpret_cast<guchar *>(pixels);
398 }
399
400 guchar *ddsReadX1R5G5B5(uint width, uint height, const unsigned char *buffer) {
401         auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
402         if (pixels == nullptr) return nullptr;
403         uint index = 128;
404         for (uint i = 0; i<height*width; i++) {
405                 uint rgba = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2;
406                 uint r = BIT5[(rgba & X1R5G5B5_MASKS[0]) >> 10];
407                 uint g = BIT5[(rgba & X1R5G5B5_MASKS[1]) >> 5];
408                 uint b = BIT5[(rgba & X1R5G5B5_MASKS[2])];
409                 uint a = 255;
410                 pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16);
411         }
412         return reinterpret_cast<guchar *>(pixels);
413 }
414
415 guchar *ddsReadA4R4G4B4(uint width, uint height, const unsigned char *buffer) {
416         auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
417         if (pixels == nullptr) return nullptr;
418         uint index = 128;
419         for (uint i = 0; i<height*width; i++) {
420                 uint rgba = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2;
421                 uint r = 17 * ((rgba & A4R4G4B4_MASKS[0]) >> 8);
422                 uint g = 17 * ((rgba & A4R4G4B4_MASKS[1]) >> 4);
423                 uint b = 17 * ((rgba & A4R4G4B4_MASKS[2]));
424                 uint a = 17 * ((rgba & A4R4G4B4_MASKS[3]) >> 12);
425                 pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16);
426         }
427         return reinterpret_cast<guchar *>(pixels);
428 }
429
430 guchar *ddsReadX4R4G4B4(uint width, uint height, const unsigned char *buffer) {
431         auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
432         if (pixels == nullptr) return nullptr;
433         uint index = 128;
434         for (uint i = 0; i<height*width; i++) {
435                 uint rgba = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2;
436                 uint r = 17 * ((rgba & A4R4G4B4_MASKS[0]) >> 8);
437                 uint g = 17 * ((rgba & A4R4G4B4_MASKS[1]) >> 4);
438                 uint b = 17 * ((rgba & A4R4G4B4_MASKS[2]));
439                 uint a = 255;
440                 pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16);
441         }
442         return reinterpret_cast<guchar *>(pixels);
443 }
444
445 guchar *ddsReadR5G6B5(uint width, uint height, const unsigned char *buffer) {
446         auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
447         if (pixels == nullptr) return nullptr;
448         uint index = 128;
449         for (uint i = 0; i<height*width; i++) {
450                 uint rgba = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2;
451                 uint r = BIT5[((rgba & R5G6B5_MASKS[0]) >> 11)];
452                 uint g = BIT6[((rgba & R5G6B5_MASKS[1]) >> 5)];
453                 uint b = BIT5[((rgba & R5G6B5_MASKS[2]))];
454                 uint a = 255;
455                 pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16);
456         }
457         return reinterpret_cast<guchar *>(pixels);
458 }
459
460 guchar *ddsReadR8G8B8(uint width, uint height, const unsigned char *buffer) {
461         auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
462         if (pixels == nullptr) return nullptr;
463         uint index = 128;
464         for (uint i = 0; i<height*width; i++) {
465                 uint b = buffer[index++] & 0xFF;
466                 uint g = buffer[index++] & 0xFF;
467                 uint r = buffer[index++] & 0xFF;
468                 uint a = 255;
469                 pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16);
470         }
471         return reinterpret_cast<guchar *>(pixels);
472 }
473
474 guchar *ddsReadA8B8G8R8(uint width, uint height, const unsigned char *buffer) {
475         auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
476         if (pixels == nullptr) return nullptr;
477         uint index = 128;
478         for (uint i = 0; i<height*width; i++) {
479                 uint r = buffer[index++] & 0xFF;
480                 uint g = buffer[index++] & 0xFF;
481                 uint b = buffer[index++] & 0xFF;
482                 uint a = buffer[index++] & 0xFF;
483                 pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16);
484         }
485         return reinterpret_cast<guchar *>(pixels);
486 }
487
488 guchar *ddsReadX8B8G8R8(uint width, uint height, const unsigned char *buffer) {
489         auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
490         if (pixels == nullptr) return nullptr;
491         uint index = 128;
492         for (uint i = 0; i<height*width; i++) {
493                 uint r = buffer[index++] & 0xFF;
494                 uint g = buffer[index++] & 0xFF;
495                 uint b = buffer[index++] & 0xFF;
496                 uint a = 255; index++;
497                 pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16);
498         }
499         return reinterpret_cast<guchar *>(pixels);
500 }
501
502 guchar *ddsReadA8R8G8B8(uint width, uint height, const unsigned char *buffer) {
503         auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
504         if (pixels == nullptr) return nullptr;
505         uint index = 128;
506         for (uint i = 0; i<height*width; i++) {
507                 uint b = buffer[index++] & 0xFF;
508                 uint g = buffer[index++] & 0xFF;
509                 uint r = buffer[index++] & 0xFF;
510                 uint a = buffer[index++] & 0xFF;
511                 pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16);
512         }
513         return reinterpret_cast<guchar *>(pixels);
514 }
515
516 guchar *ddsReadX8R8G8B8(uint width, uint height, const unsigned char *buffer) {
517         auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
518         if (pixels == nullptr) return nullptr;
519         uint index = 128;
520         for (uint i = 0; i<height*width; i++) {
521                 uint b = buffer[index++] & 0xFF;
522                 uint g = buffer[index++] & 0xFF;
523                 uint r = buffer[index++] & 0xFF;
524                 uint a = 255; index++;
525                 pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16);
526         }
527         return reinterpret_cast<guchar *>(pixels);
528 }
529
530 static gboolean image_loader_dds_load (gpointer loader, const guchar *buf, gsize, GError **)
531 {
532         auto ld = static_cast<ImageLoaderDDS *>(loader);
533         uint width = ddsGetWidth(buf);
534         uint height = ddsGetHeight(buf);
535         uint type = ddsGetType(buf);
536         if (type == 0) return FALSE;
537         {
538                 guchar *pixels = nullptr;
539                 guint rowstride = width * 4;
540                 switch (type) {
541                 case DXT1: pixels = ddsDecodeDXT1(width, height, buf); break;
542                 case DXT2: pixels = ddsDecodeDXT2(width, height, buf); break;
543                 case DXT3: pixels = ddsDecodeDXT3(width, height, buf); break;
544                 case DXT4: pixels = ddsDecodeDXT4(width, height, buf); break;
545                 case DXT5: pixels = ddsDecodeDXT5(width, height, buf); break;
546                 case A1R5G5B5: pixels = ddsReadA1R5G5B5(width, height, buf); break;
547                 case X1R5G5B5: pixels = ddsReadX1R5G5B5(width, height, buf); break;
548                 case A4R4G4B4: pixels = ddsReadA4R4G4B4(width, height, buf); break;
549                 case X4R4G4B4: pixels = ddsReadX4R4G4B4(width, height, buf); break;
550                 case R5G6B5: pixels = ddsReadR5G6B5(width, height, buf); break;
551                 case R8G8B8: pixels = ddsReadR8G8B8(width, height, buf); break;
552                 case A8B8G8R8: pixels = ddsReadA8B8G8R8(width, height, buf); break;
553                 case X8B8G8R8: pixels = ddsReadX8B8G8R8(width, height, buf); break;
554                 case A8R8G8B8: pixels = ddsReadA8R8G8B8(width, height, buf); break;
555                 case X8R8G8B8: pixels = ddsReadX8R8G8B8(width, height, buf); break;
556                 }
557                 ld->pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8, width, height, rowstride, free_buffer, nullptr);
558                 ld->area_updated_cb(loader, 0, 0, width, height, ld->data);
559                 return TRUE;
560         }
561 }
562
563 static gpointer image_loader_dds_new(ImageLoaderBackendCbAreaUpdated area_updated_cb, ImageLoaderBackendCbSize size_cb, ImageLoaderBackendCbAreaPrepared area_prepared_cb, gpointer data)
564 {
565         auto loader = g_new0(ImageLoaderDDS, 1);
566         loader->area_updated_cb = area_updated_cb;
567         loader->size_cb = size_cb;
568         loader->area_prepared_cb = area_prepared_cb;
569         loader->data = data;
570         return loader;
571 }
572
573 static void image_loader_dds_set_size(gpointer loader, int width, int height)
574 {
575         auto ld = static_cast<ImageLoaderDDS *>(loader);
576         ld->requested_width = width;
577         ld->requested_height = height;
578 }
579
580 static GdkPixbuf* image_loader_dds_get_pixbuf(gpointer loader)
581 {
582         auto ld = static_cast<ImageLoaderDDS *>(loader);
583         return ld->pixbuf;
584 }
585
586 static gchar* image_loader_dds_get_format_name(gpointer)
587 {
588         return g_strdup("dds");
589 }
590 static gchar** image_loader_dds_get_format_mime_types(gpointer)
591 {
592         static const gchar *mime[] = {"image/vnd-ms.dds", nullptr};
593         return g_strdupv(const_cast<gchar **>(mime));
594 }
595
596 static gboolean image_loader_dds_close(gpointer, GError **)
597 {
598         return TRUE;
599 }
600
601 static void image_loader_dds_abort(gpointer loader)
602 {
603         auto ld = static_cast<ImageLoaderDDS *>(loader);
604         ld->abort = TRUE;
605 }
606
607 static void image_loader_dds_free(gpointer loader)
608 {
609         auto ld = static_cast<ImageLoaderDDS *>(loader);
610         if (ld->pixbuf) g_object_unref(ld->pixbuf);
611         g_free(ld);
612 }
613
614 void image_loader_backend_set_dds(ImageLoaderBackend *funcs)
615 {
616         funcs->loader_new = image_loader_dds_new;
617         funcs->set_size = image_loader_dds_set_size;
618         funcs->load = image_loader_dds_load;
619         funcs->write = nullptr;
620         funcs->get_pixbuf = image_loader_dds_get_pixbuf;
621         funcs->close = image_loader_dds_close;
622         funcs->abort = image_loader_dds_abort;
623         funcs->free = image_loader_dds_free;
624         funcs->get_format_name = image_loader_dds_get_format_name;
625         funcs->get_format_mime_types = image_loader_dds_get_format_mime_types;
626 }
627
628 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */