⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bitmap.cpp

📁 3D数学基础:图形与游戏开发书籍源码,里面有很多实用的代码,对做3D的同志很有意义
💻 CPP
字号:
/////////////////////////////////////////////////////////////////////////////
//
// 3D Math Primer for Games and Graphics Development
//
// Bitmap.cpp - Simple bitmap loader
//
// Visit gamemath.com for the latest version of this file.
//
/////////////////////////////////////////////////////////////////////////////

#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "Bitmap.h"
#include "CommonStuff.h"
#include "Renderer.h"

/////////////////////////////////////////////////////////////////////////////
//
// Local stuff
//
/////////////////////////////////////////////////////////////////////////////

// File header for .TGA file

#pragma pack(1)

struct TGAHeader {
	unsigned char	imageIDLength;
	unsigned char	colorMapType;
	unsigned char	imageType;
	unsigned short	colorMapFirstIndex;
	unsigned short	colorMapLength;
	unsigned char	colorMapBitsPerEntry;
	unsigned short	xOrigin, yOrigin;
	unsigned short	width, height;
	unsigned char	bitsPerPixel;
	unsigned char	imageDescriptor;
};

#pragma pack()

/////////////////////////////////////////////////////////////////////////////
//
// class Bitmap member functions
//
/////////////////////////////////////////////////////////////////////////////

//---------------------------------------------------------------------------
// Bitmap::Bitmap
//
// Constructor - reset interval variables to default, empty state

Bitmap::Bitmap() {
	sizeX = 0;
	sizeY = 0;
	fmt = eFormat_None;
	data = NULL;
}

//---------------------------------------------------------------------------
// Bitmap::~Bitmap
//
// Destructor - make sure resources are freed

Bitmap::~Bitmap() {
	freeMemory();
}

//---------------------------------------------------------------------------
// Bitmap::allocateMemory
//
// Allocate a bitmap in the specified format

void	Bitmap::allocateMemory(int xs, int ys, EFormat format) {

	// Sanity check

	assert(xs > 0);
	assert(ys > 0);

	// First, free up anything already allocated

	freeMemory();

	// Figure out how big one row is, in bytes

	int	rowBytes;
	switch (format) {
		case eFormat_8888:
			rowBytes = xs*4;
			break;

		default:
			assert(false); // bogus pixel format
	}

	// Allocate memory

	data = malloc(ys * rowBytes);
	if (data == NULL) {
		ABORT("Out of memory for bitmap");
	}

	// Remember dimensions

	sizeX = xs;
	sizeY = ys;
	fmt = format;
}

//---------------------------------------------------------------------------
// Bitmap::freeMemory
//
// Allocate a bitmap in the specified format

void	Bitmap::freeMemory() {

	// Free memory, if some was allocated

	if (data != NULL) {
		free(data);
		data = NULL;
	}

	// Reset

	sizeX = 0;
	sizeY = 0;
	fmt = eFormat_None;
}

//---------------------------------------------------------------------------
// Bitmap::getPix
//
// Fetch a pixel at the given coordinates.  The pixel is always returned in
// 32-bit 0xAARRGGBB format, the same as used by the Renderer class
// and MAKE_ARGB macro.

unsigned	Bitmap::getPix(int x, int y) const {

	// Safety check

	if ((x < 0) || (y < 0) || (x >= sizeX) || (y >= sizeY) || (data == NULL)) {
		assert(false);
		return 0;
	}

	// Check format

	unsigned result;
	switch (fmt) {
		case eFormat_8888:
			result = ((unsigned *)data)[y*sizeX + x];
			break;

		default:
			assert(false);
			result = 0;
			break;
	}

	// Return it

	return result;
}

//---------------------------------------------------------------------------
// Bitmap::setPix
//
// Set a pixel at the given coordinates.  The pixel is specified in
// 32-bit 0xAARRGGBB format, the same as used by the Renderer class
// and MAKE_ARGB macro.

void	Bitmap::setPix(int x, int y, unsigned argb) {

	// Safety check

	if ((x < 0) || (y < 0) || (x >= sizeX) || (y >= sizeY) || (data == NULL)) {
		assert(false);
		return;
	}

	// Check format

	switch (fmt) {
		case eFormat_8888:
			((unsigned *)data)[y*sizeX + x] = argb;
			break;

		default:
			assert(false);
			break;
	}
}

//---------------------------------------------------------------------------
// Bitmap::load
//
// Load a bitmap from an image file.  Uses the extension to
// figure out how to load.

bool	Bitmap::load(const char *filename, char *returnErrMsg) {

	// Free up anything already allocated

	freeMemory();

	// Fetch extension.  I wish I could use the _splitpath function,
	// but it's not cross-platform.  I'll parse the thing myself.

	const char *ext = strchr(filename, '.');
	if (ext == NULL) {
		strcpy(returnErrMsg, "Filename has no extension");
		return false;
	}
	for (;;) {
		const char *dot = strchr(ext+1, '.');
		if (dot == NULL) {
			break;
		}
		ext = dot;
	}

	// Check for known extensions

	if (stricmp(ext, ".tga") == 0) {
		return loadTGA(filename, returnErrMsg);
	}
	if (stricmp(ext, ".bmp") == 0) {
		return loadBMP(filename, returnErrMsg);
	}

	// Unknown extension

	sprintf(returnErrMsg, "Unknown/unsupported file extension '%s'", ext);
	return false;
}

//---------------------------------------------------------------------------
// Bitmap::loadTGA
//
// Load image in .TGA format.

bool	Bitmap::loadTGA(const char *filename, char *returnErrMsg) {

	// Open the file

	FILE *f = fopen(filename, "rb");
	if (f == NULL) {
		strcpy(returnErrMsg, "Can't open file.");
failed:

		// Cleanup

		freeMemory();
		if (f != NULL) {
			fclose(f);
		}

		// Report failure

		return false;
	}

	// Read TGA header

	TGAHeader	head;
	if (fread(&head, sizeof(head), 1, f) != 1) {
ioError:
		strcpy(returnErrMsg, "I/O error, or file is corrupt.");
		goto failed;
	}

	// Check format

	if (head.imageType == 2) { // UNCOMPRESSED_TRUECOLOR
		if ((head.bitsPerPixel != 24) && (head.bitsPerPixel != 32)) {
			sprintf(returnErrMsg, "%d-bit truecolor image not supported", (int)head.bitsPerPixel);
			goto failed;
		}
		if (head.colorMapType != 0) {
			strcpy(returnErrMsg, "Truecolor image with colormap not supported");
			goto failed;
		}
	//} else if (head.imageType == 1) { // UNCOMPRESSED_COLORMAPPED
	//	if (
	//		(head.colorMapType != 1) ||
	//		(head.bitsPerPixel != 8) ||
	//		(head.colorMapFirstIndex != 0) ||
	//		(head.colorMapLength != 256) ||
	//		(head.colorMapBitsPerEntry != 24)
	//	) {
	//		strcpy(returnErrMsg, "Invalid colormapped image file format");
	//		return 0;
	//	}
	} else {
		sprintf(returnErrMsg, ".TGA image type %d not supported", (int)head.imageType);
		goto failed;
	}

	// Check origin

	assert(!(head.imageDescriptor & 0x10)); // x origin at the right not supported

	// Allocate image of the correct size

	allocateMemory(head.width, head.height, eFormat_8888);

	// Read the image data, in file order

	int	rowSz = head.bitsPerPixel / 8 * sizeX;
	for (int y = 0 ; y < sizeY ; ++y) {

		// Figure out which row this is in the image.
		// TGA's can be stored "upside down"

		int	dy;
		if (head.imageDescriptor & 0x20) {
			dy = y;
		} else {
			dy = sizeY - y - 1;
		}

		// Get shortcut pointer to first pixel in the row

		unsigned *destPtr = (unsigned *)data + dy*sizeX;

		// Read in the data for this row

		for (int x = 0 ; x < sizeX ; ++x) {
			int b = fgetc(f);
			int g = fgetc(f);
			int r = fgetc(f);
			int a;
			if (head.bitsPerPixel == 24) {
				a = 255;
			} else {
				a = fgetc(f);
			}
			if (b < 0 || g < 0 || r < 0 || a < 0) {
				goto ioError;
			}
			*destPtr = MAKE_ARGB(a, r, g, b);
			++destPtr;
		}
	}

	// OK

	fclose(f);
	return true;
}

//---------------------------------------------------------------------------
// Bitmap::loadBMP
//
// Load image in .BMP format.

bool	Bitmap::loadBMP(const char *filename, char *returnErrMsg) {

	// Free up anything already allocated

	freeMemory();

	// !FIXME!

	assert(false);
	strcpy(returnErrMsg, "BMP support not implemented yet");
	return false;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -