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