• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.10.1 API Reference
  • KDE Home
  • Contact Us
 

KImgIO

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

KDE's Doxygen guidelines are available online.

KImgIO

Skip menu "KImgIO"
  • Main Page
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.10.1 API Reference

Skip menu "kdelibs-4.10.1 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal