aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderDDS.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderDDS.cpp')
-rw-r--r--src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderDDS.cpp712
1 files changed, 712 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderDDS.cpp b/src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderDDS.cpp
new file mode 100644
index 0000000..646abd2
--- /dev/null
+++ b/src/others/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
25namespace irr
26{
27
28namespace video
29{
30
31namespace
32{
33
34/*!
35 DDSDecodePixelFormat()
36 determines which pixel format the dds texture is in
37*/
38void 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/*!
66DDSGetInfo()
67extracts relevant info from a dds texture, returns 0 on success
68*/
69s32 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*/
99void 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/*
190DDSDecodeColorBlock()
191decodes a dds color block
192fixme: make endian-safe
193*/
194
195void 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/*
247DDSDecodeAlphaExplicit()
248decodes a dds explicit alpha block
249*/
250void 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/*
284DDSDecodeAlpha3BitLinear()
285decodes interpolated alpha block
286*/
287void 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/*
393DDSDecompressDXT1()
394decompresses a dxt1 format texture
395*/
396s32 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/*
428DDSDecompressDXT3()
429decompresses a dxt3 format texture
430*/
431
432s32 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/*
482DDSDecompressDXT5()
483decompresses a dxt5 format texture
484*/
485s32 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/*
535DDSDecompressDXT2()
536decompresses a dxt2 format texture (fixme: un-premultiply alpha)
537*/
538s32 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/*
549DDSDecompressDXT4()
550decompresses a dxt4 format texture (fixme: un-premultiply alpha)
551*/
552s32 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/*
563DDSDecompressARGB8888()
564decompresses an argb 8888 format texture
565*/
566s32 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/*
591DDSDecompress()
592decompresses a dds texture into an rgba image buffer, returns 0 on success
593*/
594s32 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")
648bool 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
655bool 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
671IImage* 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
702IImageLoader* createImageLoaderDDS()
703{
704 return new CImageLoaderDDS();
705}
706
707
708} // end namespace video
709} // end namespace irr
710
711#endif
712