/*	=================================================================================================
		スプライト管理ルーチン
					Programed By K.Tadamori		2000/12/23 - 

	-------------------------------------------------------------------------------------------------
		スプライトバッファリング　および　表示を担当します
		表示時にオフセットを掛ける機能も実装されています
	=================================================================================================	*/



/*	-------------------------------------------------------------------------------------------------
 *		構築
	-------------------------------------------------------------------------------------------------	*/
#include <sys/bios.h>
#include "sprite.h"

/*	-------------------------------------------------------------------------------------------------
 *		グローバル変数
	-------------------------------------------------------------------------------------------------	*/

/*	-------------------------------------------------------------------------------------------------
 *		ローカル構造体宣言
	-------------------------------------------------------------------------------------------------	*/
typedef struct {
	int iImageNo;
	int iX, iY;
	int	iParam;
} SPRITE_SET_BUFFER;

typedef struct {
	unsigned char ** pImagePatTable;
	int	iOffsetX, iOffsetY;								/*	オフセット設定								*/

	/*	スプライトバッファー		*/
	int	iBufferNo;
	SPRITE_SET_BUFFER	Buffer[SPRITE_IMAGE_NUMBER];

	/*	スプライトＲＡＭイメージ	*/
	int iSPNumber;
	int	iCharBuf[SPRITE_NUMBER];
	int	iSPX[SPRITE_NUMBER];
	int iSPY[SPRITE_NUMBER];

} SPRITE_REG;

/*	-------------------------------------------------------------------------------------------------
 *		ローカル変数
	-------------------------------------------------------------------------------------------------	*/
SPRITE_REG	l_sprite;

/*	-------------------------------------------------------------------------------------------------
 *		ローカル関数
	-------------------------------------------------------------------------------------------------	*/
void _Sprite_Update();

/*	-------------------------------------------------------------------------------------------------
 *		[概要]
 *
 *		[IN]
 *
 *		[OUT]
 *
 *		[RETURN]
 *
	-------------------------------------------------------------------------------------------------	*/
void sprite_Init()
{
	/*	初期化	*/
	l_sprite.iBufferNo = 0;
	l_sprite.iOffsetX = 0;
	l_sprite.iOffsetY = 0;
	l_sprite.iSPNumber = 0;

	/*	スプライト表示を有効にします	*/
	sprite_set_range(0, 0);								/*	ごみを表示しないようにスプライトを無効に	*/
}

/*	-------------------------------------------------------------------------------------------------
 *		[概要]
 *			スプライト表示を有効にします
	-------------------------------------------------------------------------------------------------	*/
void sprite_On()
{
	unsigned	uVal;
	uVal = display_status();
	uVal = uVal | DCM_SPR;
	display_control(uVal);
}

/*	-------------------------------------------------------------------------------------------------
 *		[概要]
 *			スプライト表示を無効にします
	-------------------------------------------------------------------------------------------------	*/
void sprite_Off()
{
	unsigned	uVal;
	uVal = display_status();
	uVal = uVal & (0xffff^DCM_SPR);
	display_control(uVal);
}

/*	-------------------------------------------------------------------------------------------------
 *		[概要]
 *
 *		[IN]
 *
 *		[OUT]
 *
 *		[RETURN]
 *
	-------------------------------------------------------------------------------------------------	*/
void sprite_Term()
{
}

/*	-------------------------------------------------------------------------------------------------
 *		[概要]
 *
 *		[IN]
 *
 *		[OUT]
 *
 *		[RETURN]
 *
	-------------------------------------------------------------------------------------------------	*/
void sprite_Sethome(int iX, int iY)
{
	l_sprite.iOffsetX = iX;
	l_sprite.iOffsetY = iY;
}

/*	-------------------------------------------------------------------------------------------------
 *		[概要]
 *			イメージテーブルのアドレスを設定します。
 *			イメージは複数のキャラクターの組み合わせを表現します
 *
 *			<ex>
 *				Image 0 ...	2 * 3
 *								0, 1
 *								2, 3
 *								4, 5
 *				上記データの先頭アドレスを集めた物をテーブルと呼びます
 *
 *		[IN]
 *
 *		[OUT]
 *
 *		[RETURN]
 *
 *	-------------------------------------------------------------------------------------------------	*/
void sprite_SetImagePatternTable( unsigned char ** pPatternTbl )
{
	l_sprite.pImagePatTable = pPatternTbl;
}

/*	-------------------------------------------------------------------------------------------------
 *		[概要]
 *			表示するキャラクターをバッファリングする
 *			実際に表示するにはsprite_draw() をコールすると表示されます。
 *		[IN]
 *
 *		[OUT]
 *
 *		[RETURN]
 *
	-------------------------------------------------------------------------------------------------	*/
void sprite_Set( int iImageNo, int iX, int iY, int iParam )
{
	if( l_sprite.iBufferNo >= SPRITE_IMAGE_NUMBER ){ return;	}

	l_sprite.Buffer[l_sprite.iBufferNo].iImageNo = iImageNo;
	l_sprite.Buffer[l_sprite.iBufferNo].iX = iX;
	l_sprite.Buffer[l_sprite.iBufferNo].iY = iY;
	l_sprite.Buffer[l_sprite.iBufferNo].iParam = iParam;

	l_sprite.iBufferNo++;
}

/*	-------------------------------------------------------------------------------------------------
 *		[概要]
 *			バッファーに貯めた要求を反映させる。
 *
 *		[IN]
 *
 *		[OUT]
 *
 *		[RETURN]
 *
	-------------------------------------------------------------------------------------------------	*/
void sprite_Draw()
{
	int	i;
	unsigned char j, k;
	int iX, iY, iXBack;
	int iXX, iYY;
	unsigned char * pImage;
	int * pWork;
	int iParam;

	/*	初期化				*/
	l_sprite.iSPNumber = 0;

	/*	スプライトの設定	*/
	for( i = 0; i < l_sprite.iBufferNo; i++ ){
		/*	準備	*/
		pImage = l_sprite.pImagePatTable[l_sprite.Buffer[i].iImageNo];
		pWork = (int *)(&(pImage[2]));

		iX = l_sprite.Buffer[i].iX - l_sprite.iOffsetX;
		iY = l_sprite.Buffer[i].iY - l_sprite.iOffsetY;
		iXBack = iX;
		iParam = l_sprite.Buffer[i].iParam;
		if( iParam & CFM_FLIP_V ){
			iYY = -8;
			iY = iY + ( pImage[1] - 1 ) * 8;
		} else {
			iYY = 8;
		}
		if( iParam & CFM_FLIP_H ){
			iXX = -8;
			iX = iX + ( pImage[0] - 1 ) * 8;
			iXBack = iX;
		} else {
			iXX = 8;
		}

		/*	展開	*/
		for( j = 0; j < pImage[1]; j++ ){
			for( k = 0; k < pImage[0]; k++ ){
				l_sprite.iSPX[l_sprite.iSPNumber] = iX;
				l_sprite.iSPY[l_sprite.iSPNumber] = iY;
				l_sprite.iCharBuf[l_sprite.iSPNumber] = *pWork | iParam;

				pWork++;
				iX += iXX;
				l_sprite.iSPNumber++;
				if( l_sprite.iSPNumber >= SPRITE_NUMBER ){ break;	}
			}
			if( l_sprite.iSPNumber >= SPRITE_NUMBER ){ break;	}
			iX = iXBack;
			iY += iYY;
		}
		if( l_sprite.iSPNumber >= SPRITE_NUMBER ){ break;	}
	}

	/*	バッファー使用完了	*/
	l_sprite.iBufferNo = 0;

	/*	Debug : Update	実際は垂直期間内に行う（割り込みを使用する！）*/
	_Sprite_Update();
}

/*	-------------------------------------------------------------------------------------------------
 *		[概要]
 *			キャラクターを設定します
 *		[IN]
 *
 *		[OUT]
 *
 *		[RETURN]
 *
 *	-------------------------------------------------------------------------------------------------	*/
void sprite_SetCharacter( int iStartNo, int iEndNo, void * pChrData )
{
	font_set_colordata( iStartNo, iEndNo, pChrData );
}

/*	-------------------------------------------------------------------------------------------------
 *		[概要]
 *
 *		[IN]
 *
 *		[OUT]
 *
 *		[RETURN]
 *
 *	-------------------------------------------------------------------------------------------------	*/
void _Sprite_Update()
{
	/*	一気に更新する方法があるはず・・・		*/
	int i;
	for( i = 0; i < l_sprite.iSPNumber; i++ ){
		sprite_set_location( i, l_sprite.iSPX[i], l_sprite.iSPY[i] );
		sprite_set_char( i, l_sprite.iCharBuf[i] );
	}
	sprite_set_range( 0, l_sprite.iSPNumber );
}

/*	-------------------------------------------------------------------------------------------------
 *		[概要]
 *
 *		[IN]
 *
 *		[OUT]
 *
 *		[RETURN]
 *
 *	-------------------------------------------------------------------------------------------------	*/
