• 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 <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 <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 
36 typedef TQ_UINT32 uint;
37 typedef TQ_UINT16 ushort;
38 typedef TQ_UINT8 uchar;
39 
40 namespace { // 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  QRgb * scanline = (QRgb *) 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  QRgb * scanline = (QRgb *) 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  QRgb * scanline = (QRgb *) 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  QRgb * scanline = (QRgb *) 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  QRgb * scanline = (QRgb *) 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  QRgb * scanline[4];
528 
529  for( uint y = 0; y < h; y += 4 ) {
530  for( uint j = 0; j < 4; j++ ) {
531  scanline[j] = (QRgb *) 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  QRgb * scanline[4];
568 
569  for( uint y = 0; y < h; y += 4 ) {
570  for( uint j = 0; j < 4; j++ ) {
571  scanline[j] = (QRgb *) 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  QRgb * scanline[4];
620 
621  for( uint y = 0; y < h; y += 4 ) {
622  for( uint j = 0; j < 4; j++ ) {
623  scanline[j] = (QRgb *) 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  QRgb * scanline[4];
675 
676  for( uint y = 0; y < h; y += 4 ) {
677  for( uint j = 0; j < 4; j++ ) {
678  scanline[j] = (QRgb *) 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  QRgb * scanline[4];
724 
725  for( uint y = 0; y < h; y += 4 ) {
726  for( uint j = 0; j < 4; j++ ) {
727  scanline[j] = (QRgb *) 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  QRgb * src = (QRgb *) face.scanLine( y );
945  QRgb * dst = (QRgb *) img.scanLine( y + offset_y ) + offset_x;
946  memcpy( dst, src, sizeof(QRgb) * header.width );
947  }
948  }
949 
950  return true;
951  }
952 
953 }
954 
955 
956 KDE_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 
1014 KDE_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
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kimgio by doxygen 1.8.8
This website is maintained by Timothy Pearson.