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