/*=========================================================================

	sprbank.cpp

	Author:		PKG
	Created: 
	Project:	PRLSR
	Purpose: 

	Copyright (c) 2000 Climax Development Ltd

===========================================================================*/


/*----------------------------------------------------------------------
	Includes
	-------- */

#ifndef __GFX_SPRBANK_H__
#include "gfx\sprbank.h"
#endif

#ifndef _FILEIO_HEADER_
#include "FileIO/FileIO.h"
#endif

#ifndef	__MEMORY_HEADER__
#include "Mem\Memory.h"
#endif

#ifndef __PRIM_HEADER__
#include "gfx\prim.h"
#endif

#ifndef __MATHTABLE_HEADER__
#include "utils\mathtab.h"
#endif


/*	Std Lib
	------- */

/*----------------------------------------------------------------------
	Tyepdefs && Defines
	------------------- */

/*----------------------------------------------------------------------
	Structure defintions
	-------------------- */


/*----------------------------------------------------------------------
	Positional Vars
	--------------- */

/*----------------------------------------------------------------------
	Function Prototypes
	------------------- */

/*----------------------------------------------------------------------
	Vars
	---- */

// Linked list of loaded instances
static SpriteBankInstance	*s_bankList = NULL;


/*----------------------------------------------------------------------
	Function:
	Purpose:
	Params:
	Returns:
  ---------------------------------------------------------------------- */
SpriteBankInstance::SpriteBankInstance( SpriteBankInstance *_next )
{
	m_frameHdr=NULL;
	m_file=FileEquate( -1 );
	m_refCount=0;
	m_next=_next;
}

/*----------------------------------------------------------------------
	Function:
	Purpose:
	Params:
	Returns:
  ---------------------------------------------------------------------- */
SpriteBankInstance::~SpriteBankInstance()
{
	ASSERT( !m_frameHdr );
}

/*----------------------------------------------------------------------
	Function:
	Purpose:
	Params:
	Returns:
  ---------------------------------------------------------------------- */

void SpriteBankInstance::load( FileEquate _file )
{
	if( m_refCount )
	{
		ASSERT( _file == m_file );
		m_refCount++;
	}
	else
	{
		m_tpageDesc=TPLoadTexWithHeaders(_file,&m_frameHdr);

		m_file=_file;
		m_refCount=1;
	}

}

/*----------------------------------------------------------------------
	Function:
	Purpose:
	Params:
	Returns:	true if there are no more references to this bank
  ---------------------------------------------------------------------- */
int SpriteBankInstance::dump()
{
	int ret=false;
	ASSERT(m_frameHdr);

	m_refCount--;
	if( m_refCount == 0 )
	{
		TPFree(m_tpageDesc);
		MemFree(m_frameHdr);
		m_frameHdr=NULL;
		ret=true;
	}
	return ret;
}





/*----------------------------------------------------------------------
	Function:
	Purpose:
	Params:
	Returns:
  ---------------------------------------------------------------------- */
SpriteBank::SpriteBank()
{
	m_SpriteBankInstance = NULL;
}

/*----------------------------------------------------------------------
	Function:
	Purpose:
	Params:
	Returns:
  ---------------------------------------------------------------------- */
SpriteBank::~SpriteBank()
{
	ASSERT(!m_SpriteBankInstance);
}

/*----------------------------------------------------------------------
	Function:
	Purpose:
	Params:		also creates the instance if required
	Returns:
  ---------------------------------------------------------------------- */
void SpriteBank::load( FileEquate _file )
{
	ASSERT(!m_SpriteBankInstance);

	if( !s_bankList )
	{
		// first sprite bank load
		s_bankList=new ("SpriteBank::load") SpriteBankInstance( NULL );
		s_bankList->load( _file );
		m_SpriteBankInstance=s_bankList;
	}
	else
	{
//		ASSERT(!"Sprite Bank Already Loaded");
		SpriteBankInstance *sbiPtr=s_bankList;
		do
		{
			if( sbiPtr->getFile() == _file )
			{
				// file already loaded - reference it
				sbiPtr->load( _file );
				m_SpriteBankInstance=sbiPtr;
				return;
			}
			sbiPtr=sbiPtr->getNext();
		}
		while( sbiPtr );

		// file not loaded - create new instance
		sbiPtr=s_bankList;
		s_bankList=new ("SpriteBank::load") SpriteBankInstance( sbiPtr );
		s_bankList->load( _file );
		m_SpriteBankInstance=s_bankList;
	}
}

/*----------------------------------------------------------------------
	Function:
	Purpose:
	Params:		also deletes the instance if required
	Returns:
  ---------------------------------------------------------------------- */

void SpriteBank::dump()
{
	ASSERT( m_SpriteBankInstance );
	if( m_SpriteBankInstance->dump() )
	{
		// just removed last last reference - delete instance
		if( m_SpriteBankInstance==s_bankList)
		{
			// first entry in bank list
			s_bankList=m_SpriteBankInstance->getNext();
		}
		else
		{
			SpriteBankInstance *sbiPtr=s_bankList;
			while( sbiPtr->getNext() != m_SpriteBankInstance )
			{
				sbiPtr=sbiPtr->getNext();
			};
			sbiPtr->setNext( sbiPtr->getNext()->getNext() );
		}

		delete m_SpriteBankInstance;
	}
	m_SpriteBankInstance=NULL;
}

/*----------------------------------------------------------------------
	Function:
	Purpose:
	Params:
	Returns:
  ---------------------------------------------------------------------- */
void SpriteBank::prepareFT4(POLY_FT4 *_ft4,sFrameHdr *_fh,int _x,int _y,bool _xFlip,bool _yFlip)
{
		int		W=_fh->W,H=_fh->H;

		setShadeTexPolyFT4(_ft4);
		setShadeTex(_ft4,0);
		setRGB0(_ft4,128,128,128);
		if (_xFlip)
			{
			_x-=_fh->XOfs;
			_x-=W;
			}
		else
			_x+=_fh->XOfs;

		if (_yFlip)
			{
			_y-=_fh->YOfs;
			_y-=H;
			}
		else
			_y+=_fh->YOfs;

		setXYWH(_ft4,_x,_y,W,H);
		setUVTp(_fh,_ft4,_xFlip,_yFlip);
}

/*----------------------------------------------------------------------
	Function:
	Purpose:
	Params:
	Returns:
  ---------------------------------------------------------------------- */
void SpriteBank::prepareGT4(POLY_GT4 *_gt4,sFrameHdr *_fh,int _x,int _y,bool _xFlip,bool _yFlip)
{
		int		W=_fh->W,H=_fh->H;

		setShadeTexPolyGT4(_gt4);
		setShadeTex(_gt4,0);
//		setRGB0(_gt4,128,128,128);
		if (_xFlip)
			{
			_x-=_fh->XOfs;
			_x-=W;
			}
		else
			_x+=_fh->XOfs;

		if (_yFlip)
			{
			_y-=_fh->YOfs;
			_y-=H;
			}
		else
			_y+=_fh->YOfs;

		setXYWH(_gt4,_x,_y,W,H);
		setUVTp(_fh,_gt4,_xFlip,_yFlip);
}


/*----------------------------------------------------------------------
	Function:
	Purpose:	Pass Z scale as 8 bit fraction, 256 = 1:1, 512 = enlarge X2, etc.
	Params:
	Returns:
  ---------------------------------------------------------------------- */
void SpriteBank::prepareFT4Scaled(POLY_FT4 *_ft4,sFrameHdr *_fh,int _x,int _y,bool _xFlip,bool _yFlip,long _z)
{
	int W=_fh->W,H=_fh->H;

	W *= _z;
	H *= _z;
	W>>=8;
	H>>=8;

	// Why not center the thing in here!? (pkg)
	_x-=(((_fh->W*_z)>>8)-_fh->W)/2;
	_y-=(((_fh->H*_z)>>8)-_fh->H)/2;


	setShadeTexPolyFT4(_ft4);
	if (_xFlip)
		{
		_x-=_fh->XOfs;
		_x-=W;
		}
	else
		_z+=_fh->XOfs;

	_y+=_fh->YOfs;

	setXYWH(_ft4,_x,_y,W,H);
	setUVTp(_fh,_ft4,_xFlip,_yFlip);
}


/*----------------------------------------------------------------------
	Function:
	Purpose:	NB: Still needs to be aspect corrected.. (PKG)
	Params:
	Returns:
  ---------------------------------------------------------------------- */
void SpriteBank::prepareFT4RotatedScaled(POLY_FT4 *_ft4,sFrameHdr *_fh,int _xCentre,int _yCentre,int _xScale,int _yScale,int _rot)
{
	int		halfW,halfH;
	int		ca,sa;
	int		cw,ch,sw,sh;
	int		width,height;
	int		aspect;

	halfW=(_fh->W*_xScale)>>(12+1);
	halfH=(_fh->H*_yScale)>>(12+1);
	ca=mcos(_rot);
	sa=msin(_rot);
	cw=(ca*halfW)>>12;
	ch=(ca*halfH)>>12;
	sw=(sa*halfW)>>12;
	sh=(sa*halfH)>>12;

//	aspect=(512<<12)/384;//((_fh->H<<12)/_fh->W)/2;
//	ch=(ch*aspect)>>12;
//	sh=(sh*aspect)>>12;

	_ft4->x0=_xCentre-cw+sh;	_ft4->y0=_yCentre-sw-ch;
	_ft4->x1=_xCentre+cw+sh;	_ft4->y1=_yCentre+sw-ch;
	_ft4->x2=_xCentre-cw-sh;	_ft4->y2=_yCentre-sw+ch;
	_ft4->x3=_xCentre+cw-sh;	_ft4->y3=_yCentre+sw+ch;

	setShadeTexPolyFT4(_ft4);
	setShadeTex(_ft4,0);
	setRGB0(_ft4,128,128,128);
//	setUVTp(_fh,_ft4,false,false);
////////////////////////////////	
	int		U=_fh->U;
	int		V=_fh->V;
	int		W=_fh->W;
	int		H=_fh->H;
	
	if (!_fh->Rotated) 
	{
		_ft4->u0=U;
		_ft4->u1=U+W;
		_ft4->u2=U;
		_ft4->u3=U+W;

		_ft4->v0=V;
		_ft4->v1=V;
		_ft4->v2=V+H-1;
		_ft4->v3=V+H-1;
	} 
	else 
	{
		_ft4->v0=V+W-1;
		_ft4->v2=V+W-1;
		_ft4->v1=V-1;
		_ft4->v3=V-1;

		_ft4->u0=U;
		_ft4->u1=U;
		_ft4->u2=U+H;
		_ft4->u3=U+H;
	}
	_ft4->u1--; _ft4->u3--;
	_ft4->v2--; _ft4->v3--;
	_ft4->tpage=_fh->TPage;
	_ft4->clut=_fh->Clut;
////////////////////////////////	
}


/*----------------------------------------------------------------------
	Function:
	Purpose:
	Params:
	Returns:
  ---------------------------------------------------------------------- */
void SpriteBank::setUVTp(sFrameHdr *_fh,POLY_FT4 *_ft4,int _xFlip,int _yFlip)
{
	int		U=_fh->U;
	int		V=_fh->V;
	int		W=_fh->W;
	int		H=_fh->H;

	if (!_fh->Rotated) 
		{
		if (_xFlip) 
			{
			_ft4->u0=U+W-1;
			_ft4->u1=U-1;
			_ft4->u2=U+W-1;
	 		_ft4->u3=U-1;
			} 
		else 
			{
			_ft4->u0=U;
			_ft4->u1=U+W;
			_ft4->u2=U;
 			_ft4->u3=U+W;
	 		}
		if (_yFlip) 
			{
			_ft4->v0=V+H-1;
			_ft4->v1=V+H-1;
			_ft4->v2=V-1;
			_ft4->v3=V-1;
			} 
		else 
			{
			_ft4->v0=V;
			_ft4->v1=V;
			_ft4->v2=V+H;
			_ft4->v3=V+H;
			}
		} 
	else 
		{
		if (_xFlip) 
			{
			_ft4->v0=V;
			_ft4->v2=V;
			_ft4->v1=V+W;
			_ft4->v3=V+W;
			} 
		else 
			{
			_ft4->v0=V+W-1;
			_ft4->v2=V+W-1;
			_ft4->v1=V-1;
			_ft4->v3=V-1;
			}
		if (_yFlip) 
			{
			_ft4->u0=U+H-1;
			_ft4->u1=U+H-1;
			_ft4->u2=U-1;
			_ft4->u3=U-1;
			} 
		else 
			{
			_ft4->u0=U;
			_ft4->u1=U;
			_ft4->u2=U+H;
			_ft4->u3=U+H;
			}
		}
	_ft4->tpage=_fh->TPage;
	_ft4->clut=_fh->Clut;
}

void SpriteBank::setUVTp(sFrameHdr *_fh,POLY_GT4 *_gt4,int _xFlip,int _yFlip)
{
	int		U=_fh->U;
	int		V=_fh->V;
	int		W=_fh->W;
	int		H=_fh->H;

	if (!_fh->Rotated) 
		{
		if (_xFlip) 
			{
			_gt4->u0=U+W-1;
			_gt4->u1=U-1;
			_gt4->u2=U+W-1;
	 		_gt4->u3=U-1;
			} 
		else 
			{
			_gt4->u0=U;
			_gt4->u1=U+W;
			_gt4->u2=U;
 			_gt4->u3=U+W;
	 		}
		if (_yFlip) 
			{
			_gt4->v0=V+H-1;
			_gt4->v1=V+H-1;
			_gt4->v2=V-1;
			_gt4->v3=V-1;
			} 
		else 
			{
			_gt4->v0=V;
			_gt4->v1=V;
			_gt4->v2=V+H;
			_gt4->v3=V+H;
			}
		} 
	else 
		{
		if (_xFlip) 
			{
			_gt4->v0=V;
			_gt4->v2=V;
			_gt4->v1=V+W;
			_gt4->v3=V+W;
			} 
		else 
			{
			_gt4->v0=V+W-1;
			_gt4->v2=V+W-1;
			_gt4->v1=V-1;
			_gt4->v3=V-1;
			}
		if (_yFlip) 
			{
			_gt4->u0=U+H-1;
			_gt4->u1=U+H-1;
			_gt4->u2=U-1;
			_gt4->u3=U-1;
			} 
		else 
			{
			_gt4->u0=U;
			_gt4->u1=U;
			_gt4->u2=U+H;
			_gt4->u3=U+H;
			}
		}
	_gt4->tpage=_fh->TPage;
	_gt4->clut=_fh->Clut;
}