diff options
Diffstat (limited to 'libraries/irrlicht-1.8.1/source/Irrlicht/CImageLoaderDDS.cpp')
-rw-r--r-- | libraries/irrlicht-1.8.1/source/Irrlicht/CImageLoaderDDS.cpp | 712 |
1 files changed, 712 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8.1/source/Irrlicht/CImageLoaderDDS.cpp b/libraries/irrlicht-1.8.1/source/Irrlicht/CImageLoaderDDS.cpp new file mode 100644 index 0000000..646abd2 --- /dev/null +++ b/libraries/irrlicht-1.8.1/source/Irrlicht/CImageLoaderDDS.cpp | |||
@@ -0,0 +1,712 @@ | |||
1 | // Copyright (C) 2002-2012 Thomas Alten | ||
2 | // This file is part of the "Irrlicht Engine". | ||
3 | // For conditions of distribution and use, see copyright notice in irrlicht.h | ||
4 | |||
5 | /* | ||
6 | Based on Code from Copyright (c) 2003 Randy Reddig | ||
7 | Based on code from Nvidia's DDS example: | ||
8 | http://www.nvidia.com/object/dxtc_decompression_code.html | ||
9 | |||
10 | mainly c to cpp | ||
11 | */ | ||
12 | |||
13 | |||
14 | #include "CImageLoaderDDS.h" | ||
15 | |||
16 | #ifdef _IRR_COMPILE_WITH_DDS_LOADER_ | ||
17 | |||
18 | #include "IReadFile.h" | ||
19 | #include "os.h" | ||
20 | #include "CColorConverter.h" | ||
21 | #include "CImage.h" | ||
22 | #include "irrString.h" | ||
23 | |||
24 | |||
25 | namespace irr | ||
26 | { | ||
27 | |||
28 | namespace video | ||
29 | { | ||
30 | |||
31 | namespace | ||
32 | { | ||
33 | |||
34 | /*! | ||
35 | DDSDecodePixelFormat() | ||
36 | determines which pixel format the dds texture is in | ||
37 | */ | ||
38 | void DDSDecodePixelFormat( ddsBuffer *dds, eDDSPixelFormat *pf ) | ||
39 | { | ||
40 | /* dummy check */ | ||
41 | if( dds == NULL || pf == NULL ) | ||
42 | return; | ||
43 | |||
44 | /* extract fourCC */ | ||
45 | const u32 fourCC = dds->pixelFormat.fourCC; | ||
46 | |||
47 | /* test it */ | ||
48 | if( fourCC == 0 ) | ||
49 | *pf = DDS_PF_ARGB8888; | ||
50 | else if( fourCC == *((u32*) "DXT1") ) | ||
51 | *pf = DDS_PF_DXT1; | ||
52 | else if( fourCC == *((u32*) "DXT2") ) | ||
53 | *pf = DDS_PF_DXT2; | ||
54 | else if( fourCC == *((u32*) "DXT3") ) | ||
55 | *pf = DDS_PF_DXT3; | ||
56 | else if( fourCC == *((u32*) "DXT4") ) | ||
57 | *pf = DDS_PF_DXT4; | ||
58 | else if( fourCC == *((u32*) "DXT5") ) | ||
59 | *pf = DDS_PF_DXT5; | ||
60 | else | ||
61 | *pf = DDS_PF_UNKNOWN; | ||
62 | } | ||
63 | |||
64 | |||
65 | /*! | ||
66 | DDSGetInfo() | ||
67 | extracts relevant info from a dds texture, returns 0 on success | ||
68 | */ | ||
69 | s32 DDSGetInfo( ddsBuffer *dds, s32 *width, s32 *height, eDDSPixelFormat *pf ) | ||
70 | { | ||
71 | /* dummy test */ | ||
72 | if( dds == NULL ) | ||
73 | return -1; | ||
74 | |||
75 | /* test dds header */ | ||
76 | if( *((s32*) dds->magic) != *((s32*) "DDS ") ) | ||
77 | return -1; | ||
78 | if( DDSLittleLong( dds->size ) != 124 ) | ||
79 | return -1; | ||
80 | |||
81 | /* extract width and height */ | ||
82 | if( width != NULL ) | ||
83 | *width = DDSLittleLong( dds->width ); | ||
84 | if( height != NULL ) | ||
85 | *height = DDSLittleLong( dds->height ); | ||
86 | |||
87 | /* get pixel format */ | ||
88 | DDSDecodePixelFormat( dds, pf ); | ||
89 | |||
90 | /* return ok */ | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | |||
95 | /*! | ||
96 | DDSGetColorBlockColors() | ||
97 | extracts colors from a dds color block | ||
98 | */ | ||
99 | void DDSGetColorBlockColors( ddsColorBlock *block, ddsColor colors[ 4 ] ) | ||
100 | { | ||
101 | u16 word; | ||
102 | |||
103 | |||
104 | /* color 0 */ | ||
105 | word = DDSLittleShort( block->colors[ 0 ] ); | ||
106 | colors[ 0 ].a = 0xff; | ||
107 | |||
108 | /* extract rgb bits */ | ||
109 | colors[ 0 ].b = (u8) word; | ||
110 | colors[ 0 ].b <<= 3; | ||
111 | colors[ 0 ].b |= (colors[ 0 ].b >> 5); | ||
112 | word >>= 5; | ||
113 | colors[ 0 ].g = (u8) word; | ||
114 | colors[ 0 ].g <<= 2; | ||
115 | colors[ 0 ].g |= (colors[ 0 ].g >> 5); | ||
116 | word >>= 6; | ||
117 | colors[ 0 ].r = (u8) word; | ||
118 | colors[ 0 ].r <<= 3; | ||
119 | colors[ 0 ].r |= (colors[ 0 ].r >> 5); | ||
120 | |||
121 | /* same for color 1 */ | ||
122 | word = DDSLittleShort( block->colors[ 1 ] ); | ||
123 | colors[ 1 ].a = 0xff; | ||
124 | |||
125 | /* extract rgb bits */ | ||
126 | colors[ 1 ].b = (u8) word; | ||
127 | colors[ 1 ].b <<= 3; | ||
128 | colors[ 1 ].b |= (colors[ 1 ].b >> 5); | ||
129 | word >>= 5; | ||
130 | colors[ 1 ].g = (u8) word; | ||
131 | colors[ 1 ].g <<= 2; | ||
132 | colors[ 1 ].g |= (colors[ 1 ].g >> 5); | ||
133 | word >>= 6; | ||
134 | colors[ 1 ].r = (u8) word; | ||
135 | colors[ 1 ].r <<= 3; | ||
136 | colors[ 1 ].r |= (colors[ 1 ].r >> 5); | ||
137 | |||
138 | /* use this for all but the super-freak math method */ | ||
139 | if( block->colors[ 0 ] > block->colors[ 1 ] ) | ||
140 | { | ||
141 | /* four-color block: derive the other two colors. | ||
142 | 00 = color 0, 01 = color 1, 10 = color 2, 11 = color 3 | ||
143 | these two bit codes correspond to the 2-bit fields | ||
144 | stored in the 64-bit block. */ | ||
145 | |||
146 | word = ((u16) colors[ 0 ].r * 2 + (u16) colors[ 1 ].r ) / 3; | ||
147 | /* no +1 for rounding */ | ||
148 | /* as bits have been shifted to 888 */ | ||
149 | colors[ 2 ].r = (u8) word; | ||
150 | word = ((u16) colors[ 0 ].g * 2 + (u16) colors[ 1 ].g) / 3; | ||
151 | colors[ 2 ].g = (u8) word; | ||
152 | word = ((u16) colors[ 0 ].b * 2 + (u16) colors[ 1 ].b) / 3; | ||
153 | colors[ 2 ].b = (u8) word; | ||
154 | colors[ 2 ].a = 0xff; | ||
155 | |||
156 | word = ((u16) colors[ 0 ].r + (u16) colors[ 1 ].r * 2) / 3; | ||
157 | colors[ 3 ].r = (u8) word; | ||
158 | word = ((u16) colors[ 0 ].g + (u16) colors[ 1 ].g * 2) / 3; | ||
159 | colors[ 3 ].g = (u8) word; | ||
160 | word = ((u16) colors[ 0 ].b + (u16) colors[ 1 ].b * 2) / 3; | ||
161 | colors[ 3 ].b = (u8) word; | ||
162 | colors[ 3 ].a = 0xff; | ||
163 | } | ||
164 | else | ||
165 | { | ||
166 | /* three-color block: derive the other color. | ||
167 | 00 = color 0, 01 = color 1, 10 = color 2, | ||
168 | 11 = transparent. | ||
169 | These two bit codes correspond to the 2-bit fields | ||
170 | stored in the 64-bit block */ | ||
171 | |||
172 | word = ((u16) colors[ 0 ].r + (u16) colors[ 1 ].r) / 2; | ||
173 | colors[ 2 ].r = (u8) word; | ||
174 | word = ((u16) colors[ 0 ].g + (u16) colors[ 1 ].g) / 2; | ||
175 | colors[ 2 ].g = (u8) word; | ||
176 | word = ((u16) colors[ 0 ].b + (u16) colors[ 1 ].b) / 2; | ||
177 | colors[ 2 ].b = (u8) word; | ||
178 | colors[ 2 ].a = 0xff; | ||
179 | |||
180 | /* random color to indicate alpha */ | ||
181 | colors[ 3 ].r = 0x00; | ||
182 | colors[ 3 ].g = 0xff; | ||
183 | colors[ 3 ].b = 0xff; | ||
184 | colors[ 3 ].a = 0x00; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | |||
189 | /* | ||
190 | DDSDecodeColorBlock() | ||
191 | decodes a dds color block | ||
192 | fixme: make endian-safe | ||
193 | */ | ||
194 | |||
195 | void DDSDecodeColorBlock( u32 *pixel, ddsColorBlock *block, s32 width, u32 colors[ 4 ] ) | ||
196 | { | ||
197 | s32 r, n; | ||
198 | u32 bits; | ||
199 | u32 masks[] = { 3, 12, 3 << 4, 3 << 6 }; /* bit masks = 00000011, 00001100, 00110000, 11000000 */ | ||
200 | s32 shift[] = { 0, 2, 4, 6 }; | ||
201 | |||
202 | |||
203 | /* r steps through lines in y */ | ||
204 | for( r = 0; r < 4; r++, pixel += (width - 4) ) /* no width * 4 as u32 ptr inc will * 4 */ | ||
205 | { | ||
206 | /* width * 4 bytes per pixel per line, each j dxtc row is 4 lines of pixels */ | ||
207 | |||
208 | /* n steps through pixels */ | ||
209 | for( n = 0; n < 4; n++ ) | ||
210 | { | ||
211 | bits = block->row[ r ] & masks[ n ]; | ||
212 | bits >>= shift[ n ]; | ||
213 | |||
214 | switch( bits ) | ||
215 | { | ||
216 | case 0: | ||
217 | *pixel = colors[ 0 ]; | ||
218 | pixel++; | ||
219 | break; | ||
220 | |||
221 | case 1: | ||
222 | *pixel = colors[ 1 ]; | ||
223 | pixel++; | ||
224 | break; | ||
225 | |||
226 | case 2: | ||
227 | *pixel = colors[ 2 ]; | ||
228 | pixel++; | ||
229 | break; | ||
230 | |||
231 | case 3: | ||
232 | *pixel = colors[ 3 ]; | ||
233 | pixel++; | ||
234 | break; | ||
235 | |||
236 | default: | ||
237 | /* invalid */ | ||
238 | pixel++; | ||
239 | break; | ||
240 | } | ||
241 | } | ||
242 | } | ||
243 | } | ||
244 | |||
245 | |||
246 | /* | ||
247 | DDSDecodeAlphaExplicit() | ||
248 | decodes a dds explicit alpha block | ||
249 | */ | ||
250 | void DDSDecodeAlphaExplicit( u32 *pixel, ddsAlphaBlockExplicit *alphaBlock, s32 width, u32 alphaZero ) | ||
251 | { | ||
252 | s32 row, pix; | ||
253 | u16 word; | ||
254 | ddsColor color; | ||
255 | |||
256 | |||
257 | /* clear color */ | ||
258 | color.r = 0; | ||
259 | color.g = 0; | ||
260 | color.b = 0; | ||
261 | |||
262 | /* walk rows */ | ||
263 | for( row = 0; row < 4; row++, pixel += (width - 4) ) | ||
264 | { | ||
265 | word = DDSLittleShort( alphaBlock->row[ row ] ); | ||
266 | |||
267 | /* walk pixels */ | ||
268 | for( pix = 0; pix < 4; pix++ ) | ||
269 | { | ||
270 | /* zero the alpha bits of image pixel */ | ||
271 | *pixel &= alphaZero; | ||
272 | color.a = word & 0x000F; | ||
273 | color.a = color.a | (color.a << 4); | ||
274 | *pixel |= *((u32*) &color); | ||
275 | word >>= 4; /* move next bits to lowest 4 */ | ||
276 | pixel++; /* move to next pixel in the row */ | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | |||
281 | |||
282 | |||
283 | /* | ||
284 | DDSDecodeAlpha3BitLinear() | ||
285 | decodes interpolated alpha block | ||
286 | */ | ||
287 | void DDSDecodeAlpha3BitLinear( u32 *pixel, ddsAlphaBlock3BitLinear *alphaBlock, s32 width, u32 alphaZero ) | ||
288 | { | ||
289 | |||
290 | s32 row, pix; | ||
291 | u32 stuff; | ||
292 | u8 bits[ 4 ][ 4 ]; | ||
293 | u16 alphas[ 8 ]; | ||
294 | ddsColor aColors[ 4 ][ 4 ]; | ||
295 | |||
296 | /* get initial alphas */ | ||
297 | alphas[ 0 ] = alphaBlock->alpha0; | ||
298 | alphas[ 1 ] = alphaBlock->alpha1; | ||
299 | |||
300 | /* 8-alpha block */ | ||
301 | if( alphas[ 0 ] > alphas[ 1 ] ) | ||
302 | { | ||
303 | /* 000 = alpha_0, 001 = alpha_1, others are interpolated */ | ||
304 | alphas[ 2 ] = ( 6 * alphas[ 0 ] + alphas[ 1 ]) / 7; /* bit code 010 */ | ||
305 | alphas[ 3 ] = ( 5 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 7; /* bit code 011 */ | ||
306 | alphas[ 4 ] = ( 4 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 7; /* bit code 100 */ | ||
307 | alphas[ 5 ] = ( 3 * alphas[ 0 ] + 4 * alphas[ 1 ]) / 7; /* bit code 101 */ | ||
308 | alphas[ 6 ] = ( 2 * alphas[ 0 ] + 5 * alphas[ 1 ]) / 7; /* bit code 110 */ | ||
309 | alphas[ 7 ] = ( alphas[ 0 ] + 6 * alphas[ 1 ]) / 7; /* bit code 111 */ | ||
310 | } | ||
311 | |||
312 | /* 6-alpha block */ | ||
313 | else | ||
314 | { | ||
315 | /* 000 = alpha_0, 001 = alpha_1, others are interpolated */ | ||
316 | alphas[ 2 ] = (4 * alphas[ 0 ] + alphas[ 1 ]) / 5; /* bit code 010 */ | ||
317 | alphas[ 3 ] = (3 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 5; /* bit code 011 */ | ||
318 | alphas[ 4 ] = (2 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 5; /* bit code 100 */ | ||
319 | alphas[ 5 ] = ( alphas[ 0 ] + 4 * alphas[ 1 ]) / 5; /* bit code 101 */ | ||
320 | alphas[ 6 ] = 0; /* bit code 110 */ | ||
321 | alphas[ 7 ] = 255; /* bit code 111 */ | ||
322 | } | ||
323 | |||
324 | /* decode 3-bit fields into array of 16 bytes with same value */ | ||
325 | |||
326 | /* first two rows of 4 pixels each */ | ||
327 | stuff = *((u32*) &(alphaBlock->stuff[ 0 ])); | ||
328 | |||
329 | bits[ 0 ][ 0 ] = (u8) (stuff & 0x00000007); | ||
330 | stuff >>= 3; | ||
331 | bits[ 0 ][ 1 ] = (u8) (stuff & 0x00000007); | ||
332 | stuff >>= 3; | ||
333 | bits[ 0 ][ 2 ] = (u8) (stuff & 0x00000007); | ||
334 | stuff >>= 3; | ||
335 | bits[ 0 ][ 3 ] = (u8) (stuff & 0x00000007); | ||
336 | stuff >>= 3; | ||
337 | bits[ 1 ][ 0 ] = (u8) (stuff & 0x00000007); | ||
338 | stuff >>= 3; | ||
339 | bits[ 1 ][ 1 ] = (u8) (stuff & 0x00000007); | ||
340 | stuff >>= 3; | ||
341 | bits[ 1 ][ 2 ] = (u8) (stuff & 0x00000007); | ||
342 | stuff >>= 3; | ||
343 | bits[ 1 ][ 3 ] = (u8) (stuff & 0x00000007); | ||
344 | |||
345 | /* last two rows */ | ||
346 | stuff = *((u32*) &(alphaBlock->stuff[ 3 ])); /* last 3 bytes */ | ||
347 | |||
348 | bits[ 2 ][ 0 ] = (u8) (stuff & 0x00000007); | ||
349 | stuff >>= 3; | ||
350 | bits[ 2 ][ 1 ] = (u8) (stuff & 0x00000007); | ||
351 | stuff >>= 3; | ||
352 | bits[ 2 ][ 2 ] = (u8) (stuff & 0x00000007); | ||
353 | stuff >>= 3; | ||
354 | bits[ 2 ][ 3 ] = (u8) (stuff & 0x00000007); | ||
355 | stuff >>= 3; | ||
356 | bits[ 3 ][ 0 ] = (u8) (stuff & 0x00000007); | ||
357 | stuff >>= 3; | ||
358 | bits[ 3 ][ 1 ] = (u8) (stuff & 0x00000007); | ||
359 | stuff >>= 3; | ||
360 | bits[ 3 ][ 2 ] = (u8) (stuff & 0x00000007); | ||
361 | stuff >>= 3; | ||
362 | bits[ 3 ][ 3 ] = (u8) (stuff & 0x00000007); | ||
363 | |||
364 | /* decode the codes into alpha values */ | ||
365 | for( row = 0; row < 4; row++ ) | ||
366 | { | ||
367 | for( pix=0; pix < 4; pix++ ) | ||
368 | { | ||
369 | aColors[ row ][ pix ].r = 0; | ||
370 | aColors[ row ][ pix ].g = 0; | ||
371 | aColors[ row ][ pix ].b = 0; | ||
372 | aColors[ row ][ pix ].a = (u8) alphas[ bits[ row ][ pix ] ]; | ||
373 | } | ||
374 | } | ||
375 | |||
376 | /* write out alpha values to the image bits */ | ||
377 | for( row = 0; row < 4; row++, pixel += width-4 ) | ||
378 | { | ||
379 | for( pix = 0; pix < 4; pix++ ) | ||
380 | { | ||
381 | /* zero the alpha bits of image pixel */ | ||
382 | *pixel &= alphaZero; | ||
383 | |||
384 | /* or the bits into the prev. nulled alpha */ | ||
385 | *pixel |= *((u32*) &(aColors[ row ][ pix ])); | ||
386 | pixel++; | ||
387 | } | ||
388 | } | ||
389 | } | ||
390 | |||
391 | |||
392 | /* | ||
393 | DDSDecompressDXT1() | ||
394 | decompresses a dxt1 format texture | ||
395 | */ | ||
396 | s32 DDSDecompressDXT1( ddsBuffer *dds, s32 width, s32 height, u8 *pixels ) | ||
397 | { | ||
398 | s32 x, y, xBlocks, yBlocks; | ||
399 | u32 *pixel; | ||
400 | ddsColorBlock *block; | ||
401 | ddsColor colors[ 4 ]; | ||
402 | |||
403 | /* setup */ | ||
404 | xBlocks = width / 4; | ||
405 | yBlocks = height / 4; | ||
406 | |||
407 | /* walk y */ | ||
408 | for( y = 0; y < yBlocks; y++ ) | ||
409 | { | ||
410 | /* 8 bytes per block */ | ||
411 | block = (ddsColorBlock*) (dds->data + y * xBlocks * 8); | ||
412 | |||
413 | /* walk x */ | ||
414 | for( x = 0; x < xBlocks; x++, block++ ) | ||
415 | { | ||
416 | DDSGetColorBlockColors( block, colors ); | ||
417 | pixel = (u32*) (pixels + x * 16 + (y * 4) * width * 4); | ||
418 | DDSDecodeColorBlock( pixel, block, width, (u32*) colors ); | ||
419 | } | ||
420 | } | ||
421 | |||
422 | /* return ok */ | ||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | |||
427 | /* | ||
428 | DDSDecompressDXT3() | ||
429 | decompresses a dxt3 format texture | ||
430 | */ | ||
431 | |||
432 | s32 DDSDecompressDXT3( ddsBuffer *dds, s32 width, s32 height, u8 *pixels ) | ||
433 | { | ||
434 | s32 x, y, xBlocks, yBlocks; | ||
435 | u32 *pixel, alphaZero; | ||
436 | ddsColorBlock *block; | ||
437 | ddsAlphaBlockExplicit *alphaBlock; | ||
438 | ddsColor colors[ 4 ]; | ||
439 | |||
440 | /* setup */ | ||
441 | xBlocks = width / 4; | ||
442 | yBlocks = height / 4; | ||
443 | |||
444 | /* create zero alpha */ | ||
445 | colors[ 0 ].a = 0; | ||
446 | colors[ 0 ].r = 0xFF; | ||
447 | colors[ 0 ].g = 0xFF; | ||
448 | colors[ 0 ].b = 0xFF; | ||
449 | alphaZero = *((u32*) &colors[ 0 ]); | ||
450 | |||
451 | /* walk y */ | ||
452 | for( y = 0; y < yBlocks; y++ ) | ||
453 | { | ||
454 | /* 8 bytes per block, 1 block for alpha, 1 block for color */ | ||
455 | block = (ddsColorBlock*) (dds->data + y * xBlocks * 16); | ||
456 | |||
457 | /* walk x */ | ||
458 | for( x = 0; x < xBlocks; x++, block++ ) | ||
459 | { | ||
460 | /* get alpha block */ | ||
461 | alphaBlock = (ddsAlphaBlockExplicit*) block; | ||
462 | |||
463 | /* get color block */ | ||
464 | block++; | ||
465 | DDSGetColorBlockColors( block, colors ); | ||
466 | |||
467 | /* decode color block */ | ||
468 | pixel = (u32*) (pixels + x * 16 + (y * 4) * width * 4); | ||
469 | DDSDecodeColorBlock( pixel, block, width, (u32*) colors ); | ||
470 | |||
471 | /* overwrite alpha bits with alpha block */ | ||
472 | DDSDecodeAlphaExplicit( pixel, alphaBlock, width, alphaZero ); | ||
473 | } | ||
474 | } | ||
475 | |||
476 | /* return ok */ | ||
477 | return 0; | ||
478 | } | ||
479 | |||
480 | |||
481 | /* | ||
482 | DDSDecompressDXT5() | ||
483 | decompresses a dxt5 format texture | ||
484 | */ | ||
485 | s32 DDSDecompressDXT5( ddsBuffer *dds, s32 width, s32 height, u8 *pixels ) | ||
486 | { | ||
487 | s32 x, y, xBlocks, yBlocks; | ||
488 | u32 *pixel, alphaZero; | ||
489 | ddsColorBlock *block; | ||
490 | ddsAlphaBlock3BitLinear *alphaBlock; | ||
491 | ddsColor colors[ 4 ]; | ||
492 | |||
493 | /* setup */ | ||
494 | xBlocks = width / 4; | ||
495 | yBlocks = height / 4; | ||
496 | |||
497 | /* create zero alpha */ | ||
498 | colors[ 0 ].a = 0; | ||
499 | colors[ 0 ].r = 0xFF; | ||
500 | colors[ 0 ].g = 0xFF; | ||
501 | colors[ 0 ].b = 0xFF; | ||
502 | alphaZero = *((u32*) &colors[ 0 ]); | ||
503 | |||
504 | /* walk y */ | ||
505 | for( y = 0; y < yBlocks; y++ ) | ||
506 | { | ||
507 | /* 8 bytes per block, 1 block for alpha, 1 block for color */ | ||
508 | block = (ddsColorBlock*) (dds->data + y * xBlocks * 16); | ||
509 | |||
510 | /* walk x */ | ||
511 | for( x = 0; x < xBlocks; x++, block++ ) | ||
512 | { | ||
513 | /* get alpha block */ | ||
514 | alphaBlock = (ddsAlphaBlock3BitLinear*) block; | ||
515 | |||
516 | /* get color block */ | ||
517 | block++; | ||
518 | DDSGetColorBlockColors( block, colors ); | ||
519 | |||
520 | /* decode color block */ | ||
521 | pixel = (u32*) (pixels + x * 16 + (y * 4) * width * 4); | ||
522 | DDSDecodeColorBlock( pixel, block, width, (u32*) colors ); | ||
523 | |||
524 | /* overwrite alpha bits with alpha block */ | ||
525 | DDSDecodeAlpha3BitLinear( pixel, alphaBlock, width, alphaZero ); | ||
526 | } | ||
527 | } | ||
528 | |||
529 | /* return ok */ | ||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | |||
534 | /* | ||
535 | DDSDecompressDXT2() | ||
536 | decompresses a dxt2 format texture (fixme: un-premultiply alpha) | ||
537 | */ | ||
538 | s32 DDSDecompressDXT2( ddsBuffer *dds, s32 width, s32 height, u8 *pixels ) | ||
539 | { | ||
540 | /* decompress dxt3 first */ | ||
541 | const s32 r = DDSDecompressDXT3( dds, width, height, pixels ); | ||
542 | |||
543 | /* return to sender */ | ||
544 | return r; | ||
545 | } | ||
546 | |||
547 | |||
548 | /* | ||
549 | DDSDecompressDXT4() | ||
550 | decompresses a dxt4 format texture (fixme: un-premultiply alpha) | ||
551 | */ | ||
552 | s32 DDSDecompressDXT4( ddsBuffer *dds, s32 width, s32 height, u8 *pixels ) | ||
553 | { | ||
554 | /* decompress dxt5 first */ | ||
555 | const s32 r = DDSDecompressDXT5( dds, width, height, pixels ); | ||
556 | |||
557 | /* return to sender */ | ||
558 | return r; | ||
559 | } | ||
560 | |||
561 | |||
562 | /* | ||
563 | DDSDecompressARGB8888() | ||
564 | decompresses an argb 8888 format texture | ||
565 | */ | ||
566 | s32 DDSDecompressARGB8888( ddsBuffer *dds, s32 width, s32 height, u8 *pixels ) | ||
567 | { | ||
568 | /* setup */ | ||
569 | u8* in = dds->data; | ||
570 | u8* out = pixels; | ||
571 | |||
572 | /* walk y */ | ||
573 | for(s32 y = 0; y < height; y++) | ||
574 | { | ||
575 | /* walk x */ | ||
576 | for(s32 x = 0; x < width; x++) | ||
577 | { | ||
578 | *out++ = *in++; | ||
579 | *out++ = *in++; | ||
580 | *out++ = *in++; | ||
581 | *out++ = *in++; | ||
582 | } | ||
583 | } | ||
584 | |||
585 | /* return ok */ | ||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | |||
590 | /* | ||
591 | DDSDecompress() | ||
592 | decompresses a dds texture into an rgba image buffer, returns 0 on success | ||
593 | */ | ||
594 | s32 DDSDecompress( ddsBuffer *dds, u8 *pixels ) | ||
595 | { | ||
596 | s32 width, height; | ||
597 | eDDSPixelFormat pf; | ||
598 | |||
599 | /* get dds info */ | ||
600 | s32 r = DDSGetInfo( dds, &width, &height, &pf ); | ||
601 | if ( r ) | ||
602 | return r; | ||
603 | |||
604 | /* decompress */ | ||
605 | switch( pf ) | ||
606 | { | ||
607 | case DDS_PF_ARGB8888: | ||
608 | /* fixme: support other [a]rgb formats */ | ||
609 | r = DDSDecompressARGB8888( dds, width, height, pixels ); | ||
610 | break; | ||
611 | |||
612 | case DDS_PF_DXT1: | ||
613 | r = DDSDecompressDXT1( dds, width, height, pixels ); | ||
614 | break; | ||
615 | |||
616 | case DDS_PF_DXT2: | ||
617 | r = DDSDecompressDXT2( dds, width, height, pixels ); | ||
618 | break; | ||
619 | |||
620 | case DDS_PF_DXT3: | ||
621 | r = DDSDecompressDXT3( dds, width, height, pixels ); | ||
622 | break; | ||
623 | |||
624 | case DDS_PF_DXT4: | ||
625 | r = DDSDecompressDXT4( dds, width, height, pixels ); | ||
626 | break; | ||
627 | |||
628 | case DDS_PF_DXT5: | ||
629 | r = DDSDecompressDXT5( dds, width, height, pixels ); | ||
630 | break; | ||
631 | |||
632 | default: | ||
633 | case DDS_PF_UNKNOWN: | ||
634 | memset( pixels, 0xFF, width * height * 4 ); | ||
635 | r = -1; | ||
636 | break; | ||
637 | } | ||
638 | |||
639 | /* return to sender */ | ||
640 | return r; | ||
641 | } | ||
642 | |||
643 | } // end anonymous namespace | ||
644 | |||
645 | |||
646 | //! returns true if the file maybe is able to be loaded by this class | ||
647 | //! based on the file extension (e.g. ".tga") | ||
648 | bool CImageLoaderDDS::isALoadableFileExtension(const io::path& filename) const | ||
649 | { | ||
650 | return core::hasFileExtension ( filename, "dds" ); | ||
651 | } | ||
652 | |||
653 | |||
654 | //! returns true if the file maybe is able to be loaded by this class | ||
655 | bool CImageLoaderDDS::isALoadableFileFormat(io::IReadFile* file) const | ||
656 | { | ||
657 | if (!file) | ||
658 | return false; | ||
659 | |||
660 | ddsBuffer header; | ||
661 | file->read(&header, sizeof(header)); | ||
662 | |||
663 | s32 width, height; | ||
664 | eDDSPixelFormat pixelFormat; | ||
665 | |||
666 | return (0 == DDSGetInfo( &header, &width, &height, &pixelFormat)); | ||
667 | } | ||
668 | |||
669 | |||
670 | //! creates a surface from the file | ||
671 | IImage* CImageLoaderDDS::loadImage(io::IReadFile* file) const | ||
672 | { | ||
673 | u8 *memFile = new u8 [ file->getSize() ]; | ||
674 | file->read ( memFile, file->getSize() ); | ||
675 | |||
676 | ddsBuffer *header = (ddsBuffer*) memFile; | ||
677 | IImage* image = 0; | ||
678 | s32 width, height; | ||
679 | eDDSPixelFormat pixelFormat; | ||
680 | |||
681 | if ( 0 == DDSGetInfo( header, &width, &height, &pixelFormat) ) | ||
682 | { | ||
683 | image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(width, height)); | ||
684 | |||
685 | if ( DDSDecompress( header, (u8*) image->lock() ) == -1) | ||
686 | { | ||
687 | image->unlock(); | ||
688 | image->drop(); | ||
689 | image = 0; | ||
690 | } | ||
691 | } | ||
692 | |||
693 | delete [] memFile; | ||
694 | if ( image ) | ||
695 | image->unlock(); | ||
696 | |||
697 | return image; | ||
698 | } | ||
699 | |||
700 | |||
701 | //! creates a loader which is able to load dds images | ||
702 | IImageLoader* createImageLoaderDDS() | ||
703 | { | ||
704 | return new CImageLoaderDDS(); | ||
705 | } | ||
706 | |||
707 | |||
708 | } // end namespace video | ||
709 | } // end namespace irr | ||
710 | |||
711 | #endif | ||
712 | |||