• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kimgio
 

kimgio

  • kimgio
dds.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2003 Ignacio Castaņo
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the Lesser GNU General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 Almost all this code is based on nVidia's DDS-loading example
10 and the DevIl's source code by Denton Woods.
11*/
12
13/* this code supports:
14 * reading:
15 * rgb and dxt dds files
16 * cubemap dds files
17 * volume dds files -- TODO
18 * writing:
19 * rgb dds files only -- TODO
20 */
21
22#include "dds.h"
23
24#include <tqimage.h>
25#include <tqdatastream.h>
26
27#include <tdeglobal.h>
28#include <kdebug.h>
29
30#include <math.h> // sqrtf
31
32#ifndef __USE_ISOC99
33#define sqrtf(x) ((float)sqrt(x))
34#endif
35
36typedef TQ_UINT32 uint;
37typedef TQ_UINT16 ushort;
38typedef TQ_UINT8 uchar;
39
40namespace { // Private.
41
42#if !defined(MAKEFOURCC)
43# define MAKEFOURCC(ch0, ch1, ch2, ch3) \
44 (uint(uchar(ch0)) | (uint(uchar(ch1)) << 8) | \
45 (uint(uchar(ch2)) << 16) | (uint(uchar(ch3)) << 24 ))
46#endif
47
48#define HORIZONTAL 1
49#define VERTICAL 2
50#define CUBE_LAYOUT HORIZONTAL
51
52 struct Color8888
53 {
54 uchar r, g, b, a;
55 };
56
57 union Color565
58 {
59 struct {
60 ushort b : 5;
61 ushort g : 6;
62 ushort r : 5;
63 } c;
64 ushort u;
65 };
66
67 union Color1555 {
68 struct {
69 ushort b : 5;
70 ushort g : 5;
71 ushort r : 5;
72 ushort a : 1;
73 } c;
74 ushort u;
75 };
76
77 union Color4444 {
78 struct {
79 ushort b : 4;
80 ushort g : 4;
81 ushort r : 4;
82 ushort a : 4;
83 } c;
84 ushort u;
85 };
86
87
88 static const uint FOURCC_DDS = MAKEFOURCC('D', 'D', 'S', ' ');
89 static const uint FOURCC_DXT1 = MAKEFOURCC('D', 'X', 'T', '1');
90 static const uint FOURCC_DXT2 = MAKEFOURCC('D', 'X', 'T', '2');
91 static const uint FOURCC_DXT3 = MAKEFOURCC('D', 'X', 'T', '3');
92 static const uint FOURCC_DXT4 = MAKEFOURCC('D', 'X', 'T', '4');
93 static const uint FOURCC_DXT5 = MAKEFOURCC('D', 'X', 'T', '5');
94 static const uint FOURCC_RXGB = MAKEFOURCC('R', 'X', 'G', 'B');
95 static const uint FOURCC_ATI2 = MAKEFOURCC('A', 'T', 'I', '2');
96
97 static const uint DDSD_CAPS = 0x00000001l;
98 static const uint DDSD_PIXELFORMAT = 0x00001000l;
99 static const uint DDSD_WIDTH = 0x00000004l;
100 static const uint DDSD_HEIGHT = 0x00000002l;
101 static const uint DDSD_PITCH = 0x00000008l;
102
103 static const uint DDSCAPS_TEXTURE = 0x00001000l;
104 static const uint DDSCAPS2_VOLUME = 0x00200000l;
105 static const uint DDSCAPS2_CUBEMAP = 0x00000200l;
106
107 static const uint DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400l;
108 static const uint DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800l;
109 static const uint DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000l;
110 static const uint DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000l;
111 static const uint DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000l;
112 static const uint DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000l;
113
114 static const uint DDPF_RGB = 0x00000040l;
115 static const uint DDPF_FOURCC = 0x00000004l;
116 static const uint DDPF_ALPHAPIXELS = 0x00000001l;
117
118 enum DDSType {
119 DDS_A8R8G8B8 = 0,
120 DDS_A1R5G5B5 = 1,
121 DDS_A4R4G4B4 = 2,
122 DDS_R8G8B8 = 3,
123 DDS_R5G6B5 = 4,
124 DDS_DXT1 = 5,
125 DDS_DXT2 = 6,
126 DDS_DXT3 = 7,
127 DDS_DXT4 = 8,
128 DDS_DXT5 = 9,
129 DDS_RXGB = 10,
130 DDS_ATI2 = 11,
131 DDS_UNKNOWN
132 };
133
134
135 struct DDSPixelFormat {
136 uint size;
137 uint flags;
138 uint fourcc;
139 uint bitcount;
140 uint rmask;
141 uint gmask;
142 uint bmask;
143 uint amask;
144 };
145
146 static TQDataStream & operator>> ( TQDataStream & s, DDSPixelFormat & pf )
147 {
148 s >> pf.size;
149 s >> pf.flags;
150 s >> pf.fourcc;
151 s >> pf.bitcount;
152 s >> pf.rmask;
153 s >> pf.gmask;
154 s >> pf.bmask;
155 s >> pf.amask;
156 return s;
157 }
158
159 struct DDSCaps {
160 uint caps1;
161 uint caps2;
162 uint caps3;
163 uint caps4;
164 };
165
166 static TQDataStream & operator>> ( TQDataStream & s, DDSCaps & caps )
167 {
168 s >> caps.caps1;
169 s >> caps.caps2;
170 s >> caps.caps3;
171 s >> caps.caps4;
172 return s;
173 }
174
175 struct DDSHeader {
176 uint size;
177 uint flags;
178 uint height;
179 uint width;
180 uint pitch;
181 uint depth;
182 uint mipmapcount;
183 uint reserved[11];
184 DDSPixelFormat pf;
185 DDSCaps caps;
186 uint notused;
187 };
188
189 static TQDataStream & operator>> ( TQDataStream & s, DDSHeader & header )
190 {
191 s >> header.size;
192 s >> header.flags;
193 s >> header.height;
194 s >> header.width;
195 s >> header.pitch;
196 s >> header.depth;
197 s >> header.mipmapcount;
198 for( int i = 0; i < 11; i++ ) {
199 s >> header.reserved[i];
200 }
201 s >> header.pf;
202 s >> header.caps;
203 s >> header.notused;
204 return s;
205 }
206
207 static bool IsValid( const DDSHeader & header )
208 {
209 if( header.size != 124 ) {
210 return false;
211 }
212 const uint required = (DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS|DDSD_PIXELFORMAT);
213 if( (header.flags & required) != required ) {
214 return false;
215 }
216 if( header.pf.size != 32 ) {
217 return false;
218 }
219 if( !(header.caps.caps1 & DDSCAPS_TEXTURE) ) {
220 return false;
221 }
222 return true;
223 }
224
225
226 // Get supported type. We currently support 10 different types.
227 static DDSType GetType( const DDSHeader & header )
228 {
229 if( header.pf.flags & DDPF_RGB ) {
230 if( header.pf.flags & DDPF_ALPHAPIXELS ) {
231 switch( header.pf.bitcount ) {
232 case 16:
233 return (header.pf.amask == 0x8000) ? DDS_A1R5G5B5 : DDS_A4R4G4B4;
234 case 32:
235 return DDS_A8R8G8B8;
236 }
237 }
238 else {
239 switch( header.pf.bitcount ) {
240 case 16:
241 return DDS_R5G6B5;
242 case 24:
243 return DDS_R8G8B8;
244 }
245 }
246 }
247 else if( header.pf.flags & DDPF_FOURCC ) {
248 switch( header.pf.fourcc ) {
249 case FOURCC_DXT1:
250 return DDS_DXT1;
251 case FOURCC_DXT2:
252 return DDS_DXT2;
253 case FOURCC_DXT3:
254 return DDS_DXT3;
255 case FOURCC_DXT4:
256 return DDS_DXT4;
257 case FOURCC_DXT5:
258 return DDS_DXT5;
259 case FOURCC_RXGB:
260 return DDS_RXGB;
261 case FOURCC_ATI2:
262 return DDS_ATI2;
263 }
264 }
265 return DDS_UNKNOWN;
266 }
267
268
269 static bool HasAlpha( const DDSHeader & header )
270 {
271 return header.pf.flags & DDPF_ALPHAPIXELS;
272 }
273
274 static bool IsCubeMap( const DDSHeader & header )
275 {
276 return header.caps.caps2 & DDSCAPS2_CUBEMAP;
277 }
278
279 static bool IsSupported( const DDSHeader & header )
280 {
281 if( header.caps.caps2 & DDSCAPS2_VOLUME ) {
282 return false;
283 }
284 if( GetType(header) == DDS_UNKNOWN ) {
285 return false;
286 }
287 return true;
288 }
289
290
291 static bool LoadA8R8G8B8( TQDataStream & s, const DDSHeader & header, TQImage & img )
292 {
293 const uint w = header.width;
294 const uint h = header.height;
295
296 for( uint y = 0; y < h; y++ ) {
297 TQRgb * scanline = (TQRgb *) img.scanLine( y );
298 for( uint x = 0; x < w; x++ ) {
299 uchar r, g, b, a;
300 s >> b >> g >> r >> a;
301 scanline[x] = tqRgba(r, g, b, a);
302 }
303 }
304
305 return true;
306 }
307
308 static bool LoadR8G8B8( TQDataStream & s, const DDSHeader & header, TQImage & img )
309 {
310 const uint w = header.width;
311 const uint h = header.height;
312
313 for( uint y = 0; y < h; y++ ) {
314 TQRgb * scanline = (TQRgb *) img.scanLine( y );
315 for( uint x = 0; x < w; x++ ) {
316 uchar r, g, b;
317 s >> b >> g >> r;
318 scanline[x] = tqRgb(r, g, b);
319 }
320 }
321
322 return true;
323 }
324
325 static bool LoadA1R5G5B5( TQDataStream & s, const DDSHeader & header, TQImage & img )
326 {
327 const uint w = header.width;
328 const uint h = header.height;
329
330 for( uint y = 0; y < h; y++ ) {
331 TQRgb * scanline = (TQRgb *) img.scanLine( y );
332 for( uint x = 0; x < w; x++ ) {
333 Color1555 color;
334 s >> color.u;
335 uchar a = (color.c.a != 0) ? 0xFF : 0;
336 uchar r = (color.c.r << 3) | (color.c.r >> 2);
337 uchar g = (color.c.g << 3) | (color.c.g >> 2);
338 uchar b = (color.c.b << 3) | (color.c.b >> 2);
339 scanline[x] = tqRgba(r, g, b, a);
340 }
341 }
342
343 return true;
344 }
345
346 static bool LoadA4R4G4B4( TQDataStream & s, const DDSHeader & header, TQImage & img )
347 {
348 const uint w = header.width;
349 const uint h = header.height;
350
351 for( uint y = 0; y < h; y++ ) {
352 TQRgb * scanline = (TQRgb *) img.scanLine( y );
353 for( uint x = 0; x < w; x++ ) {
354 Color4444 color;
355 s >> color.u;
356 uchar a = (color.c.a << 4) | color.c.a;
357 uchar r = (color.c.r << 4) | color.c.r;
358 uchar g = (color.c.g << 4) | color.c.g;
359 uchar b = (color.c.b << 4) | color.c.b;
360 scanline[x] = tqRgba(r, g, b, a);
361 }
362 }
363
364 return true;
365 }
366
367 static bool LoadR5G6B5( TQDataStream & s, const DDSHeader & header, TQImage & img )
368 {
369 const uint w = header.width;
370 const uint h = header.height;
371
372 for( uint y = 0; y < h; y++ ) {
373 TQRgb * scanline = (TQRgb *) img.scanLine( y );
374 for( uint x = 0; x < w; x++ ) {
375 Color565 color;
376 s >> color.u;
377 uchar r = (color.c.r << 3) | (color.c.r >> 2);
378 uchar g = (color.c.g << 2) | (color.c.g >> 4);
379 uchar b = (color.c.b << 3) | (color.c.b >> 2);
380 scanline[x] = tqRgb(r, g, b);
381 }
382 }
383
384 return true;
385 }
386
387 static TQDataStream & operator>> ( TQDataStream & s, Color565 & c )
388 {
389 return s >> c.u;
390 }
391
392
393 struct BlockDXT
394 {
395 Color565 col0;
396 Color565 col1;
397 uchar row[4];
398
399 void GetColors( Color8888 color_array[4] )
400 {
401 color_array[0].r = (col0.c.r << 3) | (col0.c.r >> 2);
402 color_array[0].g = (col0.c.g << 2) | (col0.c.g >> 4);
403 color_array[0].b = (col0.c.b << 3) | (col0.c.b >> 2);
404 color_array[0].a = 0xFF;
405
406 color_array[1].r = (col1.c.r << 3) | (col1.c.r >> 2);
407 color_array[1].g = (col1.c.g << 2) | (col1.c.g >> 4);
408 color_array[1].b = (col1.c.b << 3) | (col1.c.b >> 2);
409 color_array[1].a = 0xFF;
410
411 if( col0.u > col1.u ) {
412 // Four-color block: derive the other two colors.
413 color_array[2].r = (2 * color_array[0].r + color_array[1].r) / 3;
414 color_array[2].g = (2 * color_array[0].g + color_array[1].g) / 3;
415 color_array[2].b = (2 * color_array[0].b + color_array[1].b) / 3;
416 color_array[2].a = 0xFF;
417
418 color_array[3].r = (2 * color_array[1].r + color_array[0].r) / 3;
419 color_array[3].g = (2 * color_array[1].g + color_array[0].g) / 3;
420 color_array[3].b = (2 * color_array[1].b + color_array[0].b) / 3;
421 color_array[3].a = 0xFF;
422 }
423 else {
424 // Three-color block: derive the other color.
425 color_array[2].r = (color_array[0].r + color_array[1].r) / 2;
426 color_array[2].g = (color_array[0].g + color_array[1].g) / 2;
427 color_array[2].b = (color_array[0].b + color_array[1].b) / 2;
428 color_array[2].a = 0xFF;
429
430 // Set all components to 0 to match DXT specs.
431 color_array[3].r = 0x00; // color_array[2].r;
432 color_array[3].g = 0x00; // color_array[2].g;
433 color_array[3].b = 0x00; // color_array[2].b;
434 color_array[3].a = 0x00;
435 }
436 }
437 };
438
439
440 static TQDataStream & operator>> ( TQDataStream & s, BlockDXT & c )
441 {
442 return s >> c.col0 >> c.col1 >> c.row[0] >> c.row[1] >> c.row[2] >> c.row[3];
443 }
444
445 struct BlockDXTAlphaExplicit {
446 ushort row[4];
447 };
448
449 static TQDataStream & operator>> ( TQDataStream & s, BlockDXTAlphaExplicit & c )
450 {
451 return s >> c.row[0] >> c.row[1] >> c.row[2] >> c.row[3];
452 }
453
454 struct BlockDXTAlphaLinear {
455 uchar alpha0;
456 uchar alpha1;
457 uchar bits[6];
458
459 void GetAlphas( uchar alpha_array[8] )
460 {
461 alpha_array[0] = alpha0;
462 alpha_array[1] = alpha1;
463
464 // 8-alpha or 6-alpha block?
465 if( alpha_array[0] > alpha_array[1] )
466 {
467 // 8-alpha block: derive the other 6 alphas.
468 // 000 = alpha_0, 001 = alpha_1, others are interpolated
469
470 alpha_array[2] = ( 6 * alpha0 + alpha1) / 7; // bit code 010
471 alpha_array[3] = ( 5 * alpha0 + 2 * alpha1) / 7; // Bit code 011
472 alpha_array[4] = ( 4 * alpha0 + 3 * alpha1) / 7; // Bit code 100
473 alpha_array[5] = ( 3 * alpha0 + 4 * alpha1) / 7; // Bit code 101
474 alpha_array[6] = ( 2 * alpha0 + 5 * alpha1) / 7; // Bit code 110
475 alpha_array[7] = ( alpha0 + 6 * alpha1) / 7; // Bit code 111
476 }
477 else
478 {
479 // 6-alpha block: derive the other alphas.
480 // 000 = alpha_0, 001 = alpha_1, others are interpolated
481
482 alpha_array[2] = (4 * alpha0 + alpha1) / 5; // Bit code 010
483 alpha_array[3] = (3 * alpha0 + 2 * alpha1) / 5; // Bit code 011
484 alpha_array[4] = (2 * alpha0 + 3 * alpha1) / 5; // Bit code 100
485 alpha_array[5] = ( alpha0 + 4 * alpha1) / 5; // Bit code 101
486 alpha_array[6] = 0x00; // Bit code 110
487 alpha_array[7] = 0xFF; // Bit code 111
488 }
489 }
490
491 void GetBits( uchar bit_array[16] )
492 {
493 uint b = static_cast<uint>(bits[0]);
494 bit_array[0] = uchar(b & 0x07); b >>= 3;
495 bit_array[1] = uchar(b & 0x07); b >>= 3;
496 bit_array[2] = uchar(b & 0x07); b >>= 3;
497 bit_array[3] = uchar(b & 0x07); b >>= 3;
498 bit_array[4] = uchar(b & 0x07); b >>= 3;
499 bit_array[5] = uchar(b & 0x07); b >>= 3;
500 bit_array[6] = uchar(b & 0x07); b >>= 3;
501 bit_array[7] = uchar(b & 0x07); b >>= 3;
502
503 b = static_cast<uint>(bits[3]);
504 bit_array[8] = uchar(b & 0x07); b >>= 3;
505 bit_array[9] = uchar(b & 0x07); b >>= 3;
506 bit_array[10] = uchar(b & 0x07); b >>= 3;
507 bit_array[11] = uchar(b & 0x07); b >>= 3;
508 bit_array[12] = uchar(b & 0x07); b >>= 3;
509 bit_array[13] = uchar(b & 0x07); b >>= 3;
510 bit_array[14] = uchar(b & 0x07); b >>= 3;
511 bit_array[15] = uchar(b & 0x07); b >>= 3;
512 }
513 };
514
515 static TQDataStream & operator>> ( TQDataStream & s, BlockDXTAlphaLinear & c )
516 {
517 s >> c.alpha0 >> c.alpha1;
518 return s >> c.bits[0] >> c.bits[1] >> c.bits[2] >> c.bits[3] >> c.bits[4] >> c.bits[5];
519 }
520
521 static bool LoadDXT1( TQDataStream & s, const DDSHeader & header, TQImage & img )
522 {
523 const uint w = header.width;
524 const uint h = header.height;
525
526 BlockDXT block;
527 TQRgb * scanline[4];
528
529 for( uint y = 0; y < h; y += 4 ) {
530 for( uint j = 0; j < 4; j++ ) {
531 scanline[j] = (TQRgb *) img.scanLine( y + j );
532 }
533 for( uint x = 0; x < w; x += 4 ) {
534
535 // Read 64bit color block.
536 s >> block;
537
538 // Decode color block.
539 Color8888 color_array[4];
540 block.GetColors(color_array);
541
542 // bit masks = 00000011, 00001100, 00110000, 11000000
543 const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 };
544 const int shift[4] = { 0, 2, 4, 6 };
545
546 // Write color block.
547 for( uint j = 0; j < 4; j++ ) {
548 for( uint i = 0; i < 4; i++ ) {
549 if( img.valid( x+i, y+j ) ) {
550 uint idx = (block.row[j] & masks[i]) >> shift[i];
551 scanline[j][x+i] = tqRgba(color_array[idx].r, color_array[idx].g, color_array[idx].b, color_array[idx].a);
552 }
553 }
554 }
555 }
556 }
557 return true;
558 }
559
560 static bool LoadDXT3( TQDataStream & s, const DDSHeader & header, TQImage & img )
561 {
562 const uint w = header.width;
563 const uint h = header.height;
564
565 BlockDXT block;
566 BlockDXTAlphaExplicit alpha;
567 TQRgb * scanline[4];
568
569 for( uint y = 0; y < h; y += 4 ) {
570 for( uint j = 0; j < 4; j++ ) {
571 scanline[j] = (TQRgb *) img.scanLine( y + j );
572 }
573 for( uint x = 0; x < w; x += 4 ) {
574
575 // Read 128bit color block.
576 s >> alpha;
577 s >> block;
578
579 // Decode color block.
580 Color8888 color_array[4];
581 block.GetColors(color_array);
582
583 // bit masks = 00000011, 00001100, 00110000, 11000000
584 const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 };
585 const int shift[4] = { 0, 2, 4, 6 };
586
587 // Write color block.
588 for( uint j = 0; j < 4; j++ ) {
589 ushort a = alpha.row[j];
590 for( uint i = 0; i < 4; i++ ) {
591 if( img.valid( x+i, y+j ) ) {
592 uint idx = (block.row[j] & masks[i]) >> shift[i];
593 color_array[idx].a = a & 0x0f;
594 color_array[idx].a = color_array[idx].a | (color_array[idx].a << 4);
595 scanline[j][x+i] = tqRgba(color_array[idx].r, color_array[idx].g, color_array[idx].b, color_array[idx].a);
596 }
597 a >>= 4;
598 }
599 }
600 }
601 }
602 return true;
603 }
604
605 static bool LoadDXT2( TQDataStream & s, const DDSHeader & header, TQImage & img )
606 {
607 if( !LoadDXT3(s, header, img) ) return false;
608 //UndoPremultiplyAlpha(img);
609 return true;
610 }
611
612 static bool LoadDXT5( TQDataStream & s, const DDSHeader & header, TQImage & img )
613 {
614 const uint w = header.width;
615 const uint h = header.height;
616
617 BlockDXT block;
618 BlockDXTAlphaLinear alpha;
619 TQRgb * scanline[4];
620
621 for( uint y = 0; y < h; y += 4 ) {
622 for( uint j = 0; j < 4; j++ ) {
623 scanline[j] = (TQRgb *) img.scanLine( y + j );
624 }
625 for( uint x = 0; x < w; x += 4 ) {
626
627 // Read 128bit color block.
628 s >> alpha;
629 s >> block;
630
631 // Decode color block.
632 Color8888 color_array[4];
633 block.GetColors(color_array);
634
635 uchar alpha_array[8];
636 alpha.GetAlphas(alpha_array);
637
638 uchar bit_array[16];
639 alpha.GetBits(bit_array);
640
641 // bit masks = 00000011, 00001100, 00110000, 11000000
642 const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 };
643 const int shift[4] = { 0, 2, 4, 6 };
644
645 // Write color block.
646 for( uint j = 0; j < 4; j++ ) {
647 for( uint i = 0; i < 4; i++ ) {
648 if( img.valid( x+i, y+j ) ) {
649 uint idx = (block.row[j] & masks[i]) >> shift[i];
650 color_array[idx].a = alpha_array[bit_array[j*4+i]];
651 scanline[j][x+i] = tqRgba(color_array[idx].r, color_array[idx].g, color_array[idx].b, color_array[idx].a);
652 }
653 }
654 }
655 }
656 }
657
658 return true;
659 }
660 static bool LoadDXT4( TQDataStream & s, const DDSHeader & header, TQImage & img )
661 {
662 if( !LoadDXT5(s, header, img) ) return false;
663 //UndoPremultiplyAlpha(img);
664 return true;
665 }
666
667 static bool LoadRXGB( TQDataStream & s, const DDSHeader & header, TQImage & img )
668 {
669 const uint w = header.width;
670 const uint h = header.height;
671
672 BlockDXT block;
673 BlockDXTAlphaLinear alpha;
674 TQRgb * scanline[4];
675
676 for( uint y = 0; y < h; y += 4 ) {
677 for( uint j = 0; j < 4; j++ ) {
678 scanline[j] = (TQRgb *) img.scanLine( y + j );
679 }
680 for( uint x = 0; x < w; x += 4 ) {
681
682 // Read 128bit color block.
683 s >> alpha;
684 s >> block;
685
686 // Decode color block.
687 Color8888 color_array[4];
688 block.GetColors(color_array);
689
690 uchar alpha_array[8];
691 alpha.GetAlphas(alpha_array);
692
693 uchar bit_array[16];
694 alpha.GetBits(bit_array);
695
696 // bit masks = 00000011, 00001100, 00110000, 11000000
697 const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 };
698 const int shift[4] = { 0, 2, 4, 6 };
699
700 // Write color block.
701 for( uint j = 0; j < 4; j++ ) {
702 for( uint i = 0; i < 4; i++ ) {
703 if( img.valid( x+i, y+j ) ) {
704 uint idx = (block.row[j] & masks[i]) >> shift[i];
705 color_array[idx].a = alpha_array[bit_array[j*4+i]];
706 scanline[j][x+i] = tqRgb(color_array[idx].a, color_array[idx].g, color_array[idx].b);
707 }
708 }
709 }
710 }
711 }
712
713 return true;
714 }
715
716 static bool LoadATI2( TQDataStream & s, const DDSHeader & header, TQImage & img )
717 {
718 const uint w = header.width;
719 const uint h = header.height;
720
721 BlockDXTAlphaLinear xblock;
722 BlockDXTAlphaLinear yblock;
723 TQRgb * scanline[4];
724
725 for( uint y = 0; y < h; y += 4 ) {
726 for( uint j = 0; j < 4; j++ ) {
727 scanline[j] = (TQRgb *) img.scanLine( y + j );
728 }
729 for( uint x = 0; x < w; x += 4 ) {
730
731 // Read 128bit color block.
732 s >> xblock;
733 s >> yblock;
734
735 // Decode color block.
736 uchar xblock_array[8];
737 xblock.GetAlphas(xblock_array);
738
739 uchar xbit_array[16];
740 xblock.GetBits(xbit_array);
741
742 uchar yblock_array[8];
743 yblock.GetAlphas(yblock_array);
744
745 uchar ybit_array[16];
746 yblock.GetBits(ybit_array);
747
748 // Write color block.
749 for( uint j = 0; j < 4; j++ ) {
750 for( uint i = 0; i < 4; i++ ) {
751 if( img.valid( x+i, y+j ) ) {
752 const uchar nx = xblock_array[xbit_array[j*4+i]];
753 const uchar ny = yblock_array[ybit_array[j*4+i]];
754
755 const float fx = float(nx) / 127.5f - 1.0f;
756 const float fy = float(ny) / 127.5f - 1.0f;
757 const float fz = sqrtf(1.0f - fx*fx - fy*fy);
758 const uchar nz = uchar((fz + 1.0f) * 127.5f);
759
760 scanline[j][x+i] = tqRgb(nx, ny, nz);
761 }
762 }
763 }
764 }
765 }
766
767 return true;
768 }
769
770
771
772 typedef bool (* TextureLoader)( TQDataStream & s, const DDSHeader & header, TQImage & img );
773
774 // Get an appropiate texture loader for the given type.
775 static TextureLoader GetTextureLoader( DDSType type ) {
776 switch( type ) {
777 case DDS_A8R8G8B8:
778 return LoadA8R8G8B8;
779 case DDS_A1R5G5B5:
780 return LoadA1R5G5B5;
781 case DDS_A4R4G4B4:
782 return LoadA4R4G4B4;
783 case DDS_R8G8B8:
784 return LoadR8G8B8;
785 case DDS_R5G6B5:
786 return LoadR5G6B5;
787 case DDS_DXT1:
788 return LoadDXT1;
789 case DDS_DXT2:
790 return LoadDXT2;
791 case DDS_DXT3:
792 return LoadDXT3;
793 case DDS_DXT4:
794 return LoadDXT4;
795 case DDS_DXT5:
796 return LoadDXT5;
797 case DDS_RXGB:
798 return LoadRXGB;
799 case DDS_ATI2:
800 return LoadATI2;
801 default:
802 return NULL;
803 };
804 }
805
806
807 // Load a 2d texture.
808 static bool LoadTexture( TQDataStream & s, const DDSHeader & header, TQImage & img )
809 {
810 // Create dst image.
811 if( !img.create( header.width, header.height, 32 )) {
812 return false;
813 }
814
815 // Read image.
816 DDSType type = GetType( header );
817
818 // Enable alpha buffer for transparent or DDS images.
819 if( HasAlpha( header ) || type >= DDS_DXT1 ) {
820 img.setAlphaBuffer( true );
821 }
822
823 TextureLoader loader = GetTextureLoader( type );
824 if( loader == NULL ) {
825 return false;
826 }
827
828 return loader( s, header, img );
829 }
830
831
832 static int FaceOffset( const DDSHeader & header ) {
833
834 DDSType type = GetType( header );
835
836 int mipmap = kMax(int(header.mipmapcount), 1);
837 int size = 0;
838 int w = header.width;
839 int h = header.height;
840
841 if( type >= DDS_DXT1 ) {
842 int multiplier = (type == DDS_DXT1) ? 8 : 16;
843 do {
844 int face_size = kMax(w/4,1) * kMax(h/4,1) * multiplier;
845 size += face_size;
846 w >>= 1;
847 h >>= 1;
848 } while( --mipmap );
849 }
850 else {
851 int multiplier = header.pf.bitcount / 8;
852 do {
853 int face_size = w * h * multiplier;
854 size += face_size;
855 w = kMax( w>>1, 1 );
856 h = kMax( h>>1, 1 );
857 } while( --mipmap );
858 }
859
860 return size;
861 }
862
863#if CUBE_LAYOUT == HORIZONTAL
864 static int face_offset[6][2] = { {2, 1}, {0, 1}, {1, 0}, {1, 2}, {1, 1}, {3, 1} };
865#elif CUBE_LAYOUT == VERTICAL
866 static int face_offset[6][2] = { {2, 1}, {0, 1}, {1, 0}, {1, 2}, {1, 1}, {1, 3} };
867#endif
868 static int face_flags[6] = {
869 DDSCAPS2_CUBEMAP_POSITIVEX,
870 DDSCAPS2_CUBEMAP_NEGATIVEX,
871 DDSCAPS2_CUBEMAP_POSITIVEY,
872 DDSCAPS2_CUBEMAP_NEGATIVEY,
873 DDSCAPS2_CUBEMAP_POSITIVEZ,
874 DDSCAPS2_CUBEMAP_NEGATIVEZ
875 };
876
877 // Load unwrapped cube map.
878 static bool LoadCubeMap( TQDataStream & s, const DDSHeader & header, TQImage & img )
879 {
880 // Create dst image.
881#if CUBE_LAYOUT == HORIZONTAL
882 if( !img.create( 4 * header.width, 3 * header.height, 32 )) {
883 return false; // duplicate code for correct syntax coloring.
884 }
885#elif CUBE_LAYOUT == VERTICAL
886 if( !img.create( 3 * header.width, 4 * header.height, 32 )) {
887 return false;
888 }
889#endif
890
891 DDSType type = GetType( header );
892
893 // Enable alpha buffer for transparent or DDS images.
894 if( HasAlpha( header ) || type >= DDS_DXT1 ) {
895 img.setAlphaBuffer( true );
896 }
897
898 // Select texture loader.
899 TextureLoader loader = GetTextureLoader( type );
900 if( loader == NULL ) {
901 return false;
902 }
903
904 // Clear background.
905 img.fill( 0 );
906
907 // Create face image.
908 TQImage face;
909 if( !face.create( header.width, header.height, 32 )) {
910 return false;
911 }
912
913 int offset = s.device()->at();
914 int size = FaceOffset( header );
915
916 for( int i = 0; i < 6; i++ ) {
917
918 if( !(header.caps.caps2 & face_flags[i]) ) {
919 // Skip face.
920 continue;
921 }
922
923 // Seek device.
924 s.device()->at( offset );
925 offset += size;
926
927 // Load face from stream.
928 if( !loader( s, header, face ) ) {
929 return false;
930 }
931
932#if CUBE_LAYOUT == VERTICAL
933 if( i == 5 ) {
934 face = face.mirror(true, true);
935 }
936#endif
937
938 // Compute face offsets.
939 int offset_x = face_offset[i][0] * header.width;
940 int offset_y = face_offset[i][1] * header.height;
941
942 // Copy face on the image.
943 for( uint y = 0; y < header.height; y++ ) {
944 TQRgb * src = (TQRgb *) face.scanLine( y );
945 TQRgb * dst = (TQRgb *) img.scanLine( y + offset_y ) + offset_x;
946 memcpy( dst, src, sizeof(TQRgb) * header.width );
947 }
948 }
949
950 return true;
951 }
952
953}
954
955
956TDE_EXPORT void kimgio_dds_read( TQImageIO *io )
957{
958 TQDataStream s( io->ioDevice() );
959 s.setByteOrder( TQDataStream::LittleEndian );
960
961 // Validate header.
962 uint fourcc;
963 s >> fourcc;
964 if( fourcc != FOURCC_DDS ) {
965 kdDebug(399) << "This is not a DDS file." << endl;
966 io->setImage( TQImage() );
967 io->setStatus( -1 );
968 return;
969 }
970
971 // Read image header.
972 DDSHeader header;
973 s >> header;
974
975 // Check image file format.
976 if( s.atEnd() || !IsValid( header ) ) {
977 kdDebug(399) << "This DDS file is not valid." << endl;
978 io->setImage( TQImage() );
979 io->setStatus( -1 );
980 return;
981 }
982
983 // Determine image type, by now, we only support 2d textures.
984 if( !IsSupported( header ) ) {
985 kdDebug(399) << "This DDS file is not supported." << endl;
986 io->setImage( TQImage() );
987 io->setStatus( -1 );
988 return;
989 }
990
991
992 TQImage img;
993 bool result;
994
995 if( IsCubeMap( header ) ) {
996 result = LoadCubeMap( s, header, img );
997 }
998 else {
999 result = LoadTexture( s, header, img );
1000 }
1001
1002 if( result == false ) {
1003 kdDebug(399) << "Error loading DDS file." << endl;
1004 io->setImage( TQImage() );
1005 io->setStatus( -1 );
1006 return;
1007 }
1008
1009 io->setImage( img );
1010 io->setStatus( 0 );
1011}
1012
1013
1014TDE_EXPORT void kimgio_dds_write( TQImageIO * )
1015{
1016 // TODO Stub!
1017}
1018

kimgio

Skip menu "kimgio"
  • Main Page
  • File List
  • Related Pages

kimgio

Skip menu "kimgio"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kimgio by doxygen 1.9.4
This website is maintained by Timothy Pearson.