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