1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
|
// ==============================================================
// 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 <stdexcept>
#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<string> getExtensionsBmp() {
//static const string extensions[] = {"bmp", ""};
static std::vector<string> extensions;
if(extensions.empty() == true) {
extensions.push_back("bmp");
}
return extensions;
}
// =====================================================
// class BMPReader
// =====================================================
BMPReader::BMPReader(): FileReader<Pixmap2D>(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 <code>NULL</code> if the Pixmap2D could not be read, else the pixmap*/
Pixmap2D* BMPReader::read(ifstream& in, const string& path, Pixmap2D* ret) const {
if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == true) {
throw megaglest_runtime_error("Loading graphics in headless server mode not allowed!");
}
//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
|