/*
	Twilight Prophecy 3D/Multimedia SDK
	A multi-platform development system for virtual reality and multimedia.

	Copyright (C) 1997-2001 by Twilight 3D Finland Oy Ltd.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

	Please read the file LICENSE.TXT for additional details.


	source:
		bitmap implementation

	revision history:
		Dec/18/1998 - Jukka Liimatta - initial revision
		Jan/24/2001 - Jukka Liimatta - renaissance build
*/
#include <prcore/prcore.hpp>
using namespace prcore;



Bitmap::Bitmap()
{
}


Bitmap::Bitmap(const Bitmap& src)
{
	*this = src;
}


Bitmap::Bitmap(const Surface& surface)
{
	width = surface.GetWidth();
	height = surface.GetHeight();
	format = surface.GetFormat();
	pitch = width * format.GetBytes();
	image = new uint8[ height*pitch ];

	// copy image
	uint8* s = surface.GetImage();
	uint8* d = image;
	int y = height;
	do
	{
		memcpy(d,s,pitch);
		s += surface.GetPitch();
		d += pitch;
	} while (--y);
}


Bitmap::Bitmap(int width_, int height_, const PixelFormat& pxf)
{
	width = width_;
	height = height_;
	pitch = width * pxf.GetBytes();
	format = pxf;
	image = new uint8[ width*height*pxf.GetBytes() ];
}


Bitmap::Bitmap(const char* filename)
{
	LoadImage( filename );
}


Bitmap::~Bitmap()
{
	if ( image )
		delete[] image;
}


void Bitmap::operator = (const Bitmap& src)
{
	if ( src.image )
	{
		// reallocate image
		if ( pitch!=src.pitch || height!=src.height )
		{
			if ( image )
				delete[] image;
			image = new uint8[ src.pitch*src.height ];
		}

		// copy image
		uint8* s = src.image;
		uint8* d = image;
		int y = src.height;
		do
		{
			memcpy(d,s,src.pitch);
			s += src.pitch;
			d += src.pitch;
		} while (--y);
	}
	else
	{
		if ( image )
			delete[] image;
		image = NULL;
	}
	
	width = src.width;
	height = src.height;
	pitch = src.pitch;
	format = src.format;
}


Bitmap Bitmap::GetBitmap(const Rect& area) const
{
	// assert
	assert( image );

	// test area
	if ( area.width < 1 || 
		area.height < 1 || 
		area.x < 0 || 
		area.y < 0 || 
		(area.x+area.width) > width || 
		(area.y+area.height) > height ) 
		return *this;

	// clip
	Rect q;
	if ( !q.Intersect(GetRect(),area) )
		return *this;

	// new bitmap
	Bitmap p(q.width,q.height,format);

	// copy image
	int bpp = format.GetBytes();
	uint8* s = image + q.y * pitch + q.x * bpp;
	uint8* d = p.image;

	for ( int y=0; y<q.height; y++ )
	{
		memcpy(d,s,p.pitch);
		s += pitch;
		d += p.pitch;
	}

	return p;
}


void Bitmap::LoadImage(const char* filename)
{
	// assert
	assert(filename);
	
	// find codec
	BitmapCodec* codec = FindBitmapCodec(GetFilenameEXT(filename));

	if ( codec )
	{
		if ( !codec->IsDecoder() )
			return;

		// create stream
		FileStream stream(filename,Stream::READ);
		
		// decode
		codec->Decode(*this,stream);
		
		// set interface name
		SetName(filename);
	}
}


void Bitmap::SaveImage(const char* filename)
{
	// assert
	assert(filename);
	
	// find codec
	BitmapCodec* codec = FindBitmapCodec(GetFilenameEXT(filename));
	
	if ( codec )
	{
		if ( !codec->IsEncoder() ) 
			return;
			
		// create stream
		FileStream stream(filename,Stream::WRITE);
		if ( !stream.IsOpen() )
			return;
			
		// encode
		codec->Encode(stream,*this);
	}
}


void Bitmap::SetImage(int width_, int height_, const PixelFormat& pxf, void* image_)
{
	if ( image )
	delete[] image;
	
	width = width_;
	height = height_;
	pitch = width * pxf.GetBytes();
	format = pxf;
	image = (uint8*)image_;
}


void Bitmap::ResizeImage(int width_, int height_, bool filter)
{
	// assert
	assert( image );
	if ( width == width_ && height == height_ )	
		return;

	// choose blitmode
	BlitMode mode = filter ? BLIT_BILINEAR_SCALE : BLIT_SCALE;

	// conversion
	Bitmap temp(width_,height_,format);
	temp.Blit(*this,mode);
	
	// swap pointers
	if ( image )
		delete[] image;
	image = temp.image;
	temp.image = NULL;
	
	format = temp.format;
	width = temp.width;
	height = temp.height;
	pitch = temp.pitch;
}


void Bitmap::ReformatImage(const PixelFormat& pxf)
{
	assert( image );
	if ( format==pxf )
		return;

	// indexed reformat means color quantization
	if ( pxf.IsIndexed() )
	{
		QuantizeImage();
		return;
	}

	// conversion
	Bitmap temp(width,height,pxf);
	temp.Blit(*this,BLIT_COPY);
	
	// swap pointers
	delete[] image;
	image = temp.image;
	temp.image = NULL;
	
	pitch = temp.pitch;
	format = pxf;
}
