Files
glest-source/source/shared_lib/sources/graphics/TGAReader.cpp
2018-05-06 00:01:36 +02:00

376 lines
12 KiB
C++

// ==============================================================
// 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 "TGAReader.h"
#include "data_types.h"
#include "pixmap.h"
#include <stdexcept>
#include <iostream>
#include "util.h"
#include "leak_dumper.h"
using std::runtime_error;
namespace Shared {
namespace Graphics {
#pragma pack(push, 1)
/**Copied from pixmap.cpp*/
// =====================================================
// Information for reading the targa-file
// =====================================================
struct TargaFileHeader {
int8 idLength;
int8 colourMapType;
int8 dataTypeCode;
int16 colourMapOrigin;
int16 colourMapLength;
int8 colourMapDepth;
int16 xOrigin;
int16 yOrigin;
int16 width;
int16 height;
int8 bitsPerPixel;
int8 imageDescriptor;
};
#pragma pack(pop)
static const int tgaUncompressedRgb = 2;
static const int tgaUncompressedBw = 3;
// =====================================================
// class TGAReader
// =====================================================
/**Get Extension array, initialised*/
//static inline const string* getExtensionStrings() {
static inline std::vector<string> getExtensionStrings() {
//static const string extensions[] = {"tga", ""};
static std::vector<string> extensions;
if (extensions.empty() == true) {
extensions.push_back("tga");
}
return extensions;
}
TGAReader3D::TGAReader3D() : FileReader<Pixmap3D>(getExtensionStrings()) {
}
Pixmap3D* TGAReader3D::read(ifstream& in, const string& path, Pixmap3D* ret) const {
//printf("In [%s] line: %d\n",__FILE__,__LINE__);
// try {
if (GlobalStaticFlags::getIsNonGraphicalModeEnabled() == true) {
throw megaglest_runtime_error("Loading graphics in headless server mode not allowed!");
}
//read header
TargaFileHeader fileHeader;
in.read((char*) &fileHeader, sizeof(TargaFileHeader));
static bool bigEndianSystem = Shared::PlatformByteOrder::isBigEndian();
if (bigEndianSystem == true) {
fileHeader.bitsPerPixel = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.bitsPerPixel);
fileHeader.colourMapDepth = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.colourMapDepth);
fileHeader.colourMapLength = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.colourMapDepth);
fileHeader.colourMapOrigin = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.colourMapOrigin);
fileHeader.colourMapType = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.colourMapType);
fileHeader.dataTypeCode = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.dataTypeCode);
fileHeader.height = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.height);
fileHeader.idLength = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.idLength);
fileHeader.imageDescriptor = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.imageDescriptor);
fileHeader.width = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.width);
}
if (!in.good()) {
throw megaglest_runtime_error(path + " could not be read", true);
}
//check that we can load this tga file
if (fileHeader.idLength != 0) {
throw megaglest_runtime_error(path + ": id field is not 0", true);
}
if (fileHeader.dataTypeCode != tgaUncompressedRgb && fileHeader.dataTypeCode != tgaUncompressedBw) {
throw megaglest_runtime_error(path + ": only uncompressed BW and RGB targa images are supported", true);
}
//check bits per pixel
if (fileHeader.bitsPerPixel != 8 && fileHeader.bitsPerPixel != 24 && fileHeader.bitsPerPixel != 32) {
throw megaglest_runtime_error(path + ": only 8, 24 and 32 bit targa images are supported", true);
}
const int h = fileHeader.height;
const int w = fileHeader.width;
const int d = ret->getD();
const int slice = ret->getSlice();
const int fileComponents = fileHeader.bitsPerPixel / 8;
const int picComponents = (ret->getComponents() == -1) ? fileComponents : ret->getComponents();
//std::cout << "TGA-Components: Pic: " << picComponents << " old: " << (ret->getComponents()) << " File: " << fileComponents << " slice:" << ret->getSlice() << std::endl;
if (ret->getPixels() == NULL) {
ret->init(w, h, d, picComponents);
}
uint8* pixels = ret->getPixels();
if (slice > 0) {
pixels = &pixels[slice*w*h*picComponents];
}
//read file
for (int i = 0; i < h*w*picComponents; i += picComponents) {
uint8 r = 0, g = 0, b = 0, a = 0, l = 0;
if (fileComponents == 1) {
in.read((char*) &l, 1);
if (bigEndianSystem == true) {
l = Shared::PlatformByteOrder::fromCommonEndian(l);
}
r = l;
g = l;
b = l;
a = 255;
} else {
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);
}
if (fileComponents == 4) {
in.read((char*) &a, 1);
if (bigEndianSystem == true) {
a = Shared::PlatformByteOrder::fromCommonEndian(a);
}
} else {
a = 255;
}
l = (r + g + b) / 3;
}
//if (!in.good()) {
// return NULL;
//}
switch (picComponents) {
case 1:
pixels[i] = l;
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] = a;
break;
}
}
/*for(int i = 0; i < w*h*picComponents; ++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 << " ";
}*/
// }
// catch(exception& ex) {
// char szBuf[8096]="";
// snprintf(szBuf,8096,"Error in [%s] on line: %d msg: %s\n",extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,ex.what());
// throw megaglest_runtime_error(szBuf);
// }
return ret;
}
TGAReader::TGAReader() : FileReader<Pixmap2D>(getExtensionStrings()) {
}
Pixmap2D* TGAReader::read(ifstream& in, const string& path, Pixmap2D* ret) const {
//printf("In [%s] line: %d\n",__FILE__,__LINE__);
//try {
//read header
TargaFileHeader fileHeader;
in.read((char*) &fileHeader, sizeof(TargaFileHeader));
static bool bigEndianSystem = Shared::PlatformByteOrder::isBigEndian();
if (bigEndianSystem == true) {
fileHeader.bitsPerPixel = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.bitsPerPixel);
fileHeader.colourMapDepth = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.colourMapDepth);
fileHeader.colourMapLength = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.colourMapDepth);
fileHeader.colourMapOrigin = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.colourMapOrigin);
fileHeader.colourMapType = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.colourMapType);
fileHeader.dataTypeCode = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.dataTypeCode);
fileHeader.height = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.height);
fileHeader.idLength = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.idLength);
fileHeader.imageDescriptor = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.imageDescriptor);
fileHeader.width = Shared::PlatformByteOrder::fromCommonEndian(fileHeader.width);
}
if (!in.good()) {
throw megaglest_runtime_error(path + " could not be read", true);
}
//check that we can load this tga file
if (fileHeader.idLength != 0) {
throw megaglest_runtime_error(path + ": id field is not 0", true);
}
if (fileHeader.dataTypeCode != tgaUncompressedRgb && fileHeader.dataTypeCode != tgaUncompressedBw) {
throw megaglest_runtime_error(path + ": only uncompressed BW and RGB targa images are supported", true);
}
//check bits per pixel
if (fileHeader.bitsPerPixel != 8 && fileHeader.bitsPerPixel != 24 && fileHeader.bitsPerPixel != 32) {
throw megaglest_runtime_error(path + ": only 8, 24 and 32 bit targa images are supported", true);
}
const int h = fileHeader.height;
const int w = fileHeader.width;
const int fileComponents = fileHeader.bitsPerPixel / 8;
const int picComponents = (ret->getComponents() == -1) ? fileComponents : ret->getComponents();
//std::cout << "TGA-Components: Pic: " << picComponents << " old: " << (ret->getComponents()) << " File: " << fileComponents << std::endl;
ret->init(w, h, picComponents);
uint8* pixels = ret->getPixels();
//read file
for (int i = 0; i < h*w*picComponents; i += picComponents) {
uint8 r = 0, g = 0, b = 0, a = 0, l = 0;
if (fileComponents == 1) {
in.read((char*) &l, 1);
if (bigEndianSystem == true) {
l = Shared::PlatformByteOrder::fromCommonEndian(l);
}
r = l;
g = l;
b = l;
a = 255;
} else {
uint8 bgra[4] = { 0,0,0,0 };
in.read((char*) &bgra[0], fileComponents);
b = bgra[0];
g = bgra[1];
r = bgra[2];
a = 255;
if (fileComponents == 4) {
a = bgra[3];
}
if (bigEndianSystem == true) {
b = Shared::PlatformByteOrder::fromCommonEndian(b);
g = Shared::PlatformByteOrder::fromCommonEndian(g);
r = Shared::PlatformByteOrder::fromCommonEndian(r);
if (fileComponents == 4) {
a = Shared::PlatformByteOrder::fromCommonEndian(a);
}
}
// 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);
// }
//
// if(fileComponents==4){
// in.read((char*)&a, 1);
// if(bigEndianSystem == true) {
// a = Shared::PlatformByteOrder::fromCommonEndian(a);
// }
//
// }
// else {
// a= 255;
// }
l = (r + g + b) / 3;
}
if (!in.good()) {
return NULL;
}
switch (picComponents) {
case 1:
pixels[i] = l;
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] = a;
break;
}
}
/*for(int i = 0; i < w*h*picComponents; ++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 << " ";
}*/
// }
// catch(exception& ex) {
// //printf("In [%s] line: %d msf [%s]\n",__FILE__,__LINE__,ex.what());
// //abort();
// char szBuf[8096]="";
// snprintf(szBuf,8096,"Error in [%s] on line: %d msg: %s\n",extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,ex.what());
// throw megaglest_runtime_error(szBuf);
// }
//printf("In [%s] line: %d\n",__FILE__,__LINE__);
return ret;
}
}
} //end namespace