/*  $Id: pixel_buffer.cpp,v 1.41 2004/05/07 15:03:19 mbn Exp $
**
**  ClanLib Game SDK
**  Copyright (C) 2003  The ClanLib Team
**  For a total list of contributers see the file CREDITS.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This library 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
**  Lesser General Public License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*/

#include "Display/display_precomp.h"
#include "API/Display/pixel_buffer.h"
#include "API/Core/IOData/datatypes.h"
#include "pixel_buffer_generic.h"
#include "pixel_buffer_memory.h"
#include "API/Core/System/error.h"

/////////////////////////////////////////////////////////////////////////////
// CL_PixelBuffer construction:

CL_PixelBuffer::CL_PixelBuffer(CL_PixelBuffer_Generic *impl)
: impl(impl)
{
	if (impl) impl->add_ref();
}

CL_PixelBuffer::CL_PixelBuffer(int width, int height, int pitch, const CL_PixelFormat &format, void *data)
: impl(new CL_PixelBuffer_Memory(width, height, pitch, format, data))
{
	impl->add_ref();
}

CL_PixelBuffer::CL_PixelBuffer(int width, int height, int pitch, const CL_PixelFormat &format, const CL_Palette &palette, void *data)
: impl(new CL_PixelBuffer_Memory(width, height, pitch, format, palette, data))
{
	impl->add_ref();
}

CL_PixelBuffer::CL_PixelBuffer()
: impl(0)
{
}

CL_PixelBuffer::CL_PixelBuffer(const CL_PixelBuffer &copy)
: impl(copy.impl)
{
	if (impl) impl->add_ref();
}

CL_PixelBuffer::~CL_PixelBuffer()
{
	if (impl) impl->release_ref();
}

/////////////////////////////////////////////////////////////////////////////
// CL_PixelBuffer attributes:

const CL_PixelFormat &CL_PixelBuffer::get_format() const
{
	return impl->format;
}

const CL_Palette &CL_PixelBuffer::get_palette() const
{
	return impl->palette;
}

int CL_PixelBuffer::get_width() const
{
	return impl->width;
}

int CL_PixelBuffer::get_height() const
{
	return impl->height;
}

unsigned int CL_PixelBuffer::get_pitch() const
{
	return impl->pitch;
}

void *CL_PixelBuffer::get_data()
{
	return impl->get_data();
}

CL_Color CL_PixelBuffer::get_pixel(int x, int y)
{
	CL_Color color;

	lock();
	if (get_format().get_type() == pixelformat_index)
	{
		cl_uint8* buf = static_cast<cl_uint8*>(impl->get_data());
		color = impl->palette[int(buf[y*impl->pitch + x])];
	}
	else if (get_format().get_type() == pixelformat_rgba)
	{
		
	}
	unlock();

	return color;
}

/////////////////////////////////////////////////////////////////////////////
// CL_PixelBuffer operations:

CL_PixelBuffer &CL_PixelBuffer::operator =(const CL_PixelBuffer &copy)
{
	if (impl) impl->release_ref();
	impl = copy.impl;
	if (impl) impl->add_ref();
	return *this;
}

CL_PixelBuffer::operator bool() const
{
  return (impl != 0);
}

void CL_PixelBuffer::lock()
{
	impl->lock_count++;
	if (impl->lock_count == 1) impl->perform_lock();
}

void CL_PixelBuffer::unlock()
{
	impl->lock_count--;
	if (impl->lock_count == 0) impl->perform_unlock();
}

void CL_PixelBuffer::convert(CL_PixelBuffer *target)
{
	target->lock();

	convert(
		target->get_data(),
		target->get_format(),
		target->get_pitch(),
		CL_Rect(
			0, 0,
			target->get_width(), target->get_height()));

	target->unlock();
}

void CL_PixelBuffer::convert(
	void *buffer,
	const CL_PixelFormat &format,
	int dest_pitch,
	const CL_Rect &dest_rect,
	const CL_Rect &src_rect)
{
	lock();

	bool null_src = false;
	if (src_rect.left == 0 && src_rect.top == 0 && src_rect.right == 0 && src_rect.bottom == 0)
	{
		null_src = true;
	}

	if (format.get_type() == pixelformat_index)
	{
		throw CL_Error("Converting to indexed pixelformats not supported.");
	}

	if (null_src == false && dest_rect.get_size() != src_rect.get_size())
	{
		throw CL_Error("Source and destination rects must have same size. Scaled converting not supported.");
	}

	char *src_data = (char *) get_data();
	char *dest_data = (char *) buffer;
	if (null_src == false) src_data += src_rect.top*get_pitch() + src_rect.left*((get_format().get_depth()+7)/8);
	dest_data += dest_rect.top*dest_pitch + dest_rect.left*((format.get_depth()+7)/8);

	if (get_format().get_type() == pixelformat_index)
	{
		CL_PixelBuffer_Generic::convert_pal(
			src_data,
			get_format(),
			get_pitch(),
			get_palette(),
			dest_data,
			format,
			dest_pitch,
			dest_rect.get_size());
	}
	else
	{
		CL_PixelBuffer_Generic::convert(
			src_data,
			get_format(),
			get_pitch(),
			dest_data,
			format,
			dest_pitch,
			dest_rect.get_size());
	}

	unlock();
}

void CL_PixelBuffer::convert_line(void *buffer, const CL_PixelFormat &format, int y)
{
	convert(
		buffer,
		format,
		(format.get_depth()+7)/8*get_width(),
		CL_Rect(0, 0, get_width(), 1),
		CL_Rect(0, y, get_width(), 1));
}

CL_PixelBuffer CL_PixelBuffer::to_format(const CL_PixelFormat &format)
{
	lock();
	CL_PixelBuffer result(get_width(), get_height(), get_width()*((format.get_depth()+7)/8), format);
	convert(&result);
	unlock();
	return result;
}

void CL_PixelBuffer::set_colorkey(bool enabled, unsigned int colorkey)
{
	impl->format.enable_colorkey(enabled);
	impl->format.set_colorkey(colorkey);
}

void CL_PixelBuffer::draw_pixel(int x, int y, const CL_Color &color)
{
}

/////////////////////////////////////////////////////////////////////////////
// CL_PixelBuffer implementation:
