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