bitmapBmp.cpp
Engine/source/gfx/bitmap/loaders/bitmapBmp.cpp
Classes:
Public Defines
Public Variables
struct _privateRegisterBMP
Public Functions
Detailed Description
Public Defines
BI_BITFIELDS() 3L
BI_RGB() 0L
BI_RLE4() 2L
BI_RLE8() 1L
Public Variables
struct _privateRegisterBMP sStaticRegisterBMP
Public Functions
sReadBMP(Stream & stream, GBitmap * bitmap)
sWriteBMP(GBitmap * bitmap, Stream & stream, U32 compressionLevel)
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "core/stream/stream.h" 25 26#include "gfx/bitmap/gBitmap.h" 27 28 29static bool sReadBMP(Stream &stream, GBitmap *bitmap); 30static bool sWriteBMP(GBitmap *bitmap, Stream &stream, U32 compressionLevel); 31 32static struct _privateRegisterBMP 33{ 34 _privateRegisterBMP() 35 { 36 GBitmap::Registration reg; 37 38 reg.extensions.push_back( "bmp" ); 39 40 reg.readFunc = sReadBMP; 41 reg.writeFunc = sWriteBMP; 42 43 GBitmap::sRegisterFormat( reg ); 44 } 45} sStaticRegisterBMP; 46 47 48// structures mirror those defined by the win32 API 49 50struct RGBQUAD 51{ 52 U8 rgbBlue; 53 U8 rgbGreen; 54 U8 rgbRed; 55 U8 rgbReserved; 56}; 57 58struct BITMAPFILEHEADER 59{ 60 U16 bfType; 61 U32 bfSize; 62 U16 bfReserved1; 63 U16 bfReserved2; 64 U32 bfOffBits; 65}; 66 67struct BITMAPINFOHEADER 68{ 69 U32 biSize; 70 S32 biWidth; 71 S32 biHeight; 72 U16 biPlanes; 73 U16 biBitCount; 74 U32 biCompression; 75 U32 biSizeImage; 76 S32 biXPelsPerMeter; 77 S32 biYPelsPerMeter; 78 U32 biClrUsed; 79 U32 biClrImportant; 80}; 81 82// constants for the biCompression field 83#define BI_RGB 0L 84#define BI_RLE8 1L 85#define BI_RLE4 2L 86#define BI_BITFIELDS 3L 87 88 89//------------------------------------------------------------------------------ 90//-------------------------------------- Supplementary I/O (Partially located in 91// bitmapPng.cc) 92// 93 94static bool sReadBMP(Stream &stream, GBitmap *bitmap) 95{ 96 PROFILE_SCOPE(sReadBMP); 97 BITMAPINFOHEADER bi; 98 BITMAPFILEHEADER bf; 99 RGBQUAD rgb[256]; 100 101 stream.read(&bf.bfType); 102 stream.read(&bf.bfSize); 103 stream.read(&bf.bfReserved1); 104 stream.read(&bf.bfReserved2); 105 stream.read(&bf.bfOffBits); 106 107 stream.read(&bi.biSize); 108 stream.read(&bi.biWidth); 109 stream.read(&bi.biHeight); 110 stream.read(&bi.biPlanes); 111 stream.read(&bi.biBitCount); 112 stream.read(&bi.biCompression); 113 stream.read(&bi.biSizeImage); 114 stream.read(&bi.biXPelsPerMeter); 115 stream.read(&bi.biYPelsPerMeter); 116 stream.read(&bi.biClrUsed); 117 stream.read(&bi.biClrImportant); 118 119 GFXFormat fmt = GFXFormatR8G8B8; 120 if(bi.biBitCount == 8) 121 { 122 // read in texture palette 123 if(!bi.biClrUsed) 124 bi.biClrUsed = 256; 125 stream.read(sizeof(RGBQUAD) * bi.biClrUsed, rgb); 126 } 127 bitmap->allocateBitmap(bi.biWidth, bi.biHeight, false, fmt); 128 U32 width = bitmap->getWidth(); 129 U32 height = bitmap->getHeight(); 130 U32 bytesPerPixel = bitmap->getBytesPerPixel(); 131 132 for(U32 i = 0; i < bi.biHeight; i++) 133 { 134 U8 *rowDest = bitmap->getAddress(0, height - i - 1); 135 if (bi.biBitCount == 8) 136 { 137 // use palette...don't worry about being slow 138 for (S32 j=0; j<width; j++) 139 { 140 U8 palIdx; 141 stream.read(&palIdx); 142 U8 * pixelLocation = &rowDest[j*bytesPerPixel]; 143 pixelLocation[0] = rgb[palIdx].rgbRed; 144 pixelLocation[1] = rgb[palIdx].rgbGreen; 145 pixelLocation[2] = rgb[palIdx].rgbBlue; 146 if (bytesPerPixel==3) 147 pixelLocation[3] = 255; 148 } 149 } 150 else 151 stream.read(bytesPerPixel * width, rowDest); 152 } 153 154 if(bytesPerPixel == 3 && bi.biBitCount != 8) // do BGR swap 155 { 156 U8 *ptr = bitmap->getAddress(0,0); 157 for(S32 i = 0; i < width * height; i++) 158 { 159 U8 tmp = ptr[0]; 160 ptr[0] = ptr[2]; 161 ptr[2] = tmp; 162 ptr += 3; 163 } 164 } 165 166 // We know BMP's don't have any transparency 167 bitmap->setHasTransparency(false); 168 169 return true; 170} 171 172static bool sWriteBMP(GBitmap *bitmap, Stream &stream, U32 compressionLevel) 173{ 174 TORQUE_UNUSED( compressionLevel ); // BMP does not use compression 175 176 BITMAPINFOHEADER bi; 177 BITMAPFILEHEADER bf; 178 179 bi.biSize = sizeof(BITMAPINFOHEADER); 180 bi.biWidth = bitmap->getWidth(); 181 bi.biHeight = bitmap->getHeight(); //our data is top-down 182 bi.biPlanes = 1; 183 184 if(bitmap->getFormat() == GFXFormatR8G8B8) 185 { 186 bi.biBitCount = 24; 187 bi.biCompression = BI_RGB; 188 bi.biClrUsed = 0; 189 } 190 else 191 { 192 bi.biBitCount = 0; 193 bi.biCompression = BI_RGB; // Removes warning C4701 on line 194 AssertISV(false, "GBitmap::writeMSBmp - only support R8G8B8 formats!"); 195 } 196 197 U32 width = bitmap->getWidth(); 198 U32 height = bitmap->getHeight(); 199 200 U32 bytesPP = bi.biBitCount >> 3; 201 bi.biSizeImage = width * height * bytesPP; 202 bi.biXPelsPerMeter = 0; 203 bi.biYPelsPerMeter = 0; 204 bi.biClrUsed = 0; 205 bi.biClrImportant = 0; 206 207 bf.bfType = makeFourCCTag('B','M',0,0); //Type of file 'BM' 208 bf.bfOffBits= sizeof(BITMAPINFOHEADER) 209 + sizeof(BITMAPFILEHEADER) 210 + (sizeof(RGBQUAD)*bi.biClrUsed); 211 bf.bfSize = bf.bfOffBits + bi.biSizeImage; 212 bf.bfReserved1 = 0; 213 bf.bfReserved2 = 0; 214 215 stream.write(bf.bfType); 216 stream.write(bf.bfSize); 217 stream.write(bf.bfReserved1); 218 stream.write(bf.bfReserved2); 219 stream.write(bf.bfOffBits); 220 221 stream.write(bi.biSize); 222 stream.write(bi.biWidth); 223 stream.write(bi.biHeight); 224 stream.write(bi.biPlanes); 225 stream.write(bi.biBitCount); 226 stream.write(bi.biCompression); 227 stream.write(bi.biSizeImage); 228 stream.write(bi.biXPelsPerMeter); 229 stream.write(bi.biYPelsPerMeter); 230 stream.write(bi.biClrUsed); 231 stream.write(bi.biClrImportant); 232 233 //write the bitmap bits 234 U8* pMSUpsideDownBits = new U8[bi.biSizeImage]; 235 for (U32 i = 0; i < height; i++) 236 { 237 const U8* pSrc = bitmap->getAddress(0, i); 238 U8* pDst = pMSUpsideDownBits + (height - i - 1) * width * bytesPP; 239 240 dMemcpy(pDst, pSrc, width * bytesPP); 241 } 242 243 stream.write(bi.biSizeImage, pMSUpsideDownBits); 244 delete [] pMSUpsideDownBits; 245 246 return stream.getStatus() == Stream::Ok; 247} 248