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

KImgIO

  • sources
  • kde-4.12
  • kdelibs
  • 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  // Split 24 packed bits into 8 bytes, 3 bits at a time.
490  uint b = bits[0] | bits[1] << 8 | bits[2] << 16;
491  bit_array[0] = uchar(b & 0x07); b >>= 3;
492  bit_array[1] = uchar(b & 0x07); b >>= 3;
493  bit_array[2] = uchar(b & 0x07); b >>= 3;
494  bit_array[3] = uchar(b & 0x07); b >>= 3;
495  bit_array[4] = uchar(b & 0x07); b >>= 3;
496  bit_array[5] = uchar(b & 0x07); b >>= 3;
497  bit_array[6] = uchar(b & 0x07); b >>= 3;
498  bit_array[7] = uchar(b & 0x07);
499 
500  b = bits[3] | bits[4] << 8 | bits[5] << 16;
501  bit_array[8] = uchar(b & 0x07); b >>= 3;
502  bit_array[9] = uchar(b & 0x07); b >>= 3;
503  bit_array[10] = uchar(b & 0x07); b >>= 3;
504  bit_array[11] = uchar(b & 0x07); b >>= 3;
505  bit_array[12] = uchar(b & 0x07); b >>= 3;
506  bit_array[13] = uchar(b & 0x07); b >>= 3;
507  bit_array[14] = uchar(b & 0x07); b >>= 3;
508  bit_array[15] = uchar(b & 0x07);
509  }
510 };
511 
512 static QDataStream & operator>> ( QDataStream & s, BlockDXTAlphaLinear & c )
513 {
514  s >> c.alpha0 >> c.alpha1;
515  return s >> c.bits[0] >> c.bits[1] >> c.bits[2] >> c.bits[3] >> c.bits[4] >> c.bits[5];
516 }
517 
518 static bool LoadDXT1( QDataStream & s, const DDSHeader & header, QImage & img )
519 {
520  const uint w = header.width;
521  const uint h = header.height;
522 
523  BlockDXT block;
524  QRgb * scanline[4];
525 
526  for( uint y = 0; y < h; y += 4 ) {
527  for( uint j = 0; j < 4; j++ ) {
528  scanline[j] = (QRgb *) img.scanLine( y + j );
529  }
530  for( uint x = 0; x < w; x += 4 ) {
531 
532  // Read 64bit color block.
533  s >> block;
534 
535  // Decode color block.
536  Color8888 color_array[4];
537  block.GetColors(color_array);
538 
539  // bit masks = 00000011, 00001100, 00110000, 11000000
540  const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 };
541  const int shift[4] = { 0, 2, 4, 6 };
542 
543  // Write color block.
544  for( uint j = 0; j < 4; j++ ) {
545  for( uint i = 0; i < 4; i++ ) {
546  if( img.valid( x+i, y+j ) ) {
547  uint idx = (block.row[j] & masks[i]) >> shift[i];
548  scanline[j][x+i] = qRgba(color_array[idx].r, color_array[idx].g, color_array[idx].b, color_array[idx].a);
549  }
550  }
551  }
552  }
553  }
554  return true;
555 }
556 
557 static bool LoadDXT3( QDataStream & s, const DDSHeader & header, QImage & img )
558 {
559  const uint w = header.width;
560  const uint h = header.height;
561 
562  BlockDXT block;
563  BlockDXTAlphaExplicit alpha;
564  QRgb * scanline[4];
565 
566  for( uint y = 0; y < h; y += 4 ) {
567  for( uint j = 0; j < 4; j++ ) {
568  scanline[j] = (QRgb *) img.scanLine( y + j );
569  }
570  for( uint x = 0; x < w; x += 4 ) {
571 
572  // Read 128bit color block.
573  s >> alpha;
574  s >> block;
575 
576  // Decode color block.
577  Color8888 color_array[4];
578  block.GetColors(color_array);
579 
580  // bit masks = 00000011, 00001100, 00110000, 11000000
581  const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 };
582  const int shift[4] = { 0, 2, 4, 6 };
583 
584  // Write color block.
585  for( uint j = 0; j < 4; j++ ) {
586  ushort a = alpha.row[j];
587  for( uint i = 0; i < 4; i++ ) {
588  if( img.valid( x+i, y+j ) ) {
589  uint idx = (block.row[j] & masks[i]) >> shift[i];
590  color_array[idx].a = a & 0x0f;
591  color_array[idx].a = color_array[idx].a | (color_array[idx].a << 4);
592  scanline[j][x+i] = qRgba(color_array[idx].r, color_array[idx].g, color_array[idx].b, color_array[idx].a);
593  }
594  a >>= 4;
595  }
596  }
597  }
598  }
599  return true;
600 }
601 
602 static bool LoadDXT2( QDataStream & s, const DDSHeader & header, QImage & img )
603 {
604  if( !LoadDXT3(s, header, img) ) return false;
605  //UndoPremultiplyAlpha(img);
606  return true;
607 }
608 
609 static bool LoadDXT5( QDataStream & s, const DDSHeader & header, QImage & img )
610 {
611  const uint w = header.width;
612  const uint h = header.height;
613 
614  BlockDXT block;
615  BlockDXTAlphaLinear alpha;
616  QRgb * scanline[4];
617 
618  for( uint y = 0; y < h; y += 4 ) {
619  for( uint j = 0; j < 4; j++ ) {
620  scanline[j] = (QRgb *) img.scanLine( y + j );
621  }
622  for( uint x = 0; x < w; x += 4 ) {
623 
624  // Read 128bit color block.
625  s >> alpha;
626  s >> block;
627 
628  // Decode color block.
629  Color8888 color_array[4];
630  block.GetColors(color_array);
631 
632  uchar alpha_array[8];
633  alpha.GetAlphas(alpha_array);
634 
635  uchar bit_array[16];
636  alpha.GetBits(bit_array);
637 
638  // bit masks = 00000011, 00001100, 00110000, 11000000
639  const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 };
640  const int shift[4] = { 0, 2, 4, 6 };
641 
642  // Write color block.
643  for( uint j = 0; j < 4; j++ ) {
644  for( uint i = 0; i < 4; i++ ) {
645  if( img.valid( x+i, y+j ) ) {
646  uint idx = (block.row[j] & masks[i]) >> shift[i];
647  color_array[idx].a = alpha_array[bit_array[j*4+i]];
648  scanline[j][x+i] = qRgba(color_array[idx].r, color_array[idx].g, color_array[idx].b, color_array[idx].a);
649  }
650  }
651  }
652  }
653  }
654 
655  return true;
656 }
657 static bool LoadDXT4( QDataStream & s, const DDSHeader & header, QImage & img )
658 {
659  if( !LoadDXT5(s, header, img) ) return false;
660  //UndoPremultiplyAlpha(img);
661  return true;
662 }
663 
664 static bool LoadRXGB( QDataStream & s, const DDSHeader & header, QImage & img )
665 {
666  const uint w = header.width;
667  const uint h = header.height;
668 
669  BlockDXT block;
670  BlockDXTAlphaLinear alpha;
671  QRgb * scanline[4];
672 
673  for( uint y = 0; y < h; y += 4 ) {
674  for( uint j = 0; j < 4; j++ ) {
675  scanline[j] = (QRgb *) img.scanLine( y + j );
676  }
677  for( uint x = 0; x < w; x += 4 ) {
678 
679  // Read 128bit color block.
680  s >> alpha;
681  s >> block;
682 
683  // Decode color block.
684  Color8888 color_array[4];
685  block.GetColors(color_array);
686 
687  uchar alpha_array[8];
688  alpha.GetAlphas(alpha_array);
689 
690  uchar bit_array[16];
691  alpha.GetBits(bit_array);
692 
693  // bit masks = 00000011, 00001100, 00110000, 11000000
694  const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 };
695  const int shift[4] = { 0, 2, 4, 6 };
696 
697  // Write color block.
698  for( uint j = 0; j < 4; j++ ) {
699  for( uint i = 0; i < 4; i++ ) {
700  if( img.valid( x+i, y+j ) ) {
701  uint idx = (block.row[j] & masks[i]) >> shift[i];
702  color_array[idx].a = alpha_array[bit_array[j*4+i]];
703  scanline[j][x+i] = qRgb(color_array[idx].a, color_array[idx].g, color_array[idx].b);
704  }
705  }
706  }
707  }
708  }
709 
710  return true;
711 }
712 
713 static bool LoadATI2( QDataStream & s, const DDSHeader & header, QImage & img )
714 {
715  const uint w = header.width;
716  const uint h = header.height;
717 
718  BlockDXTAlphaLinear xblock;
719  BlockDXTAlphaLinear yblock;
720  QRgb * scanline[4];
721 
722  for( uint y = 0; y < h; y += 4 ) {
723  for( uint j = 0; j < 4; j++ ) {
724  scanline[j] = (QRgb *) img.scanLine( y + j );
725  }
726  for( uint x = 0; x < w; x += 4 ) {
727 
728  // Read 128bit color block.
729  s >> xblock;
730  s >> yblock;
731 
732  // Decode color block.
733  uchar xblock_array[8];
734  xblock.GetAlphas(xblock_array);
735 
736  uchar xbit_array[16];
737  xblock.GetBits(xbit_array);
738 
739  uchar yblock_array[8];
740  yblock.GetAlphas(yblock_array);
741 
742  uchar ybit_array[16];
743  yblock.GetBits(ybit_array);
744 
745  // Write color block.
746  for( uint j = 0; j < 4; j++ ) {
747  for( uint i = 0; i < 4; i++ ) {
748  if( img.valid( x+i, y+j ) ) {
749  const uchar nx = xblock_array[xbit_array[j*4+i]];
750  const uchar ny = yblock_array[ybit_array[j*4+i]];
751 
752  const float fx = float(nx) / 127.5f - 1.0f;
753  const float fy = float(ny) / 127.5f - 1.0f;
754  const float fz = sqrtf(1.0f - fx*fx - fy*fy);
755  const uchar nz = uchar((fz + 1.0f) * 127.5f);
756 
757  scanline[j][x+i] = qRgb(nx, ny, nz);
758  }
759  }
760  }
761  }
762  }
763 
764  return true;
765 }
766 
767 
768 
769 typedef bool (* TextureLoader)( QDataStream & s, const DDSHeader & header, QImage & img );
770 
771 // Get an appropriate texture loader for the given type.
772 static TextureLoader GetTextureLoader( DDSType type ) {
773  switch( type ) {
774  case DDS_A8R8G8B8:
775  return LoadA8R8G8B8;
776  case DDS_A1R5G5B5:
777  return LoadA1R5G5B5;
778  case DDS_A4R4G4B4:
779  return LoadA4R4G4B4;
780  case DDS_R8G8B8:
781  return LoadR8G8B8;
782  case DDS_R5G6B5:
783  return LoadR5G6B5;
784  case DDS_DXT1:
785  return LoadDXT1;
786  case DDS_DXT2:
787  return LoadDXT2;
788  case DDS_DXT3:
789  return LoadDXT3;
790  case DDS_DXT4:
791  return LoadDXT4;
792  case DDS_DXT5:
793  return LoadDXT5;
794  case DDS_RXGB:
795  return LoadRXGB;
796  case DDS_ATI2:
797  return LoadATI2;
798  default:
799  return NULL;
800  };
801 }
802 
803 
804 // Load a 2d texture.
805 static bool LoadTexture( QDataStream & s, const DDSHeader & header, QImage & img )
806 {
807  // Create dst image.
808  img = QImage( header.width, header.height, QImage::Format_RGB32 );
809 
810  // Read image.
811  DDSType type = GetType( header );
812 
813  // Enable alpha buffer for transparent or DDS images.
814  if( HasAlpha( header ) || type >= DDS_DXT1 ) {
815  img = img.convertToFormat( QImage::Format_ARGB32 );
816  }
817 
818  TextureLoader loader = GetTextureLoader( type );
819  if( loader == NULL ) {
820  return false;
821  }
822 
823  return loader( s, header, img );
824 }
825 
826 
827 static int FaceOffset( const DDSHeader & header ) {
828 
829  DDSType type = GetType( header );
830 
831  int mipmap = qMax(header.mipmapcount, 1U);
832  int size = 0;
833  int w = header.width;
834  int h = header.height;
835 
836  if( type >= DDS_DXT1 ) {
837  int multiplier = (type == DDS_DXT1) ? 8 : 16;
838  do {
839  int face_size = qMax(w/4,1) * qMax(h/4,1) * multiplier;
840  size += face_size;
841  w >>= 1;
842  h >>= 1;
843  } while( --mipmap );
844  }
845  else {
846  int multiplier = header.pf.bitcount / 8;
847  do {
848  int face_size = w * h * multiplier;
849  size += face_size;
850  w = qMax( w>>1, 1 );
851  h = qMax( h>>1, 1 );
852  } while( --mipmap );
853  }
854 
855  return size;
856 }
857 
858 #if CUBE_LAYOUT == HORIZONTAL
859  static int face_offset[6][2] = { {2, 1}, {0, 1}, {1, 0}, {1, 2}, {1, 1}, {3, 1} };
860 #elif CUBE_LAYOUT == VERTICAL
861  static int face_offset[6][2] = { {2, 1}, {0, 1}, {1, 0}, {1, 2}, {1, 1}, {1, 3} };
862 #endif
863  static int face_flags[6] = {
864  DDSCAPS2_CUBEMAP_POSITIVEX,
865  DDSCAPS2_CUBEMAP_NEGATIVEX,
866  DDSCAPS2_CUBEMAP_POSITIVEY,
867  DDSCAPS2_CUBEMAP_NEGATIVEY,
868  DDSCAPS2_CUBEMAP_POSITIVEZ,
869  DDSCAPS2_CUBEMAP_NEGATIVEZ
870  };
871 
872 // Load unwrapped cube map.
873 static bool LoadCubeMap( QDataStream & s, const DDSHeader & header, QImage & img )
874 {
875  // Create dst image.
876 #if CUBE_LAYOUT == HORIZONTAL
877  img = QImage( 4 * header.width, 3 * header.height, QImage::Format_RGB32 );
878 #elif CUBE_LAYOUT == VERTICAL
879  img = QImage( 3 * header.width, 4 * header.height, QImage::Format_RGB32 );
880 #endif
881 
882  DDSType type = GetType( header );
883 
884  // Enable alpha buffer for transparent or DDS images.
885  if( HasAlpha( header ) || type >= DDS_DXT1 ) {
886  img = img.convertToFormat( QImage::Format_ARGB32 );
887  }
888 
889  // Select texture loader.
890  TextureLoader loader = GetTextureLoader( type );
891  if( loader == NULL ) {
892  return false;
893  }
894 
895  // Clear background.
896  img.fill( 0 );
897 
898  // Create face image.
899  QImage face(header.width, header.height, QImage::Format_RGB32);
900 
901  int offset = s.device()->pos();
902  int size = FaceOffset( header );
903 
904  for( int i = 0; i < 6; i++ ) {
905 
906  if( !(header.caps.caps2 & face_flags[i]) ) {
907  // Skip face.
908  continue;
909  }
910 
911  // Seek device.
912  s.device()->seek( offset );
913  offset += size;
914 
915  // Load face from stream.
916  if( !loader( s, header, face ) ) {
917  return false;
918  }
919 
920 #if CUBE_LAYOUT == VERTICAL
921  if( i == 5 ) {
922  face = face.mirror(true, true);
923  }
924 #endif
925 
926  // Compute face offsets.
927  int offset_x = face_offset[i][0] * header.width;
928  int offset_y = face_offset[i][1] * header.height;
929 
930  // Copy face on the image.
931  for( uint y = 0; y < header.height; y++ ) {
932  QRgb * src = (QRgb *) face.scanLine( y );
933  QRgb * dst = (QRgb *) img.scanLine( y + offset_y ) + offset_x;
934  memcpy( dst, src, sizeof(QRgb) * header.width );
935  }
936  }
937 
938  return true;
939 }
940 
941 
942 
943 DDSHandler::DDSHandler()
944 {
945 }
946 
947 bool DDSHandler::canRead() const
948 {
949  if (canRead(device())) {
950  setFormat("dds");
951  return true;
952  }
953  return false;
954 }
955 
956 bool DDSHandler::read(QImage *image)
957 {
958  QDataStream s( device() );
959  s.setByteOrder( QDataStream::LittleEndian );
960 
961  // Validate header.
962  uint fourcc;
963  s >> fourcc;
964  if( fourcc != FOURCC_DDS ) {
965  kDebug(399) << "This is not a DDS file.";
966  return false;
967  }
968 
969  // Read image header.
970  DDSHeader header;
971  s >> header;
972 
973  // Check image file format.
974  if( s.atEnd() || !IsValid( header ) ) {
975  kDebug(399) << "This DDS file is not valid.";
976  return false;
977  }
978 
979  // Determine image type, by now, we only support 2d textures.
980  if( !IsSupported( header ) ) {
981  kDebug(399) << "This DDS file is not supported.";
982  return false;
983  }
984 
985  bool result;
986 
987  if( IsCubeMap( header ) ) {
988  result = LoadCubeMap( s, header, *image );
989  }
990  else {
991  result = LoadTexture( s, header, *image );
992  }
993 
994  return result;
995 }
996 
997 bool DDSHandler::write(const QImage &)
998 {
999  // TODO Stub!
1000  return false;
1001 }
1002 
1003 QByteArray DDSHandler::name() const
1004 {
1005  return "dds";
1006 }
1007 
1008 bool DDSHandler::canRead(QIODevice *device)
1009 {
1010  if (!device) {
1011  qWarning("DDSHandler::canRead() called with no device");
1012  return false;
1013  }
1014 
1015  qint64 oldPos = device->pos();
1016 
1017  char head[3];
1018  qint64 readBytes = device->read(head, sizeof(head));
1019  if (readBytes != sizeof(head)) {
1020  if (device->isSequential()) {
1021  while (readBytes > 0)
1022  device->ungetChar(head[readBytes-- - 1]);
1023  } else {
1024  device->seek(oldPos);
1025  }
1026  return false;
1027  }
1028 
1029  if (device->isSequential()) {
1030  while (readBytes > 0)
1031  device->ungetChar(head[readBytes-- - 1]);
1032  } else {
1033  device->seek(oldPos);
1034  }
1035 
1036  return qstrncmp(head, "DDS", 3) == 0;
1037 }
1038 
1039 class DDSPlugin : public QImageIOPlugin
1040 {
1041 public:
1042  QStringList keys() const;
1043  Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
1044  QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
1045 };
1046 
1047 QStringList DDSPlugin::keys() const
1048 {
1049  return QStringList() << "dds";
1050 }
1051 
1052 QImageIOPlugin::Capabilities DDSPlugin::capabilities(QIODevice *device, const QByteArray &format) const
1053 {
1054  if (format == "dds")
1055  return Capabilities(CanRead);
1056  if (!format.isEmpty())
1057  return 0;
1058  if (!device->isOpen())
1059  return 0;
1060 
1061  Capabilities cap;
1062  if (device->isReadable() && DDSHandler::canRead(device))
1063  cap |= CanRead;
1064  return cap;
1065 }
1066 
1067 QImageIOHandler *DDSPlugin::create(QIODevice *device, const QByteArray &format) const
1068 {
1069  QImageIOHandler *handler = new DDSHandler;
1070  handler->setDevice(device);
1071  handler->setFormat(format);
1072  return handler;
1073 }
1074 
1075 Q_EXPORT_STATIC_PLUGIN(DDSPlugin)
1076 Q_EXPORT_PLUGIN2(dds, DDSPlugin)
GetType
static DDSType GetType(const DDSHeader &header)
Definition: dds.cpp:225
DDS_DXT1
Definition: dds.cpp:122
FOURCC_DXT2
static const uint FOURCC_DXT2
Definition: dds.cpp:88
LoadRXGB
static bool LoadRXGB(QDataStream &s, const DDSHeader &header, QImage &img)
Definition: dds.cpp:664
FOURCC_DXT1
static const uint FOURCC_DXT1
Definition: dds.cpp:87
DDSCAPS2_CUBEMAP_NEGATIVEZ
static const uint DDSCAPS2_CUBEMAP_NEGATIVEZ
Definition: dds.cpp:110
DDS_RXGB
Definition: dds.cpp:127
dds.h
TextureLoader
bool(* TextureLoader)(QDataStream &s, const DDSHeader &header, QImage &img)
Definition: dds.cpp:769
DDSCAPS2_VOLUME
static const uint DDSCAPS2_VOLUME
Definition: dds.cpp:102
FaceOffset
static int FaceOffset(const DDSHeader &header)
Definition: dds.cpp:827
MAKEFOURCC
#define MAKEFOURCC(ch0, ch1, ch2, ch3)
Definition: dds.cpp:41
DDS_A1R5G5B5
Definition: dds.cpp:118
LoadR5G6B5
static bool LoadR5G6B5(QDataStream &s, const DDSHeader &header, QImage &img)
Definition: dds.cpp:363
DDS_DXT5
Definition: dds.cpp:126
ushort
quint16 ushort
Definition: dds.cpp:37
LoadDXT1
static bool LoadDXT1(QDataStream &s, const DDSHeader &header, QImage &img)
Definition: dds.cpp:518
DDPF_FOURCC
static const uint DDPF_FOURCC
Definition: dds.cpp:113
face_offset
static int face_offset[6][2]
Definition: dds.cpp:859
DDSCAPS2_CUBEMAP_NEGATIVEY
static const uint DDSCAPS2_CUBEMAP_NEGATIVEY
Definition: dds.cpp:108
DDS_R5G6B5
Definition: dds.cpp:121
DDSD_PITCH
static const uint DDSD_PITCH
Definition: dds.cpp:99
DDSD_HEIGHT
static const uint DDSD_HEIGHT
Definition: dds.cpp:98
DDS_ATI2
Definition: dds.cpp:128
DDSD_CAPS
static const uint DDSD_CAPS
Definition: dds.cpp:95
DDPF_RGB
static const uint DDPF_RGB
Definition: dds.cpp:112
LoadATI2
static bool LoadATI2(QDataStream &s, const DDSHeader &header, QImage &img)
Definition: dds.cpp:713
DDS_R8G8B8
Definition: dds.cpp:120
DDSHandler::canRead
bool canRead() const
Definition: dds.cpp:947
face_flags
static int face_flags[6]
Definition: dds.cpp:863
DDSCAPS2_CUBEMAP_POSITIVEZ
static const uint DDSCAPS2_CUBEMAP_POSITIVEZ
Definition: dds.cpp:109
operator>>
static QDataStream & operator>>(QDataStream &s, DDSPixelFormat &pf)
Definition: dds.cpp:144
IsCubeMap
static bool IsCubeMap(const DDSHeader &header)
Definition: dds.cpp:271
DDSHandler::write
bool write(const QImage &image)
Definition: dds.cpp:997
FOURCC_ATI2
static const uint FOURCC_ATI2
Definition: dds.cpp:93
DDS_DXT3
Definition: dds.cpp:124
DDS_DXT2
Definition: dds.cpp:123
IsSupported
static bool IsSupported(const DDSHeader &header)
Definition: dds.cpp:276
uchar
quint8 uchar
Definition: dds.cpp:38
DDSHandler::name
QByteArray name() const
Definition: dds.cpp:1003
DDPF_ALPHAPIXELS
static const uint DDPF_ALPHAPIXELS
Definition: dds.cpp:114
DDSD_WIDTH
static const uint DDSD_WIDTH
Definition: dds.cpp:97
HasAlpha
static bool HasAlpha(const DDSHeader &header)
Definition: dds.cpp:266
IsValid
static bool IsValid(const DDSHeader &header)
Definition: dds.cpp:205
QImageIOHandler
DDS_UNKNOWN
Definition: dds.cpp:129
LoadA8R8G8B8
static bool LoadA8R8G8B8(QDataStream &s, const DDSHeader &header, QImage &img)
Definition: dds.cpp:287
sqrtf
#define sqrtf(x)
Definition: dds.cpp:33
FOURCC_DXT4
static const uint FOURCC_DXT4
Definition: dds.cpp:90
DDS_A4R4G4B4
Definition: dds.cpp:119
FOURCC_DDS
static const uint FOURCC_DDS
Definition: dds.cpp:86
LoadA4R4G4B4
static bool LoadA4R4G4B4(QDataStream &s, const DDSHeader &header, QImage &img)
Definition: dds.cpp:342
LoadDXT4
static bool LoadDXT4(QDataStream &s, const DDSHeader &header, QImage &img)
Definition: dds.cpp:657
LoadDXT2
static bool LoadDXT2(QDataStream &s, const DDSHeader &header, QImage &img)
Definition: dds.cpp:602
DDS_DXT4
Definition: dds.cpp:125
LoadCubeMap
static bool LoadCubeMap(QDataStream &s, const DDSHeader &header, QImage &img)
Definition: dds.cpp:873
LoadA1R5G5B5
static bool LoadA1R5G5B5(QDataStream &s, const DDSHeader &header, QImage &img)
Definition: dds.cpp:321
qRgba
QRgb qRgba(const QRgb &rgb, int a)
Change a QRgb value's alpha only.
Definition: xcf.cpp:67
LoadDXT5
static bool LoadDXT5(QDataStream &s, const DDSHeader &header, QImage &img)
Definition: dds.cpp:609
DDSType
DDSType
Definition: dds.cpp:116
DDSCAPS2_CUBEMAP_POSITIVEX
static const uint DDSCAPS2_CUBEMAP_POSITIVEX
Definition: dds.cpp:105
FOURCC_DXT3
static const uint FOURCC_DXT3
Definition: dds.cpp:89
GetTextureLoader
static TextureLoader GetTextureLoader(DDSType type)
Definition: dds.cpp:772
DDSCAPS2_CUBEMAP
static const uint DDSCAPS2_CUBEMAP
Definition: dds.cpp:103
DDS_A8R8G8B8
Definition: dds.cpp:117
uint
quint32 uint
Definition: dds.cpp:36
DDSHandler
Definition: dds.h:15
LoadDXT3
static bool LoadDXT3(QDataStream &s, const DDSHeader &header, QImage &img)
Definition: dds.cpp:557
FOURCC_RXGB
static const uint FOURCC_RXGB
Definition: dds.cpp:92
DDSCAPS_TEXTURE
static const uint DDSCAPS_TEXTURE
Definition: dds.cpp:101
DDSCAPS2_CUBEMAP_NEGATIVEX
static const uint DDSCAPS2_CUBEMAP_NEGATIVEX
Definition: dds.cpp:106
LoadR8G8B8
static bool LoadR8G8B8(QDataStream &s, const DDSHeader &header, QImage &img)
Definition: dds.cpp:304
DDSHandler::DDSHandler
DDSHandler()
Definition: dds.cpp:943
DDSHandler::read
bool read(QImage *image)
Definition: dds.cpp:956
FOURCC_DXT5
static const uint FOURCC_DXT5
Definition: dds.cpp:91
DDSCAPS2_CUBEMAP_POSITIVEY
static const uint DDSCAPS2_CUBEMAP_POSITIVEY
Definition: dds.cpp:107
DDSD_PIXELFORMAT
static const uint DDSD_PIXELFORMAT
Definition: dds.cpp:96
LoadTexture
static bool LoadTexture(QDataStream &s, const DDSHeader &header, QImage &img)
Definition: dds.cpp:805
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:47:50 by doxygen 1.8.7 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 API Reference

Skip menu "kdelibs 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
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



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