Files @ r4381:c965d1f3016a
Branch filter:

Location: cpp/openttd-patchpack/source/bmp.c - annotation

belugas
(svn r6131) -Codechange : Complete all missing _ttdpatch_flags entries
-Feature : both unifiedmaglevmode are now set.
Maglev and monorail are not allowed to run on each other tracks and will not be.
Setting those flags will allow grfsets as the Norvegian one to be loaded
-Codechange : link the TTDPatch's irregularstations with OTTD's nonuniform_stations
-Codechange : Reformat the whole array (thanks Rubidium, it sure looks better now)
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4321:baa916e5dd65
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
r4300:642b2431578b
/* $Id$ */

#include "stdafx.h"
#include "openttd.h"
#include "gfx.h"
#include "bmp.h"
#include "macros.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)
{
	buffer->read = (int)fread(buffer->data, 1, BMP_BUFFER_SIZE, buffer->file);
	buffer->pos  = 0;
}

static inline bool EndOfBuffer(BmpBuffer *buffer)
{
	if (buffer->pos == buffer->read || buffer->pos < 0) AdvanceBuffer(buffer);
	return buffer->pos == buffer->read;
}

static inline byte ReadByte(BmpBuffer *buffer)
{
	if (buffer->pos == buffer->read || buffer->pos < 0) AdvanceBuffer(buffer);
	buffer->real_pos++;
	return buffer->data[buffer->pos++];
}

static inline uint16 ReadWord(BmpBuffer *buffer)
{
	uint16 var = ReadByte(buffer);
	return var | (ReadByte(buffer) << 8);
}

static inline uint32 ReadDword(BmpBuffer *buffer)
{
	uint32 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)
{
	fseek(buffer->file, offset, SEEK_SET);
	buffer->pos = -1;
	buffer->real_pos = offset;
	AdvanceBuffer(buffer);
}

/**
 * Reads a 1 bpp uncompressed bitmap
 * The bitmap is converted to a 8 bpp bitmap
 */
static inline bool BmpRead1(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
{
	uint x, y, i;
	byte pad = GB(4 - info->width / 8, 0, 2);
	byte *pixel_row;
	byte b;
	for (y = info->height; y > 0; y--) {
		x = 0;
		pixel_row = &data->bitmap[(y - 1) * info->width];
		while (x < info->width) {
			if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
			b = ReadByte(buffer);
			for (i = 8; i > 0; i--) {
				if (x < info->width) *pixel_row++ = GB(b, i - 1, 1);
				x++;
			}
		}
		/* Padding for 32 bit align */
		SkipBytes(buffer, pad);
	}
	return true;
}

/**
 * Reads a 4 bpp uncompressed bitmap
 * The bitmap is converted to a 8 bpp bitmap
 */
static inline bool BmpRead4(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
{
	uint x, y;
	byte pad = GB(4 - info->width / 2, 0, 2);
	byte *pixel_row;
	byte b;
	for (y = info->height; y > 0; y--) {
		x = 0;
		pixel_row = &data->bitmap[(y - 1) * info->width];
		while (x < info->width) {
			if (EndOfBuffer(buffer)) return false;  // the file is shorter than expected
			b = ReadByte(buffer);
			*pixel_row++ = GB(b, 4, 4);
			x++;
			if (x < info->width) {
				*pixel_row++ = GB(b, 0, 4);
				x++;
			}
		}
		/* Padding for 32 bit align */
		SkipBytes(buffer, pad);
	}
	return true;
}

/**
 * Reads a 4-bit RLE compressed bitmap
 * The bitmap is converted to a 8 bpp bitmap
 */
static inline bool BmpRead4Rle(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
{
	uint i;
	uint x = 0;
	uint y = info->height - 1;
	byte n, c, b;
	byte *pixel = &data->bitmap[y * info->width];
	while (y != 0 || x < info->width) {
		if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
		n = ReadByte(buffer);
		c = ReadByte(buffer);
		if (n == 0) {
			switch (c) {
			case 0: // end of line
				x = 0;
				pixel = &data->bitmap[--y * info->width];
				break;
			case 1: // end of bitmap
				x = info->width;
				y = 0;
				pixel = NULL;
				break;
			case 2: // delta
				x += ReadByte(buffer);
				i = ReadByte(buffer);
				if (x >= info->width || (y == 0 && i > 0)) return false;
				y -= i;
				pixel = &data->bitmap[y * info->width + x];
				break;
			default: // uncompressed
				i = 0;
				while (i++ < c) {
					if (EndOfBuffer(buffer) || x >= info->width) return false;
					b = ReadByte(buffer);
					*pixel++ = GB(b, 4, 4);
					x++;
					if (x < info->width && i++ < c) {
						*pixel++ = GB(b, 0, 4);
						x++;
					}
				}
				/* Padding for 16 bit align */
				SkipBytes(buffer, ((c + 1) / 2) % 2);
				break;
			}
		} else {
			i = 0;
			while (i++ < n) {
				if (EndOfBuffer(buffer) || x >= info->width) return false;
				*pixel++ = GB(c, 4, 4);
				x++;
				if (x < info->width && i++ < n) {
					*pixel++ = GB(c, 0, 4);
					x++;
				}
			}
		}
	}
	return true;
}

/**
 * Reads a 8 bpp bitmap
 */
static inline bool BmpRead8(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
{
	uint i;
	uint y;
	byte pad = GB(4 - info->width, 0, 2);
	byte *pixel;
	for (y = info->height; y > 0; y--) {
		if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
		pixel = &data->bitmap[(y - 1) * info->width];
		for (i = 0; i < info->width; i++) *pixel++ = ReadByte(buffer);
		/* Padding for 32 bit align */
		SkipBytes(buffer, pad);
	}
	return true;
}

/**
 * Reads a 8-bit RLE compressed bpp bitmap
 */
static inline bool BmpRead8Rle(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
{
	uint i;
	uint x = 0;
	uint y = info->height - 1;
	byte n, c;
	byte *pixel = &data->bitmap[y * info->width];
	while (y != 0 || x < info->width) {
		if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
		n = ReadByte(buffer);
		c = ReadByte(buffer);
		if (n == 0) {
			switch (c) {
			case 0: // end of line
				x = 0;
				pixel = &data->bitmap[--y * info->width];
				break;
			case 1: // end of bitmap
				x = info->width;
				y = 0;
				pixel = NULL;
				break;
			case 2: // delta
				x += ReadByte(buffer);
				i = ReadByte(buffer);
				if (x >= info->width || (y == 0 && i > 0)) return false;
				y -= i;
				pixel = &data->bitmap[y * info->width + x];
				break;
			default: // uncompressed
				if ((x += c) > info->width) return false;
				for (i = 0; i < c; i++) *pixel++ = ReadByte(buffer);
				/* Padding for 16 bit align */
				SkipBytes(buffer, c % 2);
				break;
			}
		} else {
			for (i = 0; i < n; i++) {
				if (x >= info->width) return false;
				*pixel++ = c;
				x++;
			}
		}
	}
	return true;
}

/**
 * Reads a 24 bpp uncompressed bitmap
 */
static inline bool BmpRead24(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
{
	uint x, y;
	byte pad = GB(4 - info->width * 3, 0, 2);
	byte *pixel_row;
	for (y = info->height; y > 0; y--) {
		pixel_row = &data->bitmap[(y - 1) * info->width * 3];
		for (x = 0; x < info->width; x++) {
			if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
			*(pixel_row + 2) = ReadByte(buffer); // green
			*(pixel_row + 1) = ReadByte(buffer); // blue
			*pixel_row       = ReadByte(buffer); // red
			pixel_row += 3;
		}
		/* Padding for 32 bit align */
		SkipBytes(buffer, pad);
	}
	return true;
}

/*
 * Reads bitmap headers, and palette (if any)
 */
bool BmpReadHeader(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
{
	uint32 header_size;
	assert(info != NULL);

	/* Reading BMP header */
	if (ReadWord(buffer) != 0x4D42) return false; // signature should be 'BM'
	SkipBytes(buffer, 8); // skip file size and reserved
	info->offset = ReadDword(buffer);

	/* Reading info header */
	header_size = ReadDword(buffer);
	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

	if (info->os2_bmp) {
		info->width = ReadWord(buffer);
		info->height = ReadWord(buffer);
		header_size -= 8;
	} else {
		info->width = ReadDword(buffer);
		info->height = ReadDword(buffer);
		header_size -= 12;
	}

	if (ReadWord(buffer) != 1) return false; // BMP can have only 1 plane

	info->bpp = ReadWord(buffer);
	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 */
		return false;
	}

	/* Reads compression method if available in info header*/
	if ((header_size -= 4) >= 4) {
		info->compression = ReadDword(buffer);
		header_size -= 4;
	}

	/* Only 4-bit and 8-bit rle compression is supported */
	if (info->compression > 2 || (info->compression > 0 && !(info->bpp == 4 || info->bpp == 8))) return false;

	if (info->bpp <= 8) {
		uint i;

		/* Reads number of colors if available in info header */
		if (header_size >= 16) {
			SkipBytes(buffer, 12);                  // skip image size and resolution
			info->palette_size = ReadDword(buffer); // number of colors in palette
			SkipBytes(buffer, header_size - 16);    // skip the end of info header
		}
		if (info->palette_size == 0) info->palette_size = 1 << info->bpp;

		data->palette = calloc(info->palette_size, sizeof(*(data->palette)));
		if (data->palette == NULL) return false;

		for (i = 0; i < info->palette_size; i++) {
			data->palette[i].b = ReadByte(buffer);
			data->palette[i].g = ReadByte(buffer);
			data->palette[i].r = ReadByte(buffer);
			if (!info->os2_bmp) SkipBytes(buffer, 1); // unused
		}
	}

	return buffer->real_pos <= info->offset;
}

/*
 * Reads the bitmap
 * 1 bpp and 4 bpp bitmaps are converted to 8 bpp bitmaps
 */
bool BmpReadBitmap(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
{
	assert(info != NULL && data != NULL);

	data->bitmap = calloc(info->width * info->height, ((info->bpp == 24) ? 3 : 1) * sizeof(byte));
	if (data->bitmap == NULL) return false;

	/* Load image */
	SetStreamOffset(buffer, info->offset);
	switch (info->compression) {
	case 0: // no compression
		switch (info->bpp) {
		case 1:  return BmpRead1(buffer, info, data);
		case 4:  return BmpRead4(buffer, info, data);
		case 8:  return BmpRead8(buffer, info, data);
		case 24: return BmpRead24(buffer, info, data);
		default: NOT_REACHED(); return false;
		}
	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(); return false;
	}
}

void BmpDestroyData(BmpData *data)
{
	assert(data != NULL);
	free(data->palette);
	free(data->bitmap);
}