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