// ============================================================== // This file is part of Glest Shared Library (www.glest.org) // // Copyright (C) 2001-2010 MartiƱo Figueroa and others // // You can redistribute this code and/or modify it under // the terms of the GNU General Public License as published // by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version // ============================================================== #include "BMPReader.h" #include "data_types.h" #include "pixmap.h" #include #include "util.h" #include "leak_dumper.h" using std::runtime_error; namespace Shared{ namespace Graphics{ // ===================================================== // Structs used for BMP-reading // ===================================================== #pragma pack(push, 1) struct BitmapFileHeader{ uint8 type1; uint8 type2; uint32 size; uint16 reserved1; uint16 reserved2; uint32 offsetBits; }; struct BitmapInfoHeader{ uint32 size; int32 width; int32 height; uint16 planes; uint16 bitCount; uint32 compression; uint32 sizeImage; int32 xPelsPerMeter; int32 yPelsPerMeter; uint32 clrUsed; uint32 clrImportant; }; #pragma pack(pop) /**Returns a string containing the extensions we want, intitialisation is guaranteed*/ //static inline const string* getExtensionsBmp() { static inline std::vector getExtensionsBmp() { //static const string extensions[] = {"bmp", ""}; static std::vector extensions; if(extensions.empty() == true) { extensions.push_back("bmp"); } return extensions; } // ===================================================== // class BMPReader // ===================================================== BMPReader::BMPReader(): FileReader(getExtensionsBmp()) {} /**Reads a Pixmap2D-object *This function reads a Pixmap2D-object from the given ifstream utilising the already existing Pixmap2D* ret. *Path is used for printing error messages *@return NULL if the Pixmap2D could not be read, else the pixmap*/ Pixmap2D* BMPReader::read(ifstream& in, const string& path, Pixmap2D* ret) const { assert(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == false); //read file header BitmapFileHeader fileHeader; in.read((char*)&fileHeader, sizeof(BitmapFileHeader)); static bool bigEndianSystem = Shared::PlatformByteOrder::isBigEndian(); if(bigEndianSystem == true) { fileHeader.offsetBits = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.offsetBits); fileHeader.reserved1 = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.reserved1); fileHeader.reserved2 = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.reserved2); fileHeader.size = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.size); fileHeader.type1 = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.type1); fileHeader.type2 = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.type2); } if(fileHeader.type1!='B' || fileHeader.type2!='M'){ throw megaglest_runtime_error(path +" is not a bitmap",true); } //read info header BitmapInfoHeader infoHeader; in.read((char*)&infoHeader, sizeof(BitmapInfoHeader)); if(bigEndianSystem == true) { infoHeader.bitCount = Shared::PlatformByteOrder::fromCommonEndian(infoHeader.bitCount); infoHeader.clrImportant = Shared::PlatformByteOrder::fromCommonEndian(infoHeader.clrImportant); infoHeader.clrUsed = Shared::PlatformByteOrder::fromCommonEndian(infoHeader.clrUsed); infoHeader.compression = Shared::PlatformByteOrder::fromCommonEndian(infoHeader.compression); infoHeader.height = Shared::PlatformByteOrder::fromCommonEndian(infoHeader.height); infoHeader.planes = Shared::PlatformByteOrder::fromCommonEndian(infoHeader.planes); infoHeader.size = Shared::PlatformByteOrder::fromCommonEndian(infoHeader.size); infoHeader.sizeImage = Shared::PlatformByteOrder::fromCommonEndian(infoHeader.sizeImage); infoHeader.width = Shared::PlatformByteOrder::fromCommonEndian(infoHeader.width); infoHeader.xPelsPerMeter = Shared::PlatformByteOrder::fromCommonEndian(infoHeader.xPelsPerMeter); infoHeader.yPelsPerMeter = Shared::PlatformByteOrder::fromCommonEndian(infoHeader.yPelsPerMeter); } if(infoHeader.bitCount!=24){ throw megaglest_runtime_error(path+" is not a 24 bit bitmap",true); } int h= infoHeader.height; int w= infoHeader.width; int components= (ret->getComponents() == -1)?3:ret->getComponents(); const int fileComponents = 3; //std::cout << "BMP-Components: Pic: " << components << " old: " << (ret->getComponents()) << " File: " << 3 << std::endl; ret->init(w,h,components); uint8* pixels = ret->getPixels(); char buffer[4]; //BMP is padded to sizes of 4 const int padSize = (4 - (w*fileComponents)%4)%4; //Yeah, could be faster //std::cout << "Padsize = " << padSize; for (int y = 0, i = 0; y < h; ++y) { for (int x = 0; x < w; ++x, i+=components) { uint8 r, g, b; // in.read((char*)&b, 1); // if(bigEndianSystem == true) { // b = Shared::PlatformByteOrder::fromCommonEndian(b); // } // // in.read((char*)&g, 1); // if(bigEndianSystem == true) { // g = Shared::PlatformByteOrder::fromCommonEndian(g); // } // // in.read((char*)&r, 1); // if(bigEndianSystem == true) { // r = Shared::PlatformByteOrder::fromCommonEndian(r); // } uint8 bgr[3] = {0,0,0}; in.read((char*)&bgr[0], 3); b = bgr[0]; g = bgr[1]; r = bgr[2]; if(bigEndianSystem == true) { b = Shared::PlatformByteOrder::fromCommonEndian(b); g = Shared::PlatformByteOrder::fromCommonEndian(g); r = Shared::PlatformByteOrder::fromCommonEndian(r); } if (!in.good()) { return NULL; } switch(components){ case 1: pixels[i]= (r+g+b)/3; break; case 3: pixels[i]= r; pixels[i+1]= g; pixels[i+2]= b; break; case 4: pixels[i]= r; pixels[i+1]= g; pixels[i+2]= b; pixels[i+3]= 255; break; } } if (padSize) { in.read(buffer,padSize); } } /*for(int i = 0; i < w*h*components; ++i) { if (i%39 == 0) std::cout << std::endl; int first = pixels[i]/16; if (first < 10) std:: cout << first; else std::cout << (char)('A'+(first-10)); first = pixels[i]%16; if (first < 10) std:: cout << first; else std::cout << (char)('A'+(first-10)); std::cout << " "; }*/ return ret; } }} //end namespace