1 //-----------------------------------------------------------------------------
2 //
3 // ImageLib Sources
4 // Copyright (C) 2000-2009 by Denton Woods
5 // Last modified: 02/14/2009
6 //
7 // Filename: src-IL/src/il_blp.c
8 //
9 // Description: Reads from a Blizzard Texture (.blp).
10 //                Specifications were found at http://www.wowwiki.com/BLP_files
11 //				  for BLP2 and from
12 // http://web.archive.org/web/20080117120549/magos.thejefffiles.com/War3ModelEditor/MagosBlpFormat.txt
13 //				  for BLP1.
14 //
15 //-----------------------------------------------------------------------------
16 
17 //@TODO: Add support for the BLP1 format as well.
18 
19 #include "il_internal.h"
20 #ifndef IL_NO_BLP
21 #include "il_dds.h"
22 
23 
24 typedef struct BLP1HEAD
25 {
26 	ILubyte	Sig[4];
27 	ILuint	Compression;	// Texture type: 0 = JPG, 1 = Paletted
28 	ILuint	Flags;			// #8 - Uses alpha channel (?)
29 	ILuint	Width;			// Image width in pixels
30 	ILuint	Height;			// Image height in pixels
31 	ILuint	PictureType;	// 3 - Uncompressed index list + alpha list
32 							// 4 - Uncompressed index list + alpha list
33 							// 5 - Uncompressed index list
34 	ILuint	PictureSubType;	// 1 - ???
35 	ILuint	MipOffsets[16]; // The file offsets of each mipmap, 0 for unused
36 	ILuint	MipLengths[16]; // The length of each mipmap data block
37 } BLP1HEAD;
38 
39 typedef struct BLP2HEAD
40 {
41 	ILubyte	Sig[4];         // "BLP2" signature
42 	ILuint	Type;           // Texture type: 0 = JPG, 1 = DXTC
43 	ILubyte	Compression;    // Compression mode: 1 = raw, 2 = DXTC
44 	ILubyte	AlphaBits;      // 0, 1, or 8
45 	ILubyte	AlphaType;      // 0, 1, 7 or 8
46 	ILubyte	HasMips;        // 0 = no mips levels, 1 = has mips (number of levels determined by image size)
47 	ILuint	Width;          // Image width in pixels
48 	ILuint	Height;         // Image height in pixels
49 	ILuint	MipOffsets[16]; // The file offsets of each mipmap, 0 for unused
50 	ILuint	MipLengths[16]; // The length of each mipmap data block
51 } BLP2HEAD;
52 
53 // Data formats
54 #define BLP_TYPE_JPG		0
55 #define BLP_TYPE_DXTC_RAW	1
56 #define BLP_RAW				1
57 #define BLP_DXTC			2
58 
59 #define BLP_RAW_PLUS_ALPHA1	3
60 #define BLP_RAW_PLUS_ALPHA2	4
61 #define BLP_RAW_NO_ALPHA	5
62 
63 
64 ILboolean iIsValidBlp2(void);
65 ILboolean iCheckBlp2(BLP2HEAD *Header);
66 ILboolean iLoadBlpInternal(void);
67 ILboolean iLoadBlp1(void);
68 ILboolean iCheckBlp1(BLP1HEAD *Header);
69 ILboolean iGetBlp1Head(BLP1HEAD *Header);
70 
71 
72 //! Checks if the file specified in FileName is a valid BLP file.
ilIsValidBlp(ILconst_string FileName)73 ILboolean ilIsValidBlp(ILconst_string FileName)
74 {
75 	ILHANDLE	BlpFile;
76 	ILboolean	bBlp = IL_FALSE;
77 
78 	if (!iCheckExtension(FileName, IL_TEXT("blp"))) {
79 		ilSetError(IL_INVALID_EXTENSION);
80 		return bBlp;
81 	}
82 
83 	BlpFile = iopenr(FileName);
84 	if (BlpFile == NULL) {
85 		ilSetError(IL_COULD_NOT_OPEN_FILE);
86 		return bBlp;
87 	}
88 
89 	bBlp = ilIsValidBlpF(BlpFile);
90 	icloser(BlpFile);
91 
92 	return bBlp;
93 }
94 
95 
96 //! Checks if the ILHANDLE contains a valid BLP file at the current position.
ilIsValidBlpF(ILHANDLE File)97 ILboolean ilIsValidBlpF(ILHANDLE File)
98 {
99 	ILuint		FirstPos;
100 	ILboolean	bRet;
101 
102 	iSetInputFile(File);
103 	FirstPos = itell();
104 	bRet = iIsValidBlp2();
105 	iseek(FirstPos, IL_SEEK_SET);
106 
107 	return bRet;
108 }
109 
110 
111 //! Checks if Lump is a valid BLP lump.
ilIsValidBlpL(const void * Lump,ILuint Size)112 ILboolean ilIsValidBlpL(const void *Lump, ILuint Size)
113 {
114 	iSetInputLump(Lump, Size);
115 	return iIsValidBlp2();
116 }
117 
118 
119 // Internal function used to get the BLP header from the current file.
iGetBlp2Head(BLP2HEAD * Header)120 ILboolean iGetBlp2Head(BLP2HEAD *Header)
121 {
122 	ILuint i;
123 
124 	iread(Header->Sig, 1, 4);
125 	Header->Type = GetLittleUInt();
126 	Header->Compression = igetc();
127 	Header->AlphaBits = igetc();
128 	Header->AlphaType = igetc();
129 	Header->HasMips = igetc();
130 	Header->Width = GetLittleUInt();
131 	Header->Height = GetLittleUInt();
132 	for (i = 0; i < 16; i++)
133 		Header->MipOffsets[i] = GetLittleUInt();
134 	for (i = 0; i < 16; i++)
135 		Header->MipLengths[i] = GetLittleUInt();
136 
137 	return IL_TRUE;
138 }
139 
140 
141 // Internal function to get the header and check it.
iIsValidBlp2(void)142 ILboolean iIsValidBlp2(void)
143 {
144 	BLP2HEAD Header;
145 
146 	if (!iGetBlp2Head(&Header))
147 		return IL_FALSE;
148 	iseek(-148, IL_SEEK_CUR);
149 
150 	return iCheckBlp2(&Header);
151 }
152 
153 
154 // Internal function used to check if the HEADER is a valid BLP header.
iCheckBlp2(BLP2HEAD * Header)155 ILboolean iCheckBlp2(BLP2HEAD *Header)
156 {
157 	// The file signature is 'BLP2'.
158 	if (strncmp(Header->Sig, "BLP2", 4))
159 		return IL_FALSE;
160 	// Valid types are JPEG and DXTC.  JPEG is not common, though.
161 	//  WoW only uses DXTC.
162 	if (Header->Type != BLP_TYPE_JPG && Header->Type != BLP_TYPE_DXTC_RAW)
163 		return IL_FALSE;
164 	// For BLP_TYPE_DXTC_RAW, we can have RAW and DXTC compression.
165 	if (Header->Compression != BLP_RAW && Header->Compression != BLP_DXTC)
166 		return IL_FALSE;
167 	// Alpha bits can only be 0, 1 and 8.
168 	if (Header->AlphaBits != 0 && Header->AlphaBits != 1 && Header->AlphaBits != 8)
169 		return IL_FALSE;
170 	// Alpha type can only be 0, 1, 7 and 8.
171 	if (Header->AlphaType != 0 && Header->AlphaType != 1 && Header->AlphaType != 7 && Header->AlphaType != 8)
172 		return IL_FALSE;
173 	// Width or height of 0 makes no sense.
174 	if (Header->Width == 0 || Header->Height == 0)
175 		return IL_FALSE;
176 
177 	return IL_TRUE;
178 }
179 
180 
181 //! Reads a BLP file
ilLoadBlp(ILconst_string FileName)182 ILboolean ilLoadBlp(ILconst_string FileName)
183 {
184 	ILHANDLE	BlpFile;
185 	ILboolean	bBlp = IL_FALSE;
186 
187 	BlpFile = iopenr(FileName);
188 	if (BlpFile == NULL) {
189 		ilSetError(IL_COULD_NOT_OPEN_FILE);
190 		return bBlp;
191 	}
192 
193 	bBlp = ilLoadBlpF(BlpFile);
194 	icloser(BlpFile);
195 
196 	return bBlp;
197 }
198 
199 
200 //! Reads an already-opened BLP file
ilLoadBlpF(ILHANDLE File)201 ILboolean ilLoadBlpF(ILHANDLE File)
202 {
203 	ILuint		FirstPos;
204 	ILboolean	bRet;
205 
206 	iSetInputFile(File);
207 	FirstPos = itell();
208 	bRet = iLoadBlpInternal();
209 	iseek(FirstPos, IL_SEEK_SET);
210 
211 	return bRet;
212 }
213 
214 
215 //! Reads from a memory "lump" that contains a BLP
ilLoadBlpL(const void * Lump,ILuint Size)216 ILboolean ilLoadBlpL(const void *Lump, ILuint Size)
217 {
218 	iSetInputLump(Lump, Size);
219 	return iLoadBlpInternal();
220 }
221 
222 
223 // Internal function used to load the BLP.
iLoadBlpInternal(void)224 ILboolean iLoadBlpInternal(void)
225 {
226 	BLP2HEAD	Header;
227 	ILubyte		*CompData;
228 	ILimage		*Image;
229 	ILuint		Mip, j, x, CompSize, AlphaSize, AlphaOff;
230 	ILint		y;
231 	ILboolean	BaseCreated = IL_FALSE;
232 	ILubyte		*DataAndAlpha = NULL, *Palette = NULL, AlphaMask; //, *JpegHeader, *JpegData;
233 
234 	if (iCurImage == NULL) {
235 		ilSetError(IL_ILLEGAL_OPERATION);
236 		return IL_FALSE;
237 	}
238 
239 	if (!iGetBlp2Head(&Header)) {
240 		ilSetError(IL_INVALID_FILE_HEADER);
241 		return IL_FALSE;
242 	}
243 	if (!iCheckBlp2(&Header)) {
244 		goto check_blp1;
245 	}
246 
247 //@TODO: Remove this!
248 	if (Header.Type != BLP_TYPE_DXTC_RAW)
249 		return IL_FALSE;
250 
251 	switch (Header.Compression)
252 	{
253 		case BLP_RAW:
254 			for (Mip = 0; Mip < 16; Mip++) {  // Possible maximum of 16 mipmaps
255 				if (BaseCreated) {
256 					if (Header.HasMips == 0)  // Does not have mipmaps, so we are done.
257 						break;
258 					if (Image->Width == 1 && Image->Height == 1)  // Already at the smallest mipmap (1x1), so we are done.
259 						break;
260 					if (Header.MipOffsets[Mip] == 0 || Header.MipLengths == 0)  // No more mipmaps in the file.
261 						break;
262 				}
263 
264 				switch (Header.AlphaBits)
265 				{
266 					case 0:
267 						if (!BaseCreated) {  // Have not created the base image yet, so use ilTexImage.
268 							if (!ilTexImage(Header.Width, Header.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL))
269 								return IL_FALSE;
270 							Image = iCurImage;
271 							BaseCreated = IL_TRUE;
272 
273 							Image->Pal.Palette = (ILubyte*)ialloc(256 * 4);  // 256 entries of ARGB8888 values (1024).
274 							if (Image->Pal.Palette == NULL)
275 								return IL_FALSE;
276 							Image->Pal.PalSize = 1024;
277 							Image->Pal.PalType = IL_PAL_BGRA32;  //@TODO: Find out if this is really BGRA data.
278 							if (iread(Image->Pal.Palette, 1, 1024) != 1024)  // Read in the palette.
279 								return IL_FALSE;
280 						}
281 						else {
282 							Image->Mipmaps = ilNewImageFull(Image->Width >> 1, Image->Height >> 1, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL);
283 							if (Image->Mipmaps == NULL)
284 								return IL_FALSE;
285 
286 							// Copy the palette from the first image before we change our Image pointer.
287 							iCopyPalette(&Image->Mipmaps->Pal, &Image->Pal);
288 							// Move to the next mipmap in the linked list.
289 							Image = Image->Mipmaps;
290 						}
291 						// The origin should be in the upper left.
292 						Image->Origin = IL_ORIGIN_UPPER_LEFT;
293 
294 						// These two should be the same (tells us how much data is in the file for this mipmap level).
295 						if (Header.MipLengths[Mip] != Image->SizeOfData) {
296 							ilSetError(IL_INVALID_FILE_HEADER);
297 							return IL_FALSE;
298 						}
299 						// Finally read in the image data.
300 						iseek(Header.MipOffsets[Mip], IL_SEEK_SET);
301 						if (iread(Image->Data, 1, Image->SizeOfData) != Image->SizeOfData)
302 							return IL_FALSE;
303 						break;
304 
305 					case 1:
306 						if (!BaseCreated) {  // Have not created the base image yet, so use ilTexImage.
307 							if (!ilTexImage(Header.Width, Header.Height, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL))
308 								return IL_FALSE;
309 							Image = iCurImage;
310 							BaseCreated = IL_TRUE;
311 
312 							Palette = (ILubyte*)ialloc(256 * 4);
313 							if (Palette == NULL)
314 								return IL_FALSE;
315 
316 							// Read in the palette.
317 							if (iread(Palette, 1, 1024) != 1024) {
318 								ifree(Palette);
319 								return IL_FALSE;
320 							}
321 
322 							// We only allocate this once and reuse this buffer with every mipmap (since successive ones are smaller).
323 							DataAndAlpha = (ILubyte*)ialloc(Image->Width * Image->Height);
324 							if (DataAndAlpha == NULL) {
325 								ifree(DataAndAlpha);
326 								ifree(Palette);
327 								return IL_FALSE;
328 							}
329 						}
330 						else {
331 							Image->Mipmaps = ilNewImageFull(Image->Width >> 1, Image->Height >> 1, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL);
332 							if (Image->Mipmaps == NULL)
333 								return IL_FALSE;
334 
335 							// Move to the next mipmap in the linked list.
336 							Image = Image->Mipmaps;
337 						}
338 						// The origin should be in the upper left.
339 						Image->Origin = IL_ORIGIN_UPPER_LEFT;
340 
341 						// Determine the size of the alpha data following the color indices.
342 						AlphaSize = Image->Width * Image->Height / 8;
343 						if (AlphaSize == 0)
344 							AlphaSize = 1;  // Should never be 0.
345 						// These two should be the same (tells us how much data is in the file for this mipmap level).
346 						if (Header.MipLengths[Mip] != Image->SizeOfData / 4 + AlphaSize) {
347 							ilSetError(IL_INVALID_FILE_HEADER);
348 							return IL_FALSE;
349 						}
350 
351 						// Seek to the data and read it.
352 						iseek(Header.MipOffsets[Mip], IL_SEEK_SET);
353 						if (iread(DataAndAlpha, Image->Width * Image->Height, 1) != 1) {
354 							ifree(DataAndAlpha);
355 							ifree(Palette);
356 							return IL_FALSE;
357 						}
358 
359 						// Convert the color-indexed data to BGRX.
360 						for (j = 0; j < Image->Width * Image->Height; j++) {
361 							Image->Data[j*4]   = Palette[DataAndAlpha[j]*4];
362 							Image->Data[j*4+1] = Palette[DataAndAlpha[j]*4+1];
363 							Image->Data[j*4+2] = Palette[DataAndAlpha[j]*4+2];
364 						}
365 
366 						// Read in the alpha list.
367 						if (iread(DataAndAlpha, AlphaSize, 1) != 1) {
368 							ifree(DataAndAlpha);
369 							ifree(Palette);
370 							return IL_FALSE;
371 						}
372 
373 						AlphaMask = 0x01;  // Lowest bit
374 						AlphaOff = 0;
375 						// The really strange thing about this alpha data is that it is upside-down when compared to the
376 						//   regular color-indexed data, so we have to flip it.
377 						for (y = Image->Height - 1; y >= 0; y--) {
378 							for (x = 0; x < Image->Width; x++) {
379 								if (AlphaMask == 0) {  // Shifting it past the highest bit makes it 0, since we only have 1 byte.
380 									AlphaOff++;        // Move along the alpha buffer.
381 									AlphaMask = 0x01;  // Reset the alpha mask.
382 								}
383 								// This is just 1-bit alpha, so it is either on or off.
384 								Image->Data[Image->Bps * y + x * 4 + 3] = DataAndAlpha[AlphaOff] & AlphaMask ? 0xFF : 0x00;
385 								AlphaMask <<= 1;
386 							}
387 						}
388 
389 						break;
390 
391 					default:
392 						//@TODO: Accept any other alpha values?
393 						ilSetError(IL_INVALID_FILE_HEADER);
394 						return IL_FALSE;
395 				}
396 			}
397 
398 			// Done, so we can finally free these two.
399 			ifree(DataAndAlpha);
400 			ifree(Palette);
401 
402 			break;
403 
404 		case BLP_DXTC:
405 			for (Mip = 0; Mip < 16; Mip++) {  // Possible maximum of 16 mipmaps
406 				//@TODO: Other formats
407 				//if (Header.AlphaBits == 0)
408 				//	if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL))
409 				//	return IL_FALSE;
410 				if (!BaseCreated) {  // Have not created the base image yet, so use ilTexImage.
411 					if (!ilTexImage(Header.Width, Header.Height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL))
412 						return IL_FALSE;
413 					Image = iCurImage;
414 					BaseCreated = IL_TRUE;
415 				}
416 				else {
417 					if (Header.HasMips == 0)  // Does not have mipmaps, so we are done.
418 						break;
419 					if (Image->Width == 1 && Image->Height == 1)  // Already at the smallest mipmap (1x1), so we are done.
420 						break;
421 					if (Header.MipOffsets[Mip] == 0 || Header.MipLengths[Mip] == 0)  // No more mipmaps in the file.
422 						break;
423 
424 					//@TODO: Other formats
425 					// ilNewImageFull automatically changes widths and heights of 0 to 1, so we do not have to worry about it.
426 					Image->Mipmaps = ilNewImageFull(Image->Width >> 1, Image->Height >> 1, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL);
427 					if (Image->Mipmaps == NULL)
428 						return IL_FALSE;
429 					Image = Image->Mipmaps;
430 				}
431 				// The origin should be in the upper left.
432 				Image->Origin = IL_ORIGIN_UPPER_LEFT;
433 
434 				//@TODO: Only do the allocation once.
435 				CompData = (ILubyte*)ialloc(Header.MipLengths[Mip]);
436 				if (CompData == NULL)
437 					return IL_FALSE;
438 
439 				// Read in the compressed mipmap data.
440 				iseek(Header.MipOffsets[Mip], IL_SEEK_SET);
441 				if (iread(CompData, 1, Header.MipLengths[Mip]) != Header.MipLengths[Mip]) {
442 					ifree(CompData);
443 					return IL_FALSE;
444 				}
445 
446 				switch (Header.AlphaBits)
447 				{
448 					case 0:  // DXT1 without alpha
449 					case 1:  // DXT1 with alpha
450 						// Check to make sure that the MipLength reported is the size needed, so that
451 						//  DecompressDXT1 does not crash.
452 						CompSize = ((Image->Width + 3) / 4) * ((Image->Height + 3) / 4) * 8;
453 						if (CompSize != Header.MipLengths[Mip]) {
454 							ilSetError(IL_INVALID_FILE_HEADER);
455 							ifree(CompData);
456 							return IL_FALSE;
457 						}
458 						if (!DecompressDXT1(Image, CompData)) {
459 							ifree(CompData);
460 							return IL_FALSE;
461 						}
462 						break;
463 
464 					case 8:
465 						// Check to make sure that the MipLength reported is the size needed, so that
466 						//  DecompressDXT3/5 do not crash.
467 						CompSize = ((Image->Width + 3) / 4) * ((Image->Height + 3) / 4) * 16;
468 						if (CompSize != Header.MipLengths[Mip]) {
469 							ifree(CompData);
470 							ilSetError(IL_INVALID_FILE_HEADER);
471 							return IL_FALSE;
472 						}
473 						switch (Header.AlphaType)
474 						{
475 							case 0:  // All three of
476 							case 1:  //  these refer to
477 							case 8:  //  DXT3...
478 								if (!DecompressDXT3(Image, CompData)) {
479 									ifree(CompData);
480 									return IL_FALSE;
481 								}
482 								break;
483 
484 							case 7:  // DXT5 compression
485 								if (!DecompressDXT5(Image, CompData)) {
486 									ifree(CompData);
487 									return IL_FALSE;
488 								}
489 								break;
490 
491 							//default:  // Should already be checked by iCheckBlp2.
492 						}
493 						break;
494 					//default:  // Should already be checked by iCheckBlp2.
495 				}
496 				//@TODO: Save DXTC data.
497 				ifree(CompData);
498 			}
499 			break;
500 		//default:
501 	}
502 
503 	return ilFixImage();
504 
505 check_blp1:
506 	iseek(-148, IL_SEEK_CUR);  // Go back the size of the BLP2 header, since we tried reading it.
507 	return iLoadBlp1();
508 }
509 
510 
iGetBlp1Head(BLP1HEAD * Header)511 ILboolean iGetBlp1Head(BLP1HEAD *Header)
512 {
513 	ILuint i;
514 
515 	iread(Header->Sig, 1, 4);
516 	Header->Compression = GetLittleUInt();
517 	Header->Flags = GetLittleUInt();
518 	Header->Width = GetLittleUInt();
519 	Header->Height = GetLittleUInt();
520 	Header->PictureType = GetLittleUInt();
521 	Header->PictureSubType = GetLittleUInt();
522 	for (i = 0; i < 16; i++)
523 		Header->MipOffsets[i] = GetLittleUInt();
524 	for (i = 0; i < 16; i++)
525 		Header->MipLengths[i] = GetLittleUInt();
526 
527 	return IL_TRUE;
528 }
529 
530 
iCheckBlp1(BLP1HEAD * Header)531 ILboolean iCheckBlp1(BLP1HEAD *Header)
532 {
533 	// The file signature is 'BLP1'.
534 	if (strncmp(Header->Sig, "BLP1", 4))
535 		return IL_FALSE;
536 	// Valid types are JPEG and RAW.  JPEG is not common, though.
537 	if (Header->Compression != BLP_TYPE_JPG && Header->Compression != BLP_RAW)
538 		return IL_FALSE;
539 //@TODO: Find out what Flags is for.
540 
541 	// PictureType determines whether this has an alpha list.
542 	if (Header->PictureType != BLP_RAW_PLUS_ALPHA1 && Header->PictureType != BLP_RAW_PLUS_ALPHA2
543 		&& Header->PictureType != BLP_RAW_NO_ALPHA)
544 		return IL_FALSE;
545 	// Width or height of 0 makes no sense.
546 	if (Header->Width == 0 || Header->Height == 0)
547 		return IL_FALSE;
548 
549 	return IL_TRUE;
550 }
551 
552 
iLoadBlp1()553 ILboolean iLoadBlp1()
554 {
555 	BLP1HEAD	Header;
556 	ILubyte		*DataAndAlpha, *Palette;
557 	ILuint		i;
558 	ILimage		*Image = iCurImage;
559 	ILboolean	BaseCreated = IL_FALSE;
560 #ifndef IL_NO_JPG
561 	ILubyte		*JpegHeader, *JpegData;
562 	ILuint		JpegHeaderSize;
563 #endif//IL_NO_JPG
564 
565 	if (!iGetBlp1Head(&Header))
566 		return IL_FALSE;
567 	if (!iCheckBlp1(&Header)) {
568 		ilSetError(IL_INVALID_FILE_HEADER);
569 		return IL_FALSE;
570 	}
571 
572 	//@TODO: Remove this.
573 	i = 0;
574 
575 	switch (Header.Compression)
576 	{
577 		case BLP_TYPE_JPG:
578 #ifdef IL_NO_JPG
579 			// We can only do the Jpeg decoding if we do not have IL_NO_JPEG defined.
580 			return IL_FALSE;
581 #else
582 			JpegHeaderSize = GetLittleUInt();
583 			JpegHeader = (ILubyte*)ialloc(JpegHeaderSize);
584 			if (JpegHeader == NULL)
585 				return IL_FALSE;
586 			// Read the shared Jpeg header.
587 			if (iread(JpegHeader, 1, JpegHeaderSize) != JpegHeaderSize) {
588 				ifree(JpegHeader);
589 				return IL_FALSE;
590 			}
591 
592 			//for (i = 0; i < 16; i++) {  // Possible maximum of 16 mipmaps
593 				//@TODO: Check return value?
594 				iseek(Header.MipOffsets[i], IL_SEEK_SET);
595 				JpegData = (ILubyte*)ialloc(JpegHeaderSize + Header.MipLengths[i]);
596 				if (JpegData == NULL) {
597 					ifree(JpegHeader);
598 					return IL_FALSE;
599 				}
600 				memcpy(JpegData, JpegHeader, JpegHeaderSize);
601 				if (iread(JpegData + JpegHeaderSize, Header.MipLengths[i], 1) != 1)
602 					return IL_FALSE;
603 
604 				// Just send the data straight to the Jpeg loader.
605 				if (!ilLoadJpegL(JpegData, JpegHeaderSize + Header.MipLengths[i]))
606 					return IL_FALSE;
607 
608 				// The image data is in BGR(A) order, even though it is Jpeg-compressed.
609 				if (Image->Format == IL_RGBA)
610 					Image->Format = IL_BGRA;
611 				if (Image->Format == IL_RGB)
612 					Image->Format = IL_BGR;
613 
614 				ifree(JpegData);
615 			//}
616 			ifree(JpegHeader);
617 #endif//IL_NO_JPG
618 			break;
619 
620 		case BLP_RAW:
621 			switch (Header.PictureType)
622 			{
623 				// There is no alpha list, so we just read like a normal indexed image.
624 				case BLP_RAW_NO_ALPHA:
625 					for (i = 0; i < 16; i++) {  // Possible maximum of 16 mipmaps
626 						if (!BaseCreated) {  // Have not created the base image yet, so use ilTexImage.
627 							if (!ilTexImage(Header.Width, Header.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL))
628 								return IL_FALSE;
629 							Image = iCurImage;
630 							BaseCreated = IL_TRUE;
631 
632 							// We have a BGRA palette.
633 							Image->Pal.Palette = (ILubyte*)ialloc(256 * 4);
634 							if (Image->Pal.Palette == NULL)
635 								return IL_FALSE;
636 							Image->Pal.PalSize = 1024;
637 							Image->Pal.PalType = IL_PAL_BGRA32;
638 
639 							// Read in the palette ...
640 							if (iread(Image->Pal.Palette, 1, 1024) != 1024)
641 								return IL_FALSE;
642 						}
643 						else {
644 							if (Image->Width == 1 && Image->Height == 1)  // Already at the smallest mipmap (1x1), so we are done.
645 								break;
646 							if (Header.MipOffsets[i] == 0 || Header.MipLengths[i] == 0)  // No more mipmaps in the file.
647 								break;
648 
649 							Image->Mipmaps = ilNewImageFull(Image->Width >> 1, Image->Height >> 1, 1, 1, IL_COLOR_INDEX, IL_UNSIGNED_BYTE, NULL);
650 							if (Image->Mipmaps == NULL)
651 								return IL_FALSE;
652 
653 							// Copy the palette from the first image before we change our Image pointer.
654 							Image->Mipmaps->Pal.Palette = (ILubyte*)ialloc(256 * 4);
655 							if (Image->Mipmaps->Pal.Palette == NULL)
656 								return IL_FALSE;
657 							Image->Mipmaps->Pal.PalSize = 1024;
658 							Image->Mipmaps->Pal.PalType = IL_PAL_BGRA32;
659 							memcpy(Image->Mipmaps->Pal.Palette, Image->Pal.Palette, 1024);
660 
661 							// Move to the next mipmap in the linked list.
662 							Image = Image->Mipmaps;
663 						}
664 						// The origin should be in the upper left.
665 						Image->Origin = IL_ORIGIN_UPPER_LEFT;
666 
667 						// Seek to the data and read it.
668 						iseek(Header.MipOffsets[i], IL_SEEK_SET);
669 						if (iread(Image->Data, 1, Image->SizeOfData) != Image->SizeOfData)
670 							return IL_FALSE;
671 					}
672 					break;
673 
674 				// These cases are identical and have an alpha list following the image data.
675 				case BLP_RAW_PLUS_ALPHA1:
676 				case BLP_RAW_PLUS_ALPHA2:
677 					// Create the image.
678 					if (!ilTexImage(Header.Width, Header.Height, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL))
679 						return IL_FALSE;
680 
681 					DataAndAlpha = (ILubyte*)ialloc(Header.Width * Header.Height);
682 					Palette = (ILubyte*)ialloc(256 * 4);
683 					if (DataAndAlpha == NULL || Palette == NULL) {
684 						ifree(DataAndAlpha);
685 						ifree(Palette);
686 						return IL_FALSE;
687 					}
688 
689 					// Read in the data and the palette.
690 					if (iread(Palette, 1, 1024) != 1024) {
691 						ifree(Palette);
692 						return IL_FALSE;
693 					}
694 					// Seek to the data and read it.
695 					iseek(Header.MipOffsets[i], IL_SEEK_SET);
696 					if (iread(DataAndAlpha, Header.Width * Header.Height, 1) != 1) {
697 						ifree(DataAndAlpha);
698 						ifree(Palette);
699 						return IL_FALSE;
700 					}
701 
702 					// Convert the color-indexed data to BGRX.
703 					for (i = 0; i < Header.Width * Header.Height; i++) {
704 						Image->Data[i*4]   = Palette[DataAndAlpha[i]*4];
705 						Image->Data[i*4+1] = Palette[DataAndAlpha[i]*4+1];
706 						Image->Data[i*4+2] = Palette[DataAndAlpha[i]*4+2];
707 					}
708 
709 					// Read in the alpha list.
710 					if (iread(DataAndAlpha, Header.Width * Header.Height, 1) != 1) {
711 						ifree(DataAndAlpha);
712 						ifree(Palette);
713 						return IL_FALSE;
714 					}
715 					// Finally put the alpha data into the image data.
716 					for (i = 0; i < Header.Width * Header.Height; i++) {
717 						Image->Data[i*4+3] = DataAndAlpha[i];
718 					}
719 
720 					ifree(DataAndAlpha);
721 					ifree(Palette);
722 					break;
723 			}
724 			break;
725 
726 		//default:  // Should already be checked by iCheckBlp1.
727 	}
728 
729 	// Set the origin (always upper left).
730 	Image->Origin = IL_ORIGIN_UPPER_LEFT;
731 
732 	return ilFixImage();
733 }
734 
735 
736 #endif//IL_NO_BLP
737