//----------------------------------------------------------------------------- // Torque Game Engine // Copyright (C) GarageGames.com, Inc. //----------------------------------------------------------------------------- #include "dgl/gBitmap.h" #include "dgl/gPalette.h" #include "core/stream.h" #include "platform/platform.h" // structures mirror those defined by the win32 API struct RGBQUAD { U8 rgbBlue; U8 rgbGreen; U8 rgbRed; U8 rgbReserved; }; struct BITMAPFILEHEADER { U16 bfType; U32 bfSize; U16 bfReserved1; U16 bfReserved2; U32 bfOffBits; }; struct BITMAPINFOHEADER{ U32 biSize; S32 biWidth; S32 biHeight; U16 biPlanes; U16 biBitCount; U32 biCompression; U32 biSizeImage; S32 biXPelsPerMeter; S32 biYPelsPerMeter; U32 biClrUsed; U32 biClrImportant; }; // constants for the biCompression field #define BI_RGB 0L #define BI_RLE8 1L #define BI_RLE4 2L #define BI_BITFIELDS 3L //------------------------------------------------------------------------------ //-------------------------------------- Supplimentary I/O (Partially located in // bitmapPng.cc) // bool GBitmap::readMSBmp(Stream& stream) { BITMAPINFOHEADER bi; BITMAPFILEHEADER bf; RGBQUAD rgb[256]; stream.read(&bf.bfType); stream.read(&bf.bfSize); stream.read(&bf.bfReserved1); stream.read(&bf.bfReserved2); stream.read(&bf.bfOffBits); stream.read(&bi.biSize); stream.read(&bi.biWidth); stream.read(&bi.biHeight); stream.read(&bi.biPlanes); stream.read(&bi.biBitCount); stream.read(&bi.biCompression); stream.read(&bi.biSizeImage); stream.read(&bi.biXPelsPerMeter); stream.read(&bi.biYPelsPerMeter); stream.read(&bi.biClrUsed); stream.read(&bi.biClrImportant); BitmapFormat fmt = RGB; if(bi.biBitCount == 8) { fmt = Palettized; if(!bi.biClrUsed) bi.biClrUsed = 256; stream.read(sizeof(RGBQUAD) * bi.biClrUsed, rgb); pPalette = new GPalette; for (U32 i = 0; i < 256; i++) { (pPalette->getColors())[i].red = rgb[i].rgbRed; (pPalette->getColors())[i].green = rgb[i].rgbGreen; (pPalette->getColors())[i].blue = rgb[i].rgbBlue; (pPalette->getColors())[i].alpha = 255; } } U8 *rowBuffer = new U8[bi.biWidth * 4]; allocateBitmap(bi.biWidth, bi.biHeight, false, fmt); S32 width = getWidth(); S32 height = getHeight(); for(int i = 0; i < bi.biHeight; i++) { U8 *rowDest = getAddress(0, height - i - 1); stream.read(bytesPerPixel * width, rowDest); } if(bytesPerPixel == 3) // do BGR swap { U8 *ptr = getAddress(0,0); for(int i = 0; i < width * height; i++) { U8 tmp = ptr[0]; ptr[0] = ptr[2]; ptr[2] = tmp; ptr += 3; } } delete[] rowBuffer; return true; } bool GBitmap::writeMSBmp(Stream& io_rStream) const { RGBQUAD rgb[256]; BITMAPINFOHEADER bi; BITMAPFILEHEADER bf; bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = getWidth(); bi.biHeight = getHeight(); //our data is top-down bi.biPlanes = 1; if(getFormat() == Palettized) { bi.biBitCount = 8; bi.biCompression = BI_RGB; bi.biClrUsed = 256; AssertFatal(pPalette != NULL, "Error, must have a palette"); } else if(getFormat() == RGB) { bi.biBitCount = 24; bi.biCompression = BI_RGB; bi.biClrUsed = 0; } U32 bytesPP = bi.biBitCount >> 3; bi.biSizeImage = getWidth() * getHeight() * bytesPP; bi.biXPelsPerMeter = 0; bi.biYPelsPerMeter = 0; bi.biClrUsed = 0; bi.biClrImportant = 0; bf.bfType = makeFourCCTag('B','M',0,0); //Type of file 'BM' bf.bfOffBits= sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER) + (sizeof(RGBQUAD)*bi.biClrUsed); bf.bfSize = bf.bfOffBits + bi.biSizeImage; bf.bfReserved1 = 0; bf.bfReserved2 = 0; io_rStream.write(bf.bfType); io_rStream.write(bf.bfSize); io_rStream.write(bf.bfReserved1); io_rStream.write(bf.bfReserved2); io_rStream.write(bf.bfOffBits); io_rStream.write(bi.biSize); io_rStream.write(bi.biWidth); io_rStream.write(bi.biHeight); io_rStream.write(bi.biPlanes); io_rStream.write(bi.biBitCount); io_rStream.write(bi.biCompression); io_rStream.write(bi.biSizeImage); io_rStream.write(bi.biXPelsPerMeter); io_rStream.write(bi.biYPelsPerMeter); io_rStream.write(bi.biClrUsed); io_rStream.write(bi.biClrImportant); if(getFormat() == Palettized) { for (S32 ndx=0; ndx<256; ndx++) { rgb[ndx].rgbRed = pPalette->getColor(ndx).red; rgb[ndx].rgbGreen = pPalette->getColor(ndx).green; rgb[ndx].rgbBlue = pPalette->getColor(ndx).blue; rgb[ndx].rgbReserved = 0; } io_rStream.write(sizeof(RGBQUAD)*256, (U8*)&rgb); } //write the bitmap bits U8* pMSUpsideDownBits = new U8[bi.biSizeImage]; for (U32 i = 0; i < getHeight(); i++) { const U8* pSrc = getAddress(0, i); U8* pDst = pMSUpsideDownBits + (getHeight() - i - 1) * getWidth() * bytesPP; dMemcpy(pDst, pSrc, getWidth() * bytesPP); } io_rStream.write(bi.biSizeImage, pMSUpsideDownBits); delete [] pMSUpsideDownBits; return io_rStream.getStatus() == Stream::Ok; }