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