/*--------------------------------------------------------------------------
 * File: vio.c
 * Written by: Alexander Boczar, 1997-04-16
 * Description: VIO image loader/saver
 *
 * Updates:
 * -- Date -- | ----- Name ----- |-- Did what....
 * 1998-01-19 | Fredrik Kling    | routines for 32bits...
 * 1997-12-12 | Fredrik Kling    | Routines for 16bits
 * 1997-xx-xx | Alexander Boczar |
 *
 * Todo:
 *
 -------------------------------------------------------------------------------*/

#include "formats/vio.h"
#include "system/xstdio.h"
#include "system/xstring.h"

#define VERSION 0x0120

/*############################################################################
#
# VIO Loader
#
############################################################################*/

VIO *vio_load( char *filename)
{
	VIO *image;
	XFILE *f;
	int x,y;

  if ( (f = xfopen( filename, "rb")) == NULL)
		return( NULL);

  if ( xfrle_dword( f) != 'VIO\0')
		return( NULL);

  if ( xfrle_word( f) != VERSION)
		return( NULL);

  image = (VIO *)xmalloc( sizeof(VIO));

	image->width = xfrle_dword( f);
	image->height = xfrle_dword( f);
	image->flags = xfrle_dword( f);

	if ( image->flags & VIOFLAG_8BIT)
	{
		image->palette = (RGB *)xmalloc( 256 * sizeof(RGB));
		xfread( image->palette, sizeof(RGB), 256, f);

		image->image8 = (BYTE *)xmalloc( (image->width * image->height) * sizeof( BYTE));
		xfread( image->image8, sizeof(BYTE), (image->width * image->height), f);
	}
	if ( image->flags & VIOFLAG_16BIT)
	{
		image->image16 = (WORD *)xmalloc( (image->width * image->height) * sizeof( WORD));
		xfread( image->image16, sizeof(WORD), (image->width * image->height), f);
	}
	if ( image->flags & VIOFLAG_24BIT)
	{
		image->image24 = (RGB *)xmalloc( (image->width * image->height) * sizeof( RGB));
		xfread( image->image24, sizeof(RGB), (image->width * image->height), f);
	}
	if ( image->flags & VIOFLAG_32BIT)
	{
		image->image32 = (RGBA *)xmalloc( (image->width * image->height) * sizeof( RGBA));
		xfread( image->image32, sizeof(RGBA), (image->width * image->height), f);
	}

	if ( image->flags & VIOFLAG_ZBUFFER)
	{
    image->zbuffer = (int *)xmalloc( (image->width * image->height) * sizeof( int));
		for( y=0; y<image->height; y++)
			for( x=0; x<image->width; x++)
        image->zbuffer[ y * image->width + x] = xfrle_dword( f);
	}

	xfclose( f);
	return( image);
}

/*############################################################################
#
# VIO Saver
#
############################################################################*/

int vio_save( char *filename, VIO *image)
{
	FILE *f;
	int x,y;

	if ( (f = fopen( filename, "wb")) == NULL)
		return( FALSE);

	fwle_dword( f, 'VIO\0');
	fwle_word( f, VERSION);
	fwle_dword( f, image->width);
	fwle_dword( f, image->height);
	fwle_dword( f, image->flags);

	if ( image->flags & VIOFLAG_8BIT)
	{
		fwrite( image->palette, sizeof(RGB), 256, f);
		fwrite( image->image8, sizeof(BYTE), (image->width * image->height), f);
	}

	if ( image->flags & VIOFLAG_16BIT)
	{
		fwrite( image->image16, sizeof(WORD), (image->width * image->height), f);
	}
	if ( image->flags & VIOFLAG_24BIT)
	{
		fwrite( image->image24, sizeof(RGB), (image->width * image->height), f);
	}
	if ( image->flags & VIOFLAG_32BIT)
	{
		fwrite( image->image32, sizeof(RGBA), (image->width * image->height), f);
	}

	if ( image->flags & VIOFLAG_ZBUFFER)
	{
		for( y=0; y<image->height; y++)
			for( x=0; x<image->width; x++)
        fwle_dword( f, image->zbuffer[ y * image->width + x]);
	}

	fclose( f);
	return( TRUE);
}

/*############################################################################
#
# VIO Create 8bit vio from raw
#
############################################################################*/

VIO *vio_create8bit( int *zbuffer, RGB *palette, BYTE *image, int width, int height)
{
	VIO *vio;

	if( (image == NULL) || (palette == NULL))
		return( NULL);

	if( (vio = (VIO *)xmalloc( sizeof(VIO))) == NULL)
		return( NULL);
	vio->width = width;
	vio->height = height;
	vio->flags = VIOFLAG_8BIT | VIOFLAG_PALETTE;

	if( (vio->image8 = (BYTE *)xmalloc( sizeof( BYTE) * width * height)) == NULL)
	{
		xfree( vio);
		return( NULL);
	}
	memcpy( vio->image8, image, sizeof( BYTE) * width * height);
	if( (vio->palette = (RGB *)xmalloc( sizeof( RGB) * 256)) == NULL)
	{
		xfree( vio->image8);
		xfree( vio);
		return( NULL);
	}
	memcpy( vio->palette, palette, sizeof( RGB) * 256);

	if( zbuffer != NULL)
	{
    if( (vio->zbuffer = (int *)xmalloc( sizeof( int) * width * height)) == NULL)
		{
			xfree( vio->palette);
			xfree( vio->image8);
			xfree( vio);
			return( NULL);
		}
    memcpy( vio->zbuffer, zbuffer, sizeof( int) * width * height);
		vio->flags |= VIOFLAG_ZBUFFER;
	}
	return( vio);
}
/*############################################################################
#
# VIO - Create 16bit vio from raw
#
############################################################################*/

VIO *vio_create16bit (int *zbuffer, RGB *image, int width, int height)
{
	VIO *vio;

	if (image==NULL) return NULL;
	if ((vio = (VIO*)xmalloc (sizeof (VIO))) == NULL) return NULL;

	vio->width = width;
	vio->height = height;
	vio->flags = VIOFLAG_16BIT;

	return vio;
}

/*############################################################################
#
# VIO - Create 24bit vio from raw
#
############################################################################*/

VIO *vio_create24bit( int *zbuffer, RGB *image, int width, int height)
{
	VIO *vio;

	if( image == NULL)
		return( NULL);

	if( (vio = (VIO *)xmalloc( sizeof(VIO))) == NULL)
		return( NULL);
	vio->width = width;
	vio->height = height;;
	vio->flags = VIOFLAG_24BIT;

	if( (vio->image24 = (RGB *)xmalloc( sizeof( RGB) * width * height)) == NULL)
	{
		xfree( vio);
		return( NULL);
	}
	memcpy( vio->image24, image, sizeof( RGB) * width * height);

	if( zbuffer != NULL)
	{
    if( (vio->zbuffer = (int *)xmalloc( sizeof( int) * width * height)) == NULL)
		{
			xfree( vio->image24);
			xfree( vio);
			return( NULL);
		}
    memcpy( vio->zbuffer, zbuffer, sizeof( int) * width * height);
		vio->flags |= VIOFLAG_ZBUFFER;
	}
	return( vio);
}

/*############################################################################
#
# VIO - Create 32bit vio from raw
#
############################################################################*/

VIO *vio_create32bit( int *zbuffer, RGBA *image, int width, int height)
{
	VIO *vio;

	if( image == NULL)
		return( NULL);

	if( (vio = (VIO *)xmalloc( sizeof(VIO))) == NULL)
		return( NULL);
	vio->width = width;
	vio->height = height;;
	vio->flags = VIOFLAG_32BIT;

	if( (vio->image32 = (RGBA *)xmalloc( sizeof( RGBA) * width * height)) == NULL)
	{
		xfree( vio);
		return( NULL);
	}
	memcpy( vio->image32, image, sizeof( RGBA) * width * height);

	if( zbuffer != NULL)
	{
    if( (vio->zbuffer = (int *)xmalloc( sizeof( int) * width * height)) == NULL)
		{
			xfree( vio->image24);
			xfree( vio);
			return( NULL);
		}
    memcpy( vio->zbuffer, zbuffer, sizeof( int) * width * height);
		vio->flags |= VIOFLAG_ZBUFFER;
	}
	return( vio);
}

/*############################################################################
#
# VIO - free
#
############################################################################*/

void vio_free( VIO *image)
{
	if( image != NULL)
	{
		if( image->palette != NULL) xfree( image->palette);
		if( image->image8 != NULL) xfree( image->image8);
		if( image->image16 != NULL) xfree (image->image16);
		if( image->image24 != NULL) xfree( image->image24);
		if( image->image32 != NULL) xfree( image->image32);
		xfree( image);
	}
}

/*############################################################################
#
# VIO - Add 8bit copy if possible to an existing vio
#
############################################################################*/
static void convert8to16 (RGB *palette, BYTE *source, WORD *dest, int size)
{
	int i;
	BYTE c;
	WORD w;

	/* Assume palette data ranging from 0 to 256! */
	for (i=0;i<size;i++)
	{
		c=source[i];
		w = (palette[c].r>>3) << (5+6);
		w |= (palette[c].g>>2) << (5);
		w |= (palette[c].b>>3);
		dest[i] = w;
	}
}
static void convert24to16 (RGB *source, WORD *dest, int size)
{
	int i;
	RGB c;
	WORD w;

	for (i=0;i<size;i++)
	{
		c = source[i];
		w = (c.r>>3) << (5+6);
		w |= (c.g>>2) << (5);
		w |= (c.b>>3);
		dest[i]=w;
	}
}
static void convert32to16 (RGBA *source, WORD *dest, int size)
{

}
static void convert16to8 (RGB *palette, WORD *source, BYTE *dest, int size)
{

}
static void convert8to32 (RGB *palette, BYTE *source, RGBA *dest, int size)
{
	int i;
	for (i=0;i<size;i++)
	{
		dest[i].r = palette[source[i]].r;
		dest[i].g = palette[source[i]].g;
		dest[i].b = palette[source[i]].b;
		dest[i].a = 0;
	}
}
static void convert24to32 (RGB *src, RGBA *dst, int size)
{
	int i;
	RGB c;
	RGBA cd;

	for (i=0;i<size;i++)
	{
		c = src[i];
		cd.r = c.r, cd.g = c.g, cd.b = c.b;
		dst[i]=cd;
	}
}
int vio_make24bit (VIO *image)
{
	return FALSE;
}
int vio_make32bit (VIO *image)
{
	int size = image->width * image->height;

	if (image->flags & VIOFLAG_32BIT) return TRUE;

	if ((image->image32 = xmalloc (sizeof (RGBA) * size))==NULL) return (FALSE);

	if (image->flags & VIOFLAG_8BIT)
		convert8to32 (image->palette, image->image8, image->image32, size);
	else if (image->flags & VIOFLAG_24BIT)
		convert24to32 (image->image24, image->image32, size);
	else return FALSE;

	image->flags |= VIOFLAG_32BIT;
	return TRUE;
}
int vio_make16bit (VIO *image)
{
	int size = image->width * image->height;

	if (image->flags & VIOFLAG_16BIT) return TRUE;


	if ((image->image16 = xmalloc (sizeof (WORD) * size)) == NULL) return (FALSE);


	if (image->flags & VIOFLAG_8BIT)
		convert8to16 (image->palette, image->image8, image->image16, size);
	else if (image->flags & VIOFLAG_24BIT)
		convert24to16 (image->image24, image->image16, size);
	else if (image->flags & VIOFLAG_32BIT)
		convert32to16 (image->image32, image->image16, size);

	image->flags |= VIOFLAG_16BIT;
	return TRUE;
}

int vio_make8bit( VIO *image)
{
	int size = image->width * image->height;

	if( (image->flags & VIOFLAG_8BIT))
		return( TRUE);

	if( (image->palette = (RGB *)xmalloc( 256 * sizeof(RGB))) == NULL)
		return( FALSE);
	if( (image->image8 = (BYTE *)xmalloc( size * sizeof( BYTE))) == NULL)
	{
    xfree( image->palette);
		return( FALSE);
	}

	if( image->flags & VIOFLAG_16BIT)
		convert16to8 ( image->palette, image->image16, image->image8, size);
	else if( image->flags & VIOFLAG_24BIT)
		convert24to8( image->palette, image->image24, image->image8, size);
	else if( image->flags & VIOFLAG_32BIT)
		convert32to8( image->palette, image->image32, image->image8, size);

	image->flags |= VIOFLAG_8BIT | VIOFLAG_PALETTE;
	return( TRUE);
}

