// Pic.cpp

#include <windows.h>

#include "Types.h"
#include "File.h"
#include "Misc.h"
#include "Pic.h"


typedef struct
{
	u8
		r,
		g,
		b;
} RGB24;

typedef struct
{
	char    Manufacturer;
	char    Version;
	char    Encoding;
	char    BitsPerPixel;
	short   Xmin;
	short   Ymin;
	short   Xmax;
	short   Ymax;
	short   Hres;
	short   Vres;
	RGB24   Palette[16];
	char    Reserved;
	char    NPlanes;
	short   BytesPerLine;
	short   PaletteType;
	char    Unused[58];
} PCXheader;


CPic::CPic()
{
	Width = 0;
	Height = 0;
	Data = NULL;
	Targa = NULL;
}


CPic::~CPic()
{
	delete [] Data;
	delete [] Targa;
}


void CPic::LoadPCX( const char *filename )
{
	CFile
		file;
	PCXheader
		header;
	s32
		x,
		y,
		off = 0,
		colour,
		run,
		control;

	delete [] Data;
	Data = NULL;

	delete [] Targa;
	Targa = NULL;


	if (!file.Open( filename ))
	{
		Error( "Cannot open: '%s'", filename );
		return;
	}

	file.Read( &header, 128 );

	if (header.BitsPerPixel != 8)
	{
		Error( "%s is not an 8-bit file!", filename );
		file.Close();
		return;
	}

	Width   = (header.Xmax - header.Xmin) + 1;
	Height  = (header.Ymax - header.Ymin) + 1;

	Data = new u8[Width * Height];

	for (y=0; y<Height; y++)
	{
		x = 0;
		while (x < header.BytesPerLine)
		{
			file.Read( &control, 1 );
			if ((control & 0xc0) == 0xc0)
			{
				run = control & 0x3f;
				file.Read( &control, 1 );
			}
			else
				run = 1;

			while (run)
			{
				colour = control & 255;

				if (x < Width)
					Data[off++] = colour;

				x++;
				run--;
			}
		}
	}


	file.Seek( -768 );

	for (x=0; x<256; x++)
	{
		file.Read( &y, 3 );

		Palette[x].r = (u8)(y >> 0);
		Palette[x].g = (u8)(y >> 8);
		Palette[x].b = (u8)(y >> 16);
		Palette[x].a = 255;
	}


	file.Close();
}


void CPic::LoadTGA( const char *filename )
{
	CFile
		file;
	s32
		i,
		depth = 0;
	u8
		t;

	delete [] Data;
	Data = NULL;

	delete [] Targa;
	Targa = NULL;


	if (!file.Open( filename ))
	{
		Error( "Cannot open: '%s'", filename );
		return;
	}

	Width = 0;
	Height = 0;
	file.Seek( 12 );
	file.Read( &Width, 2 );
	file.Read( &Height, 2 );

	file.Read( &depth, 1 );
	if (depth != 32)
	{
		Error( "'%s' is not 32bpp!", filename );
		return;
	}

	file.Seek( 18 );

	Targa = new RGBA32[Width * Height];

	for (i=(Height-1); i>=0; i--)
		file.Read( &Targa[i*Width], Width*4 );

	for (i=0; i<(Width*Height); i++)
	{
		t = Targa[i].r;
		Targa[i].r = Targa[i].b;
		Targa[i].b = t;
	}

	file.Close();
}


void CPic::Extract( s32 x, s32 y, s32 w, s32 h, void *data )
{
	s32
		i;

	if (!data)
		return;

	if (Data)
	{
		u8
			*ptr = (u8 *)data;

		while (h > 0)
		{
			for (i=0; i<w; i++)
			{
				if ((x+i) >= 0 && (x+i) < Width &&
						y >= 0 && y < Height)
					ptr[i] = Data[(y*Width)+(x+i)];
				else
					ptr[i] = 0;
			}

			ptr += w;
			y++;
			h--;
		}
	}

	if (Targa)
	{
		RGBA32
			*ptr = (RGBA32 *)data;

		while (h > 0)
		{
			CopyMemory( ptr, &Targa[(y*Width)+x], w*4 );
			ptr += w;
			y++;
			h--;
		}
	}
}
