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