2 * Copyright (C) 2018 The Geeqie Team
4 * Author: Wolfgang Lieff
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.
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.
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.
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
27 #include "image-load-dds.h"
31 #include "image-load.h"
33 struct ImageLoaderDDS {
34 ImageLoaderBackendCbAreaUpdated area_updated_cb;
35 ImageLoaderBackendCbSize size_cb;
36 ImageLoaderBackendCbAreaPrepared area_prepared_cb;
39 guint requested_width;
40 guint requested_height;
44 static void free_buffer(guchar *pixels, gpointer)
49 uint ddsGetHeight(unsigned const char * buffer) {
50 return (buffer[12] & 0xFF) | (buffer[13] & 0xFF) << 8 | (buffer[14] & 0xFF) << 16 | (buffer[15] & 0xFF) << 24;
53 uint ddsGetWidth(unsigned const char * buffer) {
54 return (buffer[16] & 0xFF) | (buffer[17] & 0xFF) << 8 | (buffer[18] & 0xFF) << 16 | (buffer[19] & 0xFF) << 24;
57 #pragma GCC diagnostic push
58 #pragma GCC diagnostic ignored "-Wunused-function"
59 uint ddsGetMipmap_unused(unsigned const char * buffer) {
60 return (buffer[28] & 0xFF) | (buffer[29] & 0xFF) << 8 | (buffer[30] & 0xFF) << 16 | (buffer[31] & 0xFF) << 24;
62 #pragma GCC diagnostic pop
64 uint ddsGetPixelFormatFlags(unsigned const char * buffer) {
65 return (buffer[80] & 0xFF) | (buffer[81] & 0xFF) << 8 | (buffer[82] & 0xFF) << 16 | (buffer[83] & 0xFF) << 24;
68 uint ddsGetFourCC(unsigned const char * buffer) {
69 return (buffer[84] & 0xFF) << 24 | (buffer[85] & 0xFF) << 16 | (buffer[86] & 0xFF) << 8 | (buffer[87] & 0xFF);
72 uint ddsGetBitCount(unsigned const char * buffer) {
73 return (buffer[88] & 0xFF) | (buffer[89] & 0xFF) << 8 | (buffer[90] & 0xFF) << 16 | (buffer[91] & 0xFF) << 24;
76 uint ddsGetRedMask(unsigned const char * buffer) {
77 return (buffer[92] & 0xFF) | (buffer[93] & 0xFF) << 8 | (buffer[94] & 0xFF) << 16 | (buffer[95] & 0xFF) << 24;
80 uint ddsGetGreenMask(unsigned const char * buffer) {
81 return (buffer[96] & 0xFF) | (buffer[97] & 0xFF) << 8 | (buffer[98] & 0xFF) << 16 | (buffer[99] & 0xFF) << 24;
84 uint ddsGetBlueMask(unsigned const char * buffer) {
85 return (buffer[100] & 0xFF) | (buffer[101] & 0xFF) << 8 | (buffer[102] & 0xFF) << 16 | (buffer[103] & 0xFF) << 24;
88 uint ddsGetAlphaMask(unsigned const char * buffer) {
89 return (buffer[104] & 0xFF) | (buffer[105] & 0xFF) << 8 | (buffer[106] & 0xFF) << 16 | (buffer[107] & 0xFF) << 24;
99 A1R5G5B5 = ((1 << 16) | 2),
100 X1R5G5B5 = ((2 << 16) | 2),
101 A4R4G4B4 = ((3 << 16) | 2),
102 X4R4G4B4 = ((4 << 16) | 2),
103 R5G6B5 = ((5 << 16) | 2),
104 R8G8B8 = ((1 << 16) | 3),
105 A8B8G8R8 = ((1 << 16) | 4),
106 X8B8G8R8 = ((2 << 16) | 4),
107 A8R8G8B8 = ((3 << 16) | 4),
108 X8R8G8B8 = ((4 << 16) | 4)
112 static const uint A1R5G5B5_MASKS[] = { 0x7C00, 0x03E0, 0x001F, 0x8000 };
113 static const uint X1R5G5B5_MASKS[] = { 0x7C00, 0x03E0, 0x001F, 0x0000 };
114 static const uint A4R4G4B4_MASKS[] = { 0x0F00, 0x00F0, 0x000F, 0xF000 };
115 static const uint X4R4G4B4_MASKS[] = { 0x0F00, 0x00F0, 0x000F, 0x0000 };
116 static const uint R5G6B5_MASKS[] = { 0xF800, 0x07E0, 0x001F, 0x0000 };
117 static const uint R8G8B8_MASKS[] = { 0xFF0000, 0x00FF00, 0x0000FF, 0x000000 };
118 static const uint A8B8G8R8_MASKS[] = { 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 };
119 static const uint X8B8G8R8_MASKS[] = { 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000 };
120 static const uint A8R8G8B8_MASKS[] = { 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000 };
121 static const uint X8R8G8B8_MASKS[] = { 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000 };
123 // BIT4 = 17 * index;
124 static const uint BIT5[] = { 0, 8, 16, 25, 33, 41, 49, 58, 66, 74, 82, 90, 99, 107, 115, 123, 132, 140, 148, 156, 165, 173, 181, 189, 197, 206, 214, 222, 230, 239, 247, 255 };
125 static const uint BIT6[] = { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 130, 134, 138, 142, 146, 150, 154, 158, 162, 166, 170, 174, 178, 182, 186, 190, 194, 198, 202, 206, 210, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251, 255 };
127 static uint ddsGetType(const unsigned char *buffer) {
129 uint flags = ddsGetPixelFormatFlags(buffer);
130 if ((flags & 0x04) != 0) {
132 type = ddsGetFourCC(buffer);
134 else if ((flags & 0x40) != 0) {
136 uint bitCount = ddsGetBitCount(buffer);
137 uint redMask = ddsGetRedMask(buffer);
138 uint greenMask = ddsGetGreenMask(buffer);
139 uint blueMask = ddsGetBlueMask(buffer);
140 uint alphaMask = ((flags & 0x01) != 0) ? ddsGetAlphaMask(buffer) : 0; // 0x01 alpha
141 if (bitCount == 16) {
142 if (redMask == A1R5G5B5_MASKS[0] && greenMask == A1R5G5B5_MASKS[1] && blueMask == A1R5G5B5_MASKS[2] && alphaMask == A1R5G5B5_MASKS[3]) {
146 else if (redMask == X1R5G5B5_MASKS[0] && greenMask == X1R5G5B5_MASKS[1] && blueMask == X1R5G5B5_MASKS[2] && alphaMask == X1R5G5B5_MASKS[3]) {
150 else if (redMask == A4R4G4B4_MASKS[0] && greenMask == A4R4G4B4_MASKS[1] && blueMask == A4R4G4B4_MASKS[2] && alphaMask == A4R4G4B4_MASKS[3]) {
154 else if (redMask == X4R4G4B4_MASKS[0] && greenMask == X4R4G4B4_MASKS[1] && blueMask == X4R4G4B4_MASKS[2] && alphaMask == X4R4G4B4_MASKS[3]) {
158 else if (redMask == R5G6B5_MASKS[0] && greenMask == R5G6B5_MASKS[1] && blueMask == R5G6B5_MASKS[2] && alphaMask == R5G6B5_MASKS[3]) {
163 // Unsupported 16bit RGB image
166 else if (bitCount == 24) {
167 if (redMask == R8G8B8_MASKS[0] && greenMask == R8G8B8_MASKS[1] && blueMask == R8G8B8_MASKS[2] && alphaMask == R8G8B8_MASKS[3]) {
172 // Unsupported 24bit RGB image
175 else if (bitCount == 32) {
176 if (redMask == A8B8G8R8_MASKS[0] && greenMask == A8B8G8R8_MASKS[1] && blueMask == A8B8G8R8_MASKS[2] && alphaMask == A8B8G8R8_MASKS[3]) {
180 else if (redMask == X8B8G8R8_MASKS[0] && greenMask == X8B8G8R8_MASKS[1] && blueMask == X8B8G8R8_MASKS[2] && alphaMask == X8B8G8R8_MASKS[3]) {
184 else if (redMask == A8R8G8B8_MASKS[0] && greenMask == A8R8G8B8_MASKS[1] && blueMask == A8R8G8B8_MASKS[2] && alphaMask == A8R8G8B8_MASKS[3]) {
188 else if (redMask == X8R8G8B8_MASKS[0] && greenMask == X8R8G8B8_MASKS[1] && blueMask == X8R8G8B8_MASKS[2] && alphaMask == X8R8G8B8_MASKS[3]) {
193 // Unsupported 32bit RGB image
198 // YUV or LUMINANCE image
203 uint ddsGetDXTColor2_1(uint c0, uint c1, uint a) {
205 uint r = (2 * BIT5[(c0 & 0xFC00) >> 11] + BIT5[(c1 & 0xFC00) >> 11]) / 3;
206 uint g = (2 * BIT6[(c0 & 0x07E0) >> 5] + BIT6[(c1 & 0x07E0) >> 5]) / 3;
207 uint b = (2 * BIT5[c0 & 0x001F] + BIT5[c1 & 0x001F]) / 3;
208 return (a << 24) | (r << 0) | (g << 8) | (b << 16);
211 uint ddsGetDXTColor1_1(uint c0, uint c1, uint a) {
213 uint r = (BIT5[(c0 & 0xFC00) >> 11] + BIT5[(c1 & 0xFC00) >> 11]) / 2;
214 uint g = (BIT6[(c0 & 0x07E0) >> 5] + BIT6[(c1 & 0x07E0) >> 5]) / 2;
215 uint b = (BIT5[c0 & 0x001F] + BIT5[c1 & 0x001F]) / 2;
216 return (a << 24) | (r << 0) | (g << 8) | (b << 16);
219 uint ddsGetDXTColor1(uint c, uint a) {
220 uint r = BIT5[(c & 0xFC00) >> 11];
221 uint g = BIT6[(c & 0x07E0) >> 5];
222 uint b = BIT5[(c & 0x001F)];
223 return (a << 24) | (r << 0) | (g << 8) | (b << 16);
226 uint ddsGetDXTColor(uint c0, uint c1, uint a, uint t) {
228 case 0: return ddsGetDXTColor1(c0, a);
229 case 1: return ddsGetDXTColor1(c1, a);
230 case 2: return (c0 > c1) ? ddsGetDXTColor2_1(c0, c1, a) : ddsGetDXTColor1_1(c0, c1, a);
231 case 3: return (c0 > c1) ? ddsGetDXTColor2_1(c1, c0, a) : 0;
236 guchar *ddsDecodeDXT1(uint width, uint height, const unsigned char *buffer) {
237 auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
238 if (pixels == nullptr) return nullptr;
240 uint w = (width + 3) / 4;
241 uint h = (height + 3) / 4;
242 for (uint i = 0; i<h; i++) {
243 for (uint j = 0; j<w; j++) {
244 uint c0 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2;
245 uint c1 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2;
246 for (uint k = 0; k<4; k++) {
247 if (4 * i + k >= height) break;
248 uint t0 = (buffer[index] & 0x03);
249 uint t1 = (buffer[index] & 0x0C) >> 2;
250 uint t2 = (buffer[index] & 0x30) >> 4;
251 uint t3 = (buffer[index++] & 0xC0) >> 6;
252 pixels[4 * width*i + 4 * j + width*k + 0] = ddsGetDXTColor(c0, c1, 0xFF, t0);
253 if (4 * j + 1 >= width) continue;
254 pixels[4 * width*i + 4 * j + width*k + 1] = ddsGetDXTColor(c0, c1, 0xFF, t1);
255 if (4 * j + 2 >= width) continue;
256 pixels[4 * width*i + 4 * j + width*k + 2] = ddsGetDXTColor(c0, c1, 0xFF, t2);
257 if (4 * j + 3 >= width) continue;
258 pixels[4 * width*i + 4 * j + width*k + 3] = ddsGetDXTColor(c0, c1, 0xFF, t3);
262 return reinterpret_cast<guchar *>(pixels);
265 guchar *ddsDecodeDXT3(uint width, uint height, const unsigned char *buffer) {
266 auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
267 if (pixels == nullptr) return nullptr;
269 uint w = (width + 3) / 4;
270 uint h = (height + 3) / 4;
272 for (uint i = 0; i<h; i++) {
273 for (uint j = 0; j<w; j++) {
274 // create alpha table(4bit to 8bit)
275 for (uint k = 0; k<4; k++) {
276 uint a0 = (buffer[index++] & 0xFF);
277 uint a1 = (buffer[index++] & 0xFF);
278 // 4bit alpha to 8bit alpha
279 alphaTable[4 * k + 0] = 17 * ((a0 & 0xF0) >> 4);
280 alphaTable[4 * k + 1] = 17 * (a0 & 0x0F);
281 alphaTable[4 * k + 2] = 17 * ((a1 & 0xF0) >> 4);
282 alphaTable[4 * k + 3] = 17 * (a1 & 0x0F);
284 uint c0 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2;
285 uint c1 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2;
286 for (uint k = 0; k<4; k++) {
287 if (4 * i + k >= height) break;
288 uint t0 = (buffer[index] & 0x03);
289 uint t1 = (buffer[index] & 0x0C) >> 2;
290 uint t2 = (buffer[index] & 0x30) >> 4;
291 uint t3 = (buffer[index++] & 0xC0) >> 6;
292 pixels[4 * width*i + 4 * j + width*k + 0] = ddsGetDXTColor(c0, c1, alphaTable[4 * k + 0], t0);
293 if (4 * j + 1 >= width) continue;
294 pixels[4 * width*i + 4 * j + width*k + 1] = ddsGetDXTColor(c0, c1, alphaTable[4 * k + 1], t1);
295 if (4 * j + 2 >= width) continue;
296 pixels[4 * width*i + 4 * j + width*k + 2] = ddsGetDXTColor(c0, c1, alphaTable[4 * k + 2], t2);
297 if (4 * j + 3 >= width) continue;
298 pixels[4 * width*i + 4 * j + width*k + 3] = ddsGetDXTColor(c0, c1, alphaTable[4 * k + 3], t3);
302 return reinterpret_cast<guchar *>(pixels);
305 guchar *ddsDecodeDXT2(uint width, uint height, const unsigned char *buffer) {
306 return ddsDecodeDXT3(width, height, buffer);
309 int ddsGetDXT5Alpha(uint a0, uint a1, uint t) {
310 if (a0 > a1) switch (t) {
313 case 2: return (6 * a0 + a1) / 7;
314 case 3: return (5 * a0 + 2 * a1) / 7;
315 case 4: return (4 * a0 + 3 * a1) / 7;
316 case 5: return (3 * a0 + 4 * a1) / 7;
317 case 6: return (2 * a0 + 5 * a1) / 7;
318 case 7: return (a0 + 6 * a1) / 7;
323 case 2: return (4 * a0 + a1) / 5;
324 case 3: return (3 * a0 + 2 * a1) / 5;
325 case 4: return (2 * a0 + 3 * a1) / 5;
326 case 5: return (a0 + 4 * a1) / 5;
333 guchar *ddsDecodeDXT5(uint width, uint height, const unsigned char *buffer) {
334 auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
335 if (pixels == nullptr) return nullptr;
337 uint w = (width + 3) / 4;
338 uint h = (height + 3) / 4;
340 for (uint i = 0; i<h; i++) {
341 for (uint j = 0; j<w; j++) {
342 // create alpha table
343 uint a0 = (buffer[index++] & 0xFF);
344 uint a1 = (buffer[index++] & 0xFF);
345 uint b0 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8 | (buffer[index + 2] & 0xFF) << 16; index += 3;
346 uint b1 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8 | (buffer[index + 2] & 0xFF) << 16; index += 3;
347 alphaTable[0] = b0 & 0x07;
348 alphaTable[1] = (b0 >> 3) & 0x07;
349 alphaTable[2] = (b0 >> 6) & 0x07;
350 alphaTable[3] = (b0 >> 9) & 0x07;
351 alphaTable[4] = (b0 >> 12) & 0x07;
352 alphaTable[5] = (b0 >> 15) & 0x07;
353 alphaTable[6] = (b0 >> 18) & 0x07;
354 alphaTable[7] = (b0 >> 21) & 0x07;
355 alphaTable[8] = b1 & 0x07;
356 alphaTable[9] = (b1 >> 3) & 0x07;
357 alphaTable[10] = (b1 >> 6) & 0x07;
358 alphaTable[11] = (b1 >> 9) & 0x07;
359 alphaTable[12] = (b1 >> 12) & 0x07;
360 alphaTable[13] = (b1 >> 15) & 0x07;
361 alphaTable[14] = (b1 >> 18) & 0x07;
362 alphaTable[15] = (b1 >> 21) & 0x07;
363 uint c0 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2;
364 uint c1 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2;
365 for (uint k = 0; k<4; k++) {
366 if (4 * i + k >= height) break;
367 uint t0 = (buffer[index] & 0x03);
368 uint t1 = (buffer[index] & 0x0C) >> 2;
369 uint t2 = (buffer[index] & 0x30) >> 4;
370 uint t3 = (buffer[index++] & 0xC0) >> 6;
371 pixels[4 * width*i + 4 * j + width*k + 0] = ddsGetDXTColor(c0, c1, ddsGetDXT5Alpha(a0, a1, alphaTable[4 * k + 0]), t0);
372 if (4 * j + 1 >= width) continue;
373 pixels[4 * width*i + 4 * j + width*k + 1] = ddsGetDXTColor(c0, c1, ddsGetDXT5Alpha(a0, a1, alphaTable[4 * k + 1]), t1);
374 if (4 * j + 2 >= width) continue;
375 pixels[4 * width*i + 4 * j + width*k + 2] = ddsGetDXTColor(c0, c1, ddsGetDXT5Alpha(a0, a1, alphaTable[4 * k + 2]), t2);
376 if (4 * j + 3 >= width) continue;
377 pixels[4 * width*i + 4 * j + width*k + 3] = ddsGetDXTColor(c0, c1, ddsGetDXT5Alpha(a0, a1, alphaTable[4 * k + 3]), t3);
381 return reinterpret_cast<guchar *>(pixels);
384 guchar *ddsDecodeDXT4(uint width, uint height, const unsigned char *buffer) {
385 return ddsDecodeDXT5(width, height, buffer);
388 guchar *ddsReadA1R5G5B5(uint width, uint height, const unsigned char *buffer) {
389 auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
390 if (pixels == nullptr) return nullptr;
392 for (uint i = 0; i<height*width; i++) {
393 uint rgba = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2;
394 uint r = BIT5[(rgba & A1R5G5B5_MASKS[0]) >> 10];
395 uint g = BIT5[(rgba & A1R5G5B5_MASKS[1]) >> 5];
396 uint b = BIT5[(rgba & A1R5G5B5_MASKS[2])];
397 uint a = 255 * ((rgba & A1R5G5B5_MASKS[3]) >> 15);
398 pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16);
400 return reinterpret_cast<guchar *>(pixels);
403 guchar *ddsReadX1R5G5B5(uint width, uint height, const unsigned char *buffer) {
404 auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
405 if (pixels == nullptr) return nullptr;
407 for (uint i = 0; i<height*width; i++) {
408 uint rgba = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2;
409 uint r = BIT5[(rgba & X1R5G5B5_MASKS[0]) >> 10];
410 uint g = BIT5[(rgba & X1R5G5B5_MASKS[1]) >> 5];
411 uint b = BIT5[(rgba & X1R5G5B5_MASKS[2])];
413 pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16);
415 return reinterpret_cast<guchar *>(pixels);
418 guchar *ddsReadA4R4G4B4(uint width, uint height, const unsigned char *buffer) {
419 auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
420 if (pixels == nullptr) return nullptr;
422 for (uint i = 0; i<height*width; i++) {
423 uint rgba = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2;
424 uint r = 17 * ((rgba & A4R4G4B4_MASKS[0]) >> 8);
425 uint g = 17 * ((rgba & A4R4G4B4_MASKS[1]) >> 4);
426 uint b = 17 * ((rgba & A4R4G4B4_MASKS[2]));
427 uint a = 17 * ((rgba & A4R4G4B4_MASKS[3]) >> 12);
428 pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16);
430 return reinterpret_cast<guchar *>(pixels);
433 guchar *ddsReadX4R4G4B4(uint width, uint height, const unsigned char *buffer) {
434 auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
435 if (pixels == nullptr) return nullptr;
437 for (uint i = 0; i<height*width; i++) {
438 uint rgba = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2;
439 uint r = 17 * ((rgba & A4R4G4B4_MASKS[0]) >> 8);
440 uint g = 17 * ((rgba & A4R4G4B4_MASKS[1]) >> 4);
441 uint b = 17 * ((rgba & A4R4G4B4_MASKS[2]));
443 pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16);
445 return reinterpret_cast<guchar *>(pixels);
448 guchar *ddsReadR5G6B5(uint width, uint height, const unsigned char *buffer) {
449 auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
450 if (pixels == nullptr) return nullptr;
452 for (uint i = 0; i<height*width; i++) {
453 uint rgba = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2;
454 uint r = BIT5[((rgba & R5G6B5_MASKS[0]) >> 11)];
455 uint g = BIT6[((rgba & R5G6B5_MASKS[1]) >> 5)];
456 uint b = BIT5[((rgba & R5G6B5_MASKS[2]))];
458 pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16);
460 return reinterpret_cast<guchar *>(pixels);
463 guchar *ddsReadR8G8B8(uint width, uint height, const unsigned char *buffer) {
464 auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
465 if (pixels == nullptr) return nullptr;
467 for (uint i = 0; i<height*width; i++) {
468 uint b = buffer[index++] & 0xFF;
469 uint g = buffer[index++] & 0xFF;
470 uint r = buffer[index++] & 0xFF;
472 pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16);
474 return reinterpret_cast<guchar *>(pixels);
477 guchar *ddsReadA8B8G8R8(uint width, uint height, const unsigned char *buffer) {
478 auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
479 if (pixels == nullptr) return nullptr;
481 for (uint i = 0; i<height*width; i++) {
482 uint r = buffer[index++] & 0xFF;
483 uint g = buffer[index++] & 0xFF;
484 uint b = buffer[index++] & 0xFF;
485 uint a = buffer[index++] & 0xFF;
486 pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16);
488 return reinterpret_cast<guchar *>(pixels);
491 guchar *ddsReadX8B8G8R8(uint width, uint height, const unsigned char *buffer) {
492 auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
493 if (pixels == nullptr) return nullptr;
495 for (uint i = 0; i<height*width; i++) {
496 uint r = buffer[index++] & 0xFF;
497 uint g = buffer[index++] & 0xFF;
498 uint b = buffer[index++] & 0xFF;
499 uint a = 255; index++;
500 pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16);
502 return reinterpret_cast<guchar *>(pixels);
505 guchar *ddsReadA8R8G8B8(uint width, uint height, const unsigned char *buffer) {
506 auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
507 if (pixels == nullptr) return nullptr;
509 for (uint i = 0; i<height*width; i++) {
510 uint b = buffer[index++] & 0xFF;
511 uint g = buffer[index++] & 0xFF;
512 uint r = buffer[index++] & 0xFF;
513 uint a = buffer[index++] & 0xFF;
514 pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16);
516 return reinterpret_cast<guchar *>(pixels);
519 guchar *ddsReadX8R8G8B8(uint width, uint height, const unsigned char *buffer) {
520 auto pixels = static_cast<uint *>(g_try_malloc(4 * width*height));
521 if (pixels == nullptr) return nullptr;
523 for (uint i = 0; i<height*width; i++) {
524 uint b = buffer[index++] & 0xFF;
525 uint g = buffer[index++] & 0xFF;
526 uint r = buffer[index++] & 0xFF;
527 uint a = 255; index++;
528 pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16);
530 return reinterpret_cast<guchar *>(pixels);
533 static gboolean image_loader_dds_load (gpointer loader, const guchar *buf, gsize, GError **)
535 auto ld = static_cast<ImageLoaderDDS *>(loader);
536 uint width = ddsGetWidth(buf);
537 uint height = ddsGetHeight(buf);
538 uint type = ddsGetType(buf);
539 if (type == 0) return FALSE;
541 guchar *pixels = nullptr;
542 guint rowstride = width * 4;
544 case DXT1: pixels = ddsDecodeDXT1(width, height, buf); break;
545 case DXT2: pixels = ddsDecodeDXT2(width, height, buf); break;
546 case DXT3: pixels = ddsDecodeDXT3(width, height, buf); break;
547 case DXT4: pixels = ddsDecodeDXT4(width, height, buf); break;
548 case DXT5: pixels = ddsDecodeDXT5(width, height, buf); break;
549 case A1R5G5B5: pixels = ddsReadA1R5G5B5(width, height, buf); break;
550 case X1R5G5B5: pixels = ddsReadX1R5G5B5(width, height, buf); break;
551 case A4R4G4B4: pixels = ddsReadA4R4G4B4(width, height, buf); break;
552 case X4R4G4B4: pixels = ddsReadX4R4G4B4(width, height, buf); break;
553 case R5G6B5: pixels = ddsReadR5G6B5(width, height, buf); break;
554 case R8G8B8: pixels = ddsReadR8G8B8(width, height, buf); break;
555 case A8B8G8R8: pixels = ddsReadA8B8G8R8(width, height, buf); break;
556 case X8B8G8R8: pixels = ddsReadX8B8G8R8(width, height, buf); break;
557 case A8R8G8B8: pixels = ddsReadA8R8G8B8(width, height, buf); break;
558 case X8R8G8B8: pixels = ddsReadX8R8G8B8(width, height, buf); break;
560 ld->pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8, width, height, rowstride, free_buffer, nullptr);
561 ld->area_updated_cb(loader, 0, 0, width, height, ld->data);
566 static gpointer image_loader_dds_new(ImageLoaderBackendCbAreaUpdated area_updated_cb, ImageLoaderBackendCbSize size_cb, ImageLoaderBackendCbAreaPrepared area_prepared_cb, gpointer data)
568 auto loader = g_new0(ImageLoaderDDS, 1);
569 loader->area_updated_cb = area_updated_cb;
570 loader->size_cb = size_cb;
571 loader->area_prepared_cb = area_prepared_cb;
576 static void image_loader_dds_set_size(gpointer loader, int width, int height)
578 auto ld = static_cast<ImageLoaderDDS *>(loader);
579 ld->requested_width = width;
580 ld->requested_height = height;
583 static GdkPixbuf* image_loader_dds_get_pixbuf(gpointer loader)
585 auto ld = static_cast<ImageLoaderDDS *>(loader);
589 static gchar* image_loader_dds_get_format_name(gpointer)
591 return g_strdup("dds");
593 static gchar** image_loader_dds_get_format_mime_types(gpointer)
595 static const gchar *mime[] = {"image/vnd-ms.dds", nullptr};
596 return g_strdupv(const_cast<gchar **>(mime));
599 static gboolean image_loader_dds_close(gpointer, GError **)
604 static void image_loader_dds_abort(gpointer loader)
606 auto ld = static_cast<ImageLoaderDDS *>(loader);
610 static void image_loader_dds_free(gpointer loader)
612 auto ld = static_cast<ImageLoaderDDS *>(loader);
613 if (ld->pixbuf) g_object_unref(ld->pixbuf);
617 void image_loader_backend_set_dds(ImageLoaderBackend *funcs)
619 funcs->loader_new = image_loader_dds_new;
620 funcs->set_size = image_loader_dds_set_size;
621 funcs->load = image_loader_dds_load;
622 funcs->write = nullptr;
623 funcs->get_pixbuf = image_loader_dds_get_pixbuf;
624 funcs->close = image_loader_dds_close;
625 funcs->abort = image_loader_dds_abort;
626 funcs->free = image_loader_dds_free;
627 funcs->get_format_name = image_loader_dds_get_format_name;
628 funcs->get_format_mime_types = image_loader_dds_get_format_mime_types;
631 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */