/*******************************************************************************
 *  The most useful SET5.23 program in the world!
 *  ---------------------------------------------
 *	Thomas Szirtes / Elton Bird   Sega Europe
 *	Version 3 
 *  	Re-engineered for : Set 5.23, KAMUI 1.34
 *
 *	Demonstrates kamui initialization and simple test program
 *  	System malloc and file handling
 *  	Loading of Textures - NEW
 *	Please also look at new modified sbinit.c
 *  	Demonstrates use of new fast kamui macros
 *
 *******************************************************************************/

 
#define		_STRICT_UNION_ 
#define	 	_CLX2_
#define 	_CLX_
#include	<shinobi.h>
#include	"kamui2.h"

#define		VBUFFER_SIZE 	8*3*2000

/* new macro stuff - use level 4 */
#define		_KM_USE_VERTEX_MACRO_L4_
#include	"kamuix.h"

#include	"file.h"

KMVERTEX3               triangle[4];                           
KMVERTEXBUFFDESC        vertex_buffer;                          
KMSTRIPCONTEXT          global_sc;
KMSTRIPHEAD				global_sh;

KMDWORD					FBarea[24576 + 19456];	/*	FBstruct 4096 Entry (= 4096 * 24 / 4)*/

KMSYSTEMCONFIGSTRUCT	SystemConfig;

KMSURFACEDESC			surface1;				/* surface 1 (front buffer) */
KMSURFACEDESC			surface2;				/* surface 2 (back buffer) */
PKMSURFACEDESC 			psurface[2];			/* array of pointers to surfaces */

void definetriangle(KMVERTEX3 *tri)
{
	tri[0].ParamControlWord 	=       KM_VERTEXPARAM_NORMAL;
	tri[0].fX				=       100.f;
	tri[0].fY				=       100.f;

	tri[1].ParamControlWord		=       KM_VERTEXPARAM_NORMAL;	
	tri[1].fX				=       100.f;
	tri[1].fY				=       200.f;
	
	tri[2].ParamControlWord 	=       KM_VERTEXPARAM_NORMAL;
	tri[2].fX				=       200.f;
	tri[2].fY				=       100.f;

	tri[3].ParamControlWord 	=       KM_VERTEXPARAM_ENDOFSTRIP;
	tri[3].fX				=       200.f;
	tri[3].fY				=       200.f;
	
}


void	InitStripContext03(	PKMSTRIPCONTEXT pStripContext,PKMSTRIPHEAD	pStripHead,PKMSURFACEDESC	pTextureDesc)
{
	memset( pStripContext, 0, sizeof(global_sc));
	pStripContext->nSize = sizeof(KMSTRIPCONTEXT);
	pStripContext->StripControl.nListType		= KM_OPAQUE_POLYGON;
	pStripContext->StripControl.nUserClipMode		= KM_USERCLIP_DISABLE;
	pStripContext->StripControl.nShadowMode		= KM_NORMAL_POLYGON;
	pStripContext->StripControl.bOffset			= KM_FALSE;
	pStripContext->StripControl.bGouraud		= KM_TRUE;
	pStripContext->ObjectControl.nDepthCompare	= KM_GREATER;
	pStripContext->ObjectControl.nCullingMode		= KM_CULLSMALL;
	pStripContext->ObjectControl.bZWriteDisable	= KM_FALSE;
	pStripContext->ObjectControl.bDCalcControl			= KM_FALSE;
	pStripContext->ImageControl[KM_IMAGE_PARAM1].nSRCBlendingMode	= KM_ONE;
	pStripContext->ImageControl[KM_IMAGE_PARAM1].nDSTBlendingMode	= KM_ZERO;
	pStripContext->ImageControl[KM_IMAGE_PARAM1].bSRCSelect		= KM_FALSE;
	pStripContext->ImageControl[KM_IMAGE_PARAM1].bDSTSelect		= KM_FALSE;
	pStripContext->ImageControl[KM_IMAGE_PARAM1].nFogMode			= KM_NOFOG;
	pStripContext->ImageControl[KM_IMAGE_PARAM1].bColorClamp		= KM_FALSE;
	pStripContext->ImageControl[KM_IMAGE_PARAM1].bUseAlpha		= KM_FALSE;
	pStripContext->ImageControl[KM_IMAGE_PARAM1].bIgnoreTextureAlpha	= KM_FALSE;
	pStripContext->ImageControl[KM_IMAGE_PARAM1].nFlipUV			= KM_NOFLIP;
	pStripContext->ImageControl[KM_IMAGE_PARAM1].nClampUV			= KM_NOCLAMP;
	pStripContext->ImageControl[KM_IMAGE_PARAM1].nFilterMode		= KM_BILINEAR;
	pStripContext->ImageControl[KM_IMAGE_PARAM1].bSuperSampleMode	= KM_FALSE;
	pStripContext->ImageControl[KM_IMAGE_PARAM1].dwMipmapAdjust		= KM_MIPMAP_D_ADJUST_1_00;
	pStripContext->ImageControl[KM_IMAGE_PARAM1].nTextureShadingMode	= KM_MODULATE;
	pStripContext->ImageControl[KM_IMAGE_PARAM1].pTextureSurfaceDesc	= pTextureDesc;

	kmGenerateStripHead03( pStripHead,pStripContext );
}




/**************************************************************
 *      void InitSystem (void)
 *      
 *      Initialize display, buffers and clipping
 **************************************************************/


void InitSystem( void )
{
	KMSTATUS                      ks;
	KMPACKEDARGB			border;

	/* Initialize shinobi - special modified version - will initialize Kamui depending
	   on compiler switch */
 	sbInitSystem(KM_DSPMODE_NTSCNI640x480, KM_DSPBPP_RGB565, 1);
  
	border.dwPacked	=	0x00000000;
	kmSetBorderColor(border);

	psurface[0]			=	&surface1;
	psurface[1]			=	&surface2;
	/* generate vertex buffer */

	SystemConfig.dwSize					=	sizeof(KMSYSTEMCONFIGSTRUCT);
	SystemConfig.flags					=	KM_CONFIGFLAG_ENABLE_CLEAR_FRAMEBUFFER;
	/* for Frame buffer */
	SystemConfig.ppSurfaceDescArray		=	&psurface[0];		/* Array of SurfaceDesc	pointer	*/
	SystemConfig.fb.nNumOfFrameBuffer	=	2;			/* Number Of Frame Buffer		*/
	/* for Texture Memory */
	SystemConfig.nTextureMemorySize		=	0x100000*2;	/* Texture 2MB					*/
	SystemConfig.nNumOfTextureStruct	=	4096;		/* テクスチャ管理構造体の数		*/
	SystemConfig.nNumOfSmallVQStruct	=	1024;		/* VQテクスチャ管理構造体の数	*/
	SystemConfig.pTextureWork			=	&FBarea[0];	/* テクスチャ管理構造体領域		*/
	/* for Vertex buffer */
	SystemConfig.pBufferDesc			=	&vertex_buffer;	/* pointer to VERTEXBUFFDESC */
	SystemConfig.nNumOfVertexBank		=	2;
 	SystemConfig.pVertexBuffer	=(PKMDWORD)(((KMDWORD)  syMalloc(2*sizeof(KMDWORD)*VBUFFER_SIZE) & 0x0FFFFFFFUL) | 0xA0000000);
	SystemConfig.nVertexBufferSize		=	2*sizeof(KMDWORD)*VBUFFER_SIZE;	/* 2MB						*/
	SystemConfig.nPassDepth			=	1;
	SystemConfig.Pass[0].dwRegionArrayFlag = KM_PASSINFO_AUTOSORT;
	SystemConfig.Pass[0].fBufferSize[0] =  50.0f;
	SystemConfig.Pass[0].fBufferSize[1] =   0.0f;
	SystemConfig.Pass[0].fBufferSize[2] =  50.0f;
	SystemConfig.Pass[0].fBufferSize[3] =   0.0f;
	SystemConfig.Pass[0].fBufferSize[4] =   0.0f;

	kmSetSystemConfiguration( &SystemConfig );


//	InitVertexContext(&global_vc);

//	ks      =       kmSetVertexRenderState(&global_vc);
//	if (ks!=KMSTATUS_SUCCESS) {  return; }

//	ks      =       kmSetBackGroundRenderState(&global_vc);
//	if (ks!=KMSTATUS_SUCCESS) {  return; }
}


/**************************************************************
 *      void QuitSystem (void)
 *      
 **************************************************************/

void QuitSystem( void )
{
 	syFree	(SystemConfig.pVertexBuffer); 

	sbExitSystem();
}



/**************************************************************************
 *
 * void  LoadTexture (char *filename , PKMSURFACEDESC pTexSurfaceDesc)    
 *
 * Uses File access functions in File.c
 *
 *************************************************************************/

void	LoadTexture(char *filename , PKMSURFACEDESC pTexSurfaceDesc)
{
	Uint32		n;
	int			t;	
	GDFS			gdfs;
	long			filelen;
	DWORD			nSize;
	PKMDWORD		pTexture;
	KMSTATUS		status;
	KMTEXTURETYPE	nTextureType;

	/* Open file - allocate memory and load*/ 
	
	gdfs  =  t_fopen( filename, NULL );      		/* Open File     */
	gdFsGetFileSize(gdfs, &filelen);			/* length of texture file*/
	pTexture	=	(PKMDWORD)syMalloc(filelen);	/* allocate main memory*/
	t_fread((Uint8 *)pTexture, filelen,1,gdfs);	/* read in texture file*/
	t_fclose(gdfs);						/* file close*/
		
	/* parse GBIX - cheating not checking chunk sizes */
	if(pTexture[0]!=0x58494247)
	{
		t=0;
	}
	else
	{
		t=3;
	}

	/* parse PVRT  */
	if(pTexture[t]!=0x54525650)
	{
		syFree(pTexture);
		return;
	}
	
	nTextureType	=		pTexture[t+2];
	nSize			=		pTexture[t+3];

	status	=	kmCreateTextureSurface(
								pTexSurfaceDesc,
								(nSize&0xffff), 
								((nSize>>16)&0xffff), 
								nTextureType	
							  	);
			
	 
	status	=	kmLoadTexture(
							pTexSurfaceDesc,
							pTexture + (16 / sizeof(KMDWORD)) + t		
							);
	syFree(pTexture);
}



void checkfile(int *buffer,int b_length)
{
	int n;
	for (n=0;n<(b_length/4);n++)
	{
		if (buffer[n]!=n)
		{	
			while(1);
		}
	}
}


/**************************************************************
 *      void main( int argc, char *argv[ ], char *envp[ ] )
 *      
 **************************************************************/
const PDS_PERIPHERAL    *per;

Uint8	*buffer1;
Uint8	*buffer2;
Uint8	*buffer3;

void main( void )
{
	KMSTATUS                      ks;
	int                           frame=0,n,m;
	GDFS                          fd;
	KMSURFACEDESC			texture1;
   
	InitSystem();

	definetriangle(triangle);


	LoadTexture("Starfish.pvr",&texture1);

/*	global_vc.pTextureSurfaceDesc	=	&texture1;
	kmProcessVertexRenderState	(&global_vc);*/

	InitStripContext03(&global_sc,&global_sh,&texture1);


	/* main loop */
	while( TRUE )       
	{
  		/* now you can get the peripheral data for the desired port */
 		per = pdGetPeripheral(PDD_PORT_A0); 

		/* this checks which button is pressed - just like Ninja */

	if (per->on & PDD_DGT_KL) 
		{
			triangle[0].fX  -=      1.0f;
			triangle[1].fX  -=      1.0f;
			triangle[2].fX  -=      1.0f;
			triangle[3].fX  -=      1.0f;
		}

		if (per->on & PDD_DGT_KU) 
		{
			triangle[0].fY  -=      1.0f;
			triangle[1].fY  -=      1.0f;
			triangle[2].fY  -=      1.0f;
			triangle[3].fY  -=      1.0f;
		}

		if (per->on & PDD_DGT_KD) 
		{
			triangle[0].fY  +=      1.0f;
			triangle[1].fY  +=      1.0f;
			triangle[2].fY  +=      1.0f;
			triangle[3].fY  +=      1.0f;
		}

		if (per->on & PDD_DGT_KR) 
		{
			triangle[0].fX  +=      1.0f;
			triangle[1].fX  +=      1.0f;
			triangle[2].fX  +=      1.0f;
			triangle[3].fX  +=      1.0f;

		}


		kmBeginScene(&SystemConfig);

	
		kmBeginPass(&vertex_buffer);

	  	/* Set our frame render state */
//		ks = kmSetVertexRenderState(&global_vc);

		/* new macro l3 to set a triangle down */
  //		kmxxGetCurrentPtr(&vertex_buffer)
	//	kmxxStartVertexStrip(&vertex_buffer)
 		kmxxGetCurrentPtr(&vertex_buffer);
		kmxxStartStrip(&vertex_buffer,&global_sh);

	
		kmxxSetVertex_3( KM_VERTEXPARAM_NORMAL,
					triangle[0].fX, triangle[0].fY, 0.5f, 
					0.0f, 0.0f, 
					0xffffffff, 0xff000000 )

		kmxxSetVertex_3( KM_VERTEXPARAM_NORMAL,
					triangle[1].fX, triangle[1].fY, 0.5f, 
					0.0f, 1.0f, 
				    0xffffffff, 0xff000000 )

		kmxxSetVertex_3( KM_VERTEXPARAM_NORMAL,
					triangle[2].fX, triangle[2].fY, 0.5f, 
					1.0f, 0.0f, 
					0xffffffff, 0xff000000 )
  	  	kmxxSetVertex_3( KM_VERTEXPARAM_ENDOFSTRIP, 
					triangle[3].fX, triangle[3].fY, 0.5f, 
					1.0f, 1.0f, 
					0xffffffff, 0xff000000 )
   
		kmxxReleaseCurrentPtr(&vertex_buffer);

  	  	kmEndPass(&vertex_buffer);
	   	/* go away and render */

   	    kmRender(KM_RENDER_FLIP);

   		kmEndScene(&SystemConfig);


		/* must call this straight after flip frame buffer */
 		pdExecPeripheralServer(); 

   	}

      ks      =       kmDiscardVertexBuffer(&vertex_buffer);
	
	/*	Free memory */

	QuitSystem();

}
