il_dds-save.c
Upload User: wmy0603
Upload Date: 2022-05-02
Package Size: 1808k
Code Size: 34k
Development Platform:

Visual C++

  1. //-----------------------------------------------------------------------------
  2. //
  3. // ImageLib Sources
  4. // Copyright (C) 2000-2009 by Denton Woods
  5. // Last modified: 02/09/2009
  6. //
  7. // Filename: src-IL/src/il_dds-save.c
  8. //
  9. // Description: Saves a DirectDraw Surface (.dds) file.
  10. //
  11. //-----------------------------------------------------------------------------
  12. #include "il_internal.h"
  13. #include "il_dds.h"
  14. #include "il_manip.h"
  15. #include <limits.h>
  16. #ifndef IL_NO_DDS
  17. //! Writes a Dds file
  18. ILboolean ilSave_DDS(const ILstring FileName)
  19. {
  20. ILHANDLE DdsFile;
  21. ILuint DdsSize;
  22. if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
  23. if (iFileExists(FileName)) {
  24. ilSetError(IL_FILE_ALREADY_EXISTS);
  25. return IL_FALSE;
  26. }
  27. }
  28. DdsFile = iopenw(FileName);
  29. if (DdsFile == NULL) {
  30. ilSetError(IL_COULD_NOT_OPEN_FILE);
  31. return IL_FALSE;
  32. }
  33. DdsSize = ilSaveF_DDS(DdsFile);
  34. iclosew(DdsFile);
  35. if (DdsSize == 0)
  36. return IL_FALSE;
  37. return IL_TRUE;
  38. }
  39. //! Writes a Dds to an already-opened file
  40. ILuint ilSaveF_DDS(ILHANDLE File)
  41. {
  42. ILuint Pos;
  43. iSetOutputFile(File);
  44. Pos = itellw();
  45. if (iSaveDdsInternal() == IL_FALSE)
  46. return 0;  // Error occurred
  47. return itellw() - Pos;  // Return the number of bytes written.
  48. }
  49. //! Writes a Dds to a memory "lump"
  50. ILuint ilSaveL_DDS(void *Lump, ILuint Size)
  51. {
  52. ILuint Pos;
  53. iSetOutputLump(Lump, Size);
  54. Pos = itellw();
  55. if (iSaveDdsInternal() == IL_FALSE)
  56. return 0;  // Error occurred
  57. return itellw() - Pos;  // Return the number of bytes written.
  58. }
  59. //! Checks if an image is a cubemap
  60. ILuint GetCubemapInfo(ILimage* image, ILint* faces)
  61. {
  62. ILint indices[] = { -1, -1, -1,  -1, -1, -1 }, i;
  63. ILimage *img;
  64. ILuint ret = 0, srcMipmapCount, srcImagesCount, mipmapCount;
  65. if (image == NULL)
  66. return 0;
  67. iGetIntegervImage(image, IL_NUM_IMAGES, (ILint*) &srcImagesCount);
  68. if (srcImagesCount != 5) //write only complete cubemaps (TODO?)
  69. return 0;
  70. img = image;
  71. iGetIntegervImage(image, IL_NUM_MIPMAPS, (ILint*) &srcMipmapCount);
  72. mipmapCount = srcMipmapCount;
  73. for (i = 0; i < 6; ++i) {
  74. switch (img->CubeFlags)
  75. {
  76. case DDS_CUBEMAP_POSITIVEX:
  77. indices[i] = 0;
  78. break;
  79. case DDS_CUBEMAP_NEGATIVEX:
  80. indices[i] = 1;
  81. break;
  82. case DDS_CUBEMAP_POSITIVEY:
  83. indices[i] = 2;
  84. break;
  85. case DDS_CUBEMAP_NEGATIVEY:
  86. indices[i] = 3;
  87. break;
  88. case DDS_CUBEMAP_POSITIVEZ:
  89. indices[i] = 4;
  90. break;
  91. case DDS_CUBEMAP_NEGATIVEZ:
  92. indices[i] = 5;
  93. break;
  94. }
  95.         iGetIntegervImage(img, IL_NUM_MIPMAPS, (ILint*) &srcMipmapCount);
  96. if (srcMipmapCount != mipmapCount)
  97. return 0; //equal # of mipmaps required
  98. ret |= img->CubeFlags;
  99. img = img->Next;
  100. }
  101. for (i = 0; i < 6; ++i)
  102. if (indices[i] == -1)
  103. return 0; //one face not found
  104. if (ret != 0) //should always be true
  105. ret |= DDS_CUBEMAP;
  106. for (i = 0; i < 6; ++i)
  107. faces[indices[i]] = i;
  108. return ret;
  109. }
  110. // Internal function used to save the Dds.
  111. ILboolean iSaveDdsInternal()
  112. {
  113. ILenum DXTCFormat;
  114. ILuint counter, numMipMaps, image, numFaces, i;
  115. ILubyte *CurData = NULL;
  116. ILint CubeTable[6] = { 0 };
  117. ILuint CubeFlags;
  118. CubeFlags = GetCubemapInfo(iCurImage, CubeTable);
  119. image = ilGetInteger(IL_CUR_IMAGE);
  120. DXTCFormat = iGetInt(IL_DXTC_FORMAT);
  121. WriteHeader(iCurImage, DXTCFormat, CubeFlags);
  122. if (CubeFlags != 0)
  123. numFaces = ilGetInteger(IL_NUM_FACES); // Should always be 5 for now
  124. else
  125. numFaces = 0;
  126. numMipMaps = ilGetInteger(IL_NUM_MIPMAPS); //this assumes all faces have same # of mipmaps
  127. for (i = 0; i <= numFaces; ++i) {
  128. for (counter = 0; counter <= numMipMaps; counter++) {
  129. ilBindImage(image);
  130. ilActiveImage(CubeTable[i]);
  131. ilActiveMipmap(counter);
  132. if (iCurImage->Origin != IL_ORIGIN_UPPER_LEFT) {
  133. CurData = iCurImage->Data;
  134. iCurImage->Data = iGetFlipped(iCurImage);
  135. if (iCurImage->Data == NULL) {
  136. iCurImage->Data = CurData;
  137. return IL_FALSE;
  138. }
  139. }
  140. if (!Compress(iCurImage, DXTCFormat))
  141. return IL_FALSE;
  142. if (iCurImage->Origin != IL_ORIGIN_UPPER_LEFT) {
  143. ifree(iCurImage->Data);
  144. iCurImage->Data = CurData;
  145. }
  146. }
  147. }
  148. return IL_TRUE;
  149. }
  150. // @TODO:  Finish this, as it is incomplete.
  151. ILboolean WriteHeader(ILimage *Image, ILenum DXTCFormat, ILuint CubeFlags)
  152. {
  153. ILuint i, FourCC, Flags1 = 0, Flags2 = 0, ddsCaps1 = 0,
  154. LinearSize, BlockSize, ddsCaps2 = 0;
  155. Flags1 |= DDS_LINEARSIZE | DDS_MIPMAPCOUNT 
  156. | DDS_WIDTH | DDS_HEIGHT | DDS_CAPS | DDS_PIXELFORMAT;
  157. Flags2 |= DDS_FOURCC;
  158. if (Image->Depth > 1)
  159. Flags1 |= DDS_DEPTH;
  160. // @TODO:  Fix the pre-multiplied alpha problem.
  161. if (DXTCFormat == IL_DXT2)
  162. DXTCFormat = IL_DXT3;
  163. else if (DXTCFormat == IL_DXT4)
  164. DXTCFormat = IL_DXT5;
  165. switch (DXTCFormat)
  166. {
  167. case IL_DXT1:
  168. case IL_DXT1A:
  169. FourCC = IL_MAKEFOURCC('D','X','T','1');
  170. break;
  171. case IL_DXT2:
  172. FourCC = IL_MAKEFOURCC('D','X','T','2');
  173. break;
  174. case IL_DXT3:
  175. FourCC = IL_MAKEFOURCC('D','X','T','3');
  176. break;
  177. case IL_DXT4:
  178. FourCC = IL_MAKEFOURCC('D','X','T','4');
  179. break;
  180. case IL_DXT5:
  181. FourCC = IL_MAKEFOURCC('D','X','T','5');
  182. break;
  183. case IL_ATI1N:
  184. FourCC = IL_MAKEFOURCC('A', 'T', 'I', '1');
  185. break;
  186. case IL_3DC:
  187. FourCC = IL_MAKEFOURCC('A','T','I','2');
  188. break;
  189. case IL_RXGB:
  190. FourCC = IL_MAKEFOURCC('R','X','G','B');
  191. break;
  192. default:
  193. // Error!
  194. ilSetError(IL_INTERNAL_ERROR);  // Should never happen, though.
  195. return IL_FALSE;
  196. }
  197. iwrite("DDS ", 1, 4);
  198. SaveLittleUInt(124); // Size1
  199. SaveLittleUInt(Flags1); // Flags1
  200. SaveLittleUInt(Image->Height);
  201. SaveLittleUInt(Image->Width);
  202. if (DXTCFormat == IL_DXT1 || DXTCFormat == IL_DXT1A || DXTCFormat == IL_ATI1N) {
  203. BlockSize = 8;
  204. }
  205. else {
  206. BlockSize = 16;
  207. }
  208. LinearSize = (((Image->Width + 3)/4) * ((Image->Height + 3)/4)) * BlockSize * Image->Depth;
  209. /*
  210. // doing this is actually wrong, linear size is only size of one cube face
  211. if (CubeFlags != 0) {
  212. ILint numFaces = 0;
  213. for (i = 0; i < 6; ++i)
  214. if (CubeFlags & CubemapDirections[i])
  215. ++numFaces;
  216. LinearSize *= numFaces;
  217. }
  218. */
  219. SaveLittleUInt(LinearSize); // LinearSize (TODO: change this when uncompressed formats are supported)
  220. if (Image->Depth > 1) {
  221. SaveLittleUInt(Image->Depth); // Depth
  222. ddsCaps2 |= DDS_VOLUME;
  223. }
  224. else
  225. SaveLittleUInt(0); // Depth
  226. SaveLittleUInt(ilGetInteger(IL_NUM_MIPMAPS) + 1);  // MipMapCount
  227. SaveLittleUInt(0); // AlphaBitDepth
  228. for (i = 0; i < 10; i++)
  229. SaveLittleUInt(0); // Not used
  230. SaveLittleUInt(32); // Size2
  231. SaveLittleUInt(Flags2); // Flags2
  232. SaveLittleUInt(FourCC); // FourCC
  233. SaveLittleUInt(0); // RGBBitCount
  234. SaveLittleUInt(0); // RBitMask
  235. SaveLittleUInt(0); // GBitMask
  236. SaveLittleUInt(0); // BBitMask
  237. SaveLittleUInt(0); // RGBAlphaBitMask
  238. ddsCaps1 |= DDS_TEXTURE;
  239. //changed 20040516: set mipmap flag on mipmap images
  240. //(non-compressed .dds files still not supported,
  241. //though)
  242. if (ilGetInteger(IL_NUM_MIPMAPS) > 0)
  243. ddsCaps1 |= DDS_MIPMAP | DDS_COMPLEX;
  244. if (CubeFlags != 0) {
  245. ddsCaps1 |= DDS_COMPLEX;
  246. ddsCaps2 |= CubeFlags;
  247. }
  248. SaveLittleUInt(ddsCaps1); // ddsCaps1
  249. SaveLittleUInt(ddsCaps2); // ddsCaps2
  250. SaveLittleUInt(0); // ddsCaps3
  251. SaveLittleUInt(0); // ddsCaps4
  252. SaveLittleUInt(0); // TextureStage
  253. return IL_TRUE;
  254. }
  255. #endif//IL_NO_DDS
  256. ILuint ILAPIENTRY ilGetDXTCData(void *Buffer, ILuint BufferSize, ILenum DXTCFormat)
  257. {
  258. ILubyte *CurData = NULL;
  259. ILuint retVal;
  260. ILint BlockNum;
  261. if (Buffer == NULL) {  // Return the number that will be written with a subsequent call.
  262. BlockNum = ((iCurImage->Width + 3)/4) * ((iCurImage->Height + 3)/4)
  263. * iCurImage->Depth;
  264. switch (DXTCFormat)
  265. {
  266. case IL_DXT1:
  267. case IL_DXT1A:
  268. case IL_ATI1N:
  269. return BlockNum * 8;
  270. case IL_DXT3:
  271. case IL_DXT5:
  272. case IL_3DC:
  273. case IL_RXGB:
  274. return BlockNum * 16;
  275. default:
  276. ilSetError(IL_FORMAT_NOT_SUPPORTED);
  277. return 0;
  278. }
  279. }
  280. if (DXTCFormat == iCurImage->DxtcFormat && iCurImage->DxtcSize && iCurImage->DxtcData) {
  281. memcpy(Buffer, iCurImage->DxtcData, IL_MIN(BufferSize, iCurImage->DxtcSize));
  282. return IL_MIN(BufferSize, iCurImage->DxtcSize);
  283. }
  284. if (iCurImage->Origin != IL_ORIGIN_UPPER_LEFT) {
  285. CurData = iCurImage->Data;
  286. iCurImage->Data = iGetFlipped(iCurImage);
  287. if (iCurImage->Data == NULL) {
  288. iCurImage->Data = CurData;
  289. return 0;
  290. }
  291. }
  292. //@TODO: Is this the best way to do this?
  293. iSetOutputLump(Buffer, BufferSize);
  294. retVal = Compress(iCurImage, DXTCFormat);
  295. if (iCurImage->Origin != IL_ORIGIN_UPPER_LEFT) {
  296. ifree(iCurImage->Data);
  297. iCurImage->Data = CurData;
  298. }
  299. return retVal;
  300. }
  301. // Added the next two functions based on Charles Bloom's rant at
  302. //  http://cbloomrants.blogspot.com/2008/12/12-08-08-dxtc-summary.html.
  303. //  This code is by ryg and from the Molly Rocket forums:
  304. //  https://mollyrocket.com/forums/viewtopic.php?t=392.
  305. static ILint Mul8Bit(ILint a, ILint b)
  306. {
  307. ILint t = a*b + 128;
  308. return (t + (t >> 8)) >> 8;
  309. }
  310. ILushort As16Bit(ILint r, ILint g, ILint b)
  311. {
  312. return (Mul8Bit(r,31) << 11) + (Mul8Bit(g,63) << 5) + Mul8Bit(b,31);
  313. }
  314. ILushort *CompressTo565(ILimage *Image)
  315. {
  316. ILimage *TempImage;
  317. ILushort *Data;
  318. ILuint i, j;
  319. if ((Image->Type != IL_UNSIGNED_BYTE && Image->Type != IL_BYTE) || Image->Format == IL_COLOUR_INDEX) {
  320. TempImage = iConvertImage(iCurImage, IL_BGRA, IL_UNSIGNED_BYTE);  // @TODO: Needs to be BGRA.
  321. if (TempImage == NULL)
  322. return NULL;
  323. }
  324. else {
  325. TempImage = Image;
  326. }
  327. Data = (ILushort*)ialloc(iCurImage->Width * iCurImage->Height * 2 * iCurImage->Depth);
  328. if (Data == NULL) {
  329. if (TempImage != Image)
  330. ilCloseImage(TempImage);
  331. return NULL;
  332. }
  333. //changed 20040623: Use TempImages format :)
  334. switch (TempImage->Format)
  335. {
  336. case IL_RGB:
  337. for (i = 0, j = 0; i < TempImage->SizeOfData; i += 3, j++) {
  338. /*Data[j]  = (TempImage->Data[i  ] >> 3) << 11;
  339. Data[j] |= (TempImage->Data[i+1] >> 2) << 5;
  340. Data[j] |=  TempImage->Data[i+2] >> 3;*/
  341. Data[j] = As16Bit(TempImage->Data[i], TempImage->Data[i+1], TempImage->Data[i+2]);
  342. }
  343. break;
  344. case IL_RGBA:
  345. for (i = 0, j = 0; i < TempImage->SizeOfData; i += 4, j++) {
  346. /*Data[j]  = (TempImage->Data[i  ] >> 3) << 11;
  347. Data[j] |= (TempImage->Data[i+1] >> 2) << 5;
  348. Data[j] |=  TempImage->Data[i+2] >> 3;*/
  349. Data[j] = As16Bit(TempImage->Data[i], TempImage->Data[i+1], TempImage->Data[i+2]);
  350. }
  351. break;
  352. case IL_BGR:
  353. for (i = 0, j = 0; i < TempImage->SizeOfData; i += 3, j++) {
  354. /*Data[j]  = (TempImage->Data[i+2] >> 3) << 11;
  355. Data[j] |= (TempImage->Data[i+1] >> 2) << 5;
  356. Data[j] |=  TempImage->Data[i  ] >> 3;*/
  357. Data[j] = As16Bit(TempImage->Data[i+2], TempImage->Data[i+1], TempImage->Data[i]);
  358. }
  359. break;
  360. case IL_BGRA:
  361. for (i = 0, j = 0; i < TempImage->SizeOfData; i += 4, j++) {
  362. /*Data[j]  = (TempImage->Data[i+2] >> 3) << 11;
  363. Data[j] |= (TempImage->Data[i+1] >> 2) << 5;
  364. Data[j] |=  TempImage->Data[i  ] >> 3;*/
  365. Data[j] = As16Bit(TempImage->Data[i+2], TempImage->Data[i+1], TempImage->Data[i]);
  366. }
  367. break;
  368. case IL_LUMINANCE:
  369. for (i = 0, j = 0; i < TempImage->SizeOfData; i++, j++) {
  370. //@TODO: Do better conversion here.
  371. /*Data[j]  = (TempImage->Data[i] >> 3) << 11;
  372. Data[j] |= (TempImage->Data[i] >> 2) << 5;
  373. Data[j] |=  TempImage->Data[i] >> 3;*/
  374. Data[j] = As16Bit(TempImage->Data[i], TempImage->Data[i], TempImage->Data[i]);
  375. }
  376. break;
  377. case IL_LUMINANCE_ALPHA:
  378. for (i = 0, j = 0; i < TempImage->SizeOfData; i += 2, j++) {
  379. //@TODO: Do better conversion here.
  380. /*Data[j]  = (TempImage->Data[i] >> 3) << 11;
  381. Data[j] |= (TempImage->Data[i] >> 2) << 5;
  382. Data[j] |=  TempImage->Data[i] >> 3;*/
  383. Data[j] = As16Bit(TempImage->Data[i], TempImage->Data[i], TempImage->Data[i]);
  384. }
  385. break;
  386. case IL_ALPHA:
  387. memset(Data, 0, iCurImage->Width * iCurImage->Height * 2 * iCurImage->Depth);
  388. break;
  389. }
  390. if (TempImage != Image)
  391. ilCloseImage(TempImage);
  392. return Data;
  393. }
  394. ILubyte *CompressTo88(ILimage *Image)
  395. {
  396. ILimage *TempImage;
  397. ILubyte *Data;
  398. ILuint i, j;
  399. if ((Image->Type != IL_UNSIGNED_BYTE && Image->Type != IL_BYTE) || Image->Format == IL_COLOUR_INDEX) {
  400. TempImage = iConvertImage(iCurImage, IL_BGR, IL_UNSIGNED_BYTE);  // @TODO: Needs to be BGRA.
  401. if (TempImage == NULL)
  402. return NULL;
  403. }
  404. else {
  405. TempImage = Image;
  406. }
  407. Data = (ILubyte*)ialloc(iCurImage->Width * iCurImage->Height * 2 * iCurImage->Depth);
  408. if (Data == NULL) {
  409. if (TempImage != Image)
  410. ilCloseImage(TempImage);
  411. return NULL;
  412. }
  413. //changed 20040623: Use TempImage's format :)
  414. switch (TempImage->Format)
  415. {
  416. case IL_RGB:
  417. for (i = 0, j = 0; i < TempImage->SizeOfData; i += 3, j += 2) {
  418. Data[j  ] = TempImage->Data[i+1];
  419. Data[j+1] = TempImage->Data[i  ];
  420. }
  421. break;
  422. case IL_RGBA:
  423. for (i = 0, j = 0; i < TempImage->SizeOfData; i += 4, j += 2) {
  424. Data[j  ] = TempImage->Data[i+1];
  425. Data[j+1] = TempImage->Data[i  ];
  426. }
  427. break;
  428. case IL_BGR:
  429. for (i = 0, j = 0; i < TempImage->SizeOfData; i += 3, j += 2) {
  430. Data[j  ] = TempImage->Data[i+1];
  431. Data[j+1] = TempImage->Data[i+2];
  432. }
  433. break;
  434. case IL_BGRA:
  435. for (i = 0, j = 0; i < TempImage->SizeOfData; i += 4, j += 2) {
  436. Data[j  ] = TempImage->Data[i+1];
  437. Data[j+1] = TempImage->Data[i+2];
  438. }
  439. break;
  440. case IL_LUMINANCE:
  441. case IL_LUMINANCE_ALPHA:
  442. for (i = 0, j = 0; i < TempImage->SizeOfData; i++, j += 2) {
  443. Data[j  ] = Data[j+1] = 0; //??? Luminance is no normal map format...
  444. }
  445. break;
  446. }
  447. if (TempImage != Image)
  448. ilCloseImage(TempImage);
  449. return Data;
  450. }
  451. void CompressToRXGB(ILimage *Image, ILushort** xgb, ILubyte** r)
  452. {
  453. ILimage *TempImage;
  454. ILuint i, j;
  455. ILushort *Data;
  456. ILubyte *Alpha;
  457. *xgb = NULL;
  458. *r = NULL;
  459. if ((Image->Type != IL_UNSIGNED_BYTE && Image->Type != IL_BYTE) || Image->Format == IL_COLOUR_INDEX) {
  460. TempImage = iConvertImage(iCurImage, IL_BGR, IL_UNSIGNED_BYTE);  // @TODO: Needs to be BGRA.
  461. if (TempImage == NULL)
  462. return;
  463. }
  464. else {
  465. TempImage = Image;
  466. }
  467. *xgb = (ILushort*)ialloc(iCurImage->Width * iCurImage->Height * 2 * iCurImage->Depth);
  468. *r = (ILubyte*)ialloc(iCurImage->Width * iCurImage->Height * iCurImage->Depth);
  469. if (*xgb == NULL || *r == NULL) {
  470. if (TempImage != Image)
  471. ilCloseImage(TempImage);
  472. return;
  473. }
  474. //Alias pointers to be able to use copy'n'pasted code :)
  475. Data = *xgb;
  476. Alpha = *r;
  477. switch (TempImage->Format)
  478. {
  479. case IL_RGB:
  480. for (i = 0, j = 0; i < TempImage->SizeOfData; i += 3, j++) {
  481. Alpha[j] = TempImage->Data[i];
  482. Data[j] = (TempImage->Data[i+1] >> 2) << 5;
  483. Data[j] |=  TempImage->Data[i+2] >> 3;
  484. }
  485. break;
  486. case IL_RGBA:
  487. for (i = 0, j = 0; i < TempImage->SizeOfData; i += 4, j++) {
  488. Alpha[j]  = TempImage->Data[i];
  489. Data[j] = (TempImage->Data[i+1] >> 2) << 5;
  490. Data[j] |=  TempImage->Data[i+2] >> 3;
  491. }
  492. break;
  493. case IL_BGR:
  494. for (i = 0, j = 0; i < TempImage->SizeOfData; i += 3, j++) {
  495. Alpha[j]  = TempImage->Data[i+2];
  496. Data[j] = (TempImage->Data[i+1] >> 2) << 5;
  497. Data[j] |=  TempImage->Data[i  ] >> 3;
  498. }
  499. break;
  500. case IL_BGRA:
  501. for (i = 0, j = 0; i < TempImage->SizeOfData; i += 4, j++) {
  502. Alpha[j]  = TempImage->Data[i+2];
  503. Data[j] = (TempImage->Data[i+1] >> 2) << 5;
  504. Data[j] |=  TempImage->Data[i  ] >> 3;
  505. }
  506. break;
  507. case IL_LUMINANCE:
  508. for (i = 0, j = 0; i < TempImage->SizeOfData; i++, j++) {
  509. Alpha[j]  = TempImage->Data[i];
  510. Data[j] = (TempImage->Data[i] >> 2) << 5;
  511. Data[j] |=  TempImage->Data[i] >> 3;
  512. }
  513. break;
  514. case IL_LUMINANCE_ALPHA:
  515. for (i = 0, j = 0; i < TempImage->SizeOfData; i += 2, j++) {
  516. Alpha[j]  = TempImage->Data[i];
  517. Data[j] = (TempImage->Data[i] >> 2) << 5;
  518. Data[j] |=  TempImage->Data[i] >> 3;
  519. }
  520. break;
  521. }
  522. if (TempImage != Image)
  523. ilCloseImage(TempImage);
  524. }
  525. ILuint Compress(ILimage *Image, ILenum DXTCFormat)
  526. {
  527. ILushort *Data, Block[16], ex0, ex1, *Runner16, t0, t1;
  528. ILuint x, y, z, i, BitMask, DXTCSize;//, Rms1, Rms2;
  529. ILubyte *Alpha, AlphaBlock[16], AlphaBitMask[6], /*AlphaOut[16],*/ a0, a1;
  530. ILboolean HasAlpha;
  531. ILuint Count = 0;
  532. ILubyte *Data3Dc, *Runner8, *ByteData, *BlockData;
  533. if (DXTCFormat == IL_3DC) {
  534. Data3Dc = CompressTo88(Image);
  535. if (Data3Dc == NULL)
  536. return 0;
  537. Runner8 = Data3Dc;
  538. for (z = 0; z < Image->Depth; z++) {
  539. for (y = 0; y < Image->Height; y += 4) {
  540. for (x = 0; x < Image->Width; x += 4) {
  541. Get3DcBlock(AlphaBlock, Runner8, Image, x, y, 0);
  542. ChooseAlphaEndpoints(AlphaBlock, &a0, &a1);
  543. GenAlphaBitMask(a0, a1, AlphaBlock, AlphaBitMask, NULL);
  544. iputc(a0);
  545. iputc(a1);
  546. iwrite(AlphaBitMask, 1, 6);
  547. Get3DcBlock(AlphaBlock, Runner8, Image, x, y, 1);
  548. ChooseAlphaEndpoints(AlphaBlock, &a0, &a1);
  549. GenAlphaBitMask(a0, a1, AlphaBlock, AlphaBitMask, NULL);
  550. iputc(a0);
  551. iputc(a1);
  552. iwrite(AlphaBitMask, 1, 6);
  553. Count += 16;
  554. }
  555. }
  556. Runner8 += Image->Width * Image->Height * 2;
  557. }
  558. ifree(Data3Dc);
  559. }
  560. else if (DXTCFormat == IL_ATI1N)
  561. {
  562. ILimage *TempImage;
  563. if (Image->Bpp != 1) {
  564. TempImage = iConvertImage(iCurImage, IL_LUMINANCE, IL_UNSIGNED_BYTE);
  565. if (TempImage == NULL)
  566. return 0;
  567. }
  568. else {
  569. TempImage = Image;
  570. }
  571. Runner8 = TempImage->Data;
  572. for (z = 0; z < Image->Depth; z++) {
  573. for (y = 0; y < Image->Height; y += 4) {
  574. for (x = 0; x < Image->Width; x += 4) {
  575. GetAlphaBlock(AlphaBlock, Runner8, Image, x, y);
  576. ChooseAlphaEndpoints(AlphaBlock, &a0, &a1);
  577. GenAlphaBitMask(a0, a1, AlphaBlock, AlphaBitMask, NULL);
  578. iputc(a0);
  579. iputc(a1);
  580. iwrite(AlphaBitMask, 1, 6);
  581. Count += 8;
  582. }
  583. }
  584. Runner8 += Image->Width * Image->Height;
  585. }
  586. if (TempImage != Image)
  587. ilCloseImage(TempImage);
  588. }
  589. else
  590. {
  591. // We want to try nVidia compression first, because it is the fastest.
  592. #ifdef IL_USE_DXTC_NVIDIA
  593. if (ilIsEnabled(IL_NVIDIA_COMPRESS) && Image->Depth == 1) {  // See if we need to use the nVidia Texture Tools library.
  594. if (DXTCFormat == IL_DXT1 || DXTCFormat == IL_DXT1A || DXTCFormat == IL_DXT3 || DXTCFormat == IL_DXT5) {
  595. // NVTT needs data as BGRA 32-bit.
  596. if (Image->Format != IL_BGRA || Image->Type != IL_UNSIGNED_BYTE) {  // No need to convert if already this format/type.
  597. ByteData = ilConvertBuffer(Image->SizeOfData, Image->Format, IL_BGRA, Image->Type, IL_UNSIGNED_BYTE, NULL, Image->Data);
  598. if (ByteData == NULL)
  599. return 0;
  600. }
  601. else
  602. ByteData = Image->Data;
  603. // Here's where all the compression and writing goes on.
  604. if (!ilNVidiaCompressDXTFile(ByteData, Image->Width, Image->Height, 1, DXTCFormat))
  605. return 0;
  606. if (ByteData != Image->Data)
  607. ifree(ByteData);
  608. return Image->Width * Image->Height * 4;  // Either compresses all or none.
  609. }
  610. }
  611. #endif//IL_USE_DXTC_NVIDIA
  612. // libsquish generates better quality output than DevIL does, so we try it next.
  613. #ifdef IL_USE_DXTC_SQUISH
  614. if (ilIsEnabled(IL_SQUISH_COMPRESS) && Image->Depth == 1) {  // See if we need to use the nVidia Texture Tools library.
  615. if (DXTCFormat == IL_DXT1 || DXTCFormat == IL_DXT1A || DXTCFormat == IL_DXT3 || DXTCFormat == IL_DXT5) {
  616. // libsquish needs data as RGBA 32-bit.
  617. if (Image->Format != IL_RGBA || Image->Type != IL_UNSIGNED_BYTE) {  // No need to convert if already this format/type.
  618. ByteData = ilConvertBuffer(Image->SizeOfData, Image->Format, IL_RGBA, Image->Type, IL_UNSIGNED_BYTE, NULL, Image->Data);
  619. if (ByteData == NULL)
  620. return 0;
  621. }
  622. else
  623. ByteData = Image->Data;
  624. // Get compressed data here.
  625. BlockData = ilSquishCompressDXT(ByteData, Image->Width, Image->Height, 1, DXTCFormat, &DXTCSize);
  626. if (BlockData == NULL)
  627. return 0;
  628. if (iwrite(BlockData, 1, DXTCSize) != DXTCSize) {
  629. if (ByteData != Image->Data)
  630. ifree(ByteData);
  631. ifree(BlockData);
  632. return 0;
  633. }
  634. if (ByteData != Image->Data)
  635. ifree(ByteData);
  636. ifree(BlockData);
  637. return Image->Width * Image->Height * 4;  // Either compresses all or none.
  638. }
  639. }
  640. #endif//IL_USE_DXTC_SQUISH
  641. if (DXTCFormat != IL_RXGB) {
  642. Data = CompressTo565(Image);
  643. if (Data == NULL)
  644. return 0;
  645. Alpha = ilGetAlpha(IL_UNSIGNED_BYTE);
  646. if (Alpha == NULL) {
  647. ifree(Data);
  648. return 0;
  649. }
  650. }
  651. else {
  652. CompressToRXGB(Image, &Data, &Alpha);
  653. if (Data == NULL || Alpha == NULL) {
  654. if (Data != NULL)
  655. ifree(Data);
  656. if (Alpha != NULL)
  657. ifree(Alpha);
  658. return 0;
  659. }
  660. }
  661. Runner8 = Alpha;
  662. Runner16 = Data;
  663. switch (DXTCFormat)
  664. {
  665. case IL_DXT1:
  666. case IL_DXT1A:
  667. for (z = 0; z < Image->Depth; z++) {
  668. for (y = 0; y < Image->Height; y += 4) {
  669. for (x = 0; x < Image->Width; x += 4) {
  670. GetAlphaBlock(AlphaBlock, Runner8, Image, x, y);
  671. HasAlpha = IL_FALSE;
  672. for (i = 0 ; i < 16; i++) {
  673. if (AlphaBlock[i] < 128) {
  674. HasAlpha = IL_TRUE;
  675. break;
  676. }
  677. }
  678. GetBlock(Block, Runner16, Image, x, y);
  679. ChooseEndpoints(Block, &ex0, &ex1);
  680. CorrectEndDXT1(&ex0, &ex1, HasAlpha);
  681. SaveLittleUShort(ex0);
  682. SaveLittleUShort(ex1);
  683. if (HasAlpha)
  684. BitMask = GenBitMask(ex0, ex1, 3, Block, AlphaBlock, NULL);
  685. else
  686. BitMask = GenBitMask(ex0, ex1, 4, Block, NULL, NULL);
  687. SaveLittleUInt(BitMask);
  688. Count += 8;
  689. }
  690. }
  691. Runner16 += Image->Width * Image->Height;
  692. Runner8 += Image->Width * Image->Height;
  693. }
  694. break;
  695. /*case IL_DXT2:
  696. for (y = 0; y < Image->Height; y += 4) {
  697. for (x = 0; x < Image->Width; x += 4) {
  698. GetAlphaBlock(AlphaBlock, Alpha, Image, x, y);
  699. for (i = 0; i < 16; i += 2) {
  700. iputc((ILubyte)(((AlphaBlock[i] >> 4) << 4) | (AlphaBlock[i+1] >> 4)));
  701. }
  702. GetBlock(Block, Data, Image, x, y);
  703. PreMult(Block, AlphaBlock);
  704. ChooseEndpoints(Block, &ex0, &ex1);
  705. SaveLittleUShort(ex0);
  706. SaveLittleUShort(ex1);
  707. BitMask = GenBitMask(ex0, ex1, 4, Block, NULL, NULL);
  708. SaveLittleUInt(BitMask);
  709. }
  710. }
  711. break;*/
  712. case IL_DXT3:
  713. for (z = 0; z < Image->Depth; z++) {
  714. for (y = 0; y < Image->Height; y += 4) {
  715. for (x = 0; x < Image->Width; x += 4) {
  716. GetAlphaBlock(AlphaBlock, Runner8, Image, x, y);
  717. for (i = 0; i < 16; i += 2) {
  718. iputc((ILubyte)(((AlphaBlock[i+1] >> 4) << 4) | (AlphaBlock[i] >> 4)));
  719. }
  720. GetBlock(Block, Runner16, Image, x, y);
  721. ChooseEndpoints(Block, &t0, &t1);
  722. ex0 = IL_MAX(t0, t1);
  723. ex1 = IL_MIN(t0, t1);
  724. CorrectEndDXT1(&ex0, &ex1, 0);
  725. SaveLittleUShort(ex0);
  726. SaveLittleUShort(ex1);
  727. BitMask = GenBitMask(ex0, ex1, 4, Block, NULL, NULL);
  728. SaveLittleUInt(BitMask);
  729. Count += 16;
  730. }
  731. }
  732. Runner16 += Image->Width * Image->Height;
  733. Runner8 += Image->Width * Image->Height;
  734. }
  735. break;
  736. case IL_RXGB:
  737. case IL_DXT5:
  738. for (z = 0; z < Image->Depth; z++) {
  739. for (y = 0; y < Image->Height; y += 4) {
  740. for (x = 0; x < Image->Width; x += 4) {
  741. GetAlphaBlock(AlphaBlock, Runner8, Image, x, y);
  742. ChooseAlphaEndpoints(AlphaBlock, &a0, &a1);
  743. GenAlphaBitMask(a0, a1, AlphaBlock, AlphaBitMask, NULL/*AlphaOut*/);
  744. /*Rms2 = RMSAlpha(AlphaBlock, AlphaOut);
  745. GenAlphaBitMask(a0, a1, 8, AlphaBlock, AlphaBitMask, AlphaOut);
  746. Rms1 = RMSAlpha(AlphaBlock, AlphaOut);
  747. if (Rms2 <= Rms1) {  // Yeah, we have to regenerate...
  748. GenAlphaBitMask(a0, a1, 6, AlphaBlock, AlphaBitMask, AlphaOut);
  749. Rms2 = a1;  // Just reuse Rms2 as a temporary variable...
  750. a1 = a0;
  751. a0 = Rms2;
  752. }*/
  753. iputc(a0);
  754. iputc(a1);
  755. iwrite(AlphaBitMask, 1, 6);
  756. GetBlock(Block, Runner16, Image, x, y);
  757. ChooseEndpoints(Block, &t0, &t1);
  758. ex0 = IL_MAX(t0, t1);
  759. ex1 = IL_MIN(t0, t1);
  760. CorrectEndDXT1(&ex0, &ex1, 0);
  761. SaveLittleUShort(ex0);
  762. SaveLittleUShort(ex1);
  763. BitMask = GenBitMask(ex0, ex1, 4, Block, NULL, NULL);
  764. SaveLittleUInt(BitMask);
  765. Count += 16;
  766. }
  767. }
  768. Runner16 += Image->Width * Image->Height;
  769. Runner8 += Image->Width * Image->Height;
  770. }
  771. break;
  772. }
  773. ifree(Data);
  774. ifree(Alpha);
  775. } //else no 3DC
  776. return Count;  // Returns 0 if no compression was done.
  777. }
  778. // Assumed to be 16-bit (5:6:5).
  779. ILboolean GetBlock(ILushort *Block, ILushort *Data, ILimage *Image, ILuint XPos, ILuint YPos)
  780. {
  781.     ILuint x, y, i = 0, Offset = YPos * Image->Width + XPos;
  782. for (y = 0; y < 4; y++) {
  783. for (x = 0; x < 4; x++) {
  784.     if (XPos + x < Image->Width && YPos + y < Image->Height)
  785. Block[i++] = Data[Offset + x];
  786. else
  787. // Variant of bugfix from https://sourceforge.net/forum/message.php?msg_id=5486779.
  788. //  If we are out of bounds of the image, just copy the adjacent data.
  789.     Block[i++] = Data[Offset];
  790. }
  791. // We do not want to read past the end of the image.
  792. if (YPos + y + 1 < Image->Height)
  793. Offset += Image->Width;
  794. }
  795. return IL_TRUE;
  796. }
  797. ILboolean GetAlphaBlock(ILubyte *Block, ILubyte *Data, ILimage *Image, ILuint XPos, ILuint YPos)
  798. {
  799. ILuint x, y, i = 0, Offset = YPos * Image->Width + XPos;
  800. for (y = 0; y < 4; y++) {
  801. for (x = 0; x < 4; x++) {
  802.     if (XPos + x < Image->Width && YPos + y < Image->Height)
  803. Block[i++] = Data[Offset + x];
  804. else
  805. // Variant of bugfix from https://sourceforge.net/forum/message.php?msg_id=5486779.
  806. //  If we are out of bounds of the image, just copy the adjacent data.
  807.     Block[i++] = Data[Offset];
  808. }
  809. // We do not want to read past the end of the image.
  810. if (YPos + y + 1 < Image->Height)
  811. Offset += Image->Width;
  812. }
  813. return IL_TRUE;
  814. }
  815. ILboolean Get3DcBlock(ILubyte *Block, ILubyte *Data, ILimage *Image, ILuint XPos, ILuint YPos, int channel)
  816. {
  817. ILuint x, y, i = 0, Offset = 2*(YPos * Image->Width + XPos) + channel;
  818. for (y = 0; y < 4; y++) {
  819. for (x = 0; x < 4; x++) {
  820. if (x < Image->Width && y < Image->Height)
  821.                 Block[i++] = Data[Offset + 2*x];
  822.             else
  823.                 Block[i++] = Data[Offset];
  824. }
  825.         Offset += 2*Image->Width;
  826. }
  827. return IL_TRUE;
  828. }
  829. void ShortToColor565(ILushort Pixel, Color565 *Colour)
  830. {
  831. Colour->nRed   = (Pixel & 0xF800) >> 11;
  832. Colour->nGreen = (Pixel & 0x07E0) >> 5;
  833. Colour->nBlue  = (Pixel & 0x001F);
  834. return;
  835. }
  836. void ShortToColor888(ILushort Pixel, Color888 *Colour)
  837. {
  838. Colour->r = ((Pixel & 0xF800) >> 11) << 3;
  839. Colour->g = ((Pixel & 0x07E0) >> 5)  << 2;
  840. Colour->b = ((Pixel & 0x001F))       << 3;
  841. return;
  842. }
  843. ILushort Color565ToShort(Color565 *Colour)
  844. {
  845. return (Colour->nRed << 11) | (Colour->nGreen << 5) | (Colour->nBlue);
  846. }
  847. ILushort Color888ToShort(Color888 *Colour)
  848. {
  849. return ((Colour->r >> 3) << 11) | ((Colour->g >> 2) << 5) | (Colour->b >> 3);
  850. }
  851. ILuint GenBitMask(ILushort ex0, ILushort ex1, ILuint NumCols, ILushort *In, ILubyte *Alpha, Color888 *OutCol)
  852. {
  853. ILuint i, j, Closest, Dist, BitMask = 0;
  854. ILubyte Mask[16];
  855. Color888 c, Colours[4];
  856. ShortToColor888(ex0, &Colours[0]);
  857. ShortToColor888(ex1, &Colours[1]);
  858. if (NumCols == 3) {
  859. Colours[2].r = (Colours[0].r + Colours[1].r) / 2;
  860. Colours[2].g = (Colours[0].g + Colours[1].g) / 2;
  861. Colours[2].b = (Colours[0].b + Colours[1].b) / 2;
  862. Colours[3].r = (Colours[0].r + Colours[1].r) / 2;
  863. Colours[3].g = (Colours[0].g + Colours[1].g) / 2;
  864. Colours[3].b = (Colours[0].b + Colours[1].b) / 2;
  865. }
  866. else {  // NumCols == 4
  867. Colours[2].r = (2 * Colours[0].r + Colours[1].r + 1) / 3;
  868. Colours[2].g = (2 * Colours[0].g + Colours[1].g + 1) / 3;
  869. Colours[2].b = (2 * Colours[0].b + Colours[1].b + 1) / 3;
  870. Colours[3].r = (Colours[0].r + 2 * Colours[1].r + 1) / 3;
  871. Colours[3].g = (Colours[0].g + 2 * Colours[1].g + 1) / 3;
  872. Colours[3].b = (Colours[0].b + 2 * Colours[1].b + 1) / 3;
  873. }
  874. for (i = 0; i < 16; i++) {
  875. if (Alpha) {  // Test to see if we have 1-bit transparency
  876. if (Alpha[i] < 128) {
  877. Mask[i] = 3;  // Transparent
  878. if (OutCol) {
  879. OutCol[i].r = Colours[3].r;
  880. OutCol[i].g = Colours[3].g;
  881. OutCol[i].b = Colours[3].b;
  882. }
  883. continue;
  884. }
  885. }
  886. // If no transparency, try to find which colour is the closest.
  887. Closest = UINT_MAX;
  888. ShortToColor888(In[i], &c);
  889. for (j = 0; j < NumCols; j++) {
  890. Dist = Distance(&c, &Colours[j]);
  891. if (Dist < Closest) {
  892. Closest = Dist;
  893. Mask[i] = j;
  894. if (OutCol) {
  895. OutCol[i].r = Colours[j].r;
  896. OutCol[i].g = Colours[j].g;
  897. OutCol[i].b = Colours[j].b;
  898. }
  899. }
  900. }
  901. }
  902. for (i = 0; i < 16; i++) {
  903. BitMask |= (Mask[i] << (i*2));
  904. }
  905. return BitMask;
  906. }
  907. void GenAlphaBitMask(ILubyte a0, ILubyte a1, ILubyte *In, ILubyte *Mask, ILubyte *Out)
  908. {
  909. ILubyte Alphas[8], M[16];
  910. ILuint i, j, Closest, Dist;
  911. Alphas[0] = a0;
  912. Alphas[1] = a1;
  913. // 8-alpha or 6-alpha block?
  914. if (a0 > a1) {
  915. // 8-alpha block:  derive the other six alphas.
  916. // Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated.
  917. Alphas[2] = (6 * Alphas[0] + 1 * Alphas[1] + 3) / 7; // bit code 010
  918. Alphas[3] = (5 * Alphas[0] + 2 * Alphas[1] + 3) / 7; // bit code 011
  919. Alphas[4] = (4 * Alphas[0] + 3 * Alphas[1] + 3) / 7; // bit code 100
  920. Alphas[5] = (3 * Alphas[0] + 4 * Alphas[1] + 3) / 7; // bit code 101
  921. Alphas[6] = (2 * Alphas[0] + 5 * Alphas[1] + 3) / 7; // bit code 110
  922. Alphas[7] = (1 * Alphas[0] + 6 * Alphas[1] + 3) / 7; // bit code 111
  923. }
  924. else {
  925. // 6-alpha block.
  926. // Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated.
  927. Alphas[2] = (4 * Alphas[0] + 1 * Alphas[1] + 2) / 5; // Bit code 010
  928. Alphas[3] = (3 * Alphas[0] + 2 * Alphas[1] + 2) / 5; // Bit code 011
  929. Alphas[4] = (2 * Alphas[0] + 3 * Alphas[1] + 2) / 5; // Bit code 100
  930. Alphas[5] = (1 * Alphas[0] + 4 * Alphas[1] + 2) / 5; // Bit code 101
  931. Alphas[6] = 0x00; // Bit code 110
  932. Alphas[7] = 0xFF; // Bit code 111
  933. }
  934. for (i = 0; i < 16; i++) {
  935. Closest = UINT_MAX;
  936. for (j = 0; j < 8; j++) {
  937. Dist = abs((ILint)In[i] - (ILint)Alphas[j]);
  938. if (Dist < Closest) {
  939. Closest = Dist;
  940. M[i] = j;
  941. }
  942. }
  943. }
  944. if (Out) {
  945. for (i = 0; i < 16; i++) {
  946. Out[i] = Alphas[M[i]];
  947. }
  948. }
  949. //this was changed 20040623. There was a shift bug in here. Now the code
  950. //produces much higher quality images.
  951. // First three bytes.
  952. Mask[0] = (M[0]) | (M[1] << 3) | ((M[2] & 0x03) << 6);
  953. Mask[1] = ((M[2] & 0x04) >> 2) | (M[3] << 1) | (M[4] << 4) | ((M[5] & 0x01) << 7);
  954. Mask[2] = ((M[5] & 0x06) >> 1) | (M[6] << 2) | (M[7] << 5);
  955. // Second three bytes.
  956. Mask[3] = (M[8]) | (M[9] << 3) | ((M[10] & 0x03) << 6);
  957. Mask[4] = ((M[10] & 0x04) >> 2) | (M[11] << 1) | (M[12] << 4) | ((M[13] & 0x01) << 7);
  958. Mask[5] = ((M[13] & 0x06) >> 1) | (M[14] << 2) | (M[15] << 5);
  959. return;
  960. }
  961. ILuint RMSAlpha(ILubyte *Orig, ILubyte *Test)
  962. {
  963. ILuint RMS = 0, i;
  964. ILint d;
  965. for (i = 0; i < 16; i++) {
  966. d = Orig[i] - Test[i];
  967. RMS += d*d;
  968. }
  969. //RMS /= 16;
  970. return RMS;
  971. }
  972. ILuint Distance(Color888 *c1, Color888 *c2)
  973. {
  974. return  (c1->r - c2->r) * (c1->r - c2->r) +
  975. (c1->g - c2->g) * (c1->g - c2->g) +
  976. (c1->b - c2->b) * (c1->b - c2->b);
  977. }
  978. #define Sum(c) ((c)->r + (c)->g + (c)->b)
  979. #define NormSquared(c) ((c)->r * (c)->r + (c)->g * (c)->g + (c)->b * (c)->b)
  980. void ChooseEndpoints(ILushort *Block, ILushort *ex0, ILushort *ex1)
  981. {
  982. ILuint i;
  983. Color888 Colours[16];
  984. ILint Lowest=0, Highest=0;
  985. for (i = 0; i < 16; i++) {
  986. ShortToColor888(Block[i], &Colours[i]);
  987. if (NormSquared(&Colours[i]) < NormSquared(&Colours[Lowest]))
  988. Lowest = i;
  989. if (NormSquared(&Colours[i]) > NormSquared(&Colours[Highest]))
  990.   Highest = i;
  991. }
  992. *ex0 = Block[Highest];
  993. *ex1 = Block[Lowest];
  994. }
  995. #undef Sum
  996. #undef NormSquared
  997. void ChooseAlphaEndpoints(ILubyte *Block, ILubyte *a0, ILubyte *a1)
  998. {
  999. ILuint i, Lowest = 0xFF, Highest = 0;
  1000. for (i = 0; i < 16; i++) {
  1001. if (Block[i] < Lowest)
  1002. Lowest = Block[i];
  1003. if (Block[i] > Highest)
  1004. Highest = Block[i];
  1005. }
  1006. *a0 = Lowest;
  1007. *a1 = Highest;
  1008. }
  1009. void CorrectEndDXT1(ILushort *ex0, ILushort *ex1, ILboolean HasAlpha)
  1010. {
  1011. ILushort Temp;
  1012. if (HasAlpha) {
  1013. if (*ex0 > *ex1) {
  1014. Temp = *ex0;
  1015. *ex0 = *ex1;
  1016. *ex1 = Temp;
  1017. }
  1018. }
  1019. else {
  1020. if (*ex0 < *ex1) {
  1021. Temp = *ex0;
  1022. *ex0 = *ex1;
  1023. *ex1 = Temp;
  1024. }
  1025. }
  1026. return;
  1027. }
  1028. void PreMult(ILushort *Data, ILubyte *Alpha)
  1029. {
  1030. Color888 Colour;
  1031. ILuint i;
  1032. for (i = 0; i < 16; i++) {
  1033. ShortToColor888(Data[i], &Colour);
  1034. Colour.r = (ILubyte)(((ILuint)Colour.r * Alpha[i]) >> 8);
  1035. Colour.g = (ILubyte)(((ILuint)Colour.g * Alpha[i]) >> 8);
  1036. Colour.b = (ILubyte)(((ILuint)Colour.b * Alpha[i]) >> 8);
  1037. /*Colour.r = (ILubyte)(Colour.r * (Alpha[i] / 255.0));
  1038. Colour.g = (ILubyte)(Colour.g * (Alpha[i] / 255.0));
  1039. Colour.b = (ILubyte)(Colour.b * (Alpha[i] / 255.0));*/
  1040. Data[i] = Color888ToShort(&Colour);
  1041. ShortToColor888(Data[i], &Colour);
  1042. }
  1043. return;
  1044. }
  1045. //! Compresses data to a DXT format using different methods.
  1046. //  The data must be in unsigned byte RGBA or BGRA format.  Only DXT1, DXT3 and DXT5 are supported.
  1047. ILAPI ILubyte* ILAPIENTRY ilCompressDXT(ILubyte *Data, ILuint Width, ILuint Height, ILuint Depth, ILenum DXTCFormat, ILuint *DXTCSize)
  1048. {
  1049. ILimage *TempImage, *CurImage = iCurImage;
  1050. ILuint BuffSize;
  1051. ILubyte *Buffer;
  1052. if ((DXTCFormat != IL_DXT1 && DXTCFormat != IL_DXT1A && DXTCFormat != IL_DXT3 && DXTCFormat != IL_DXT5)
  1053. || Data == NULL || Width == 0 || Height == 0 || Depth == 0) {
  1054. ilSetError(IL_INVALID_PARAM);
  1055. return NULL;
  1056. }
  1057. // We want to try nVidia compression first, because it is the fastest.
  1058. #ifdef IL_USE_DXTC_NVIDIA
  1059. if (ilIsEnabled(IL_NVIDIA_COMPRESS) && Depth == 1) {  // See if we need to use the nVidia Texture Tools library.
  1060. // NVTT needs data as BGRA 32-bit.
  1061. // Here's where all the compression and writing goes on.
  1062. return ilNVidiaCompressDXT(Data, Width, Height, 1, DXTCFormat, DXTCSize);
  1063. }
  1064. #endif//IL_USE_DXTC_NVIDIA
  1065. // libsquish generates better quality output than DevIL does, so we try it next.
  1066. #ifdef IL_USE_DXTC_SQUISH
  1067. if (ilIsEnabled(IL_SQUISH_COMPRESS) && Depth == 1) {  // See if we need to use the nVidia Texture Tools library.
  1068. if (DXTCFormat == IL_DXT1 || DXTCFormat == IL_DXT1A || DXTCFormat == IL_DXT3 || DXTCFormat == IL_DXT5) {
  1069. // libsquish needs data as RGBA 32-bit.
  1070. // Get compressed data here.
  1071. return ilSquishCompressDXT(Data, Width, Height, 1, DXTCFormat, DXTCSize);
  1072. }
  1073. }
  1074. #endif//IL_USE_DXTC_SQUISH
  1075. TempImage = (ILimage*)ialloc(sizeof(ILimage));
  1076. memset(TempImage, 0, sizeof(ILimage));
  1077. TempImage->Width = Width;
  1078. TempImage->Height = Height;
  1079. TempImage->Depth = Depth;
  1080. TempImage->Bpp = 4;  // RGBA or BGRA
  1081. TempImage->Format = IL_BGRA;
  1082. TempImage->Bpc = 1;  // Unsigned bytes only
  1083. TempImage->Type = IL_UNSIGNED_BYTE;
  1084. TempImage->SizeOfPlane = TempImage->Bps * Height;
  1085. TempImage->SizeOfData  = TempImage->SizeOfPlane * Depth;
  1086. TempImage->Origin = IL_ORIGIN_UPPER_LEFT;
  1087. TempImage->Data = Data;
  1088. BuffSize = ilGetDXTCData(NULL, 0, DXTCFormat);
  1089. if (BuffSize == 0)
  1090. return NULL;
  1091. Buffer = (ILubyte*)ialloc(BuffSize);
  1092. if (Buffer == NULL)
  1093. return NULL;
  1094. if (ilGetDXTCData(Buffer, BuffSize, DXTCFormat) != BuffSize) {
  1095. ifree(Buffer);
  1096. return NULL;
  1097. }
  1098. *DXTCSize = BuffSize;
  1099. // Restore backup of iCurImage.
  1100. iCurImage = CurImage;
  1101. TempImage->Data = NULL;
  1102. ilCloseImage(TempImage);
  1103. return Buffer;
  1104. }