/*
	ZBitmap.hpp
	Author: Chris Ertel <crertel@762studios.com>,
			James Russell <jcrussell@762studios.com>
	Created: 12/09/2010

	Purpose:	
	
	Bitmap metadata class. This is designed as a metadata package for the data, and
	does not assume ownership of the data.  By passing around a ZBitmap instead of a raw 
	pointer to byte data we always have metadata about the byte data on hand.

	License:

	TODO
*/

#pragma once

#ifndef _ZBITMAP_H
#define _ZBITMAP_H

#include <ZUtil/ZUtilBuild.hpp>

//This is the format of the bitmap, which describes color layout and bits per channel
enum ZBitmapFormat
{
	ZBF_UNKNOWN,	//Unknown Format (usually uninitialized)

	ZBF_R8,			//8-bit Red Channel
	ZBF_R8I,		//8-bit Signed Red Channel
	ZBF_R16,		//16-bit Red Channel
	ZBF_R16I,		//16-bit Signed Red Channel
	ZBF_R32,		//32-bit Red Channel
	ZBF_R32I,		//32-bit Signed Red Channel
	ZBF_R32F,		//32-bit Floating Point Red Channel

	ZBF_RG8,		//8-bit Red, Green Channel
	ZBF_RG8I,		//8-bit Signed Red, Green Channel
	ZBF_RG16,		//16-bit Red, Green Channel
	ZBF_RG16I,		//16-bit Signed Red, Green Channel
	ZBF_RG32,		//32-bit Red, Green Channel
	ZBF_RG32I,		//32-bit Signed Red, Green Channel
	ZBF_RG32F,		//32-bit Floating Point Red, Green Channel
	
	ZBF_RGB8,		//8-bit Red, Green, Blue Channel
	ZBF_RGB8I,		//8-bit Signed Red, Green, Blue Channel
	ZBF_RGB16,		//16-bit Red, Green, Blue Channel
	ZBF_RGB16I,		//16-bit Signed Red, Green, Blue Channel
	ZBF_RGB32,		//32-bit Red, Green, Blue Channel
	ZBF_RGB32I,		//32-bit Signed Red, Green, Blue Channel
	ZBF_RGB32F,		//32-bit Floating Point Red, Green, Blue Channel

	ZBF_RGBA8,		//8-bit Red, Green, Blue, Alpha Channel
	ZBF_RGBA8I,		//8-bit Signed Red, Green, Blue, Alpha Channel
	ZBF_RGBA16,		//16-bit Red, Green, Blue, Alpha Channel
	ZBF_RGBA16I,	//16-bit Signed Red, Green, Blue, Alpha Channel
	ZBF_RGBA32,		//32-bit Red, Green, Blue, Alpha Channel
	ZBF_RGBA32I,	//32-bit Signed Red, Green, Blue, Alpha Channel
	ZBF_RGBA32F,	//32-bit Floating Point Red, Green, Blue, Alpha Channel

	ZBF_BGR8,		//8-bit Blue, Green, Red Channel
	ZBF_BGR8I,		//8-bit Signed Blue, Green, Red Channel
	ZBF_BGR16,		//16-bit Blue, Green, Red Channel
	ZBF_BGR16I,		//16-bit Signed Blue, Green, Red Channel
	ZBF_BGR32,		//32-bit Blue, Green, Red Channel
	ZBF_BGR32I,		//32-bit Signed Blue, Green, Red Channel
	ZBF_BGR32F,		//32-bit Floating Point Blue, Green, Red Channel

	ZBF_BGRA8,		//8-bit Blue, Green, Red, Alpha Channel
	ZBF_BGRA8I,		//8-bit Signed Blue, Green, Red, Alpha Channel
	ZBF_BGRA16,		//16-bit Blue, Green, Red, Alpha Channel
	ZBF_BGRA16I,	//16-bit Signed Blue, Green, Red, Alpha Channel
	ZBF_BGRA32,		//32-bit Blue, Green, Red, Alpha Channel
	ZBF_BGRA32I,	//32-bit Signed Blue, Green, Red, Alpha Channel
	ZBF_BGRA32F,	//32-bit Floating Point Blue, Green, Red, Alpha Channel

	ZBF_DEPTH32,	//32-bit Unsigned Depth

	ZBCM_SIZE
};

/*
Bitmap data class.
*/
class ZBitmap
{
protected:
	ZBitmapFormat	Format;		//Format of the bitmap
	uint32_t		Width;		//Width of the bitmap
	uint32_t		Height;		//Height of the bitmap
	uint32_t		Depth;		//Depth of the bitmap
	void*			Data;		//Pointer to the bitmap data (can be NULL)

public:

	/*
	Default Constructor
	*/
	ZBitmap()
		: Format(ZBF_UNKNOWN),
		  Width(1),
		  Height(1),
		  Depth(1),
		  Data(NULL)
	{ }

	/*
	Constructor.

	@param _format - the bitmap format 
	@param _width - the width (pixels)
	@param _height - the height (pixels)
	*/
	ZBitmap(ZBitmapFormat _format, uint32_t _width, uint32_t _height)
		: Format(_format),
		  Width(_width),
		  Height(_height),
		  Depth(1),
		  Data(NULL)
	{ }

	/*
	Constructor.

	@param _format - the bitmap format 
	@param _width - the width (pixels)
	@param _height - the height (pixels)
	@param _depth - the depth (pixels)
	*/
	ZBitmap(ZBitmapFormat _format, uint32_t _width, uint32_t _height, uint32_t _depth)
		: Format(_format),
		  Width(_width),
		  Height(_height),
		  Depth(_depth),
		  Data(NULL)
	{ }
	
	/*
	Constructor.

	@param _format - the bitmap format 
	@param _width - the width (pixels)
	@param _height - the height (pixels)
	@param _depth - the depth (pixels)
	@param _data - the bitmap data
	*/
	ZBitmap(ZBitmapFormat _format, uint32_t _width, uint32_t _height, uint32_t _depth, void* _data)
		: Format(_format),
		  Width(_width),
		  Height(_height),
		  Depth(_depth),
		  Data(_data)
	{ }

	//Determines (based off Format) the Bits Per Pixel of this bitmap
	size_t GetBPP() const
	{
		switch(Format)
		{
		case ZBF_R8:		return 8;
		case ZBF_R8I:		return 8;
		case ZBF_R16:		return 16;
		case ZBF_R16I:		return 16;
		case ZBF_R32:		return 32;
		case ZBF_R32I:		return 32;
		case ZBF_R32F:		return 32;

		case ZBF_RG8:		return 16;
		case ZBF_RG8I:		return 16;
		case ZBF_RG16:		return 32;
		case ZBF_RG16I:		return 32;
		case ZBF_RG32:		return 64;
		case ZBF_RG32I:		return 64;
		case ZBF_RG32F:		return 64;
		
		case ZBF_RGB8:		return 24;
		case ZBF_RGB8I:		return 24;
		case ZBF_RGB16:		return 48;
		case ZBF_RGB16I:	return 48;
		case ZBF_RGB32:		return 96;
		case ZBF_RGB32I:	return 96;
		case ZBF_RGB32F:	return 96;

		case ZBF_RGBA8:		return 32;
		case ZBF_RGBA8I:	return 32;
		case ZBF_RGBA16:	return 64;
		case ZBF_RGBA16I:	return 64;
		case ZBF_RGBA32:	return 128;
		case ZBF_RGBA32I:	return 128;
		case ZBF_RGBA32F:	return 128;

		case ZBF_BGR8:		return 24;
		case ZBF_BGR8I:		return 24;
		case ZBF_BGR16:		return 48;
		case ZBF_BGR16I:	return 48;
		case ZBF_BGR32:		return 96;
		case ZBF_BGR32I:	return 96;
		case ZBF_BGR32F:	return 96;

		case ZBF_BGRA8:		return 32;
		case ZBF_BGRA8I:	return 32;
		case ZBF_BGRA16:	return 64;
		case ZBF_BGRA16I:	return 64;
		case ZBF_BGRA32:	return 128;
		case ZBF_BGRA32I:	return 128;
		case ZBF_BGRA32F:	return 128;

		default:			return 0;
		}
	}

	//Determines (based off of Width, Height, and Depth) the dimension of this bitmap (1, 2, or 3, 0 if inconsistent values)
	size_t GetDimension() const
	{
		if (Width > 1 && Height > 1 && Depth > 1)
			return 3;
		else if (Width > 1 && Height > 1 && Depth <= 1)
			return 2;
		else if (Width > 1 && Height <= 1 && Depth <= 1)
			return 1;

		return 0;
	}	

	//Computes and returns the size of the bitmap (in bytes)
	size_t GetSize() const
	{ 
		return (Width * Depth * Height * GetBPP()) / 8; 
	}

	//Getter and Settter for 'Format'
	inline ZBitmapFormat GetFormat() const { return this->Format; }
	inline void  SetFormat(ZBitmapFormat _format) { this->Format = _format; }

	//Getter and Setter for 'Width', in pixels
	inline uint32_t GetWidth() const { return this->Width; }
	inline void  SetWidth(uint32_t _width) { this->Width = _width; }

	//Getter and Setter for 'Height', in pixels
	inline uint32_t GetHeight() const { return this->Height; }
	inline void  SetHeight(uint32_t _height) { this->Height = _height; }

	//Getter and Setter for 'Depth', in pixels
	inline uint32_t GetDepth() const { return this->Depth; }
	inline void  SetDepth(uint32_t _depth) { this->Depth = _depth; }

	//Getter and Setter for 'Data'
	inline void* GetData() const { return this->Data; }
	inline void  SetData(void* _data) { this->Data = _data; }
};

#endif
