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