mirror of https://github.com/OpenTTD/OpenTTD
Codechange: Replace BmpBuffer with RandomAccessFile.
parent
719763dfcb
commit
cb23651f43
204
src/bmp.cpp
204
src/bmp.cpp
|
@ -8,92 +8,32 @@
|
||||||
/** @file bmp.cpp Read and write support for bmps. */
|
/** @file bmp.cpp Read and write support for bmps. */
|
||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
|
#include "random_access_file_type.h"
|
||||||
#include "bmp.h"
|
#include "bmp.h"
|
||||||
#include "core/bitmath_func.hpp"
|
#include "core/bitmath_func.hpp"
|
||||||
|
|
||||||
#include "safeguards.h"
|
#include "safeguards.h"
|
||||||
|
|
||||||
void BmpInitializeBuffer(BmpBuffer *buffer, FILE *file)
|
|
||||||
{
|
|
||||||
buffer->pos = -1;
|
|
||||||
buffer->file = file;
|
|
||||||
buffer->read = 0;
|
|
||||||
buffer->real_pos = ftell(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void AdvanceBuffer(BmpBuffer *buffer)
|
|
||||||
{
|
|
||||||
if (buffer->read < 0) return;
|
|
||||||
|
|
||||||
buffer->read = (int)fread(buffer->data, 1, BMP_BUFFER_SIZE, buffer->file);
|
|
||||||
buffer->pos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool EndOfBuffer(BmpBuffer *buffer)
|
|
||||||
{
|
|
||||||
if (buffer->read < 0) return false;
|
|
||||||
|
|
||||||
if (buffer->pos == buffer->read || buffer->pos < 0) AdvanceBuffer(buffer);
|
|
||||||
return buffer->pos == buffer->read;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint8_t ReadByte(BmpBuffer *buffer)
|
|
||||||
{
|
|
||||||
if (buffer->read < 0) return 0;
|
|
||||||
|
|
||||||
if (buffer->pos == buffer->read || buffer->pos < 0) AdvanceBuffer(buffer);
|
|
||||||
buffer->real_pos++;
|
|
||||||
return buffer->data[buffer->pos++];
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint16_t ReadWord(BmpBuffer *buffer)
|
|
||||||
{
|
|
||||||
uint16_t var = ReadByte(buffer);
|
|
||||||
return var | (ReadByte(buffer) << 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint32_t ReadDword(BmpBuffer *buffer)
|
|
||||||
{
|
|
||||||
uint32_t var = ReadWord(buffer);
|
|
||||||
return var | (ReadWord(buffer) << 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void SkipBytes(BmpBuffer *buffer, int bytes)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < bytes; i++) ReadByte(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void SetStreamOffset(BmpBuffer *buffer, int offset)
|
|
||||||
{
|
|
||||||
if (fseek(buffer->file, offset, SEEK_SET) < 0) {
|
|
||||||
buffer->read = -1;
|
|
||||||
}
|
|
||||||
buffer->pos = -1;
|
|
||||||
buffer->real_pos = offset;
|
|
||||||
AdvanceBuffer(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a 1 bpp uncompressed bitmap
|
* Reads a 1 bpp uncompressed bitmap
|
||||||
* The bitmap is converted to a 8 bpp bitmap
|
* The bitmap is converted to a 8 bpp bitmap
|
||||||
*/
|
*/
|
||||||
static inline bool BmpRead1(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
static inline bool BmpRead1(RandomAccessFile &file, BmpInfo &info, BmpData &data)
|
||||||
{
|
{
|
||||||
uint8_t pad = GB(4 - info.width / 8, 0, 2);
|
uint8_t pad = GB(4 - info.width / 8, 0, 2);
|
||||||
for (uint y = info.height; y > 0; y--) {
|
for (uint y = info.height; y > 0; y--) {
|
||||||
uint x = 0;
|
uint x = 0;
|
||||||
uint8_t *pixel_row = &data.bitmap[(y - 1) * static_cast<size_t>(info.width)];
|
uint8_t *pixel_row = &data.bitmap[(y - 1) * static_cast<size_t>(info.width)];
|
||||||
while (x < info.width) {
|
while (x < info.width) {
|
||||||
if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
|
if (file.AtEndOfFile()) return false; // the file is shorter than expected
|
||||||
uint8_t b = ReadByte(buffer);
|
uint8_t b = file.ReadByte();
|
||||||
for (uint i = 8; i > 0; i--) {
|
for (uint i = 8; i > 0; i--) {
|
||||||
if (x < info.width) *pixel_row++ = GB(b, i - 1, 1);
|
if (x < info.width) *pixel_row++ = GB(b, i - 1, 1);
|
||||||
x++;
|
x++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Padding for 32 bit align */
|
/* Padding for 32 bit align */
|
||||||
SkipBytes(buffer, pad);
|
file.SkipBytes(pad);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -102,15 +42,15 @@ static inline bool BmpRead1(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
||||||
* Reads a 4 bpp uncompressed bitmap
|
* Reads a 4 bpp uncompressed bitmap
|
||||||
* The bitmap is converted to a 8 bpp bitmap
|
* The bitmap is converted to a 8 bpp bitmap
|
||||||
*/
|
*/
|
||||||
static inline bool BmpRead4(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
static inline bool BmpRead4(RandomAccessFile &file, BmpInfo &info, BmpData &data)
|
||||||
{
|
{
|
||||||
uint8_t pad = GB(4 - info.width / 2, 0, 2);
|
uint8_t pad = GB(4 - info.width / 2, 0, 2);
|
||||||
for (uint y = info.height; y > 0; y--) {
|
for (uint y = info.height; y > 0; y--) {
|
||||||
uint x = 0;
|
uint x = 0;
|
||||||
uint8_t *pixel_row = &data.bitmap[(y - 1) * static_cast<size_t>(info.width)];
|
uint8_t *pixel_row = &data.bitmap[(y - 1) * static_cast<size_t>(info.width)];
|
||||||
while (x < info.width) {
|
while (x < info.width) {
|
||||||
if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
|
if (file.AtEndOfFile()) return false; // the file is shorter than expected
|
||||||
uint8_t b = ReadByte(buffer);
|
uint8_t b = file.ReadByte();
|
||||||
*pixel_row++ = GB(b, 4, 4);
|
*pixel_row++ = GB(b, 4, 4);
|
||||||
x++;
|
x++;
|
||||||
if (x < info.width) {
|
if (x < info.width) {
|
||||||
|
@ -119,7 +59,7 @@ static inline bool BmpRead4(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Padding for 32 bit align */
|
/* Padding for 32 bit align */
|
||||||
SkipBytes(buffer, pad);
|
file.SkipBytes(pad);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -128,16 +68,16 @@ static inline bool BmpRead4(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
||||||
* Reads a 4-bit RLE compressed bitmap
|
* Reads a 4-bit RLE compressed bitmap
|
||||||
* The bitmap is converted to a 8 bpp bitmap
|
* The bitmap is converted to a 8 bpp bitmap
|
||||||
*/
|
*/
|
||||||
static inline bool BmpRead4Rle(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
static inline bool BmpRead4Rle(RandomAccessFile &file, BmpInfo &info, BmpData &data)
|
||||||
{
|
{
|
||||||
uint x = 0;
|
uint x = 0;
|
||||||
uint y = info.height - 1;
|
uint y = info.height - 1;
|
||||||
uint8_t *pixel = &data.bitmap[y * static_cast<size_t>(info.width)];
|
uint8_t *pixel = &data.bitmap[y * static_cast<size_t>(info.width)];
|
||||||
while (y != 0 || x < info.width) {
|
while (y != 0 || x < info.width) {
|
||||||
if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
|
if (file.AtEndOfFile()) return false; // the file is shorter than expected
|
||||||
|
|
||||||
uint8_t n = ReadByte(buffer);
|
uint8_t n = file.ReadByte();
|
||||||
uint8_t c = ReadByte(buffer);
|
uint8_t c = file.ReadByte();
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 0: // end of line
|
case 0: // end of line
|
||||||
|
@ -150,9 +90,9 @@ static inline bool BmpRead4Rle(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case 2: { // delta
|
case 2: { // delta
|
||||||
if (EndOfBuffer(buffer)) return false;
|
if (file.AtEndOfFile()) return false;
|
||||||
uint8_t dx = ReadByte(buffer);
|
uint8_t dx = file.ReadByte();
|
||||||
uint8_t dy = ReadByte(buffer);
|
uint8_t dy = file.ReadByte();
|
||||||
|
|
||||||
/* Check for over- and underflow. */
|
/* Check for over- and underflow. */
|
||||||
if (x + dx >= info.width || x + dx < x || dy > y) return false;
|
if (x + dx >= info.width || x + dx < x || dy > y) return false;
|
||||||
|
@ -166,8 +106,8 @@ static inline bool BmpRead4Rle(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
||||||
default: { // uncompressed
|
default: { // uncompressed
|
||||||
uint i = 0;
|
uint i = 0;
|
||||||
while (i++ < c) {
|
while (i++ < c) {
|
||||||
if (EndOfBuffer(buffer) || x >= info.width) return false;
|
if (file.AtEndOfFile() || x >= info.width) return false;
|
||||||
uint8_t b = ReadByte(buffer);
|
uint8_t b = file.ReadByte();
|
||||||
*pixel++ = GB(b, 4, 4);
|
*pixel++ = GB(b, 4, 4);
|
||||||
x++;
|
x++;
|
||||||
if (i++ < c) {
|
if (i++ < c) {
|
||||||
|
@ -177,7 +117,7 @@ static inline bool BmpRead4Rle(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Padding for 16 bit align */
|
/* Padding for 16 bit align */
|
||||||
SkipBytes(buffer, ((c + 1) / 2) % 2);
|
file.SkipBytes(((c + 1) / 2) % 2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -202,15 +142,15 @@ static inline bool BmpRead4Rle(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
||||||
/**
|
/**
|
||||||
* Reads a 8 bpp bitmap
|
* Reads a 8 bpp bitmap
|
||||||
*/
|
*/
|
||||||
static inline bool BmpRead8(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
static inline bool BmpRead8(RandomAccessFile &file, BmpInfo &info, BmpData &data)
|
||||||
{
|
{
|
||||||
uint8_t pad = GB(4 - info.width, 0, 2);
|
uint8_t pad = GB(4 - info.width, 0, 2);
|
||||||
for (uint y = info.height; y > 0; y--) {
|
for (uint y = info.height; y > 0; y--) {
|
||||||
if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
|
if (file.AtEndOfFile()) return false; // the file is shorter than expected
|
||||||
uint8_t *pixel = &data.bitmap[(y - 1) * static_cast<size_t>(info.width)];
|
uint8_t *pixel = &data.bitmap[(y - 1) * static_cast<size_t>(info.width)];
|
||||||
for (uint i = 0; i < info.width; i++) *pixel++ = ReadByte(buffer);
|
for (uint i = 0; i < info.width; i++) *pixel++ = file.ReadByte();
|
||||||
/* Padding for 32 bit align */
|
/* Padding for 32 bit align */
|
||||||
SkipBytes(buffer, pad);
|
file.SkipBytes(pad);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -218,16 +158,16 @@ static inline bool BmpRead8(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
||||||
/**
|
/**
|
||||||
* Reads a 8-bit RLE compressed bpp bitmap
|
* Reads a 8-bit RLE compressed bpp bitmap
|
||||||
*/
|
*/
|
||||||
static inline bool BmpRead8Rle(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
static inline bool BmpRead8Rle(RandomAccessFile &file, BmpInfo &info, BmpData &data)
|
||||||
{
|
{
|
||||||
uint x = 0;
|
uint x = 0;
|
||||||
uint y = info.height - 1;
|
uint y = info.height - 1;
|
||||||
uint8_t *pixel = &data.bitmap[y * static_cast<size_t>(info.width)];
|
uint8_t *pixel = &data.bitmap[y * static_cast<size_t>(info.width)];
|
||||||
while (y != 0 || x < info.width) {
|
while (y != 0 || x < info.width) {
|
||||||
if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
|
if (file.AtEndOfFile()) return false; // the file is shorter than expected
|
||||||
|
|
||||||
uint8_t n = ReadByte(buffer);
|
uint8_t n = file.ReadByte();
|
||||||
uint8_t c = ReadByte(buffer);
|
uint8_t c = file.ReadByte();
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 0: // end of line
|
case 0: // end of line
|
||||||
|
@ -240,9 +180,9 @@ static inline bool BmpRead8Rle(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case 2: { // delta
|
case 2: { // delta
|
||||||
if (EndOfBuffer(buffer)) return false;
|
if (file.AtEndOfFile()) return false;
|
||||||
uint8_t dx = ReadByte(buffer);
|
uint8_t dx = file.ReadByte();
|
||||||
uint8_t dy = ReadByte(buffer);
|
uint8_t dy = file.ReadByte();
|
||||||
|
|
||||||
/* Check for over- and underflow. */
|
/* Check for over- and underflow. */
|
||||||
if (x + dx >= info.width || x + dx < x || dy > y) return false;
|
if (x + dx >= info.width || x + dx < x || dy > y) return false;
|
||||||
|
@ -255,12 +195,12 @@ static inline bool BmpRead8Rle(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
||||||
|
|
||||||
default: { // uncompressed
|
default: { // uncompressed
|
||||||
for (uint i = 0; i < c; i++) {
|
for (uint i = 0; i < c; i++) {
|
||||||
if (EndOfBuffer(buffer) || x >= info.width) return false;
|
if (file.AtEndOfFile() || x >= info.width) return false;
|
||||||
*pixel++ = ReadByte(buffer);
|
*pixel++ = file.ReadByte();
|
||||||
x++;
|
x++;
|
||||||
}
|
}
|
||||||
/* Padding for 16 bit align */
|
/* Padding for 16 bit align */
|
||||||
SkipBytes(buffer, c % 2);
|
file.SkipBytes(c % 2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -280,20 +220,20 @@ static inline bool BmpRead8Rle(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
||||||
/**
|
/**
|
||||||
* Reads a 24 bpp uncompressed bitmap
|
* Reads a 24 bpp uncompressed bitmap
|
||||||
*/
|
*/
|
||||||
static inline bool BmpRead24(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
static inline bool BmpRead24(RandomAccessFile &file, BmpInfo &info, BmpData &data)
|
||||||
{
|
{
|
||||||
uint8_t pad = GB(4 - info.width * 3, 0, 2);
|
uint8_t pad = GB(4 - info.width * 3, 0, 2);
|
||||||
for (uint y = info.height; y > 0; --y) {
|
for (uint y = info.height; y > 0; --y) {
|
||||||
uint8_t *pixel_row = &data.bitmap[(y - 1) * static_cast<size_t>(info.width) * 3];
|
uint8_t *pixel_row = &data.bitmap[(y - 1) * static_cast<size_t>(info.width) * 3];
|
||||||
for (uint x = 0; x < info.width; ++x) {
|
for (uint x = 0; x < info.width; ++x) {
|
||||||
if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
|
if (file.AtEndOfFile()) return false; // the file is shorter than expected
|
||||||
*(pixel_row + 2) = ReadByte(buffer); // green
|
*(pixel_row + 2) = file.ReadByte(); // green
|
||||||
*(pixel_row + 1) = ReadByte(buffer); // blue
|
*(pixel_row + 1) = file.ReadByte(); // blue
|
||||||
*pixel_row = ReadByte(buffer); // red
|
*pixel_row = file.ReadByte(); // red
|
||||||
pixel_row += 3;
|
pixel_row += 3;
|
||||||
}
|
}
|
||||||
/* Padding for 32 bit align */
|
/* Padding for 32 bit align */
|
||||||
SkipBytes(buffer, pad);
|
file.SkipBytes(pad);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -301,34 +241,34 @@ static inline bool BmpRead24(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
||||||
/*
|
/*
|
||||||
* Reads bitmap headers, and palette (if any)
|
* Reads bitmap headers, and palette (if any)
|
||||||
*/
|
*/
|
||||||
bool BmpReadHeader(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
bool BmpReadHeader(RandomAccessFile &file, BmpInfo &info, BmpData &data)
|
||||||
{
|
{
|
||||||
info = {};
|
info = {};
|
||||||
|
|
||||||
/* Reading BMP header */
|
/* Reading BMP header */
|
||||||
if (ReadWord(buffer) != 0x4D42) return false; // signature should be 'BM'
|
if (file.ReadWord() != 0x4D42) return false; // signature should be 'BM'
|
||||||
SkipBytes(buffer, 8); // skip file size and reserved
|
file.SkipBytes(8); // skip file size and reserved
|
||||||
info.offset = ReadDword(buffer);
|
info.offset = file.ReadDword() + file.GetStartPos();
|
||||||
|
|
||||||
/* Reading info header */
|
/* Reading info header */
|
||||||
uint32_t header_size = ReadDword(buffer);
|
uint32_t header_size = file.ReadDword();
|
||||||
if (header_size < 12) return false; // info header should be at least 12 bytes long
|
if (header_size < 12) return false; // info header should be at least 12 bytes long
|
||||||
|
|
||||||
info.os2_bmp = (header_size == 12); // OS/2 1.x or windows 2.x info header is 12 bytes long
|
info.os2_bmp = (header_size == 12); // OS/2 1.x or windows 2.x info header is 12 bytes long
|
||||||
|
|
||||||
if (info.os2_bmp) {
|
if (info.os2_bmp) {
|
||||||
info.width = ReadWord(buffer);
|
info.width = file.ReadWord();
|
||||||
info.height = ReadWord(buffer);
|
info.height = file.ReadWord();
|
||||||
header_size -= 8;
|
header_size -= 8;
|
||||||
} else {
|
} else {
|
||||||
info.width = ReadDword(buffer);
|
info.width = file.ReadDword();
|
||||||
info.height = ReadDword(buffer);
|
info.height = file.ReadDword();
|
||||||
header_size -= 12;
|
header_size -= 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ReadWord(buffer) != 1) return false; // BMP can have only 1 plane
|
if (file.ReadWord() != 1) return false; // BMP can have only 1 plane
|
||||||
|
|
||||||
info.bpp = ReadWord(buffer);
|
info.bpp = file.ReadWord();
|
||||||
if (info.bpp != 1 && info.bpp != 4 && info.bpp != 8 && info.bpp != 24) {
|
if (info.bpp != 1 && info.bpp != 4 && info.bpp != 8 && info.bpp != 24) {
|
||||||
/* Only 1 bpp, 4 bpp, 8bpp and 24 bpp bitmaps are supported */
|
/* Only 1 bpp, 4 bpp, 8bpp and 24 bpp bitmaps are supported */
|
||||||
return false;
|
return false;
|
||||||
|
@ -336,7 +276,7 @@ bool BmpReadHeader(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
||||||
|
|
||||||
/* Reads compression method if available in info header*/
|
/* Reads compression method if available in info header*/
|
||||||
if ((header_size -= 4) >= 4) {
|
if ((header_size -= 4) >= 4) {
|
||||||
info.compression = ReadDword(buffer);
|
info.compression = file.ReadDword();
|
||||||
header_size -= 4;
|
header_size -= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,9 +286,9 @@ bool BmpReadHeader(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
||||||
if (info.bpp <= 8) {
|
if (info.bpp <= 8) {
|
||||||
/* Reads number of colours if available in info header */
|
/* Reads number of colours if available in info header */
|
||||||
if (header_size >= 16) {
|
if (header_size >= 16) {
|
||||||
SkipBytes(buffer, 12); // skip image size and resolution
|
file.SkipBytes(12); // skip image size and resolution
|
||||||
info.palette_size = ReadDword(buffer); // number of colours in palette
|
info.palette_size = file.ReadDword(); // number of colours in palette
|
||||||
SkipBytes(buffer, header_size - 16); // skip the end of info header
|
file.SkipBytes(header_size - 16); // skip the end of info header
|
||||||
}
|
}
|
||||||
|
|
||||||
uint maximum_palette_size = 1U << info.bpp;
|
uint maximum_palette_size = 1U << info.bpp;
|
||||||
|
@ -360,37 +300,39 @@ bool BmpReadHeader(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
||||||
data.palette.resize(info.palette_size);
|
data.palette.resize(info.palette_size);
|
||||||
|
|
||||||
for (auto &colour : data.palette) {
|
for (auto &colour : data.palette) {
|
||||||
colour.b = ReadByte(buffer);
|
colour.b = file.ReadByte();
|
||||||
colour.g = ReadByte(buffer);
|
colour.g = file.ReadByte();
|
||||||
colour.r = ReadByte(buffer);
|
colour.r = file.ReadByte();
|
||||||
if (!info.os2_bmp) SkipBytes(buffer, 1); // unused
|
if (!info.os2_bmp) file.SkipBytes(1); // unused
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffer->real_pos <= info.offset;
|
return file.GetPos() <= info.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reads the bitmap
|
* Reads the bitmap
|
||||||
* 1 bpp and 4 bpp bitmaps are converted to 8 bpp bitmaps
|
* 1 bpp and 4 bpp bitmaps are converted to 8 bpp bitmaps
|
||||||
*/
|
*/
|
||||||
bool BmpReadBitmap(BmpBuffer *buffer, BmpInfo &info, BmpData &data)
|
bool BmpReadBitmap(RandomAccessFile &file, BmpInfo &info, BmpData &data)
|
||||||
{
|
{
|
||||||
data.bitmap.resize(static_cast<size_t>(info.width) * info.height * ((info.bpp == 24) ? 3 : 1));
|
data.bitmap.resize(static_cast<size_t>(info.width) * info.height * ((info.bpp == 24) ? 3 : 1));
|
||||||
|
|
||||||
/* Load image */
|
/* Load image */
|
||||||
SetStreamOffset(buffer, info.offset);
|
file.SeekTo(info.offset, SEEK_SET);
|
||||||
switch (info.compression) {
|
switch (info.compression) {
|
||||||
case 0: // no compression
|
case 0: // no compression
|
||||||
switch (info.bpp) {
|
switch (info.bpp) {
|
||||||
case 1: return BmpRead1(buffer, info, data);
|
case 1: return BmpRead1(file, info, data);
|
||||||
case 4: return BmpRead4(buffer, info, data);
|
case 4: return BmpRead4(file, info, data);
|
||||||
case 8: return BmpRead8(buffer, info, data);
|
case 8: return BmpRead8(file, info, data);
|
||||||
case 24: return BmpRead24(buffer, info, data);
|
case 24: return BmpRead24(file, info, data);
|
||||||
|
default: NOT_REACHED();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: return BmpRead8Rle(file, info, data); // 8-bit RLE compression
|
||||||
|
case 2: return BmpRead4Rle(file, info, data); // 4-bit RLE compression
|
||||||
default: NOT_REACHED();
|
default: NOT_REACHED();
|
||||||
}
|
|
||||||
case 1: return BmpRead8Rle(buffer, info, data); // 8-bit RLE compression
|
|
||||||
case 2: return BmpRead4Rle(buffer, info, data); // 4-bit RLE compression
|
|
||||||
default: NOT_REACHED();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
18
src/bmp.h
18
src/bmp.h
|
@ -11,9 +11,10 @@
|
||||||
#define BMP_H
|
#define BMP_H
|
||||||
|
|
||||||
#include "gfx_type.h"
|
#include "gfx_type.h"
|
||||||
|
#include "random_access_file_type.h"
|
||||||
|
|
||||||
struct BmpInfo {
|
struct BmpInfo {
|
||||||
uint32_t offset; ///< offset of bitmap data from .bmp file beginning
|
size_t offset; ///< offset of bitmap data from .bmp file beginning
|
||||||
uint32_t width; ///< bitmap width
|
uint32_t width; ///< bitmap width
|
||||||
uint32_t height; ///< bitmap height
|
uint32_t height; ///< bitmap height
|
||||||
bool os2_bmp; ///< true if OS/2 1.x or windows 2.x bitmap
|
bool os2_bmp; ///< true if OS/2 1.x or windows 2.x bitmap
|
||||||
|
@ -27,18 +28,7 @@ struct BmpData {
|
||||||
std::vector<uint8_t> bitmap;
|
std::vector<uint8_t> bitmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define BMP_BUFFER_SIZE 1024
|
bool BmpReadHeader(RandomAccessFile &file, BmpInfo &info, BmpData &data);
|
||||||
|
bool BmpReadBitmap(RandomAccessFile &file, BmpInfo &info, BmpData &data);
|
||||||
struct BmpBuffer {
|
|
||||||
uint8_t data[BMP_BUFFER_SIZE];
|
|
||||||
int pos;
|
|
||||||
int read;
|
|
||||||
FILE *file;
|
|
||||||
uint real_pos;
|
|
||||||
};
|
|
||||||
|
|
||||||
void BmpInitializeBuffer(BmpBuffer *buffer, FILE *file);
|
|
||||||
bool BmpReadHeader(BmpBuffer *buffer, BmpInfo &info, BmpData &data);
|
|
||||||
bool BmpReadBitmap(BmpBuffer *buffer, BmpInfo &info, BmpData &data);
|
|
||||||
|
|
||||||
#endif /* BMP_H */
|
#endif /* BMP_H */
|
||||||
|
|
|
@ -263,35 +263,29 @@ static void ReadHeightmapBMPImageData(std::span<uint8_t> map, const BmpInfo &inf
|
||||||
*/
|
*/
|
||||||
static bool ReadHeightmapBMP(const char *filename, uint *x, uint *y, std::vector<uint8_t> *map)
|
static bool ReadHeightmapBMP(const char *filename, uint *x, uint *y, std::vector<uint8_t> *map)
|
||||||
{
|
{
|
||||||
FILE *f;
|
BmpInfo info{};
|
||||||
BmpInfo info;
|
|
||||||
BmpData data{};
|
BmpData data{};
|
||||||
BmpBuffer buffer;
|
|
||||||
|
|
||||||
f = FioFOpenFile(filename, "rb", HEIGHTMAP_DIR);
|
if (!FioCheckFileExists(filename, HEIGHTMAP_DIR)) {
|
||||||
if (f == nullptr) {
|
|
||||||
ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_PNGMAP_FILE_NOT_FOUND, WL_ERROR);
|
ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_PNGMAP_FILE_NOT_FOUND, WL_ERROR);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BmpInitializeBuffer(&buffer, f);
|
RandomAccessFile file(filename, HEIGHTMAP_DIR);
|
||||||
|
|
||||||
if (!BmpReadHeader(&buffer, info, data)) {
|
if (!BmpReadHeader(file, info, data)) {
|
||||||
ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_BMPMAP_IMAGE_TYPE, WL_ERROR);
|
ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_BMPMAP_IMAGE_TYPE, WL_ERROR);
|
||||||
fclose(f);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsValidHeightmapDimension(info.width, info.height)) {
|
if (!IsValidHeightmapDimension(info.width, info.height)) {
|
||||||
ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_HEIGHTMAP_TOO_LARGE, WL_ERROR);
|
ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_HEIGHTMAP_TOO_LARGE, WL_ERROR);
|
||||||
fclose(f);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (map != nullptr) {
|
if (map != nullptr) {
|
||||||
if (!BmpReadBitmap(&buffer, info, data)) {
|
if (!BmpReadBitmap(file, info, data)) {
|
||||||
ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_BMPMAP_IMAGE_TYPE, WL_ERROR);
|
ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_BMPMAP_IMAGE_TYPE, WL_ERROR);
|
||||||
fclose(f);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,7 +296,6 @@ static bool ReadHeightmapBMP(const char *filename, uint *x, uint *y, std::vector
|
||||||
*x = info.width;
|
*x = info.width;
|
||||||
*y = info.height;
|
*y = info.height;
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue