TDE core libraries
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

dds.cpp 24KB

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