#include "Sprites.h"

#include <stdio.h>
#include <stdlib.h>

#include "kernel.h"
#include "Task.h"

CSpriteArea* Sprites_LoadFile(const char* filename)
{
	FILE*			file;
	int			ext;
	_kernel_swi_regs	regs;
	CSpriteArea*		pArea;


	file = fopen(filename, "rb");

	if (file == NULL)
		return NULL;

	/* Get sprite file size */
	fseek(file, 0, SEEK_END);
	ext = 16 + (int) ftell(file);
	fclose(file);

	/* Allocate sprite area */
	pArea = malloc(ext);
	if (pArea == NULL)
		return NULL;

	/* Init sprite area */
	pArea->size = ext;
	pArea->sproff = sizeof(CSpriteArea);
	regs.r[0] = 0x109;
	regs.r[1] = (int) pArea;
	if (_kernel_swi(0x02002e, &regs, &regs))
	{
		free(pArea);
		return NULL;
	}

	/* Load sprites */
	regs.r[0] = 0x10A;
	regs.r[1] = (int) pArea;
	regs.r[2] = (int) filename;
	if (_kernel_swi(0x02002e, &regs, &regs))
	{
		free(pArea);
		return NULL;
	}

	return pArea;
}

CSize GetSpriteSize(const CSpriteArea* pSpriteArea, const char* pSpriteName)
{
	_kernel_swi_regs	regs;
	const _kernel_oserror*	err;
	CSize			size = {0, 0};

	/* Get sprite pixel sizes */
	regs.r[0] = 0x100 + 40;
	regs.r[1] = (int) pSpriteArea;
	regs.r[2] = (int) pSpriteName;
	err = _kernel_swi(0x2002e, &regs, &regs);
	if (err) return size;

	/* Return size in pixels */
	size.cx = regs.r[3];
	size.cy = regs.r[4];

	return size;
}

CSize Desktop_GetSpriteSize(const CSpriteArea* pSpriteArea, const char* pSpriteName)
{
	const Mode_Info*	Mode = Task_GetModeInfo();
	_kernel_swi_regs	regs;
	const _kernel_oserror*	err;
	CSpriteFactors		scale;
	CSize			size = {0, 0};

	/* Get wimp scale factors */
	regs.r[0] = 0x100;
	regs.r[1] = (int) pSpriteArea;
	regs.r[2] = (int) pSpriteName;
	regs.r[6] = (int) &scale;
	regs.r[7] = 0;
	err = _kernel_swi(0x600ed, &regs, &regs);
	if (err) return size;

	/* Get sprite pixel sizes */
	regs.r[0] = 0x100 + 40;
	regs.r[1] = (int) pSpriteArea;
	regs.r[2] = (int) pSpriteName;
	err = _kernel_swi(0x2002e, &regs, &regs);
	if (err) return size;

	/* Return size in OS coordinates */
	size.cx = (Mode->dx * regs.r[3] * scale.xmag) / scale.xdiv;
	size.cy = (Mode->dy * regs.r[4] * scale.ymag) / scale.ydiv;

	return size;
}

void Desktop_PlotSprite(const CSpriteArea* pSpriteArea,
			const char* pSpriteName,
			const CPoint* ppt,
			const CRect* prect)
{
	_kernel_swi_regs	regs;
	_kernel_oserror*	err;
	CSpriteFactors		scale;
	int			ptable[256];
	int			mode;
	int			palette;
	int			matrix[6];
	CSpriteHdr*		pSprite;

	/* User Area, Select sprite */
	regs.r[0] = 0x100 + 24;
	regs.r[1] = (int) pSpriteArea;
	regs.r[2] = (int) pSpriteName;
	if ((err = _kernel_swi(0x2002e, &regs, &regs)) != NULL)
		return;

	pSprite = (CSpriteHdr*) regs.r[2];

	/* Get wimp scale factors and translation table from Wimp_ReadPixTrans */
	regs.r[0] = 0x200;
	regs.r[1] = (int) pSpriteArea;
	regs.r[2] = (int) pSprite;
	regs.r[6] = (int) &scale;
	regs.r[7] = (int) ptable;
	if ((err = _kernel_swi(0x600ed, &regs, &regs)) != NULL)
		return;

	/* Read palette info */
	regs.r[0] = 0x200 + 37;
	regs.r[1] = (int) pSpriteArea;
	regs.r[2] = (int) pSprite;
	regs.r[3] = -1;
	if ((err = _kernel_swi(0x2002e, &regs, &regs)) != NULL)
		return;

	palette = regs.r[4];
	mode = regs.r[5];

	/* Call OS_ReadModeVariable for log2 number of bits per pixel */
	regs.r[0] = mode;
	regs.r[1] = 9;
	err = _kernel_swi(0x20035, &regs, &regs);

	/* Has a palette or has more than 16 colours ? */
	if (palette
	||  (regs.r[2] > 2))
	{
		/* Get translation table from ColourTrans_SelectTable */
		regs.r[0] = (int) pSpriteArea;
		regs.r[1] = (int) pSprite;
		regs.r[2] = -1;
		regs.r[3] = -1;
		regs.r[4] = (int) ptable;
 		/* Do not use bit 4 (0x10), OS_SpriteOp does not know about multibyte colors */
		regs.r[5] = 0x01;
		err = _kernel_swi(0x60740, &regs, &regs);
	}

	matrix[0] = (scale.xmag << 16) / scale.xdiv;
	matrix[1] = 0;
	matrix[2] = 0;
	matrix[3] = (scale.ymag << 16) / scale.ydiv;
	matrix[4] = ppt->x << 8;
	matrix[5] = ppt->y << 8;

	/* Plot sprite */
	/* Note that there is a palette bug for sprites with 256 entries
	   I just noticed on RISC OS 3.7, if you can use opcode 52 instead */
	regs.r[0] = 0x200 + 56;
	regs.r[1] = (int) pSpriteArea;
	regs.r[2] = (int) pSprite;
	regs.r[3] = 2;
	regs.r[4] = (int) prect;
	regs.r[5] = 0x18;
	regs.r[6] = (int) matrix;
	regs.r[7] = (int) ptable;
	err = _kernel_swi(0x2002e, &regs, &regs);
}
