1 //-----------------------------------------------------------------------------
2 //
3 // ImageLib Sources
4 // Copyright (C) 2000-2009 by Denton Woods
5 // Last modified: 02/28/2009
6 //
7 // Filename: src-IL/src/il_dds.c
8 //
9 // Description: Reads from a DirectDraw Surface (.dds) file.
10 //
11 //-----------------------------------------------------------------------------
12 
13 
14 //
15 //
16 // Note:  Almost all this code is from nVidia's DDS-loading example at
17 //	http://www.nvidia.com/view.asp?IO=dxtc_decompression_code
18 //	and from the specs at
19 //	http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dx8_c/hh/dx8_c/graphics_using_0j03.asp
20 //	and
21 //	http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dx8_c/directx_cpp/Graphics/ProgrammersGuide/Appendix/DDSFileFormat/ovwDDSFileFormat.asp
22 //	However, some not really valid .dds files are also read, for example
23 //	Volume Textures without the COMPLEX bit set, so the specs aren't taken
24 //	too strictly while reading.
25 
26 
27 #include "il_internal.h"
28 #ifndef IL_NO_DDS
29 #include "il_dds.h"
30 
31 
32 // Global variables
33 static DDSHEAD	Head;				// Image header
34 static ILubyte	*CompData = NULL;	// Compressed data
35 static ILuint	CompSize;			// Compressed size
36 //static ILuint	CompFormat;			// Compressed format
37 static ILimage	*Image;
38 static ILint	Width, Height, Depth;
39 static ILboolean	Has16BitComponents;
40 
41 ILuint CubemapDirections[CUBEMAP_SIDES] = {
42 	DDS_CUBEMAP_POSITIVEX,
43 	DDS_CUBEMAP_NEGATIVEX,
44 	DDS_CUBEMAP_POSITIVEY,
45 	DDS_CUBEMAP_NEGATIVEY,
46 	DDS_CUBEMAP_POSITIVEZ,
47 	DDS_CUBEMAP_NEGATIVEZ
48 };
49 
50 
51 //! Checks if the file specified in FileName is a valid .dds file.
ilIsValidDds(ILconst_string FileName)52 ILboolean ilIsValidDds(ILconst_string FileName)
53 {
54 	ILHANDLE	DdsFile;
55 	ILboolean	bDds = IL_FALSE;
56 
57 	if (!iCheckExtension(FileName, IL_TEXT("dds"))) {
58 		ilSetError(IL_INVALID_EXTENSION);
59 		return bDds;
60 	}
61 
62 	DdsFile = iopenr(FileName);
63 	if (DdsFile == NULL) {
64 		ilSetError(IL_COULD_NOT_OPEN_FILE);
65 		return bDds;
66 	}
67 
68 	bDds = ilIsValidDdsF(DdsFile);
69 	icloser(DdsFile);
70 
71 	return bDds;
72 }
73 
74 
75 //! Checks if the ILHANDLE contains a valid .dds file at the current position.
ilIsValidDdsF(ILHANDLE File)76 ILboolean ilIsValidDdsF(ILHANDLE File)
77 {
78 	ILuint		FirstPos;
79 	ILboolean	bRet;
80 
81 	iSetInputFile(File);
82 	FirstPos = itell();
83 	bRet = iIsValidDds();
84 	iseek(FirstPos, IL_SEEK_SET);
85 
86 	return bRet;
87 }
88 
89 
90 //! Checks if Lump is a valid .dds lump.
ilIsValidDdsL(const void * Lump,ILuint Size)91 ILboolean ilIsValidDdsL(const void *Lump, ILuint Size)
92 {
93 	iSetInputLump(Lump, Size);
94 	return iIsValidDds();
95 }
96 
97 
98 // Internal function used to get the .dds header from the current file.
iGetDdsHead(DDSHEAD * Header)99 ILboolean iGetDdsHead(DDSHEAD *Header)
100 {
101 	ILint i;
102 
103 	iread(&Header->Signature, 1, 4);
104 	Header->Size1 = GetLittleUInt();
105 	Header->Flags1 = GetLittleUInt();
106 	Header->Height = GetLittleUInt();
107 	Header->Width = GetLittleUInt();
108 	Header->LinearSize = GetLittleUInt();
109 	Header->Depth = GetLittleUInt();
110 	Header->MipMapCount = GetLittleUInt();
111 	Header->AlphaBitDepth = GetLittleUInt();
112 
113 	for (i = 0; i < 10; ++i)
114 		Header->NotUsed[i] = GetLittleUInt();
115 
116 	Header->Size2 = GetLittleUInt();
117 	Header->Flags2 = GetLittleUInt();
118 	Header->FourCC = GetLittleUInt();
119 	Header->RGBBitCount = GetLittleUInt();
120 	Header->RBitMask = GetLittleUInt();
121 	Header->GBitMask = GetLittleUInt();
122 	Header->BBitMask = GetLittleUInt();
123 	Header->RGBAlphaBitMask = GetLittleUInt();
124 	Header->ddsCaps1 = GetLittleUInt();
125 	Header->ddsCaps2 = GetLittleUInt();
126 	Header->ddsCaps3 = GetLittleUInt();
127 	Header->ddsCaps4 = GetLittleUInt();
128 	Header->TextureStage = GetLittleUInt();
129 
130 	if (Head.Depth == 0)
131 		Head.Depth = 1;
132 
133 	return IL_TRUE;
134 }
135 
136 
137 // Internal function to get the header and check it.
iIsValidDds()138 ILboolean iIsValidDds()
139 {
140 	ILboolean	IsValid;
141 	DDSHEAD		Head;
142 
143 	iGetDdsHead(&Head);
144 	iseek(-(ILint)sizeof(DDSHEAD), IL_SEEK_CUR);  // Go ahead and restore to previous state
145 
146 	IsValid = iCheckDds(&Head);
147 
148 	return IsValid;
149 }
150 
151 
152 // Internal function used to check if the HEADER is a valid .dds header.
iCheckDds(DDSHEAD * Head)153 ILboolean iCheckDds(DDSHEAD *Head)
154 {
155 	if (strncmp((const char*)Head->Signature, "DDS ", 4))
156 		return IL_FALSE;
157 	//note that if Size1 is "DDS " this is not a valid dds file according
158 	//to the file spec. Some broken tool out there seems to produce files
159 	//with this value in the size field, so we support reading them...
160 	if (Head->Size1 != 124 && Head->Size1 != IL_MAKEFOURCC('D', 'D', 'S', ' '))
161 		return IL_FALSE;
162 	if (Head->Size2 != 32)
163 		return IL_FALSE;
164 	if (Head->Width == 0 || Head->Height == 0)
165 		return IL_FALSE;
166 	return IL_TRUE;
167 }
168 
169 
170 //! Reads a .dds file
ilLoadDds(ILconst_string FileName)171 ILboolean ilLoadDds(ILconst_string FileName)
172 {
173 	ILHANDLE	DdsFile;
174 	ILboolean	bDds = IL_FALSE;
175 
176 	DdsFile = iopenr(FileName);
177 	if (DdsFile == NULL) {
178 		ilSetError(IL_COULD_NOT_OPEN_FILE);
179 		return bDds;
180 	}
181 
182 	bDds = ilLoadDdsF(DdsFile);
183 	icloser(DdsFile);
184 
185 	return bDds;
186 }
187 
188 
189 //! Reads an already-opened .dds file
ilLoadDdsF(ILHANDLE File)190 ILboolean ilLoadDdsF(ILHANDLE File)
191 {
192 	ILuint		FirstPos;
193 	ILboolean	bRet;
194 
195 	iSetInputFile(File);
196 	FirstPos = itell();
197 	bRet = iLoadDdsInternal();
198 	iseek(FirstPos, IL_SEEK_SET);
199 
200 	return bRet;
201 }
202 
203 
204 //! Reads from a memory "lump" that contains a .dds
ilLoadDdsL(const void * Lump,ILuint Size)205 ILboolean ilLoadDdsL(const void *Lump, ILuint Size)
206 {
207 	iSetInputLump(Lump, Size);
208 	return iLoadDdsInternal();
209 }
210 
211 
Check16BitComponents(DDSHEAD * Header)212 void Check16BitComponents(DDSHEAD *Header)
213 {
214 	if (Header->RGBBitCount != 32)
215 		Has16BitComponents = IL_FALSE;
216 	// a2b10g10r10 format
217 	if (Header->RBitMask == 0x3FF00000 && Header->GBitMask == 0x000FFC00 && Header->BBitMask == 0x000003FF
218 		&& Header->RGBAlphaBitMask == 0xC0000000)
219 		Has16BitComponents = IL_TRUE;
220 	// a2r10g10b10 format
221 	else if (Header->RBitMask == 0x000003FF && Header->GBitMask == 0x000FFC00 && Header->BBitMask == 0x3FF00000
222 		&& Header->RGBAlphaBitMask == 0xC0000000)
223 		Has16BitComponents = IL_TRUE;
224 	else
225 		Has16BitComponents = IL_FALSE;
226 	return;
227 }
228 
229 
iCompFormatToBpp(ILenum Format)230 ILubyte iCompFormatToBpp(ILenum Format)
231 {
232 	//non-compressed (= non-FOURCC) codes
233 	if (Format == PF_LUMINANCE || Format == PF_LUMINANCE_ALPHA || Format == PF_ARGB)
234 		return Head.RGBBitCount/8;
235 
236 	//fourcc formats
237 	else if (Format == PF_RGB || Format == PF_3DC || Format == PF_RXGB)
238 		return 3;
239 	else if (Format == PF_ATI1N)
240 		return 1;
241 	//else if (Format == PF_R16F)
242 	//	return 2;
243 	else if (Format == PF_A16B16G16R16 || Format == PF_A16B16G16R16F
244 		|| Format == PF_G32R32F)
245 		return 8;
246 	else if (Format == PF_A32B32G32R32F)
247 		return 16;
248 	else //if (Format == PF_G16R16F || Format == PF_R32F || dxt)
249 		return 4;
250 }
251 
252 
iCompFormatToBpc(ILenum Format)253 ILubyte iCompFormatToBpc(ILenum Format)
254 {
255 	if (Has16BitComponents)
256 		return 2;
257 	if (Format == PF_R16F || Format == PF_G16R16F || Format == PF_A16B16G16R16F)
258 		//DevIL has no internal half type, so these formats are converted to 32 bits
259 		return 4;
260 	else if (Format == PF_R32F || Format == PF_R16F || Format == PF_G32R32F || Format == PF_A32B32G32R32F)
261 		return 4;
262 	else if(Format == PF_A16B16G16R16)
263 		return 2;
264 	else
265 		return 1;
266 }
267 
268 
iCompFormatToChannelCount(ILenum Format)269 ILubyte iCompFormatToChannelCount(ILenum Format)
270 {
271 	if (Format == PF_RGB || Format == PF_3DC || Format == PF_RXGB)
272 		return 3;
273 	else if (Format == PF_LUMINANCE || /*Format == PF_R16F || Format == PF_R32F ||*/ Format == PF_ATI1N)
274 		return 1;
275 	else if (Format == PF_LUMINANCE_ALPHA /*|| Format == PF_G16R16F || Format == PF_G32R32F*/)
276 		return 2;
277 	else if (Format == PF_G16R16F || Format == PF_G32R32F || Format == PF_R32F || Format == PF_R16F)
278 		return 3;
279 	else //if(Format == PF_ARGB || dxt)
280 		return 4;
281 }
282 
283 
iLoadDdsCubemapInternal(ILuint CompFormat)284 ILboolean iLoadDdsCubemapInternal(ILuint CompFormat)
285 {
286 	ILuint	i;
287 	ILubyte	Bpp, Channels, Bpc;
288 	ILimage *startImage;
289 
290 	CompData = NULL;
291 
292 	Bpp = iCompFormatToBpp(CompFormat);
293 	Channels = iCompFormatToChannelCount(CompFormat);
294 	Bpc = iCompFormatToBpc(CompFormat);
295 	if (CompFormat == PF_LUMINANCE && Head.RGBBitCount == 16 && Head.RBitMask == 0xFFFF) { //@TODO: This is a HACK.
296 		Bpc = 2; Bpp = 2;
297 	}
298 
299 	startImage = Image;
300 	// Run through cube map possibilities
301 	for (i = 0; i < CUBEMAP_SIDES; i++) {
302 		// Reset each time
303 		Width = Head.Width;
304 		Height = Head.Height;
305 		Depth = Head.Depth;
306 		if (Head.ddsCaps2 & CubemapDirections[i]) {
307 			if (i != 0) {
308 				Image->Faces = ilNewImage(Width, Height, Depth, Channels, Bpc);
309 				if (Image->Faces == NULL)
310 					return IL_FALSE;
311 
312 				Image = Image->Faces;
313 
314 				if (CompFormat == PF_R16F
315 					|| CompFormat == PF_G16R16F
316 					|| CompFormat == PF_A16B16G16R16F
317 					|| CompFormat == PF_R32F
318 					|| CompFormat == PF_G32R32F
319 					|| CompFormat == PF_A32B32G32R32F) {
320 					// DevIL's format autodetection doesn't work for
321 					//  float images...correct this.
322 					Image->Type = IL_FLOAT;
323 					Image->Bpp = Channels;
324 				}
325 
326 				ilBindImage(ilGetCurName()); // Set to parent image first.
327 				//ilActiveImage(i); //@TODO: now Image == iCurImage...globals SUCK, fix this!!!
328 				ilActiveFace(i);
329 			}
330 
331 			if (!ReadData())
332 				return IL_FALSE;
333 
334 			if (!AllocImage(CompFormat)) {
335 				if (CompData) {
336 					ifree(CompData);
337 					CompData = NULL;
338 				}
339 				return IL_FALSE;
340 			}
341 
342 			Image->CubeFlags = CubemapDirections[i];
343 
344 			if (!DdsDecompress(CompFormat)) {
345 				if (CompData) {
346 					ifree(CompData);
347 					CompData = NULL;
348 				}
349 				return IL_FALSE;
350 			}
351 
352 			if (!ReadMipmaps(CompFormat)) {
353 				if (CompData) {
354 					ifree(CompData);
355 					CompData = NULL;
356 				}
357 				return IL_FALSE;
358 			}
359 		}
360 	}
361 
362 	if (CompData) {
363 		ifree(CompData);
364 		CompData = NULL;
365 	}
366 
367 	ilBindImage(ilGetCurName());  // Set to parent image first.
368 	return ilFixImage();
369 }
370 
371 
iLoadDdsInternal()372 ILboolean iLoadDdsInternal()
373 {
374 	ILuint	BlockSize = 0;
375 	ILuint	CompFormat;
376 
377 	CompData = NULL;
378 	Image = NULL;
379 
380 	if (iCurImage == NULL) {
381 		ilSetError(IL_ILLEGAL_OPERATION);
382 		return IL_FALSE;
383 	}
384 
385 	if (!iGetDdsHead(&Head)) {
386 		ilSetError(IL_INVALID_FILE_HEADER);
387 		return IL_FALSE;
388 	}
389 	if (!iCheckDds(&Head)) {
390 		ilSetError(IL_INVALID_FILE_HEADER);
391 		return IL_FALSE;
392 	}
393 
394 	BlockSize = DecodePixelFormat(&CompFormat);
395 	if (CompFormat == PF_UNKNOWN) {
396 		ilSetError(IL_INVALID_FILE_HEADER);
397 		return IL_FALSE;
398 	}
399 	Check16BitComponents(&Head);
400 
401 	// Microsoft bug, they're not following their own documentation.
402 	if (!(Head.Flags1 & (DDS_LINEARSIZE | DDS_PITCH))
403 		|| Head.LinearSize == 0) {
404 		Head.Flags1 |= DDS_LINEARSIZE;
405 		Head.LinearSize = BlockSize;
406 	}
407 
408 	Image = iCurImage;
409 	if (Head.ddsCaps1 & DDS_COMPLEX) {
410 		if (Head.ddsCaps2 & DDS_CUBEMAP) {
411 			if (!iLoadDdsCubemapInternal(CompFormat))
412 				return IL_FALSE;
413 			return IL_TRUE;
414 		}
415 	}
416 
417 	Width = Head.Width;
418 	Height = Head.Height;
419 	Depth = Head.Depth;
420 	AdjustVolumeTexture(&Head, CompFormat);
421 
422 	if (!ReadData())
423 		return IL_FALSE;
424 	if (!AllocImage(CompFormat)) {
425 		if (CompData) {
426 			ifree(CompData);
427 			CompData = NULL;
428 		}
429 		return IL_FALSE;
430 	}
431 	if (!DdsDecompress(CompFormat)) {
432 		if (CompData) {
433 			ifree(CompData);
434 			CompData = NULL;
435 		}
436 		return IL_FALSE;
437 	}
438 
439 	if (!ReadMipmaps(CompFormat)) {
440 		if (CompData) {
441 			ifree(CompData);
442 			CompData = NULL;
443 		}
444 		return IL_FALSE;
445 	}
446 
447 	if (CompData) {
448 		ifree(CompData);
449 		CompData = NULL;
450 	}
451 
452 	ilBindImage(ilGetCurName());  // Set to parent image first.
453 	return ilFixImage();
454 }
455 
456 
DecodePixelFormat(ILuint * CompFormat)457 ILuint DecodePixelFormat(ILuint *CompFormat)
458 {
459 	ILuint BlockSize;
460 
461 	if (Head.Flags2 & DDS_FOURCC) {
462 		BlockSize = ((Head.Width + 3)/4) * ((Head.Height + 3)/4) * Head.Depth;
463 		switch (Head.FourCC)
464 		{
465 			case IL_MAKEFOURCC('D','X','T','1'):
466 				*CompFormat = PF_DXT1;
467 				BlockSize *= 8;
468 				break;
469 
470 			case IL_MAKEFOURCC('D','X','T','2'):
471 				*CompFormat = PF_DXT2;
472 				BlockSize *= 16;
473 				break;
474 
475 			case IL_MAKEFOURCC('D','X','T','3'):
476 				*CompFormat = PF_DXT3;
477 				BlockSize *= 16;
478 				break;
479 
480 			case IL_MAKEFOURCC('D','X','T','4'):
481 				*CompFormat = PF_DXT4;
482 				BlockSize *= 16;
483 				break;
484 
485 			case IL_MAKEFOURCC('D','X','T','5'):
486 				*CompFormat = PF_DXT5;
487 				BlockSize *= 16;
488 				break;
489 
490 			case IL_MAKEFOURCC('A', 'T', 'I', '1'):
491 				*CompFormat = PF_ATI1N;
492 				BlockSize *= 8;
493 				break;
494 
495 			case IL_MAKEFOURCC('A', 'T', 'I', '2'):
496 				*CompFormat = PF_3DC;
497 				BlockSize *= 16;
498 				break;
499 
500 			case IL_MAKEFOURCC('R', 'X', 'G', 'B'):
501 				*CompFormat = PF_RXGB;
502 				BlockSize *= 16;
503 				break;
504 
505 			case IL_MAKEFOURCC('$', '\0', '\0', '\0'):
506 				*CompFormat = PF_A16B16G16R16;
507 				BlockSize = Head.Width * Head.Height * Head.Depth * 8;
508 				break;
509 
510 			case IL_MAKEFOURCC('o', '\0', '\0', '\0'):
511 				*CompFormat = PF_R16F;
512 				BlockSize = Head.Width * Head.Height * Head.Depth * 2;
513 				break;
514 
515 			case IL_MAKEFOURCC('p', '\0', '\0', '\0'):
516 				*CompFormat = PF_G16R16F;
517 				BlockSize = Head.Width * Head.Height * Head.Depth * 4;
518 				break;
519 
520 			case IL_MAKEFOURCC('q', '\0', '\0', '\0'):
521 				*CompFormat = PF_A16B16G16R16F;
522 				BlockSize = Head.Width * Head.Height * Head.Depth * 8;
523 				break;
524 
525 			case IL_MAKEFOURCC('r', '\0', '\0', '\0'):
526 				*CompFormat = PF_R32F;
527 				BlockSize = Head.Width * Head.Height * Head.Depth * 4;
528 				break;
529 
530 			case IL_MAKEFOURCC('s', '\0', '\0', '\0'):
531 				*CompFormat = PF_G32R32F;
532 				BlockSize = Head.Width * Head.Height * Head.Depth * 8;
533 				break;
534 
535 			case IL_MAKEFOURCC('t', '\0', '\0', '\0'):
536 				*CompFormat = PF_A32B32G32R32F;
537 				BlockSize = Head.Width * Head.Height * Head.Depth * 16;
538 				break;
539 
540 			default:
541 				*CompFormat = PF_UNKNOWN;
542 				BlockSize *= 16;
543 				break;
544 		}
545 	} else {
546 		// This dds texture isn't compressed so write out ARGB or luminance format
547 		if (Head.Flags2 & DDS_LUMINANCE) {
548 			if (Head.Flags2 & DDS_ALPHAPIXELS) {
549 				*CompFormat = PF_LUMINANCE_ALPHA;
550 			} else {
551 				*CompFormat = PF_LUMINANCE;
552 			}
553 		}
554 		else {
555 			if (Head.Flags2 & DDS_ALPHAPIXELS) {
556 				*CompFormat = PF_ARGB;
557 			} else {
558 				*CompFormat = PF_RGB;
559 			}
560 		}
561 		BlockSize = (Head.Width * Head.Height * Head.Depth * (Head.RGBBitCount >> 3));
562 	}
563 
564 	return BlockSize;
565 }
566 
567 
568 // The few volume textures that I have don't have consistent LinearSize
569 //	entries, even though the DDS_LINEARSIZE flag is set.
AdjustVolumeTexture(DDSHEAD * Head,ILuint CompFormat)570 void AdjustVolumeTexture(DDSHEAD *Head, ILuint CompFormat)
571 {
572 	if (Head->Depth <= 1)
573 		return;
574 
575 	// All volume textures I've seem so far didn't have the DDS_COMPLEX flag set,
576 	// even though this is normally required. But because noone does set it,
577 	// also read images without it (TODO: check file size for 3d texture?)
578 	if (/*!(Head->ddsCaps1 & DDS_COMPLEX) ||*/ !(Head->ddsCaps2 & DDS_VOLUME)) {
579 		Head->Depth = 1;
580 		Depth = 1;
581 	}
582 
583 	switch (CompFormat)
584 	{
585 		case PF_ARGB:
586 		case PF_RGB:
587 		case PF_LUMINANCE:
588 		case PF_LUMINANCE_ALPHA:
589 			//don't use the iCompFormatToBpp() function because this way
590 			//argb images with only 8 bits (eg. a1r2g3b2) work as well
591 			Head->LinearSize = IL_MAX(1,Head->Width) * IL_MAX(1,Head->Height) *
592 				(Head->RGBBitCount / 8);
593 			break;
594 
595 		case PF_DXT1:
596 
597 		case PF_ATI1N:
598 			Head->LinearSize = ((Head->Width+3)/4) * ((Head->Height+3)/4) * 8;
599 			break;
600 
601 		case PF_DXT2:
602 		case PF_DXT3:
603 		case PF_DXT4:
604 		case PF_DXT5:
605 		case PF_3DC:
606 		case PF_RXGB:
607 			Head->LinearSize = ((Head->Width+3)/4) * ((Head->Height+3)/4) * 16;
608 			break;
609 
610 		case PF_A16B16G16R16:
611 		case PF_R16F:
612 		case PF_G16R16F:
613 		case PF_A16B16G16R16F:
614 		case PF_R32F:
615 		case PF_G32R32F:
616 		case PF_A32B32G32R32F:
617 			Head->LinearSize = IL_MAX(1,Head->Width) * IL_MAX(1,Head->Height) *
618 				iCompFormatToBpp(CompFormat);
619 			break;
620 	}
621 
622 	Head->Flags1 |= DDS_LINEARSIZE;
623 	Head->LinearSize *= Head->Depth;
624 
625 	return;
626 }
627 
628 
629 // Reads the compressed data
ReadData()630 ILboolean ReadData()
631 {
632 	ILuint	Bps;
633 	ILint	y, z;
634 	ILubyte	*Temp;
635 
636 	if (CompData) {
637 		ifree(CompData);
638 		CompData = NULL;
639 	}
640 
641 	if (Head.Flags1 & DDS_LINEARSIZE) {
642 		//Head.LinearSize = Head.LinearSize * Depth;
643 
644 		CompData = (ILubyte*)ialloc(Head.LinearSize);
645 		if (CompData == NULL) {
646 			return IL_FALSE;
647 		}
648 
649 		if (iread(CompData, 1, Head.LinearSize) != (ILuint)Head.LinearSize) {
650 			ifree(CompData);
651 			CompData = NULL;
652 			return IL_FALSE;
653 		}
654 	}
655 	else {
656 		Bps = Width * Head.RGBBitCount / 8;
657 		CompSize = Bps * Height * Depth;
658 
659 		CompData = (ILubyte*)ialloc(CompSize);
660 		if (CompData == NULL) {
661 			return IL_FALSE;
662 		}
663 
664 		Temp = CompData;
665 		for (z = 0; z < Depth; z++) {
666 			for (y = 0; y < Height; y++) {
667 				if (iread(Temp, 1, Bps) != Bps) {
668 					ifree(CompData);
669 					CompData = NULL;
670 					return IL_FALSE;
671 				}
672 				Temp += Bps;
673 			}
674 		}
675 	}
676 
677 	return IL_TRUE;
678 }
679 
680 
AllocImage(ILuint CompFormat)681 ILboolean AllocImage(ILuint CompFormat)
682 {
683 	ILubyte channels = 4;
684 	ILenum format = IL_RGBA;
685 
686 	switch (CompFormat)
687 	{
688 		case PF_RGB:
689 			if (!ilTexImage(Width, Height, Depth, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL))
690 				return IL_FALSE;
691 			break;
692 		case PF_ARGB:
693 			if (!ilTexImage(Width, Height, Depth, 4, IL_RGBA, Has16BitComponents ? IL_UNSIGNED_SHORT : IL_UNSIGNED_BYTE, NULL))
694 				return IL_FALSE;
695 			break;
696 
697 		case PF_LUMINANCE:
698 			if (Head.RGBBitCount == 16 && Head.RBitMask == 0xFFFF) { //HACK
699 				if (!ilTexImage(Width, Height, Depth, 1, IL_LUMINANCE, IL_UNSIGNED_SHORT, NULL))
700 					return IL_FALSE;
701 			}
702 			else
703 				if (!ilTexImage(Width, Height, Depth, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL))
704 					return IL_FALSE;
705 			break;
706 
707 		case PF_LUMINANCE_ALPHA:
708 			if (!ilTexImage(Width, Height, Depth, 2, IL_LUMINANCE_ALPHA, IL_UNSIGNED_BYTE, NULL))
709 				return IL_FALSE;
710 			break;
711 
712 		case PF_ATI1N:
713 			//right now there's no OpenGL api to use the compressed 3dc data, so
714 			//throw it away (I don't know how DirectX works, though)?
715 			if (!ilTexImage(Width, Height, Depth, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL))
716 				return IL_FALSE;
717 			break;
718 
719 		case PF_3DC:
720 			//right now there's no OpenGL api to use the compressed 3dc data, so
721 			//throw it away (I don't know how DirectX works, though)?
722 			if (!ilTexImage(Width, Height, Depth, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL))
723 				return IL_FALSE;
724 			break;
725 
726 		case PF_A16B16G16R16:
727 			if (!ilTexImage(Width, Height, Depth, iCompFormatToChannelCount(CompFormat),
728 				ilGetFormatBpp(iCompFormatToChannelCount(CompFormat)), IL_UNSIGNED_SHORT, NULL))
729 				return IL_FALSE;
730 			break;
731 
732 		case PF_R16F:
733 		case PF_G16R16F:
734 		case PF_A16B16G16R16F:
735 		case PF_R32F:
736 		case PF_G32R32F:
737 		case PF_A32B32G32R32F:
738 			if (!ilTexImage(Width, Height, Depth, iCompFormatToChannelCount(CompFormat),
739 				ilGetFormatBpp(iCompFormatToChannelCount(CompFormat)), IL_FLOAT, NULL))
740 				return IL_FALSE;
741 			break;
742 
743 		default:
744 			if (CompFormat == PF_RXGB) {
745 				channels = 3; //normal map
746 				format = IL_RGB;
747 			}
748 
749 			if (!ilTexImage(Width, Height, Depth, channels, format, IL_UNSIGNED_BYTE, NULL))
750 				return IL_FALSE;
751 			if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE && CompData) {
752 				iCurImage->DxtcData = (ILubyte*)ialloc(Head.LinearSize);
753 				if (iCurImage->DxtcData == NULL)
754 					return IL_FALSE;
755 				iCurImage->DxtcFormat = CompFormat - PF_DXT1 + IL_DXT1;
756 				iCurImage->DxtcSize = Head.LinearSize;
757 				memcpy(iCurImage->DxtcData, CompData, iCurImage->DxtcSize);
758 			}
759 			break;
760 	}
761 
762 	Image->Origin = IL_ORIGIN_UPPER_LEFT;
763 
764 	return IL_TRUE;
765 }
766 
767 
768 /*
769  * Assumes that the global variable CompFormat stores the format of the
770  * global pointer CompData (that's the pointer to the compressed data).
771  * Decompresses this data into Image->Data, returns if it was successful.
772  * It also uses the globals Width and Height.
773  *
774  * Assumes that iCurImage has valid Width, Height, Depth, Data, SizeOfData,
775  * Bpp, Bpc, Bps, SizeOfPlane, Format and Type fields. It is more or
776  * less assumed that the image has u8 rgba data (perhaps not for float
777  * images...)
778  *
779  *
780  * @TODO: don't use globals, clean this function (and this file) up
781  */
DdsDecompress(ILuint CompFormat)782 ILboolean DdsDecompress(ILuint CompFormat)
783 {
784 	switch (CompFormat)
785 	{
786 		case PF_ARGB:
787 		case PF_RGB:
788 		case PF_LUMINANCE:
789 		case PF_LUMINANCE_ALPHA:
790 			return DecompressARGB(CompFormat);
791 
792 		case PF_DXT1:
793 			return DecompressDXT1(Image, CompData);
794 
795 		case PF_DXT2:
796 			return DecompressDXT2(Image, CompData);
797 
798 		case PF_DXT3:
799 			return DecompressDXT3(Image, CompData);
800 
801 		case PF_DXT4:
802 			return DecompressDXT4(Image, CompData);
803 
804 		case PF_DXT5:
805 			return DecompressDXT5(Image, CompData);
806 
807 		case PF_ATI1N:
808 			return DecompressAti1n();
809 
810 		case PF_3DC:
811 			return Decompress3Dc();
812 
813 		case PF_RXGB:
814 			return DecompressRXGB();
815 
816 		case PF_A16B16G16R16:
817 			memcpy(Image->Data, CompData, Image->SizeOfData);
818 			return IL_TRUE;
819 
820 		case PF_R16F:
821 		case PF_G16R16F:
822 		case PF_A16B16G16R16F:
823 		case PF_R32F:
824 		case PF_G32R32F:
825 		case PF_A32B32G32R32F:
826 			return DecompressFloat(CompFormat);
827 
828 		case PF_UNKNOWN:
829 			return IL_FALSE;
830 	}
831 
832 	return IL_FALSE;
833 }
834 
835 
ReadMipmaps(ILuint CompFormat)836 ILboolean ReadMipmaps(ILuint CompFormat)
837 {
838 	ILuint	i, CompFactor=0;
839 	ILubyte	Bpp, Channels, Bpc;
840 	ILimage	*StartImage, *TempImage;
841 	ILuint	LastLinear;
842 	ILuint	minW, minH;
843 
844 	ILboolean isCompressed = IL_FALSE;
845 
846 	Bpp = iCompFormatToBpp(CompFormat);
847 	Channels = iCompFormatToChannelCount(CompFormat);
848 	Bpc = iCompFormatToBpc(CompFormat);
849 	if (CompFormat == PF_LUMINANCE && Head.RGBBitCount == 16 && Head.RBitMask == 0xFFFF) { //HACK
850 		Bpc = 2; Bpp = 2;
851 	}
852 
853 	//This doesn't work for images which first mipmap (= the image
854 	//itself) has width or height < 4
855 	//if (Head.Flags1 & DDS_LINEARSIZE) {
856 	//	CompFactor = (Width * Height * Depth * Bpp) / Head.LinearSize;
857 	//}
858 	switch (CompFormat)
859 	{
860 		case PF_DXT1:
861 			// This is officially 6, we have 8 here because DXT1 may contain alpha.
862 			CompFactor = 8;
863 			break;
864 		case PF_DXT2:
865 		case PF_DXT3:
866 		case PF_DXT4:
867 		case PF_DXT5:
868 			CompFactor = 4;
869 			break;
870 		case PF_RXGB:
871 		case PF_3DC:
872 			// This is officially 4 for 3dc, but that's bullshit :) There's no
873 			//  alpha data in 3dc images.
874 			CompFactor = 3;
875 			break;
876 
877 		case PF_ATI1N:
878 			CompFactor = 2;
879 			break;
880 		default:
881 			CompFactor = 1;
882 	}
883 
884 	StartImage = Image;
885 
886 	if (!(Head.Flags1 & DDS_MIPMAPCOUNT) || Head.MipMapCount == 0) {
887 		//some .dds-files have their mipmap flag set,
888 		//but a mipmapcount of 0. Because mipMapCount is an uint, 0 - 1 gives
889 		//overflow - don't let this happen:
890 		Head.MipMapCount = 1;
891 	}
892 
893 	LastLinear = Head.LinearSize;
894 	for (i = 0; i < Head.MipMapCount - 1; i++) {
895 		Depth = Depth / 2;
896 		Width = Width / 2;
897 		Height = Height / 2;
898 
899 		if (Depth == 0)
900 			Depth = 1;
901 		if (Width == 0)
902 			Width = 1;
903 		if (Height == 0)
904 			Height = 1;
905 
906 		Image->Mipmaps = ilNewImage(Width, Height, Depth, Channels, Bpc);
907 		if (Image->Mipmaps == NULL)
908 			goto mip_fail;
909 		Image = Image->Mipmaps;
910 		Image->Origin = IL_ORIGIN_UPPER_LEFT;
911 
912 		if (Head.Flags1 & DDS_LINEARSIZE) {
913 			if (CompFormat == PF_R16F
914 				|| CompFormat == PF_G16R16F
915 				|| CompFormat == PF_A16B16G16R16F
916 				|| CompFormat == PF_R32F
917 				|| CompFormat == PF_G32R32F
918 				|| CompFormat == PF_A32B32G32R32F) {
919 				Head.LinearSize = Width * Height * Depth * Bpp;
920 
921 				//DevIL's format autodetection doesn't work for
922 				//float images...correct this
923 				Image->Type = IL_FLOAT;
924 				Image->Bpp = Channels;
925 			}
926 			else if (CompFormat == PF_A16B16G16R16)
927 				Head.LinearSize = Width * Height * Depth * Bpp;
928 			else if (CompFormat != PF_RGB && CompFormat != PF_ARGB
929 				&& CompFormat != PF_LUMINANCE
930 				&& CompFormat != PF_LUMINANCE_ALPHA) {
931 
932 				//compressed format
933 				minW = (((Width+3)/4))*4;
934 				minH = (((Height+3)/4))*4;
935 				Head.LinearSize = (minW * minH * Depth * Bpp) / CompFactor;
936 
937 				isCompressed = IL_TRUE;
938 			}
939 			else {
940 				//don't use Bpp to support argb images with less than 32 bits
941 				Head.LinearSize = Width * Height * Depth * (Head.RGBBitCount >> 3);
942 			}
943 		}
944 		else {
945 			Head.LinearSize >>= 1;
946 		}
947 
948 		if (!ReadData())
949 			goto mip_fail;
950 
951 		if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE && isCompressed == IL_TRUE && CompData) {
952 			Image->DxtcData = (ILubyte*)ialloc(Head.LinearSize);
953 			if (Image->DxtcData == NULL)
954 				return IL_FALSE;
955 			Image->DxtcFormat = CompFormat - PF_DXT1 + IL_DXT1;
956 			Image->DxtcSize = Head.LinearSize;
957 			memcpy(Image->DxtcData, CompData, Image->DxtcSize);
958 		}
959 
960 		if (!DdsDecompress(CompFormat))
961 			goto mip_fail;
962 	}
963 
964 	Head.LinearSize = LastLinear;
965 	Image = StartImage;
966 
967 	return IL_TRUE;
968 
969 mip_fail:
970 	Image = StartImage;
971 	StartImage = StartImage->Mipmaps;
972 	while (StartImage) {
973 		TempImage = StartImage;
974 		StartImage = StartImage->Mipmaps;
975 		ifree(TempImage);
976 	}
977 
978 	Image->Mipmaps = NULL;
979 	return IL_FALSE;
980 }
981 
982 
DxtcReadColors(const ILubyte * Data,Color8888 * Out)983 void DxtcReadColors(const ILubyte* Data, Color8888* Out)
984 {
985 	ILubyte r0, g0, b0, r1, g1, b1;
986 
987 	b0 = Data[0] & 0x1F;
988 	g0 = ((Data[0] & 0xE0) >> 5) | ((Data[1] & 0x7) << 3);
989 	r0 = (Data[1] & 0xF8) >> 3;
990 
991 	b1 = Data[2] & 0x1F;
992 	g1 = ((Data[2] & 0xE0) >> 5) | ((Data[3] & 0x7) << 3);
993 	r1 = (Data[3] & 0xF8) >> 3;
994 
995 	Out[0].r = r0 << 3 | r0 >> 2;
996 	Out[0].g = g0 << 2 | g0 >> 3;
997 	Out[0].b = b0 << 3 | b0 >> 2;
998 
999 	Out[1].r = r1 << 3 | r1 >> 2;
1000 	Out[1].g = g1 << 2 | g1 >> 3;
1001 	Out[1].b = b1 << 3 | b1 >> 2;
1002 }
1003 
1004 //@TODO: Probably not safe on Big Endian.
DxtcReadColor(ILushort Data,Color8888 * Out)1005 void DxtcReadColor(ILushort Data, Color8888* Out)
1006 {
1007 	ILubyte r, g, b;
1008 
1009 	b = Data & 0x1f;
1010 	g = (Data & 0x7E0) >> 5;
1011 	r = (Data & 0xF800) >> 11;
1012 
1013 	Out->r = r << 3 | r >> 2;
1014 	Out->g = g << 2 | g >> 3;
1015 	Out->b = b << 3 | r >> 2;
1016 }
1017 
DecompressDXT1(ILimage * lImage,ILubyte * lCompData)1018 ILboolean DecompressDXT1(ILimage *lImage, ILubyte *lCompData)
1019 {
1020 	ILuint		x, y, z, i, j, k, Select;
1021 	ILubyte		*Temp;
1022 	Color8888	colours[4], *col;
1023 	ILushort	color_0, color_1;
1024 	ILuint		bitmask, Offset;
1025 
1026 	if (!lCompData)
1027 		return IL_FALSE;
1028 
1029 	Temp = lCompData;
1030 	colours[0].a = 0xFF;
1031 	colours[1].a = 0xFF;
1032 	colours[2].a = 0xFF;
1033 	//colours[3].a = 0xFF;
1034 	for (z = 0; z < lImage->Depth; z++) {
1035 		for (y = 0; y < lImage->Height; y += 4) {
1036 			for (x = 0; x < lImage->Width; x += 4) {
1037 				color_0 = *((ILushort*)Temp);
1038 				UShort(&color_0);
1039 				color_1 = *((ILushort*)(Temp + 2));
1040 				UShort(&color_1);
1041 				DxtcReadColor(color_0, colours);
1042 				DxtcReadColor(color_1, colours + 1);
1043 				bitmask = ((ILuint*)Temp)[1];
1044 				UInt(&bitmask);
1045 				Temp += 8;
1046 
1047 				if (color_0 > color_1) {
1048 					// Four-color block: derive the other two colors.
1049 					// 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3
1050 					// These 2-bit codes correspond to the 2-bit fields
1051 					// stored in the 64-bit block.
1052 					colours[2].b = (2 * colours[0].b + colours[1].b + 1) / 3;
1053 					colours[2].g = (2 * colours[0].g + colours[1].g + 1) / 3;
1054 					colours[2].r = (2 * colours[0].r + colours[1].r + 1) / 3;
1055 					//colours[2].a = 0xFF;
1056 
1057 					colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3;
1058 					colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3;
1059 					colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3;
1060 					colours[3].a = 0xFF;
1061 				}
1062 				else {
1063 					// Three-color block: derive the other color.
1064 					// 00 = color_0,  01 = color_1,  10 = color_2,
1065 					// 11 = transparent.
1066 					// These 2-bit codes correspond to the 2-bit fields
1067 					// stored in the 64-bit block.
1068 					colours[2].b = (colours[0].b + colours[1].b) / 2;
1069 					colours[2].g = (colours[0].g + colours[1].g) / 2;
1070 					colours[2].r = (colours[0].r + colours[1].r) / 2;
1071 					//colours[2].a = 0xFF;
1072 
1073 					colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3;
1074 					colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3;
1075 					colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3;
1076 					colours[3].a = 0x00;
1077 				}
1078 
1079 				for (j = 0, k = 0; j < 4; j++) {
1080 					for (i = 0; i < 4; i++, k++) {
1081 						Select = (bitmask & (0x03 << k*2)) >> k*2;
1082 						col = &colours[Select];
1083 
1084 						if (((x + i) < lImage->Width) && ((y + j) < lImage->Height)) {
1085 							Offset = z * lImage->SizeOfPlane + (y + j) * lImage->Bps + (x + i) * lImage->Bpp;
1086 							lImage->Data[Offset + 0] = col->r;
1087 							lImage->Data[Offset + 1] = col->g;
1088 							lImage->Data[Offset + 2] = col->b;
1089 							lImage->Data[Offset + 3] = col->a;
1090 						}
1091 					}
1092 				}
1093 			}
1094 		}
1095 	}
1096 
1097 	return IL_TRUE;
1098 }
1099 
1100 
DecompressDXT2(ILimage * lImage,ILubyte * lCompData)1101 ILboolean DecompressDXT2(ILimage *lImage, ILubyte *lCompData)
1102 {
1103 	// Can do color & alpha same as dxt3, but color is pre-multiplied
1104 	//   so the result will be wrong unless corrected.
1105 	if (!DecompressDXT3(Image, CompData))
1106 		return IL_FALSE;
1107 	CorrectPreMult();
1108 
1109 	return IL_TRUE;
1110 }
1111 
1112 
DecompressDXT3(ILimage * lImage,ILubyte * lCompData)1113 ILboolean DecompressDXT3(ILimage *lImage, ILubyte *lCompData)
1114 {
1115 	ILuint		x, y, z, i, j, k, Select;
1116 	ILubyte		*Temp;
1117 	//Color565	*color_0, *color_1;
1118 	Color8888	colours[4], *col;
1119 	ILuint		bitmask, Offset;
1120 	ILushort	word;
1121 	ILubyte		*alpha;
1122 
1123 	if (!lCompData)
1124 		return IL_FALSE;
1125 
1126 	Temp = lCompData;
1127 	for (z = 0; z < lImage->Depth; z++) {
1128 		for (y = 0; y < lImage->Height; y += 4) {
1129 			for (x = 0; x < lImage->Width; x += 4) {
1130 				alpha = Temp;
1131 				Temp += 8;
1132 				DxtcReadColors(Temp, colours);
1133 				bitmask = ((ILuint*)Temp)[1];
1134 				UInt(&bitmask);
1135 				Temp += 8;
1136 
1137 				// Four-color block: derive the other two colors.
1138 				// 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3
1139 				// These 2-bit codes correspond to the 2-bit fields
1140 				// stored in the 64-bit block.
1141 				colours[2].b = (2 * colours[0].b + colours[1].b + 1) / 3;
1142 				colours[2].g = (2 * colours[0].g + colours[1].g + 1) / 3;
1143 				colours[2].r = (2 * colours[0].r + colours[1].r + 1) / 3;
1144 				//colours[2].a = 0xFF;
1145 
1146 				colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3;
1147 				colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3;
1148 				colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3;
1149 				//colours[3].a = 0xFF;
1150 
1151 				k = 0;
1152 				for (j = 0; j < 4; j++) {
1153 					for (i = 0; i < 4; i++, k++) {
1154 						Select = (bitmask & (0x03 << k*2)) >> k*2;
1155 						col = &colours[Select];
1156 
1157 						if (((x + i) < lImage->Width) && ((y + j) < lImage->Height)) {
1158 							Offset = z * lImage->SizeOfPlane + (y + j) * lImage->Bps + (x + i) * lImage->Bpp;
1159 							lImage->Data[Offset + 0] = col->r;
1160 							lImage->Data[Offset + 1] = col->g;
1161 							lImage->Data[Offset + 2] = col->b;
1162 						}
1163 					}
1164 				}
1165 
1166 				for (j = 0; j < 4; j++) {
1167 					word = alpha[2*j] + 256*alpha[2*j+1];
1168 					for (i = 0; i < 4; i++) {
1169 						if (((x + i) < lImage->Width) && ((y + j) < lImage->Height)) {
1170 							Offset = z * lImage->SizeOfPlane + (y + j) * lImage->Bps + (x + i) * lImage->Bpp + 3;
1171 							lImage->Data[Offset] = word & 0x0F;
1172 							lImage->Data[Offset] = lImage->Data[Offset] | (lImage->Data[Offset] << 4);
1173 						}
1174 						word >>= 4;
1175 					}
1176 				}
1177 
1178 			}
1179 		}
1180 	}
1181 
1182 	return IL_TRUE;
1183 }
1184 
1185 
DecompressDXT4(ILimage * lImage,ILubyte * lCompData)1186 ILboolean DecompressDXT4(ILimage *lImage, ILubyte *lCompData)
1187 {
1188 	// Can do color & alpha same as dxt5, but color is pre-multiplied
1189 	//   so the result will be wrong unless corrected.
1190 	if (!DecompressDXT5(Image, CompData))
1191 		return IL_FALSE;
1192 	CorrectPreMult();
1193 
1194 	return IL_FALSE;
1195 }
1196 
1197 
DecompressDXT5(ILimage * lImage,ILubyte * lCompData)1198 ILboolean DecompressDXT5(ILimage *lImage, ILubyte *lCompData)
1199 {
1200 	ILuint		x, y, z, i, j, k, Select;
1201 	ILubyte		*Temp; //, r0, g0, b0, r1, g1, b1;
1202 	Color8888	colours[4], *col;
1203 	ILuint		bitmask, Offset;
1204 	ILubyte		alphas[8], *alphamask;
1205 	ILuint		bits;
1206 
1207 	if (!lCompData)
1208 		return IL_FALSE;
1209 
1210 	Temp = lCompData;
1211 	for (z = 0; z < lImage->Depth; z++) {
1212 		for (y = 0; y < lImage->Height; y += 4) {
1213 			for (x = 0; x < lImage->Width; x += 4) {
1214 				if (y >= lImage->Height || x >= lImage->Width)
1215 					break;
1216 				alphas[0] = Temp[0];
1217 				alphas[1] = Temp[1];
1218 				alphamask = Temp + 2;
1219 				Temp += 8;
1220 
1221 				DxtcReadColors(Temp, colours);
1222 				bitmask = ((ILuint*)Temp)[1];
1223 				UInt(&bitmask);
1224 				Temp += 8;
1225 
1226 				// Four-color block: derive the other two colors.
1227 				// 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3
1228 				// These 2-bit codes correspond to the 2-bit fields
1229 				// stored in the 64-bit block.
1230 				colours[2].b = (2 * colours[0].b + colours[1].b + 1) / 3;
1231 				colours[2].g = (2 * colours[0].g + colours[1].g + 1) / 3;
1232 				colours[2].r = (2 * colours[0].r + colours[1].r + 1) / 3;
1233 				//colours[2].a = 0xFF;
1234 
1235 				colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3;
1236 				colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3;
1237 				colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3;
1238 				//colours[3].a = 0xFF;
1239 
1240 				k = 0;
1241 				for (j = 0; j < 4; j++) {
1242 					for (i = 0; i < 4; i++, k++) {
1243 
1244 						Select = (bitmask & (0x03 << k*2)) >> k*2;
1245 						col = &colours[Select];
1246 
1247 						// only put pixels out < width or height
1248 						if (((x + i) < lImage->Width) && ((y + j) < lImage->Height)) {
1249 							Offset = z * lImage->SizeOfPlane + (y + j) * lImage->Bps + (x + i) * lImage->Bpp;
1250 							lImage->Data[Offset + 0] = col->r;
1251 							lImage->Data[Offset + 1] = col->g;
1252 							lImage->Data[Offset + 2] = col->b;
1253 						}
1254 					}
1255 				}
1256 
1257 				// 8-alpha or 6-alpha block?
1258 				if (alphas[0] > alphas[1]) {
1259 					// 8-alpha block:  derive the other six alphas.
1260 					// Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated.
1261 					alphas[2] = (6 * alphas[0] + 1 * alphas[1] + 3) / 7;	// bit code 010
1262 					alphas[3] = (5 * alphas[0] + 2 * alphas[1] + 3) / 7;	// bit code 011
1263 					alphas[4] = (4 * alphas[0] + 3 * alphas[1] + 3) / 7;	// bit code 100
1264 					alphas[5] = (3 * alphas[0] + 4 * alphas[1] + 3) / 7;	// bit code 101
1265 					alphas[6] = (2 * alphas[0] + 5 * alphas[1] + 3) / 7;	// bit code 110
1266 					alphas[7] = (1 * alphas[0] + 6 * alphas[1] + 3) / 7;	// bit code 111
1267 				}
1268 				else {
1269 					// 6-alpha block.
1270 					// Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated.
1271 					alphas[2] = (4 * alphas[0] + 1 * alphas[1] + 2) / 5;	// Bit code 010
1272 					alphas[3] = (3 * alphas[0] + 2 * alphas[1] + 2) / 5;	// Bit code 011
1273 					alphas[4] = (2 * alphas[0] + 3 * alphas[1] + 2) / 5;	// Bit code 100
1274 					alphas[5] = (1 * alphas[0] + 4 * alphas[1] + 2) / 5;	// Bit code 101
1275 					alphas[6] = 0x00;										// Bit code 110
1276 					alphas[7] = 0xFF;										// Bit code 111
1277 				}
1278 
1279 				// Note: Have to separate the next two loops,
1280 				//	it operates on a 6-byte system.
1281 
1282 				// First three bytes
1283 				//bits = *((ILint*)alphamask);
1284 				bits = (alphamask[0]) | (alphamask[1] << 8) | (alphamask[2] << 16);
1285 				for (j = 0; j < 2; j++) {
1286 					for (i = 0; i < 4; i++) {
1287 						// only put pixels out < width or height
1288 						if (((x + i) < lImage->Width) && ((y + j) < lImage->Height)) {
1289 							Offset = z * lImage->SizeOfPlane + (y + j) * lImage->Bps + (x + i) * lImage->Bpp + 3;
1290 							lImage->Data[Offset] = alphas[bits & 0x07];
1291 						}
1292 						bits >>= 3;
1293 					}
1294 				}
1295 
1296 				// Last three bytes
1297 				//bits = *((ILint*)&alphamask[3]);
1298 				bits = (alphamask[3]) | (alphamask[4] << 8) | (alphamask[5] << 16);
1299 				for (j = 2; j < 4; j++) {
1300 					for (i = 0; i < 4; i++) {
1301 						// only put pixels out < width or height
1302 						if (((x + i) < lImage->Width) && ((y + j) < lImage->Height)) {
1303 							Offset = z * lImage->SizeOfPlane + (y + j) * lImage->Bps + (x + i) * lImage->Bpp + 3;
1304 							lImage->Data[Offset] = alphas[bits & 0x07];
1305 						}
1306 						bits >>= 3;
1307 					}
1308 				}
1309 			}
1310 		}
1311 	}
1312 
1313 	return IL_TRUE;
1314 }
1315 
1316 
Decompress3Dc()1317 ILboolean Decompress3Dc()
1318 {
1319 	int			x, y, z, i, j, k, t1, t2;
1320 	ILubyte		*Temp, *Temp2;
1321 	ILubyte		XColours[8], YColours[8];
1322 	ILuint		bitmask, bitmask2, Offset, CurrOffset;
1323 
1324 	if (!CompData)
1325 		return IL_FALSE;
1326 
1327 	Temp = CompData;
1328 	Offset = 0;
1329 	for (z = 0; z < Depth; z++) {
1330 		for (y = 0; y < Height; y += 4) {
1331 			for (x = 0; x < Width; x += 4) {
1332 				Temp2 = Temp + 8;
1333 
1334 				//Read Y palette
1335 				t1 = YColours[0] = Temp[0];
1336 				t2 = YColours[1] = Temp[1];
1337 				Temp += 2;
1338 				if (t1 > t2)
1339 					for (i = 2; i < 8; ++i)
1340 						YColours[i] = t1 + ((t2 - t1)*(i - 1))/7;
1341 				else {
1342 					for (i = 2; i < 6; ++i)
1343 						YColours[i] = t1 + ((t2 - t1)*(i - 1))/5;
1344 					YColours[6] = 0;
1345 					YColours[7] = 255;
1346 				}
1347 
1348 				// Read X palette
1349 				t1 = XColours[0] = Temp2[0];
1350 				t2 = XColours[1] = Temp2[1];
1351 				Temp2 += 2;
1352 				if (t1 > t2)
1353 					for (i = 2; i < 8; ++i)
1354 						XColours[i] = t1 + ((t2 - t1)*(i - 1))/7;
1355 				else {
1356 					for (i = 2; i < 6; ++i)
1357 						XColours[i] = t1 + ((t2 - t1)*(i - 1))/5;
1358 					XColours[6] = 0;
1359 					XColours[7] = 255;
1360 				}
1361 
1362 				//decompress pixel data
1363 				CurrOffset = Offset;
1364 				for (k = 0; k < 4; k += 2) {
1365 					// First three bytes
1366 					bitmask = ((ILuint)(Temp[0]) << 0) | ((ILuint)(Temp[1]) << 8) | ((ILuint)(Temp[2]) << 16);
1367 					bitmask2 = ((ILuint)(Temp2[0]) << 0) | ((ILuint)(Temp2[1]) << 8) | ((ILuint)(Temp2[2]) << 16);
1368 					for (j = 0; j < 2; j++) {
1369 						// only put pixels out < height
1370 						if ((y + k + j) < Height) {
1371 							for (i = 0; i < 4; i++) {
1372 								// only put pixels out < width
1373 								if (((x + i) < Width)) {
1374 									ILint t, tx, ty;
1375 
1376 									t1 = CurrOffset + (x + i)*3;
1377 									Image->Data[t1 + 1] = ty = YColours[bitmask & 0x07];
1378 									Image->Data[t1 + 0] = tx = XColours[bitmask2 & 0x07];
1379 
1380 									//calculate b (z) component ((r/255)^2 + (g/255)^2 + (b/255)^2 = 1
1381 									t = 127*128 - (tx - 127)*(tx - 128) - (ty - 127)*(ty - 128);
1382 									if (t > 0)
1383 										Image->Data[t1 + 2] = (ILubyte)(iSqrt(t) + 128);
1384 									else
1385 										Image->Data[t1 + 2] = 0x7F;
1386 								}
1387 								bitmask >>= 3;
1388 								bitmask2 >>= 3;
1389 							}
1390 							CurrOffset += Image->Bps;
1391 						}
1392 					}
1393 					Temp += 3;
1394 					Temp2 += 3;
1395 				}
1396 
1397 				//skip bytes that were read via Temp2
1398 				Temp += 8;
1399 			}
1400 			Offset += Image->Bps*4;
1401 		}
1402 	}
1403 
1404 	return IL_TRUE;
1405 }
1406 
1407 
DecompressAti1n()1408 ILboolean DecompressAti1n()
1409 {
1410 	int			x, y, z, i, j, k, t1, t2;
1411 	ILubyte		*Temp;
1412 	ILubyte		Colours[8];
1413 	ILuint		bitmask, Offset, CurrOffset;
1414 
1415 	if (!CompData)
1416 		return IL_FALSE;
1417 
1418 	Temp = CompData;
1419 	Offset = 0;
1420 	for (z = 0; z < Depth; z++) {
1421 		for (y = 0; y < Height; y += 4) {
1422 			for (x = 0; x < Width; x += 4) {
1423 				//Read palette
1424 				t1 = Colours[0] = Temp[0];
1425 				t2 = Colours[1] = Temp[1];
1426 				Temp += 2;
1427 				if (t1 > t2)
1428 					for (i = 2; i < 8; ++i)
1429 						Colours[i] = t1 + ((t2 - t1)*(i - 1))/7;
1430 				else {
1431 					for (i = 2; i < 6; ++i)
1432 						Colours[i] = t1 + ((t2 - t1)*(i - 1))/5;
1433 					Colours[6] = 0;
1434 					Colours[7] = 255;
1435 				}
1436 
1437 				//decompress pixel data
1438 				CurrOffset = Offset;
1439 				for (k = 0; k < 4; k += 2) {
1440 					// First three bytes
1441 					bitmask = ((ILuint)(Temp[0]) << 0) | ((ILuint)(Temp[1]) << 8) | ((ILuint)(Temp[2]) << 16);
1442 					for (j = 0; j < 2; j++) {
1443 						// only put pixels out < height
1444 						if ((y + k + j) < Height) {
1445 							for (i = 0; i < 4; i++) {
1446 								// only put pixels out < width
1447 								if (((x + i) < Width)) {
1448 									t1 = CurrOffset + (x + i);
1449 									Image->Data[t1] = Colours[bitmask & 0x07];
1450 								}
1451 								bitmask >>= 3;
1452 							}
1453 							CurrOffset += Image->Bps;
1454 						}
1455 					}
1456 					Temp += 3;
1457 				}
1458 			}
1459 			Offset += Image->Bps*4;
1460 		}
1461 	}
1462 
1463 	return IL_TRUE;
1464 }
1465 
1466 
1467 //This is nearly exactly the same as DecompressDXT5...
1468 //I have to clean up this file (put common code in
1469 //helper functions etc)
DecompressRXGB()1470 ILboolean DecompressRXGB()
1471 {
1472 	int			x, y, z, i, j, k, Select;
1473 	ILubyte		*Temp;
1474 	Color565	*color_0, *color_1;
1475 	Color8888	colours[4], *col;
1476 	ILuint		bitmask, Offset;
1477 	ILubyte		alphas[8], *alphamask;
1478 	ILuint		bits;
1479 
1480 	if (!CompData)
1481 		return IL_FALSE;
1482 
1483 	Temp = CompData;
1484 	for (z = 0; z < Depth; z++) {
1485 		for (y = 0; y < Height; y += 4) {
1486 			for (x = 0; x < Width; x += 4) {
1487 				if (y >= Height || x >= Width)
1488 					break;
1489 				alphas[0] = Temp[0];
1490 				alphas[1] = Temp[1];
1491 				alphamask = Temp + 2;
1492 				Temp += 8;
1493 				color_0 = ((Color565*)Temp);
1494 				color_1 = ((Color565*)(Temp+2));
1495 				bitmask = ((ILuint*)Temp)[1];
1496 				Temp += 8;
1497 
1498 				colours[0].r = color_0->nRed << 3;
1499 				colours[0].g = color_0->nGreen << 2;
1500 				colours[0].b = color_0->nBlue << 3;
1501 				colours[0].a = 0xFF;
1502 
1503 				colours[1].r = color_1->nRed << 3;
1504 				colours[1].g = color_1->nGreen << 2;
1505 				colours[1].b = color_1->nBlue << 3;
1506 				colours[1].a = 0xFF;
1507 
1508 				// Four-color block: derive the other two colors.
1509 				// 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3
1510 				// These 2-bit codes correspond to the 2-bit fields
1511 				// stored in the 64-bit block.
1512 				colours[2].b = (2 * colours[0].b + colours[1].b + 1) / 3;
1513 				colours[2].g = (2 * colours[0].g + colours[1].g + 1) / 3;
1514 				colours[2].r = (2 * colours[0].r + colours[1].r + 1) / 3;
1515 				colours[2].a = 0xFF;
1516 
1517 				colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3;
1518 				colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3;
1519 				colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3;
1520 				colours[3].a = 0xFF;
1521 
1522 				k = 0;
1523 				for (j = 0; j < 4; j++) {
1524 					for (i = 0; i < 4; i++, k++) {
1525 
1526 						Select = (bitmask & (0x03 << k*2)) >> k*2;
1527 						col = &colours[Select];
1528 
1529 						// only put pixels out < width or height
1530 						if (((x + i) < Width) && ((y + j) < Height)) {
1531 							Offset = z * Image->SizeOfPlane + (y + j) * Image->Bps + (x + i) * Image->Bpp;
1532 							Image->Data[Offset + 0] = col->r;
1533 							Image->Data[Offset + 1] = col->g;
1534 							Image->Data[Offset + 2] = col->b;
1535 						}
1536 					}
1537 				}
1538 
1539 				// 8-alpha or 6-alpha block?
1540 				if (alphas[0] > alphas[1]) {
1541 					// 8-alpha block:  derive the other six alphas.
1542 					// Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated.
1543 					alphas[2] = (6 * alphas[0] + 1 * alphas[1] + 3) / 7;	// bit code 010
1544 					alphas[3] = (5 * alphas[0] + 2 * alphas[1] + 3) / 7;	// bit code 011
1545 					alphas[4] = (4 * alphas[0] + 3 * alphas[1] + 3) / 7;	// bit code 100
1546 					alphas[5] = (3 * alphas[0] + 4 * alphas[1] + 3) / 7;	// bit code 101
1547 					alphas[6] = (2 * alphas[0] + 5 * alphas[1] + 3) / 7;	// bit code 110
1548 					alphas[7] = (1 * alphas[0] + 6 * alphas[1] + 3) / 7;	// bit code 111
1549 				}
1550 				else {
1551 					// 6-alpha block.
1552 					// Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated.
1553 					alphas[2] = (4 * alphas[0] + 1 * alphas[1] + 2) / 5;	// Bit code 010
1554 					alphas[3] = (3 * alphas[0] + 2 * alphas[1] + 2) / 5;	// Bit code 011
1555 					alphas[4] = (2 * alphas[0] + 3 * alphas[1] + 2) / 5;	// Bit code 100
1556 					alphas[5] = (1 * alphas[0] + 4 * alphas[1] + 2) / 5;	// Bit code 101
1557 					alphas[6] = 0x00;										// Bit code 110
1558 					alphas[7] = 0xFF;										// Bit code 111
1559 				}
1560 
1561 				// Note: Have to separate the next two loops,
1562 				//	it operates on a 6-byte system.
1563 				// First three bytes
1564 				bits = *((ILint*)alphamask);
1565 				for (j = 0; j < 2; j++) {
1566 					for (i = 0; i < 4; i++) {
1567 						// only put pixels out < width or height
1568 						if (((x + i) < Width) && ((y + j) < Height)) {
1569 							Offset = z * Image->SizeOfPlane + (y + j) * Image->Bps + (x + i) * Image->Bpp + 0;
1570 							Image->Data[Offset] = alphas[bits & 0x07];
1571 						}
1572 						bits >>= 3;
1573 					}
1574 				}
1575 
1576 				// Last three bytes
1577 				bits = *((ILint*)&alphamask[3]);
1578 				for (j = 2; j < 4; j++) {
1579 					for (i = 0; i < 4; i++) {
1580 						// only put pixels out < width or height
1581 						if (((x + i) < Width) && ((y + j) < Height)) {
1582 							Offset = z * Image->SizeOfPlane + (y + j) * Image->Bps + (x + i) * Image->Bpp + 0;
1583 							Image->Data[Offset] = alphas[bits & 0x07];
1584 						}
1585 						bits >>= 3;
1586 					}
1587 				}
1588 			}
1589 		}
1590 	}
1591 
1592 	return IL_TRUE;
1593 }
1594 
1595 
1596 //Taken from OpenEXR
1597 unsigned int
halfToFloat(unsigned short y)1598 halfToFloat (unsigned short y)
1599 {
1600 	int s = (y >> 15) & 0x00000001;
1601 	int e = (y >> 10) & 0x0000001f;
1602 	int m =  y		  & 0x000003ff;
1603 
1604 	if (e == 0)
1605 	{
1606 		if (m == 0)
1607 		{
1608 			//
1609 			// Plus or minus zero
1610 			//
1611 			return s << 31;
1612 		}
1613 		else
1614 		{
1615 			//
1616 			// Denormalized number -- renormalize it
1617 			//
1618 			while (!(m & 0x00000400))
1619 			{
1620 				m <<= 1;
1621 				e -=  1;
1622 			}
1623 
1624 			e += 1;
1625 			m &= ~0x00000400;
1626 		}
1627 	}
1628 	else if (e == 31)
1629 	{
1630 		if (m == 0)
1631 		{
1632 			//
1633 			// Positive or negative infinity
1634 			//
1635 			return (s << 31) | 0x7f800000;
1636 		}
1637 		else
1638 		{
1639 			//
1640 			// Nan -- preserve sign and significand bits
1641 			//
1642 			return (s << 31) | 0x7f800000 | (m << 13);
1643 		}
1644 	}
1645 
1646 	//
1647 	// Normalized number
1648 	//
1649 	e = e + (127 - 15);
1650 	m = m << 13;
1651 
1652 	//
1653 	// Assemble s, e and m.
1654 	//
1655 	return (s << 31) | (e << 23) | m;
1656 }
1657 
1658 
iConvFloat16ToFloat32(ILuint * dest,ILushort * src,ILuint size)1659 ILboolean iConvFloat16ToFloat32(ILuint* dest, ILushort* src, ILuint size)
1660 {
1661 	ILuint i;
1662 	for (i = 0; i < size; ++i, ++dest, ++src) {
1663 		//float: 1 sign bit, 8 exponent bits, 23 mantissa bits
1664 		//half: 1 sign bit, 5 exponent bits, 10 mantissa bits
1665 		*dest = halfToFloat(*src);
1666 	}
1667 
1668 	return IL_TRUE;
1669 }
1670 
1671 
1672 // Same as iConvFloat16ToFloat32, but we have to set the blue channel to 1.0f.
1673 //  The destination format is RGB, and the source is R16G16 (little endian).
iConvG16R16ToFloat32(ILuint * dest,ILushort * src,ILuint size)1674 ILboolean iConvG16R16ToFloat32(ILuint* dest, ILushort* src, ILuint size)
1675 {
1676 	ILuint i;
1677 	for (i = 0; i < size; i += 3) {
1678 		//float: 1 sign bit, 8 exponent bits, 23 mantissa bits
1679 		//half: 1 sign bit, 5 exponent bits, 10 mantissa bits
1680 		*dest++ = halfToFloat(*src++);
1681 		*dest++ = halfToFloat(*src++);
1682 		*((ILfloat*)dest++) = 1.0f;
1683 	}
1684 
1685 	return IL_TRUE;
1686 }
1687 
1688 
1689 // Same as iConvFloat16ToFloat32, but we have to set the green and blue channels
1690 //  to 1.0f.  The destination format is RGB, and the source is R16.
iConvR16ToFloat32(ILuint * dest,ILushort * src,ILuint size)1691 ILboolean iConvR16ToFloat32(ILuint* dest, ILushort* src, ILuint size)
1692 {
1693 	ILuint i;
1694 	for (i = 0; i < size; i += 3) {
1695 		//float: 1 sign bit, 8 exponent bits, 23 mantissa bits
1696 		//half: 1 sign bit, 5 exponent bits, 10 mantissa bits
1697 		*dest++ = halfToFloat(*src++);
1698 		*((ILfloat*)dest++) = 1.0f;
1699 		*((ILfloat*)dest++) = 1.0f;
1700 	}
1701 
1702 	return IL_TRUE;
1703 }
1704 
1705 
DecompressFloat(ILuint lCompFormat)1706 ILboolean DecompressFloat(ILuint lCompFormat)
1707 {
1708 	ILuint i, j, Size;
1709 
1710 	switch (lCompFormat)
1711 	{
1712 		case PF_R32F:  // Red float, green = blue = max
1713 			Size = Image->Width * Image->Height * Image->Depth * 3;
1714 			for (i = 0, j = 0; i < Size; i += 3, j++) {
1715 				((ILfloat*)Image->Data)[i] = ((ILfloat*)CompData)[j];
1716 				((ILfloat*)Image->Data)[i+1] = 1.0f;
1717 				((ILfloat*)Image->Data)[i+2] = 1.0f;
1718 			}
1719 			return IL_TRUE;
1720 		case PF_A32B32G32R32F:  // Direct copy of float RGBA data
1721 			memcpy(Image->Data, CompData, Image->SizeOfData);
1722 			return IL_TRUE;
1723 		case PF_G32R32F:  // Red float, green float, blue = max
1724 			Size = Image->Width * Image->Height * Image->Depth * 3;
1725 			for (i = 0, j = 0; i < Size; i += 3, j += 2) {
1726 				((ILfloat*)Image->Data)[i] = ((ILfloat*)CompData)[j];
1727 				((ILfloat*)Image->Data)[i+1] = ((ILfloat*)CompData)[j+1];
1728 				((ILfloat*)Image->Data)[i+2] = 1.0f;
1729 			}
1730 			return IL_TRUE;
1731 		case PF_R16F:  // Red float, green = blue = max
1732 			return iConvR16ToFloat32((ILuint*)Image->Data, (ILushort*)CompData,
1733 				Image->Width * Image->Height * Image->Depth * Image->Bpp);
1734 		case PF_A16B16G16R16F:  // Just convert from half to float.
1735 			return iConvFloat16ToFloat32((ILuint*)Image->Data, (ILushort*)CompData,
1736 				Image->Width * Image->Height * Image->Depth * Image->Bpp);
1737 		case PF_G16R16F:  // Convert from half to float, set blue = max.
1738 			return iConvG16R16ToFloat32((ILuint*)Image->Data, (ILushort*)CompData,
1739 				Image->Width * Image->Height * Image->Depth * Image->Bpp);
1740 		default:
1741 			return IL_FALSE;
1742 	}
1743 }
1744 
1745 
CorrectPreMult()1746 void CorrectPreMult()
1747 {
1748 	ILuint i;
1749 
1750 	for (i = 0; i < Image->SizeOfData; i += 4) {
1751 		if (Image->Data[i+3] != 0) {  // Cannot divide by 0.
1752 			Image->Data[i]   = (ILubyte)(((ILuint)Image->Data[i]   << 8) / Image->Data[i+3]);
1753 			Image->Data[i+1] = (ILubyte)(((ILuint)Image->Data[i+1] << 8) / Image->Data[i+3]);
1754 			Image->Data[i+2] = (ILubyte)(((ILuint)Image->Data[i+2] << 8) / Image->Data[i+3]);
1755 		}
1756 	}
1757 
1758 	return;
1759 }
1760 
1761 
DecompressARGB(ILuint CompFormat)1762 ILboolean DecompressARGB(ILuint CompFormat)
1763 {
1764 	ILuint ReadI = 0, TempBpp, i;
1765 	ILuint RedL, RedR;
1766 	ILuint GreenL, GreenR;
1767 	ILuint BlueL, BlueR;
1768 	ILuint AlphaL, AlphaR;
1769 	ILubyte	*Temp;
1770 
1771 	if (Has16BitComponents)
1772 		return DecompressARGB16(CompFormat);
1773 
1774 	if (!CompData)
1775 		return IL_FALSE;
1776 
1777 	if (CompFormat == PF_LUMINANCE && Head.RGBBitCount == 16 && Head.RBitMask == 0xFFFF) { //HACK
1778 		memcpy(Image->Data, CompData, Image->SizeOfData);
1779 		return IL_TRUE;
1780 	}
1781 
1782 	GetBitsFromMask(Head.RBitMask, &RedL, &RedR);
1783 	GetBitsFromMask(Head.GBitMask, &GreenL, &GreenR);
1784 	GetBitsFromMask(Head.BBitMask, &BlueL, &BlueR);
1785 	GetBitsFromMask(Head.RGBAlphaBitMask, &AlphaL, &AlphaR);
1786 	Temp = CompData;
1787 	TempBpp = Head.RGBBitCount / 8;
1788 
1789 	for (i = 0; i < Image->SizeOfData; i += Image->Bpp) {
1790 
1791 		//@TODO: This is SLOOOW...
1792 		//but the old version crashed in release build under
1793 		//winxp (and xp is right to stop this code - I always
1794 		//wondered that it worked the old way at all)
1795 		if (Image->SizeOfData - i < 4) { //less than 4 byte to write?
1796 			if (TempBpp == 3) { //this branch is extra-SLOOOW
1797 				ReadI =
1798 					*Temp
1799 					| ((*(Temp + 1)) << 8)
1800 					| ((*(Temp + 2)) << 16);
1801 			}
1802 			else if (TempBpp == 1)
1803 				ReadI = *((ILubyte*)Temp);
1804 			else if (TempBpp == 2)
1805 				ReadI = Temp[0] | (Temp[1] << 8);
1806 		}
1807 		else
1808 			ReadI = Temp[0] | (Temp[1] << 8) | (Temp[2] << 16) | (Temp[3] << 24);
1809 		Temp += TempBpp;
1810 
1811 		Image->Data[i] = ((ReadI & Head.RBitMask) >> RedR) << RedL;
1812 
1813 		if (Image->Bpp >= 3) {
1814 			Image->Data[i+1] = ((ReadI & Head.GBitMask) >> GreenR) << GreenL;
1815 			Image->Data[i+2] = ((ReadI & Head.BBitMask) >> BlueR) << BlueL;
1816 
1817 			if (Image->Bpp == 4) {
1818 				Image->Data[i+3] = ((ReadI & Head.RGBAlphaBitMask) >> AlphaR) << AlphaL;
1819 				if (AlphaL >= 7) {
1820 					Image->Data[i+3] = Image->Data[i+3] ? 0xFF : 0x00;
1821 				}
1822 				else if (AlphaL >= 4) {
1823 					Image->Data[i+3] = Image->Data[i+3] | (Image->Data[i+3] >> 4);
1824 				}
1825 			}
1826 		}
1827 		else if (Image->Bpp == 2) {
1828 			Image->Data[i+1] = ((ReadI & Head.RGBAlphaBitMask) >> AlphaR) << AlphaL;
1829 			if (AlphaL >= 7) {
1830 				Image->Data[i+1] = Image->Data[i+1] ? 0xFF : 0x00;
1831 			}
1832 			else if (AlphaL >= 4) {
1833 				Image->Data[i+1] = Image->Data[i+1] | (Image->Data[i+3] >> 4);
1834 			}
1835 		}
1836 	}
1837 
1838 	return IL_TRUE;
1839 }
1840 
1841 
1842 // This function simply counts how many contiguous bits are in the mask.
CountBitsFromMask(ILuint Mask)1843 ILuint CountBitsFromMask(ILuint Mask)
1844 {
1845 	ILuint		i, TestBit = 0x01, Count = 0;
1846 	ILboolean	FoundBit = IL_FALSE;
1847 
1848 	for (i = 0; i < 32; i++, TestBit <<= 1) {
1849 		if (Mask & TestBit) {
1850 			if (!FoundBit)
1851 				FoundBit = IL_TRUE;
1852 			Count++;
1853 		}
1854 		else if (FoundBit)
1855 			return Count;
1856 	}
1857 
1858 	return Count;
1859 }
1860 
1861 
1862 // Same as DecompressARGB, but it works on images with more than 8 bits
1863 //  per channel, such as a2r10g10b10 and a2b10g10r10.
DecompressARGB16(ILuint CompFormat)1864 ILboolean DecompressARGB16(ILuint CompFormat)
1865 {
1866 	ILuint ReadI = 0, TempBpp, i;
1867 	ILuint RedL, RedR;
1868 	ILuint GreenL, GreenR;
1869 	ILuint BlueL, BlueR;
1870 	ILuint AlphaL, AlphaR;
1871 	ILuint RedPad, GreenPad, BluePad, AlphaPad;
1872 	ILubyte	*Temp;
1873 
1874 	if (!CompData)
1875 		return IL_FALSE;
1876 
1877 	GetBitsFromMask(Head.RBitMask, &RedL, &RedR);
1878 	GetBitsFromMask(Head.GBitMask, &GreenL, &GreenR);
1879 	GetBitsFromMask(Head.BBitMask, &BlueL, &BlueR);
1880 	GetBitsFromMask(Head.RGBAlphaBitMask, &AlphaL, &AlphaR);
1881 	RedPad   = 16 - CountBitsFromMask(Head.RBitMask);
1882 	GreenPad = 16 - CountBitsFromMask(Head.GBitMask);
1883 	BluePad  = 16 - CountBitsFromMask(Head.BBitMask);
1884 	AlphaPad = 16 - CountBitsFromMask(Head.RGBAlphaBitMask);
1885 
1886 	RedL = RedL + RedPad;
1887 	GreenL = GreenL + GreenPad;
1888 	BlueL = BlueL + BluePad;
1889 	AlphaL = AlphaL + AlphaPad;
1890 
1891 	Temp = CompData;
1892 	TempBpp = Head.RGBBitCount / 8;
1893 
1894 	for (i = 0; i < Image->SizeOfData / 2; i += Image->Bpp) {
1895 
1896 		//@TODO: This is SLOOOW...
1897 		//but the old version crashed in release build under
1898 		//winxp (and xp is right to stop this code - I always
1899 		//wondered that it worked the old way at all)
1900 		if (Image->SizeOfData - i < 4) { //less than 4 byte to write?
1901 			if (TempBpp == 3) { //this branch is extra-SLOOOW
1902 				ReadI =
1903 					*Temp
1904 					| ((*(Temp + 1)) << 8)
1905 					| ((*(Temp + 2)) << 16);
1906 			}
1907 			else if (TempBpp == 1)
1908 				ReadI = *((ILubyte*)Temp);
1909 			else if (TempBpp == 2)
1910 				ReadI = Temp[0] | (Temp[1] << 8);
1911 		}
1912 		else
1913 			ReadI = Temp[0] | (Temp[1] << 8) | (Temp[2] << 16) | (Temp[3] << 24);
1914 		Temp += TempBpp;
1915 
1916 		((ILushort*)Image->Data)[i+2] = ((ReadI & Head.RBitMask) >> RedR) << RedL;
1917 
1918 		if (Image->Bpp >= 3) {
1919 			((ILushort*)Image->Data)[i+1] = ((ReadI & Head.GBitMask) >> GreenR) << GreenL;
1920 			((ILushort*)Image->Data)[i] = ((ReadI & Head.BBitMask) >> BlueR) << BlueL;
1921 
1922 			if (Image->Bpp == 4) {
1923 				((ILushort*)Image->Data)[i+3] = ((ReadI & Head.RGBAlphaBitMask) >> AlphaR) << AlphaL;
1924 				if (AlphaL >= 7) {
1925 					((ILushort*)Image->Data)[i+3] = ((ILushort*)Image->Data)[i+3] ? 0xFF : 0x00;
1926 				}
1927 				else if (AlphaL >= 4) {
1928 					((ILushort*)Image->Data)[i+3] = ((ILushort*)Image->Data)[i+3] | (((ILushort*)Image->Data)[i+3] >> 4);
1929 				}
1930 			}
1931 		}
1932 		else if (Image->Bpp == 2) {
1933 			((ILushort*)Image->Data)[i+1] = ((ReadI & Head.RGBAlphaBitMask) >> AlphaR) << AlphaL;
1934 			if (AlphaL >= 7) {
1935 				((ILushort*)Image->Data)[i+1] = ((ILushort*)Image->Data)[i+1] ? 0xFF : 0x00;
1936 			}
1937 			else if (AlphaL >= 4) {
1938 				((ILushort*)Image->Data)[i+1] = ((ILushort*)Image->Data)[i+1] | (Image->Data[i+3] >> 4);
1939 			}
1940 		}
1941 	}
1942 
1943 	return IL_TRUE;
1944 }
1945 
1946 
1947 // @TODO:  Look at using the BSF/BSR operands for inline ASM here.
GetBitsFromMask(ILuint Mask,ILuint * ShiftLeft,ILuint * ShiftRight)1948 void GetBitsFromMask(ILuint Mask, ILuint *ShiftLeft, ILuint *ShiftRight)
1949 {
1950 	ILuint Temp, i;
1951 
1952 	if (Mask == 0) {
1953 		*ShiftLeft = *ShiftRight = 0;
1954 		return;
1955 	}
1956 
1957 	Temp = Mask;
1958 	for (i = 0; i < 32; i++, Temp >>= 1) {
1959 		if (Temp & 1)
1960 			break;
1961 	}
1962 	*ShiftRight = i;
1963 
1964 	// Temp is preserved, so use it again:
1965 	for (i = 0; i < 8; i++, Temp >>= 1) {
1966 		if (!(Temp & 1))
1967 			break;
1968 	}
1969 	*ShiftLeft = 8 - i;
1970 
1971 	return;
1972 }
1973 
1974 
1975 //
1976 //
1977 // DXT extension code
1978 //
1979 //
ilGetDxtcData()1980 ILubyte* ILAPIENTRY ilGetDxtcData()
1981 {
1982 	if (iCurImage == NULL) {
1983 		ilSetError(IL_INTERNAL_ERROR);
1984 		return NULL;
1985 	}
1986 	return iCurImage->DxtcData;
1987 }
1988 
ilFreeSurfaceDxtcData()1989 void ilFreeSurfaceDxtcData()
1990 {
1991 	if (iCurImage != NULL && iCurImage->DxtcData != NULL) {
1992 		ifree(iCurImage->DxtcData);
1993 		iCurImage->DxtcData = NULL;
1994 		iCurImage->DxtcSize = 0;
1995 		iCurImage->DxtcFormat = IL_DXT_NO_COMP;
1996 	}
1997 }
1998 
ilFreeImageDxtcData()1999 void ilFreeImageDxtcData()
2000 {
2001 	ILint i, j;
2002 	ILuint ImgID = ilGetInteger(IL_CUR_IMAGE);
2003 	ILint ImgCount = ilGetInteger(IL_NUM_IMAGES);
2004 	ILint MipCount;
2005 
2006 	for(i = 0; i <= ImgCount; ++i) {
2007 		ilBindImage(ImgID);
2008 		ilActiveImage(i);
2009 
2010 		MipCount = ilGetInteger(IL_NUM_MIPMAPS);
2011 		for(j = 0; j <= MipCount; ++j) {
2012 			ilBindImage(ImgID);
2013 			ilActiveImage(i);
2014 			ilActiveMipmap(j);
2015 
2016 			ilFreeSurfaceDxtcData();
2017 		}
2018 	}
2019 }
2020 
2021 /*
2022  * This assumes DxtcData, DxtcFormat, width, height, and depth are valid
2023  */
ilDxtcDataToSurface()2024 ILAPI ILboolean ILAPIENTRY ilDxtcDataToSurface()
2025 {
2026 	ILuint CompFormat;
2027 
2028 	if (iCurImage == NULL || iCurImage->DxtcData == NULL) {
2029 		ilSetError(IL_INVALID_PARAM);
2030 		return IL_FALSE;
2031 	}
2032 
2033 	if (!(iCurImage->DxtcFormat == IL_DXT1 || iCurImage->DxtcFormat == IL_DXT3
2034 		|| iCurImage->DxtcFormat == IL_DXT5)) {
2035 		ilSetError(IL_INVALID_PARAM); //TODO
2036 		return IL_FALSE;
2037 	}
2038 
2039 	//@TODO: is this right for all dxt formats? works for
2040 	//  DXT1, 3, 5
2041 	iCurImage->Bpp = 4;
2042 	iCurImage->Bpc = 1;
2043 	iCurImage->Bps = iCurImage->Width*iCurImage->Bpp*iCurImage->Bpc;
2044 	iCurImage->SizeOfPlane = iCurImage->Height*iCurImage->Bps;
2045 	iCurImage->Format = IL_RGBA;
2046 	iCurImage->Type = IL_UNSIGNED_BYTE;
2047 
2048 	if (iCurImage->SizeOfData != iCurImage->SizeOfPlane*iCurImage->Depth) {
2049 		iCurImage->SizeOfData = iCurImage->Depth*iCurImage->SizeOfPlane;
2050 		if (iCurImage->Data != NULL)
2051 			ifree(iCurImage->Data);
2052 		iCurImage->Data = NULL;
2053 	}
2054 
2055 	if (iCurImage->Data == NULL) {
2056 		iCurImage->Data = ialloc(iCurImage->SizeOfData);
2057 	}
2058 
2059 	Image = iCurImage;
2060 	Width = iCurImage->Width;
2061 	Height = iCurImage->Height;
2062 	Depth = iCurImage->Depth;
2063 	switch(iCurImage->DxtcFormat)
2064 	{
2065 		case IL_DXT1: CompFormat = PF_DXT1; break;
2066 		case IL_DXT3: CompFormat = PF_DXT3; break;
2067 		case IL_DXT5: CompFormat = PF_DXT5; break;
2068 	}
2069 	CompData = iCurImage->DxtcData;
2070 	DdsDecompress(CompFormat); //globals suck...fix this
2071 
2072 	//@TODO: origin should be set in Decompress()...
2073 	iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
2074 	return ilFixCur();
2075 }
2076 
2077 
ilDxtcDataToImage()2078 ILAPI ILboolean ILAPIENTRY ilDxtcDataToImage()
2079 {
2080 	ILint i, j;
2081 	ILuint ImgID = ilGetInteger(IL_CUR_IMAGE);
2082 	ILint ImgCount = ilGetInteger(IL_NUM_IMAGES);
2083 	ILint MipCount;
2084 	ILboolean ret = IL_TRUE;
2085 
2086 	for(i = 0; i <= ImgCount; ++i) {
2087 		ilBindImage(ImgID);
2088 		ilActiveImage(i);
2089 
2090 		MipCount = ilGetInteger(IL_NUM_MIPMAPS);
2091 		for(j = 0; j <= MipCount; ++j) {
2092 			ilBindImage(ImgID);
2093 			ilActiveImage(i);
2094 			ilActiveMipmap(j);
2095 
2096 			if (!ilDxtcDataToSurface())
2097 				ret = IL_FALSE;
2098 		}
2099 	}
2100     ilBindImage(ImgID);
2101 
2102 	return ret;
2103 }
2104 
2105 
ilSurfaceToDxtcData(ILenum Format)2106 ILAPI ILboolean ILAPIENTRY ilSurfaceToDxtcData(ILenum Format)
2107 {
2108 	ILuint Size;
2109 	void* Data;
2110 	ilFreeSurfaceDxtcData();
2111 
2112 	Size = ilGetDXTCData(NULL, 0, Format);
2113 	if (Size == 0) {
2114 		return IL_FALSE;
2115 	}
2116 
2117 	Data = ialloc(Size);
2118 
2119 	if (Data == NULL)
2120 		return IL_FALSE;
2121 
2122 	ilGetDXTCData(Data, Size, Format);
2123 
2124 	//These have to be after the call to ilGetDXTCData()
2125 	iCurImage->DxtcData = Data;
2126 	iCurImage->DxtcFormat = Format;
2127 	iCurImage->DxtcSize = Size;
2128 
2129 	return IL_TRUE;
2130 }
2131 
2132 
ilImageToDxtcData(ILenum Format)2133 ILAPI ILboolean ILAPIENTRY ilImageToDxtcData(ILenum Format)
2134 {
2135 	ILint i, j;
2136 	ILuint ImgID = ilGetInteger(IL_CUR_IMAGE);
2137 	ILint ImgCount = ilGetInteger(IL_NUM_IMAGES);
2138 	ILint MipCount;
2139 	ILboolean ret = IL_TRUE;
2140 
2141 	for (i = 0; i <= ImgCount; ++i) {
2142 		ilBindImage(ImgID);
2143 		ilActiveImage(i);
2144 
2145 		MipCount = ilGetInteger(IL_NUM_MIPMAPS);
2146 		for(j = 0; j <= MipCount; ++j) {
2147 			ilBindImage(ImgID);
2148 			ilActiveImage(i);
2149 			ilActiveMipmap(j);
2150 
2151 			if (!ilSurfaceToDxtcData(Format))
2152 				ret = IL_FALSE;
2153 		}
2154 	}
2155 
2156 	return ret;
2157 }
2158 
2159 
2160 //works like ilTexImage(), ie. destroys mipmaps etc (which sucks, but
2161 //is consistent. There should be a ilTexSurface() and ilTexSurfaceDxtc()
2162 //functions as well, but for now this is sufficient)
ilTexImageDxtc(ILint w,ILint h,ILint d,ILenum DxtFormat,const ILubyte * data)2163 ILAPI ILboolean ILAPIENTRY ilTexImageDxtc(ILint w, ILint h, ILint d, ILenum DxtFormat, const ILubyte* data)
2164 {
2165 	ILimage* Image = iCurImage;
2166 
2167 	ILint xBlocks, yBlocks, BlockSize, LineSize, DataSize;
2168 
2169 
2170 	//The next few lines are copied from ilTexImage() and ilInitImage() -
2171 	//should be factored in more reusable functions...
2172 	if (Image == NULL) {
2173 		ilSetError(IL_ILLEGAL_OPERATION);
2174 		return IL_FALSE;
2175 	}
2176 
2177 	////
2178 
2179 	// Not sure if we should be getting rid of the palette...
2180 	if (Image->Pal.Palette && Image->Pal.PalSize && Image->Pal.PalType != IL_PAL_NONE) {
2181 		ifree(Image->Pal.Palette);
2182 	}
2183 
2184 	// These are set NULL later by the memset call.
2185 	ilCloseImage(Image->Mipmaps);
2186 	ilCloseImage(Image->Next);
2187 	ilCloseImage(Image->Faces);
2188 	ilCloseImage(Image->Layers);
2189 
2190 	if (Image->AnimList) ifree(Image->AnimList);
2191 	if (Image->Profile)  ifree(Image->Profile);
2192 	if (Image->DxtcData) ifree(Image->DxtcData);
2193 	if (Image->Data)	 ifree(Image->Data);
2194 
2195 
2196 	////
2197 
2198 	memset(Image, 0, sizeof(ILimage));
2199 	Image->Width	   = w;
2200 	Image->Height	   = h;
2201 	Image->Depth	   = d;
2202 
2203 	//TODO: What about origin with dxtc data?
2204 	Image->Origin	   = IL_ORIGIN_LOWER_LEFT;
2205 	Image->Pal.PalType = IL_PAL_NONE;
2206 
2207     // Allocate DXT data buffer
2208 	xBlocks = (w + 3)/4;
2209 	yBlocks = (h + 3)/4;
2210 	if (DxtFormat == IL_DXT1)
2211 		BlockSize = 8;
2212 	else
2213 		BlockSize = 16;
2214 
2215 	LineSize = xBlocks * BlockSize;
2216 
2217 	DataSize = yBlocks * LineSize * d;
2218 
2219 	Image->DxtcFormat  = DxtFormat;
2220         Image->DxtcSize = DataSize;
2221 	Image->DxtcData    = ialloc(DataSize);
2222 
2223 	if (Image->DxtcData == NULL) {
2224 		return IL_FALSE;
2225 	}
2226 
2227 	if (data != NULL)
2228 		memcpy(Image->DxtcData, data, DataSize);
2229 
2230 	return IL_TRUE;
2231 }
2232 
2233 
2234 /* ------------------------------------------------------------------- */
2235 
iFlipColorBlock(ILubyte * data)2236 void iFlipColorBlock(ILubyte *data)
2237 {
2238     ILubyte tmp;
2239 
2240     tmp = data[4];
2241     data[4] = data[7];
2242     data[7] = tmp;
2243 
2244     tmp = data[5];
2245     data[5] = data[6];
2246     data[6] = tmp;
2247 }
2248 
iFlipSimpleAlphaBlock(ILushort * data)2249 void iFlipSimpleAlphaBlock(ILushort *data)
2250 {
2251 	ILushort tmp;
2252 
2253 	tmp = data[0];
2254 	data[0] = data[3];
2255 	data[3] = tmp;
2256 
2257 	tmp = data[1];
2258 	data[1] = data[2];
2259 	data[2] = tmp;
2260 }
2261 
iComplexAlphaHelper(ILubyte * Data)2262 void iComplexAlphaHelper(ILubyte* Data)
2263 {
2264 	ILushort tmp[2];
2265 
2266 	//one 4 pixel line is 12 bit, copy each line into
2267 	//a ushort, swap them and copy back
2268 	tmp[0] = (Data[0] | (Data[1] << 8)) & 0xfff;
2269 	tmp[1] = ((Data[1] >> 4) | (Data[2] << 4)) & 0xfff;
2270 
2271 	Data[0] = (ILubyte)tmp[1];
2272 	Data[1] = (tmp[1] >> 8) | (tmp[0] << 4);
2273 	Data[2] = tmp[0] >> 4;
2274 }
2275 
iFlipComplexAlphaBlock(ILubyte * Data)2276 void iFlipComplexAlphaBlock(ILubyte *Data)
2277 {
2278 	ILubyte tmp[3];
2279 	Data += 2; //Skip 'palette'
2280 
2281 	//swap upper two rows with lower two rows
2282 	memcpy(tmp, Data, 3);
2283 	memcpy(Data, Data + 3, 3);
2284 	memcpy(Data + 3, tmp, 3);
2285 
2286 	//swap 1st with 2nd row, 3rd with 4th
2287 	iComplexAlphaHelper(Data);
2288 	iComplexAlphaHelper(Data + 3);
2289 }
2290 
iFlipDxt1(ILubyte * data,ILuint count)2291 void iFlipDxt1(ILubyte* data, ILuint count)
2292 {
2293 	ILuint i;
2294 
2295 	for (i = 0; i < count; ++i) {
2296 		iFlipColorBlock(data);
2297 		data += 8; //advance to next block
2298 	}
2299 }
2300 
iFlipDxt3(ILubyte * data,ILuint count)2301 void iFlipDxt3(ILubyte* data, ILuint count)
2302 {
2303 	ILuint i;
2304 	for (i = 0; i < count; ++i) {
2305 		iFlipSimpleAlphaBlock((ILushort*)data);
2306 		iFlipColorBlock(data + 8);
2307 		data += 16; //advance to next block
2308 	}
2309 }
2310 
iFlipDxt5(ILubyte * data,ILuint count)2311 void iFlipDxt5(ILubyte* data, ILuint count)
2312 {
2313 	ILuint i;
2314 	for (i = 0; i < count; ++i) {
2315 		iFlipComplexAlphaBlock(data);
2316 		iFlipColorBlock(data + 8);
2317 		data += 16; //advance to next block
2318 	}
2319 }
2320 
iFlip3dc(ILubyte * data,ILuint count)2321 void iFlip3dc(ILubyte* data, ILuint count)
2322 {
2323 	ILuint i;
2324 	for (i = 0; i < count; ++i) {
2325 		iFlipComplexAlphaBlock(data);
2326 		iFlipComplexAlphaBlock(data + 8);
2327 		data += 16; //advance to next block
2328 	}
2329 }
2330 
2331 
ilFlipSurfaceDxtcData()2332 ILAPI void ILAPIENTRY ilFlipSurfaceDxtcData()
2333 {
2334 	ILuint y, z;
2335 	ILuint BlockSize, LineSize;
2336 	ILubyte *Temp, *Runner, *Top, *Bottom;
2337 	ILuint numXBlocks, numYBlocks;
2338 	void (*FlipBlocks)(ILubyte* data, ILuint count);
2339 
2340 	if (iCurImage == NULL || iCurImage->DxtcData == NULL) {
2341 		ilSetError(IL_INVALID_PARAM);
2342 		return;
2343 	}
2344 
2345 	numXBlocks = (iCurImage->Width + 3)/4;
2346 	numYBlocks = (iCurImage->Height + 3)/4;
2347 
2348 	switch (iCurImage->DxtcFormat)
2349 	{
2350 		case IL_DXT1:
2351 			BlockSize = 8;
2352 			FlipBlocks = iFlipDxt1;
2353 			break;
2354 		case IL_DXT2:
2355 		case IL_DXT3:
2356 			BlockSize = 16;
2357 			FlipBlocks = iFlipDxt3;
2358 			break;
2359 		case IL_DXT4:
2360 		case IL_DXT5:
2361 		case IL_RXGB:
2362 			BlockSize = 16;
2363 			FlipBlocks = iFlipDxt5;
2364 			break;
2365 		case IL_3DC:
2366 			BlockSize = 16;
2367 			FlipBlocks = iFlip3dc;
2368 			break;
2369 		default:
2370 			ilSetError(IL_INVALID_PARAM);
2371 			return;
2372 	}
2373 
2374 	LineSize = numXBlocks * BlockSize;
2375 	Temp = ialloc(LineSize);
2376 
2377 	if (Temp == NULL)
2378 	    return;
2379 
2380 	Runner = iCurImage->DxtcData;
2381 	for (z = 0; z < iCurImage->Depth; ++z) {
2382 		Top = Runner;
2383 		Bottom = Runner + (numYBlocks - 1)*LineSize;
2384 
2385 		for (y = 0; y < numYBlocks/2; ++y) {
2386 			//swap block row
2387 			memcpy(Temp, Top, LineSize);
2388 			memcpy(Top, Bottom, LineSize);
2389 			memcpy(Bottom, Temp, LineSize);
2390 
2391 
2392 			//swap blocks
2393 			FlipBlocks(Top, numXBlocks);
2394 			FlipBlocks(Bottom, numXBlocks);
2395 
2396 			Top += LineSize;
2397 			Bottom -= LineSize;
2398 		}
2399 
2400 		//middle line
2401 		if (numYBlocks % 2 != 0)
2402 			FlipBlocks(Top, numXBlocks);
2403 
2404 		Runner += LineSize * numYBlocks;
2405 	}
2406 
2407 	ifree(Temp);
2408 }
2409 
2410 /**********************************************************************/
2411 
iInvertDxt3Alpha(ILubyte * data)2412 void iInvertDxt3Alpha(ILubyte *data)
2413 {
2414 	ILint i;
2415 
2416 	for (i = 0; i < 8; ++i) {
2417 		/*
2418 		ILubyte b, t1, t2;
2419 		b = data[i];
2420 
2421 		t1 = b & 0xf;
2422 		t1 = 15 - t1;
2423 		t2 = b >> 4;
2424 		t2 = 15 - t2;
2425 
2426 		data[i] = (t2 << 4) | t1;
2427 		*/
2428 		//simpler:
2429 		data[i] = ~data[i];
2430 	}
2431 }
2432 
iInvertDxt5Alpha(ILubyte * data)2433 void iInvertDxt5Alpha(ILubyte *data)
2434 {
2435 	ILubyte a0, a1;
2436 	ILint i, j;
2437 	const ILubyte map1[] = { 1, 0, 7, 6, 5, 4, 3, 2 };
2438 	const ILubyte map2[] = { 1, 0, 5, 4, 3, 2, 7, 6 };
2439 
2440 
2441 	a0 = data[0];
2442 	a1 = data[1];
2443 
2444 	//a0 > a1 <=> 255 - a0 < 255 - a1. Because of this,
2445 	//a1 and a2 have to be swapped, and the indices
2446 	//have to be changed as well.
2447 
2448 	//invert and swap alpha
2449 	data[0] = 255 - a1;
2450 	data[1] = 255 - a0;
2451 	data += 2;
2452 
2453 	//fix indices
2454 	for (i = 0; i < 6; i += 3) {
2455 		ILuint in = data[i] | (data[i+1] << 8) | (data[i+2] << 16);
2456 		ILuint out = 0;
2457 
2458 		for (j = 0; j < 24; j += 3) {
2459 			ILubyte b = (in >> j) & 0x7;
2460 
2461 			if (a0 > a1)
2462 				b = map1[b];
2463 			else
2464 				b = map2[b];
2465 
2466 			out |= b << j;
2467 		}
2468 
2469 		data[i] = out;
2470 		data[i+1] = out >> 8;
2471 		data[i+2] = out >> 16;
2472 	}
2473 }
2474 
2475 
ilInvertSurfaceDxtcDataAlpha()2476 ILAPI ILboolean ILAPIENTRY ilInvertSurfaceDxtcDataAlpha()
2477 {
2478 	ILint i;
2479 	ILuint BlockSize;
2480 	ILubyte *Runner;
2481 	ILint numXBlocks, numYBlocks, numBlocks;
2482 	void (*InvertAlpha)(ILubyte* data);
2483 
2484 	if (iCurImage == NULL || iCurImage->DxtcData == NULL) {
2485 		ilSetError(IL_INVALID_PARAM);
2486 		return IL_FALSE;
2487 	}
2488 
2489 	numXBlocks = (iCurImage->Width + 3)/4;
2490 	numYBlocks = (iCurImage->Height + 3)/4;
2491 	numBlocks = numXBlocks*numYBlocks*iCurImage->Depth;
2492 	BlockSize = 16;
2493 
2494 	switch (iCurImage->DxtcFormat)
2495 	{
2496 		case IL_DXT3:
2497 			InvertAlpha = iInvertDxt3Alpha;
2498 			break;
2499 		case IL_DXT5:
2500 			InvertAlpha = iInvertDxt5Alpha;
2501 			break;
2502 		default:
2503 			//DXT2/4 are not supported yet because nobody
2504 			//uses them anyway and I would have to change
2505 			//the color blocks as well...
2506 			//DXT1 is not supported because DXT1 alpha is
2507 			//seldom used and it's not easily invertable.
2508 			ilSetError(IL_INVALID_PARAM);
2509 			return IL_FALSE;
2510 	}
2511 
2512 	Runner = iCurImage->DxtcData;
2513 	for (i = 0; i < numBlocks; ++i, Runner += BlockSize) {
2514 		InvertAlpha(Runner);
2515 	}
2516 
2517 	return IL_TRUE;
2518 }
2519 
2520 
2521 
2522 
2523 #endif//IL_NO_DDS
2524