718 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			718 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /**
 | |
|   @file GImage_bmp.cpp
 | |
|   @author Morgan McGuire, http://graphics.cs.williams.edu
 | |
|   @created 2002-05-27
 | |
|   @edited  2006-05-10
 | |
|  */
 | |
| #include "G3D/platform.h"
 | |
| #include "G3D/GImage.h"
 | |
| #include "G3D/BinaryInput.h"
 | |
| #include "G3D/BinaryOutput.h"
 | |
| #include "G3D/Log.h"
 | |
| 
 | |
| namespace G3D {
 | |
| 
 | |
| #ifndef G3D_WIN32
 | |
| /**
 | |
|  This is used by the Windows bitmap I/O.
 | |
|  */
 | |
| static const int BI_RGB = 0;
 | |
| #endif
 | |
| 
 | |
| void GImage::encodeBMP(
 | |
|     BinaryOutput&       out) const {
 | |
| 
 | |
|     debugAssert(m_channels == 1 || m_channels == 3);
 | |
|     out.setEndian(G3D_LITTLE_ENDIAN);
 | |
| 
 | |
|     uint8 red;
 | |
|     uint8 green;
 | |
|     uint8 blue;
 | |
|     int pixelBufferSize = m_width * m_height * 3;
 | |
|     int fileHeaderSize = 14;
 | |
|     int infoHeaderSize = 40;
 | |
|     int BMScanWidth;
 | |
|     int BMPadding;
 | |
| 
 | |
|     // First write the BITMAPFILEHEADER
 | |
|     //
 | |
|     //  WORD    bfType; 
 | |
|     //  DWORD   bfSize; 
 | |
|     //  WORD    bfReserved1; 
 | |
|     //  WORD    bfReserved2; 
 | |
|     //  DWORD   bfOffBits; 
 | |
| 
 | |
|     // Type
 | |
|     out.writeUInt8('B');
 | |
|     out.writeUInt8('M');
 | |
| 
 | |
|     // File size
 | |
|     out.writeUInt32(fileHeaderSize + infoHeaderSize + pixelBufferSize);
 | |
| 
 | |
|     // Two reserved fields set to zero
 | |
|     out.writeUInt16(0);
 | |
|     out.writeUInt16(0);
 | |
| 
 | |
| 	// The offset, in bytes, from the BITMAPFILEHEADER structure
 | |
|     // to the bitmap bits.
 | |
|     out.writeUInt32(infoHeaderSize + fileHeaderSize);
 | |
| 
 | |
|     // Now the BITMAPINFOHEADER
 | |
|     //
 | |
|     //  DWORD  biSize; 
 | |
|     //  LONG   biWidth; 
 | |
|     //  LONG   biHeight; 
 | |
|     //  WORD   biPlanes; 
 | |
|     //  WORD   biBitCount 
 | |
|     //  DWORD  biCompression; 
 | |
|     //  DWORD  biSizeImage; 
 | |
|     //  LONG   biXPelsPerMeter; 
 | |
|     //  LONG   biYPelsPerMeter; 
 | |
|     //  DWORD  biClrUsed; 
 | |
|     //  DWORD  biClrImportant; 
 | |
| 
 | |
|     // Size of the info header
 | |
|     out.writeUInt32(infoHeaderSize);
 | |
|  
 | |
|     // Width and height of the image
 | |
| 	out.writeUInt32(m_width);
 | |
|     out.writeUInt32(m_height);
 | |
| 
 | |
|     // Planes ("must be set to 1")
 | |
|     out.writeUInt16(1);
 | |
| 
 | |
|     // BitCount and CompressionType
 | |
|     out.writeUInt16(24);
 | |
|     out.writeUInt32(BI_RGB);
 | |
| 
 | |
|     // Image size ("may be zero for BI_RGB bitmaps")
 | |
|     out.writeUInt32(0);
 | |
| 
 | |
|     // biXPelsPerMeter
 | |
|     out.writeUInt32(0);
 | |
|     // biYPelsPerMeter
 | |
|     out.writeUInt32(0);
 | |
| 
 | |
|     // biClrUsed
 | |
|     out.writeUInt32(0); 
 | |
| 
 | |
|     // biClrImportant
 | |
|     out.writeUInt32(0); 
 | |
|     
 | |
|     BMScanWidth = m_width * 3;
 | |
| 
 | |
|     if (BMScanWidth & 3) {
 | |
|         BMPadding = 4 - (BMScanWidth & 3);
 | |
|     } else {
 | |
|         BMPadding = 0;
 | |
|     }
 | |
| 
 | |
|     int hStart = m_height - 1;
 | |
|     int hEnd   = -1;
 | |
|     int hDir   = -1;
 | |
|     int dest;
 | |
| 
 | |
|     // Write the pixel data
 | |
|     for (int h = hStart; h != hEnd; h += hDir) {
 | |
|         dest = m_channels * h * m_width;
 | |
|         for (int w = 0; w < m_width; ++w) {
 | |
| 
 | |
|             if (m_channels == 3) {
 | |
|                 red   = m_byte[dest];
 | |
|                 green = m_byte[dest + 1];
 | |
|                 blue  = m_byte[dest + 2];
 | |
|             } else {
 | |
|                 red   = m_byte[dest];
 | |
|                 green = m_byte[dest];
 | |
|                 blue  = m_byte[dest];
 | |
|             }
 | |
| 
 | |
|             out.writeUInt8(blue);
 | |
|             out.writeUInt8(green);
 | |
|             out.writeUInt8(red);
 | |
| 
 | |
|             dest += m_channels;
 | |
|         }
 | |
| 
 | |
|         if (BMPadding > 0) {
 | |
|             out.skip(BMPadding);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| void GImage::decodeBMP(
 | |
|     BinaryInput&            input) {
 | |
| 
 | |
|     // The BMP decoding uses these flags.
 | |
|     static const uint16 PICTURE_NONE               = 0x0000;
 | |
|     static const uint16 PICTURE_BITMAP             = 0x1000;
 | |
| 
 | |
|     // Compression Flags
 | |
|     static const uint16 PICTURE_UNCOMPRESSED       = 0x0100;
 | |
|     static const uint16 PICTURE_MONOCHROME         = 0x0001;
 | |
|     static const uint16 PICTURE_4BIT               = 0x0002;
 | |
|     static const uint16 PICTURE_8BIT               = 0x0004;
 | |
|     static const uint16 PICTURE_16BIT              = 0x0008;
 | |
|     static const uint16 PICTURE_24BIT              = 0x0010;
 | |
|     static const uint16 PICTURE_32BIT              = 0x0020;
 | |
| 
 | |
|     (void)PICTURE_16BIT;
 | |
|     (void)PICTURE_32BIT;
 | |
| 
 | |
|     // This is a simple BMP loader that can handle uncompressed BMP files.
 | |
|     // Verify this is a BMP file by looking for the BM tag.
 | |
|     input.reset();
 | |
|     std::string tag = input.readString(2);
 | |
|     if (tag != "BM") {
 | |
|         throw Error("Not a BMP file", input.getFilename());
 | |
|     }
 | |
| 
 | |
|     m_channels = 3;
 | |
| 	// Skip to the BITMAPINFOHEADER's width and height
 | |
| 	input.skip(16);
 | |
| 
 | |
|     m_width  = input.readUInt32();
 | |
|     m_height = input.readUInt32();
 | |
| 
 | |
| 	// Skip to the bit count and compression type
 | |
| 	input.skip(2);
 | |
| 
 | |
|     uint16 bitCount        = input.readUInt16();
 | |
|     uint32 compressionType = input.readUInt32();
 | |
| 
 | |
|     uint8 red;
 | |
|     uint8 green;
 | |
|     uint8 blue;
 | |
|     uint8 blank;
 | |
| 
 | |
| 	// Only uncompressed bitmaps are supported by this code
 | |
|     if ((int32)compressionType != BI_RGB) {
 | |
|         throw Error("BMP images must be uncompressed", input.getFilename());
 | |
|     }
 | |
| 
 | |
|     uint8* palette = NULL;
 | |
| 
 | |
| 	// Create the palette if needed
 | |
|     if (bitCount <= 8) {
 | |
| 
 | |
|         // Skip to the palette color count in the header
 | |
|         input.skip(12);
 | |
| 
 | |
|         int numColors = input.readUInt32();
 | |
| 
 | |
|         palette = (uint8*)System::malloc(numColors * 3);
 | |
|         debugAssert(palette);
 | |
| 
 | |
|         // Skip past the end of the header to the palette info
 | |
|         input.skip(4);
 | |
| 
 | |
|         int c;
 | |
|         for(c = 0; c < numColors * 3; c += 3) {
 | |
|             // Palette information in bitmaps is stored in BGR_ format.
 | |
|             // That means it's blue-green-red-blank, for each entry.
 | |
|             blue  = input.readUInt8();
 | |
|             green = input.readUInt8();
 | |
|             red   = input.readUInt8();
 | |
|             blank = input.readUInt8();
 | |
| 
 | |
|             palette[c]     = red;
 | |
|             palette[c + 1] = green;
 | |
|             palette[c + 2] = blue;
 | |
|         }
 | |
| 	}
 | |
| 
 | |
|     int hStart = 0;
 | |
|     int hEnd   = 0;
 | |
|     int hDir   = 0;
 | |
| 
 | |
|     if (m_height < 0) {
 | |
|         m_height = -m_height;
 | |
|         hStart = 0;
 | |
|         hEnd   = m_height;
 | |
|         hDir   = 1;
 | |
|     } else {
 | |
|         //height = height;
 | |
|         hStart = m_height - 1;
 | |
|         hEnd   = -1;
 | |
|         hDir   = -1;
 | |
|     }
 | |
| 
 | |
|     m_byte = (uint8*)m_memMan->alloc(m_width * m_height * 3);
 | |
|     debugAssert(m_byte);
 | |
| 
 | |
|     int BMScanWidth;
 | |
|     int BMPadding;
 | |
|     uint8 BMGroup;
 | |
|     uint8 BMPixel8;
 | |
|     int currPixel;
 | |
|     int dest;
 | |
|     int flags = PICTURE_NONE;
 | |
| 
 | |
|     if (bitCount == 1) {
 | |
|         // Note that this file is not necessarily grayscale, since it's possible
 | |
|         // the palette is blue-and-white, or whatever. But of course most image
 | |
|         // programs only write 1-bit images if they're black-and-white.
 | |
|         flags = PICTURE_BITMAP | PICTURE_UNCOMPRESSED | PICTURE_MONOCHROME;
 | |
| 
 | |
|         // For bitmaps, each scanline is dword-aligned.
 | |
|         BMScanWidth = (m_width + 7) >> 3;
 | |
|         if (BMScanWidth & 3) {
 | |
|             BMScanWidth += 4 - (BMScanWidth & 3);
 | |
|         }
 | |
| 
 | |
|         // Powers of 2
 | |
|         int pow2[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
 | |
| 
 | |
|         for (int h = hStart; h != hEnd; h += hDir) {
 | |
| 
 | |
|             currPixel = 0;
 | |
|             dest = 3 * h * m_width;
 | |
| 
 | |
|             for (int w = 0; w < BMScanWidth; ++w) {
 | |
| 
 | |
|                 BMGroup = input.readUInt8();
 | |
| 
 | |
|                 // Now we read the pixels. Usually there are eight pixels per byte,
 | |
|                 // since each pixel is represented by one bit, but if the width
 | |
|                 // is not a multiple of eight, the last byte will have some bits
 | |
|                 // set, with the others just being extra. Plus there's the
 | |
|                 // dword-alignment padding. So we keep checking to see if we've
 | |
|                 // already read "width" number of pixels.
 | |
|                 for (int i = 7; i >= 0; --i) {
 | |
|                     if (currPixel < m_width) {
 | |
|                         int src  = 3 * ((BMGroup & pow2[i]) >> i);
 | |
|                     
 | |
|                         m_byte[dest]     = palette[src];
 | |
|                         m_byte[dest + 1] = palette[src + 1];
 | |
|                         m_byte[dest + 2] = palette[src + 2];
 | |
|                     
 | |
|                         ++currPixel;
 | |
|                         dest += 3;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 	} else if (bitCount == 4) {
 | |
| 
 | |
|         flags = PICTURE_BITMAP | PICTURE_UNCOMPRESSED | PICTURE_4BIT;
 | |
| 
 | |
|         // For bitmaps, each scanline is dword-aligned.
 | |
|         int BMScanWidth = (m_width + 1) >> 1;
 | |
|         if (BMScanWidth & 3) {
 | |
|             BMScanWidth += 4 - (BMScanWidth & 3);
 | |
|         }
 | |
| 
 | |
|         for (int h = hStart; h != hEnd; h += hDir) {
 | |
| 
 | |
|             currPixel = 0;
 | |
|             dest = 3 * h * m_width;
 | |
| 
 | |
|             for (int w = 0; w < BMScanWidth; w++) {
 | |
| 
 | |
|                 BMGroup = input.readUInt8();
 | |
|                 int src[2];
 | |
|                 src[0] = 3 * ((BMGroup & 0xF0) >> 4);
 | |
|                 src[1] = 3 * (BMGroup & 0x0F);
 | |
| 
 | |
|                 // Now we read the pixels. Usually there are two pixels per byte,
 | |
|                 // since each pixel is represented by four bits, but if the width
 | |
|                 // is not a multiple of two, the last byte will have only four bits
 | |
|                 // set, with the others just being extra. Plus there's the
 | |
|                 // dword-alignment padding. So we keep checking to see if we've
 | |
|                 // already read "Width" number of pixels.
 | |
| 
 | |
|                 for (int i = 0; i < 2; ++i) {
 | |
|                     if (currPixel < m_width) {
 | |
|                         int tsrc  = src[i];
 | |
|                     
 | |
|                         m_byte[dest]     = palette[tsrc];
 | |
|                         m_byte[dest + 1] = palette[tsrc + 1];
 | |
|                         m_byte[dest + 2] = palette[tsrc + 2];
 | |
| 
 | |
|                         ++currPixel;
 | |
|                         dest += 3;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 	} else if (bitCount == 8) {
 | |
|         
 | |
|         flags = PICTURE_BITMAP | PICTURE_UNCOMPRESSED | PICTURE_8BIT;
 | |
| 
 | |
|         // For bitmaps, each scanline is dword-aligned.
 | |
|         BMScanWidth = m_width;
 | |
|         if (BMScanWidth & 3) {
 | |
|             BMScanWidth += 4 - (BMScanWidth & 3);
 | |
|         }
 | |
| 
 | |
|         for (int h = hStart; h != hEnd; h += hDir) {
 | |
| 
 | |
|             currPixel = 0;
 | |
| 
 | |
|             for (int w = 0; w < BMScanWidth; ++w) {
 | |
| 
 | |
|                 BMPixel8 = input.readUInt8();
 | |
| 
 | |
|                 if (currPixel < m_width) {
 | |
|                     dest = 3 * ((h * m_width) + currPixel);
 | |
|                     int src  = 3 * BMPixel8;
 | |
|                     
 | |
|                     m_byte[dest]     = palette[src];
 | |
|                     m_byte[dest + 1] = palette[src + 1];
 | |
|                     m_byte[dest + 2] = palette[src + 2];
 | |
|                     
 | |
|                     ++currPixel;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|     } else if (bitCount == 16) {
 | |
| 
 | |
|         m_memMan->free(m_byte);
 | |
|         m_byte = NULL;
 | |
|         System::free(palette); 
 | |
|         palette = NULL;
 | |
|     	throw Error("16-bit bitmaps not supported", input.getFilename());
 | |
| 
 | |
| 	} else if (bitCount == 24) {
 | |
|         input.skip(20);
 | |
| 
 | |
|         flags = PICTURE_BITMAP | PICTURE_UNCOMPRESSED | PICTURE_24BIT;
 | |
| 
 | |
|         // For bitmaps, each scanline is dword-aligned.
 | |
|         BMScanWidth = m_width * 3;
 | |
| 
 | |
|         if (BMScanWidth & 3) {
 | |
|             BMPadding = 4 - (BMScanWidth & 3);
 | |
|         } else {
 | |
|             BMPadding = 0;
 | |
|         }
 | |
| 
 | |
|         for (int h = hStart; h != hEnd; h += hDir) {
 | |
|             dest = 3 * h * m_width;
 | |
|             for (int w = 0; w < m_width; ++w) {
 | |
| 
 | |
|                 blue  = input.readUInt8();
 | |
|                 green = input.readUInt8();
 | |
|                 red   = input.readUInt8();
 | |
| 
 | |
|                 m_byte[dest]     = red;
 | |
|                 m_byte[dest + 1] = green;
 | |
|                 m_byte[dest + 2] = blue;
 | |
| 
 | |
|                 dest += 3;
 | |
|             }
 | |
| 
 | |
|             if (BMPadding) {
 | |
|                 input.skip(2);
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 	} else if (bitCount == 32) {
 | |
| 
 | |
|         m_memMan->free(m_byte);
 | |
|         m_byte = NULL;
 | |
|         System::free(palette); 
 | |
|         palette = NULL;
 | |
|     	throw Error("32 bit bitmaps not supported", input.getFilename());
 | |
|     
 | |
|     } else {
 | |
|         // We support all possible bit depths, so if the
 | |
|         //     code gets here, it's not even a real bitmap.
 | |
|         m_memMan->free(m_byte);
 | |
|         m_byte = NULL;
 | |
|         throw Error("Not a bitmap!", input.getFilename());
 | |
| 	}
 | |
| 
 | |
|     System::free(palette); 
 | |
|     palette = NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| void GImage::decodeICO(
 | |
|     BinaryInput&            input) {
 | |
| 
 | |
| 	// Header
 | |
| 	uint16 r = input.readUInt16();
 | |
| 	debugAssert(r == 0);
 | |
| 	r = input.readUInt16();
 | |
| 	debugAssert(r == 1);
 | |
| 
 | |
| 	// Read the number of icons, although we'll only load the
 | |
| 	// first one.
 | |
| 	int count = input.readUInt16();
 | |
| 
 | |
| 	m_channels = 4;
 | |
| 
 | |
| 	debugAssert(count > 0);
 | |
| 
 | |
|     const uint8* headerBuffer = input.getCArray() + input.getPosition();
 | |
|     int maxWidth = 0, maxHeight = 0;
 | |
|     int maxHeaderNum = 0;
 | |
|     for (int currentHeader = 0; currentHeader < count; ++currentHeader) {
 | |
|         
 | |
|         const uint8* curHeaderBuffer = headerBuffer + (currentHeader * 16);
 | |
|         int tmpWidth = curHeaderBuffer[0];
 | |
|         int tmpHeight = curHeaderBuffer[1];
 | |
|         // Just in case there is a non-square icon, checking area
 | |
|         if ((tmpWidth * tmpHeight) > (maxWidth * maxHeight)) {
 | |
|             maxWidth = tmpWidth;
 | |
|             maxHeight = tmpHeight;
 | |
|             maxHeaderNum = currentHeader;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     input.skip(maxHeaderNum * 16);
 | |
| 
 | |
|     m_width = input.readUInt8();
 | |
|     m_height = input.readUInt8();
 | |
|     int numColors = input.readUInt8();
 | |
| 	
 | |
|     m_byte = (uint8*)m_memMan->alloc(m_width * m_height * m_channels);
 | |
|     debugAssert(m_byte);
 | |
| 
 | |
|     // Bit mask for packed bits
 | |
|     int mask = 0;
 | |
|     
 | |
|     int bitsPerPixel = 8;
 | |
|     
 | |
|     switch (numColors) {
 | |
|     case 2:
 | |
|         mask      = 0x01;
 | |
|         bitsPerPixel = 1;
 | |
|         break;
 | |
|         
 | |
|     case 16:
 | |
|         mask      = 0x0F;
 | |
|         bitsPerPixel = 4;
 | |
|         break;
 | |
|         
 | |
|     case 0:
 | |
|         numColors = 256;
 | |
|         mask      = 0xFF;
 | |
|         bitsPerPixel = 8;
 | |
|         break;
 | |
| 
 | |
|     default:
 | |
|     	throw Error("Unsupported ICO color count.", input.getFilename());
 | |
|     }
 | |
| 
 | |
|     input.skip(5);
 | |
|     // Skip 'size' unused
 | |
|     input.skip(4);
 | |
|     
 | |
|     int offset = input.readUInt32();
 | |
|     
 | |
|     // Skip over any other icon descriptions
 | |
|     input.setPosition(offset);
 | |
|     
 | |
|     // Skip over bitmap header; it is redundant
 | |
|     input.skip(40);
 | |
|     
 | |
|     Array<Color4uint8> palette;
 | |
|     palette.resize(numColors, true);
 | |
|     for (int c = 0; c < numColors; ++c) {
 | |
|         palette[c].b = input.readUInt8();
 | |
|         palette[c].g = input.readUInt8();
 | |
|         palette[c].r = input.readUInt8();
 | |
|         palette[c].a = input.readUInt8();
 | |
|     }
 | |
| 
 | |
| 	// The actual image and mask follow
 | |
| 
 | |
| 	// The XOR Bitmap is stored as 1-bit, 4-bit or 8-bit uncompressed Bitmap 
 | |
| 	// using the same encoding as BMP files. The AND Bitmap is stored in as 
 | |
| 	// 1-bit uncompressed Bitmap.
 | |
| 	// 
 | |
| 	// Pixels are stored bottom-up, left-to-right. Pixel lines are padded 
 | |
| 	// with zeros to end on a 32bit (4byte) boundary. Every line will have the 
 | |
| 	// same number of bytes. Color indices are zero based, meaning a pixel color 
 | |
| 	// of 0 represents the first color table entry, a pixel color of 255 (if there
 | |
| 	// are that many) represents the 256th entry.
 | |
| /*
 | |
| 	int bitsPerRow  = width * bitsPerPixel;
 | |
| 	int bytesPerRow = iCeil((double)bitsPerRow / 8);
 | |
| 	// Rows are padded to 32-bit boundaries
 | |
| 	bytesPerRow += bytesPerRow % 4;
 | |
| 
 | |
| 	// Read the XOR values into the color channel
 | |
| 	for (int y = height - 1; y >= 0; --y) {
 | |
| 		int x = 0;
 | |
| 		// Read the row
 | |
| 		for (int i = 0; i < bytesPerRow; ++i) {
 | |
| 			uint8 byte = input.readUInt8();
 | |
| 			for (int j = 0; (j < 8) && (x < width); ++x, j += bitsPerPixel) {
 | |
| 				int bit = ((byte << j) >> (8 - bitsPerPixel)) & mask;
 | |
| 				pixel4(x, y) = colorTable[bit];
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| */
 | |
|     int hStart = 0;
 | |
|     int hEnd   = 0;
 | |
|     int hDir   = 0;
 | |
| 
 | |
|     if (m_height < 0) {
 | |
|         m_height = -m_height;
 | |
|         hStart = 0;
 | |
|         hEnd   = m_height;
 | |
|         hDir   = 1;
 | |
|     } else {
 | |
|         //height = height;
 | |
|         hStart = m_height - 1;
 | |
|         hEnd   = -1;
 | |
|         hDir   = -1;
 | |
|     }
 | |
| 
 | |
|     int BMScanWidth;
 | |
|     uint8 BMGroup;
 | |
|     uint8 BMPixel8;
 | |
|     int currPixel;
 | |
|     int dest;
 | |
| 
 | |
|     if (bitsPerPixel == 1) {
 | |
|         // Note that this file is not necessarily grayscale, since it's possible
 | |
|         // the palette is blue-and-white, or whatever. But of course most image
 | |
|         // programs only write 1-bit images if they're black-and-white.
 | |
| 
 | |
|         // For bitmaps, each scanline is dword-aligned.
 | |
|         BMScanWidth = (m_width + 7) >> 3;
 | |
|         if (BMScanWidth & 3) {
 | |
|             BMScanWidth += 4 - (BMScanWidth & 3);
 | |
|         }
 | |
| 
 | |
|         // Powers of 2
 | |
|         int pow2[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
 | |
| 
 | |
|         for (int h = hStart; h != hEnd; h += hDir) {
 | |
| 
 | |
|             currPixel = 0;
 | |
|             dest = 3 * h * m_width;
 | |
| 
 | |
|             for (int w = 0; w < BMScanWidth; ++w) {
 | |
| 
 | |
|                 BMGroup = input.readUInt8();
 | |
| 
 | |
|                 // Now we read the pixels. Usually there are eight pixels per byte,
 | |
|                 // since each pixel is represented by one bit, but if the width
 | |
|                 // is not a multiple of eight, the last byte will have some bits
 | |
|                 // set, with the others just being extra. Plus there's the
 | |
|                 // dword-alignment padding. So we keep checking to see if we've
 | |
|                 // already read "width" number of pixels.
 | |
|                 for (int i = 7; i >= 0; --i) {
 | |
|                     if (currPixel < m_width) {
 | |
|                         int src  = ((BMGroup & pow2[i]) >> i);
 | |
|                     
 | |
|                         m_byte[dest]     = palette[src].r;
 | |
|                         m_byte[dest + 1] = palette[src].g;
 | |
|                         m_byte[dest + 2] = palette[src].b;
 | |
|                     
 | |
|                         ++currPixel;
 | |
|                         dest += 4;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 	} else if (bitsPerPixel == 4) {
 | |
| 
 | |
|         // For bitmaps, each scanline is dword-aligned.
 | |
|         int BMScanWidth = (m_width + 1) >> 1;
 | |
|         if (BMScanWidth & 3) {
 | |
|             BMScanWidth += 4 - (BMScanWidth & 3);
 | |
|         }
 | |
| 
 | |
|         for (int h = hStart; h != hEnd; h += hDir) {
 | |
| 
 | |
|             currPixel = 0;
 | |
|             dest = 4 * h * m_width;
 | |
| 
 | |
|             for (int w = 0; w < BMScanWidth; w++) {
 | |
| 
 | |
|                 BMGroup = input.readUInt8();
 | |
|                 int src[2];
 | |
|                 src[0] = ((BMGroup & 0xF0) >> 4);
 | |
|                 src[1] = (BMGroup & 0x0F);
 | |
| 
 | |
|                 // Now we read the pixels. Usually there are two pixels per byte,
 | |
|                 // since each pixel is represented by four bits, but if the width
 | |
|                 // is not a multiple of two, the last byte will have only four bits
 | |
|                 // set, with the others just being extra. Plus there's the
 | |
|                 // dword-alignment padding. So we keep checking to see if we've
 | |
|                 // already read "Width" number of pixels.
 | |
| 
 | |
|                 for (int i = 0; i < 2; ++i) {
 | |
|                     if (currPixel < m_width) {
 | |
|                         int tsrc  = src[i];
 | |
|                     
 | |
|                         m_byte[dest]     = palette[tsrc].r;
 | |
|                         m_byte[dest + 1] = palette[tsrc].g;
 | |
|                         m_byte[dest + 2] = palette[tsrc].b;
 | |
| 
 | |
|                         ++currPixel;
 | |
|                         dest += 4;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 	} else if (bitsPerPixel == 8) {
 | |
|         
 | |
|         // For bitmaps, each scanline is dword-aligned.
 | |
|         BMScanWidth = m_width;
 | |
|         if (BMScanWidth & 3) {
 | |
|             BMScanWidth += 4 - (BMScanWidth & 3);
 | |
|         }
 | |
| 
 | |
|         for (int h = hStart; h != hEnd; h += hDir) {
 | |
| 
 | |
|             currPixel = 0;
 | |
| 
 | |
|             for (int w = 0; w < BMScanWidth; ++w) {
 | |
| 
 | |
|                 BMPixel8 = input.readUInt8();
 | |
| 
 | |
|                 if (currPixel < m_width) {
 | |
|                     dest = 4 * ((h * m_width) + currPixel);
 | |
|                     int src  = BMPixel8;
 | |
|                     
 | |
|                     m_byte[dest]     = palette[src].r;
 | |
|                     m_byte[dest + 1] = palette[src].g;
 | |
|                     m_byte[dest + 2] = palette[src].b;
 | |
|                     
 | |
|                     ++currPixel;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
| 	// Read the mask into the alpha channel
 | |
| 	int bitsPerRow  = m_width;
 | |
| 	int bytesPerRow = iCeil((double)bitsPerRow / 8);
 | |
| 
 | |
|     // For bitmaps, each scanline is dword-aligned.
 | |
|     //BMScanWidth = (width + 1) >> 1;
 | |
|     if (bytesPerRow & 3) {
 | |
|         bytesPerRow += 4 - (bytesPerRow & 3);
 | |
|     }
 | |
|     
 | |
|     for (int y = m_height - 1; y >= 0; --y) {
 | |
| 		int x = 0;
 | |
| 		// Read the row
 | |
| 		for (int i = 0; i < bytesPerRow; ++i) {
 | |
| 			uint8 byte = input.readUInt8();
 | |
| 			for (int j = 0; (j < 8) && (x < m_width); ++x, ++j) {
 | |
| 				int bit = (byte >> (7 - j)) & 0x01;
 | |
| 				pixel4(x, y).a = (1 - bit) * 0xFF;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| }
 |