Updates for bazel on windows.
This commit is contained in:
349
bmp.cpp
349
bmp.cpp
@@ -17,18 +17,24 @@
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include <cstdio>
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <OpenGL/gl.h>
|
||||
|
||||
// clang-format off
|
||||
#include "bmp.h"
|
||||
#ifdef WIN32
|
||||
#pragma warning(disable : 4996)
|
||||
#endif
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include "Logger.h"
|
||||
#include "opengl.h"
|
||||
|
||||
// clang-format on
|
||||
|
||||
namespace OpenArena {
|
||||
namespace {
|
||||
using std::make_shared;
|
||||
using std::shared_ptr;
|
||||
using std::string;
|
||||
using std::to_string;
|
||||
} // End namespace
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
@@ -65,184 +71,187 @@ struct BITMAP_QUAD {
|
||||
|
||||
#define BITMAP_MAGIC 19778
|
||||
|
||||
uint16_t SwapBytes(uint16_t value) {
|
||||
return ((value & 0xFF00) >> 8) | ((value & 0x00FF) << 8);
|
||||
}
|
||||
|
||||
uint32_t SwapBytes(uint32_t value) {
|
||||
return ((value & 0xFF000000) >> 24) | ((value & 0x00FF0000) >> 8) | ((value & 0x0000FF00) << 8)
|
||||
| ((value & 0x000000FF) << 24);
|
||||
}
|
||||
|
||||
void PrintBMPHeader(BITMAP_HEADER header) {
|
||||
printf("Header\n");
|
||||
printf("Type: %X\nSize: %X\nReserved1: %X\nReserved2: %X\nOffset:%X\n",
|
||||
header.type,
|
||||
header.size,
|
||||
header.reserved1,
|
||||
header.reserved2,
|
||||
header.offset);
|
||||
printf("Type: %X\nSize: %X\nReserved1: %X\nReserved2: %X\nOffset:%X\n", header.type, header.size, header.reserved1,
|
||||
header.reserved2, header.offset);
|
||||
}
|
||||
|
||||
void PrintBMPInfo(BITMAP_INFO info) {
|
||||
printf("Info\n");
|
||||
printf("Size: %X\nWidth: %X\nHeight:%X\n", info.size, info.width, info.height);
|
||||
printf("Planes: %X\nBitCount: %X\nCompression: %X\n", info.planes, info.bitCount, info.compression);
|
||||
printf(
|
||||
"SizeImage: %X\nXPelsPerMeter: %X\nYPelsPerMeter: %X\n", info.sizeImage, info.xPelsPerMeter, info.yPelsPerMeter);
|
||||
printf("SizeImage: %X\nXPelsPerMeter: %X\nYPelsPerMeter: %X\n", info.sizeImage, info.xPelsPerMeter,
|
||||
info.yPelsPerMeter);
|
||||
printf("ClrUsed: %X\nClrImportant: %X\n", info.clrUsed, info.clrImportant);
|
||||
}
|
||||
|
||||
TextureImage* LoadBMP(const char* fn) {
|
||||
// If anything is not perfect return NULL after cleaning up our mess
|
||||
BitmapImage::~BitmapImage() {}
|
||||
|
||||
FILE* f = NULL; // A pointer to our file structure
|
||||
shared_ptr<BitmapImage> BitmapImage::FromFile(string filename) {
|
||||
const string method_name = "OpenArena::BitmapImage::FromFile(string) ";
|
||||
// TODO: Switch to fstream later.
|
||||
FILE* file = nullptr;
|
||||
|
||||
// If our filename is null
|
||||
if (!fn) {
|
||||
return NULL;
|
||||
Logger::LogDebug("In " + method_name);
|
||||
|
||||
// If anything is not perfect return null after cleaning up our mess.
|
||||
|
||||
// If our filename is empty return null.
|
||||
if (filename.empty()) {
|
||||
Logger::LogError(method_name + "filename is empty");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Logger::LogDebug(method_name + "filename is " + filename);
|
||||
|
||||
// TODO: If our filename doesn't exist return null.
|
||||
|
||||
// Try to open our file and if successfull...
|
||||
|
||||
f = fopen(fn, "rb");
|
||||
if (f) {
|
||||
BITMAP_HEADER bmpHeader;
|
||||
BITMAP_INFO bmpInfo;
|
||||
BITMAP_QUAD* bmpPallette = NULL;
|
||||
uint32_t palletteEntries = 0;
|
||||
|
||||
fread(&bmpHeader, sizeof(bmpHeader), 1, f);
|
||||
uint8_t t[2] = {1, 0};
|
||||
if (*((short*)t) != 1) {
|
||||
// If big endian reorder bytes
|
||||
bmpHeader.type = ((bmpHeader.type & 0xff00) >> 8) | ((bmpHeader.type & 0x00ff) << 8);
|
||||
bmpHeader.size = (bmpHeader.size & 0xff000000) >> 24 | (bmpHeader.size & 0x00ff0000) >> 8
|
||||
| (bmpHeader.size & 0x0000ff00) << 8 | (bmpHeader.size & 0x000000ff) << 24;
|
||||
bmpHeader.reserved1 = ((bmpHeader.reserved1 & 0xff00) >> 8) | ((bmpHeader.reserved1 & 0x00ff) << 8);
|
||||
bmpHeader.reserved2 = ((bmpHeader.reserved2 & 0xff00) >> 8) | ((bmpHeader.reserved2 & 0x00ff) << 8);
|
||||
bmpHeader.offset = (bmpHeader.offset & 0xff000000) >> 24 | (bmpHeader.offset & 0x00ff0000) >> 8
|
||||
| (bmpHeader.offset & 0x0000ff00) << 8 | (bmpHeader.offset & 0x000000ff) << 24;
|
||||
}
|
||||
|
||||
fread(&bmpInfo, sizeof(bmpInfo), 1, f);
|
||||
if (*((short*)t) != 1) {
|
||||
// If big endian reorder bytes
|
||||
bmpInfo.size = (bmpInfo.size & 0xff000000) >> 24 | (bmpInfo.size & 0x00ff0000) >> 8
|
||||
| (bmpInfo.size & 0x0000ff00) << 8 | (bmpInfo.size & 0x000000ff) << 24;
|
||||
bmpInfo.width = (bmpInfo.width & 0xff000000) >> 24 | (bmpInfo.width & 0x00ff0000) >> 8
|
||||
| (bmpInfo.width & 0x0000ff00) << 8 | (bmpInfo.width & 0x000000ff) << 24;
|
||||
bmpInfo.height = (bmpInfo.height & 0xff000000) >> 24 | (bmpInfo.height & 0x00ff0000) >> 8
|
||||
| (bmpInfo.height & 0x0000ff00) << 8 | (bmpInfo.height & 0x000000ff) << 24;
|
||||
bmpInfo.planes = ((bmpInfo.planes & 0xff00) >> 8) | ((bmpInfo.planes & 0x00ff) << 8);
|
||||
bmpInfo.bitCount = ((bmpInfo.bitCount & 0xff00) >> 8) | ((bmpInfo.bitCount & 0x00ff) << 8);
|
||||
bmpInfo.compression = (bmpInfo.compression & 0xff000000) >> 24 | (bmpInfo.compression & 0x00ff0000) >> 8
|
||||
| (bmpInfo.compression & 0x0000ff00) << 8 | (bmpInfo.compression & 0x000000ff) << 24;
|
||||
bmpInfo.sizeImage = (bmpInfo.sizeImage & 0xff000000) >> 24 | (bmpInfo.sizeImage & 0x00ff0000) >> 8
|
||||
| (bmpInfo.sizeImage & 0x0000ff00) << 8 | (bmpInfo.sizeImage & 0x000000ff) << 24;
|
||||
bmpInfo.xPelsPerMeter = (bmpInfo.xPelsPerMeter & 0xff000000) >> 24 | (bmpInfo.xPelsPerMeter & 0x00ff0000) >> 8
|
||||
| (bmpInfo.xPelsPerMeter & 0x0000ff00) << 8 | (bmpInfo.xPelsPerMeter & 0x000000ff) << 24;
|
||||
bmpInfo.yPelsPerMeter = (bmpInfo.yPelsPerMeter & 0xff000000) >> 24 | (bmpInfo.yPelsPerMeter & 0x00ff0000) >> 8
|
||||
| (bmpInfo.yPelsPerMeter & 0x0000ff00) << 8 | (bmpInfo.yPelsPerMeter & 0x000000ff) << 24;
|
||||
bmpInfo.clrUsed = (bmpInfo.clrUsed & 0xff000000) >> 24 | (bmpInfo.clrUsed & 0x00ff0000) >> 8
|
||||
| (bmpInfo.clrUsed & 0x0000ff00) << 8 | (bmpInfo.clrUsed & 0x000000ff) << 24;
|
||||
bmpInfo.clrImportant = (bmpInfo.clrImportant & 0xff000000) >> 24 | (bmpInfo.clrImportant & 0x00ff0000) >> 8
|
||||
| (bmpInfo.clrImportant & 0x0000ff00) << 8 | (bmpInfo.clrImportant & 0x000000ff) << 24;
|
||||
}
|
||||
|
||||
if (bmpInfo.width < 0) {
|
||||
// This needs to be abstracted somehow
|
||||
#ifdef WIN32
|
||||
MessageBox(NULL, "Image width is negative", "ERROR", MB_OK);
|
||||
#endif
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bmpInfo.width % 4 != 0) {
|
||||
// This needs to be abstracted somehow
|
||||
#ifdef WIN32
|
||||
MessageBox(NULL, "Image width must be a multiple of 8", "ERROR", MB_OK);
|
||||
#endif
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bmpInfo.height < 0) {
|
||||
// This needs to be abstracted somehow
|
||||
#ifdef WIN32
|
||||
MessageBox(NULL, "Image height is negative", "ERROR", MB_OK);
|
||||
#endif
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bmpInfo.height % 4 != 0) {
|
||||
// This needs to be abstracted somehow
|
||||
#ifdef WIN32
|
||||
MessageBox(NULL, "Image height must be a multiple of 8", "ERROR", MB_OK);
|
||||
#endif
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((bmpInfo.bitCount != 8 && bmpInfo.bitCount != 24) || bmpInfo.compression != 0) {
|
||||
// This needs to be abstracted somehow
|
||||
#ifdef WIN32
|
||||
MessageBox(NULL,
|
||||
"Only 8 and 24 bit uncompressed windows bmp files are "
|
||||
"currently supported",
|
||||
"ERROR",
|
||||
MB_OK);
|
||||
#endif
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Allocate memory for a TextureImage structure
|
||||
TextureImage* tex = new TextureImage;
|
||||
tex->sizeX = bmpInfo.width;
|
||||
tex->sizeY = bmpInfo.height;
|
||||
if (bmpInfo.bitCount >= 8) {
|
||||
tex->bpp = bmpInfo.bitCount >> 3;
|
||||
}
|
||||
tex->type = GL_RGB;
|
||||
uint32_t pixels = tex->sizeX * tex->sizeY;
|
||||
uint32_t bytes = pixels * tex->bpp;
|
||||
tex->data = new uint8_t[bytes];
|
||||
|
||||
if (bmpInfo.bitCount == 8) {
|
||||
// Load the pallette
|
||||
palletteEntries = bmpInfo.bitCount << 8;
|
||||
bmpPallette = new BITMAP_QUAD[palletteEntries];
|
||||
fread(bmpPallette, sizeof(BITMAP_QUAD), palletteEntries, f);
|
||||
}
|
||||
|
||||
fseek(f, bmpHeader.offset, SEEK_SET);
|
||||
fread(tex->data, bytes, 1, f);
|
||||
|
||||
if (bmpInfo.bitCount == 8) {
|
||||
// Apply the pallette
|
||||
uint8_t* image = tex->data;
|
||||
tex->bpp = 24;
|
||||
bytes = pixels * tex->bpp;
|
||||
tex->data = new uint8_t[bytes];
|
||||
|
||||
uint32_t i;
|
||||
uint32_t i2;
|
||||
for (i = 0; i < pixels; i++) {
|
||||
i2 = (i << 1) + 1;
|
||||
// Should make sure image[i] < palletteEntries
|
||||
tex->data[i2] = bmpPallette[image[i]].red;
|
||||
tex->data[i2 + 1] = bmpPallette[image[i]].blue;
|
||||
tex->data[i2 + 2] = bmpPallette[image[i]].green;
|
||||
}
|
||||
|
||||
delete[] image;
|
||||
image = NULL;
|
||||
} else if (bmpInfo.bitCount == 24) {
|
||||
uint32_t i;
|
||||
uint8_t t;
|
||||
|
||||
for (i = 0; i < bytes; i += 3) {
|
||||
t = tex->data[i];
|
||||
tex->data[i] = tex->data[i + 2];
|
||||
tex->data[i + 2] = t;
|
||||
}
|
||||
}
|
||||
return tex;
|
||||
fopen_s(&file, filename.c_str(), "rb");
|
||||
if (file == nullptr) {
|
||||
Logger::LogError(method_name + "unable to open file " + filename);
|
||||
return nullptr;
|
||||
}
|
||||
return NULL;
|
||||
Logger::LogDebug(method_name + "opened file with handle " + to_string((uint64_t)file));
|
||||
BITMAP_HEADER bmpHeader;
|
||||
BITMAP_INFO bmpInfo;
|
||||
BITMAP_QUAD* bmpPallette = nullptr;
|
||||
uint32_t palletteEntries = 0;
|
||||
|
||||
if (fread(&bmpHeader, sizeof(bmpHeader), 1, file) != 1) {
|
||||
Logger::LogError(method_name + "Failed to read bitmap header.");
|
||||
fclose(file);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// TODO: Come up with a better endianness check.
|
||||
uint8_t t[2] = {1, 0};
|
||||
if (*((short*)t) != 1) {
|
||||
// If big endian reorder bytes.
|
||||
bmpHeader.type = SwapBytes(bmpHeader.type);
|
||||
bmpHeader.size = SwapBytes(bmpHeader.size);
|
||||
bmpHeader.reserved1 = SwapBytes(bmpHeader.reserved1);
|
||||
bmpHeader.reserved2 = SwapBytes(bmpHeader.reserved2);
|
||||
bmpHeader.offset = SwapBytes(bmpHeader.offset);
|
||||
}
|
||||
|
||||
if (fread(&bmpInfo, sizeof(bmpInfo), 1, file) != 1) {
|
||||
Logger::LogError(method_name + "Unable to read BITMAP_INFO.");
|
||||
fclose(file);
|
||||
return nullptr;
|
||||
}
|
||||
if (*((short*)t) != 1) {
|
||||
// If big endian reorder bytes.
|
||||
bmpInfo.size = SwapBytes(bmpInfo.size);
|
||||
bmpInfo.width = SwapBytes(bmpInfo.width);
|
||||
bmpInfo.height = SwapBytes(bmpInfo.height);
|
||||
bmpInfo.planes = SwapBytes(bmpInfo.planes);
|
||||
bmpInfo.bitCount = SwapBytes(bmpInfo.bitCount);
|
||||
bmpInfo.compression = SwapBytes(bmpInfo.compression);
|
||||
bmpInfo.sizeImage = SwapBytes(bmpInfo.sizeImage);
|
||||
bmpInfo.xPelsPerMeter = SwapBytes(bmpInfo.xPelsPerMeter);
|
||||
bmpInfo.yPelsPerMeter = SwapBytes(bmpInfo.yPelsPerMeter);
|
||||
bmpInfo.clrUsed = SwapBytes(bmpInfo.clrUsed);
|
||||
bmpInfo.clrImportant = SwapBytes(bmpInfo.clrImportant);
|
||||
}
|
||||
|
||||
if (bmpInfo.width < 0) {
|
||||
Logger::LogError("Image width is negative.");
|
||||
fclose(file);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (bmpInfo.width % 4 != 0) {
|
||||
Logger::LogError("Image width must be a multiple of 8.");
|
||||
fclose(file);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (bmpInfo.height < 0) {
|
||||
Logger::LogError("Image height is negative.");
|
||||
fclose(file);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (bmpInfo.height % 4 != 0) {
|
||||
Logger::LogError("Image height must be a multiple of 8.");
|
||||
fclose(file);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ((bmpInfo.bitCount != 8 && bmpInfo.bitCount != 24) || bmpInfo.compression != 0) {
|
||||
Logger::LogError("Only 8 and 24 bit uncompressed windows bmp files are currently supported.");
|
||||
fclose(file);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Allocate memory for our image data.
|
||||
shared_ptr<BitmapImage> bmp = make_shared<BitmapImage>();
|
||||
bmp->size_x_ = bmpInfo.width;
|
||||
bmp->size_y_ = bmpInfo.height;
|
||||
bmp->bpp_ = bmpInfo.bitCount;
|
||||
int bytes_per_pixel = bmp->bpp_ / 8;
|
||||
bmp->type_ = Type::RGB;
|
||||
int num_pixels = bmp->size_x_ * bmp->size_y_;
|
||||
int num_bytes = num_pixels * bytes_per_pixel;
|
||||
Logger::LogDebug("allocating " + to_string(num_bytes) + " bytes for pixel data");
|
||||
bmp->data_ = shared_ptr<uint8_t[]>(new uint8_t[num_bytes]);
|
||||
if (bmpInfo.bitCount == 8) {
|
||||
Logger::LogDebug("image has a pallette");
|
||||
// Load the pallette
|
||||
palletteEntries = bmpInfo.bitCount << 8;
|
||||
bmpPallette = new BITMAP_QUAD[palletteEntries];
|
||||
if (fread(bmpPallette, sizeof(BITMAP_QUAD), palletteEntries, file) != palletteEntries) {
|
||||
Logger::LogError(method_name + "Wrong number of pallette entries read.");
|
||||
fclose(file);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
Logger::LogDebug("Loading bitmap data from file.");
|
||||
fseek(file, bmpHeader.offset, SEEK_SET);
|
||||
if (fread(bmp->data_.get(), num_bytes, 1, file) != 1) {
|
||||
Logger::LogError(method_name + "Failed to read the expected number of pixels from the file.");
|
||||
fclose(file);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Logger::LogDebug("Processing image data.");
|
||||
if (bmpInfo.bitCount == 8) {
|
||||
// Apply the pallette
|
||||
shared_ptr<uint8_t[]> image = bmp->data_;
|
||||
bmp->bpp_ = 24;
|
||||
bytes_per_pixel = bmp->bpp_ / 8;
|
||||
num_bytes = num_pixels * bytes_per_pixel;
|
||||
bmp->data_ = shared_ptr<uint8_t[]>(new uint8_t[num_bytes]);
|
||||
uint32_t i;
|
||||
uint32_t i2;
|
||||
for (i = 0; i < num_pixels; i++) {
|
||||
i2 = (i << 1) + 1;
|
||||
// Should make sure image[i] < palletteEntries
|
||||
bmp->data_[i2] = bmpPallette[image[i]].red;
|
||||
bmp->data_[i2 + 1] = bmpPallette[image[i]].blue;
|
||||
bmp->data_[i2 + 2] = bmpPallette[image[i]].green;
|
||||
}
|
||||
image = nullptr;
|
||||
} else if (bmpInfo.bitCount == 24) {
|
||||
uint32_t i;
|
||||
uint8_t t;
|
||||
for (i = 0; i < num_bytes; i += 3) {
|
||||
t = bmp->data_[i];
|
||||
bmp->data_[i] = bmp->data_[i + 2];
|
||||
bmp->data_[i + 2] = t;
|
||||
}
|
||||
}
|
||||
return bmp;
|
||||
}
|
||||
}; // End namespace OpenArena
|
||||
|
||||
Reference in New Issue
Block a user