/*******************************************************************************
 *  SAMPLE PROGRAM FOR KAMUI2
 *  -------------------------------
 *	Thomas Szirtes / Sega Europe
 *	Ray Tran / Sega Europe
 *		- added support for transparent polys
 *		- multiple vertex contexts
 *		- conversion to Kamui 2
 * 
 *  For : Set 5.24, KAMUI 1.34
 *
 *******************************************************************************/

  
#define	_STRICT_UNION_
#define	_CLX2_ 
#define VBUFFER_SIZE 	8*3*2000
#define	_KM_USE_VERTEX_MACRO_L4_

#include	<shinobi.h>
#include	<kamui2.h>

#include	<kamuix.h>
#include	"file.h"


KMVERTEX3               triangle[4];                           
KMVERTEXBUFFDESC        vertex_buffer;                          

KMSTRIPCONTEXT		opaque_sc;
KMSTRIPCONTEXT		trans_sc;
KMSTRIPHEAD			opaque_sh;
KMSTRIPHEAD			trans_sh;

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

KMDWORD	FBarea[24576 + 19456];


/* System Configuration */
KMSYSTEMCONFIGSTRUCT SystemConfig;


void definetriangle(KMVERTEX3 *tri)
{
	tri[0].ParamControlWord	=       KM_VERTEXPARAM_NORMAL;
	tri[0].fX				=       100.f;
	tri[0].fY				=       100.f;
	tri[0].u.fZ				=		1.f;
	tri[0].fU				=		0.f;
	tri[0].fV				=		0.f;
	tri[0].uBaseRGB.dwPacked			=		0xffff0000;
	tri[0].uOffsetRGB.dwPacked		=		0x00000000;
	
	tri[1].ParamControlWord		=       KM_VERTEXPARAM_NORMAL;	
	tri[1].fX				=       100.f;
	tri[1].fY				=       200.f;
	tri[1].u.fZ				=		1.f;
	tri[1].fU				=		0.f;
	tri[1].fV				=		1.f;
	tri[1].uBaseRGB.dwPacked			=		0xff00ff00;
	tri[1].uOffsetRGB.dwPacked		=		0x00000000;
	
	tri[2].ParamControlWord 	=       KM_VERTEXPARAM_NORMAL;
	tri[2].fX				=       300.f;
	tri[2].fY				=       100.f;
	tri[2].u.fZ				=		1.f;
	tri[2].fU				=		1.f;
	tri[2].fV				=		0.f;
	tri[2].uBaseRGB.dwPacked			=		0xff0000ff;
	tri[2].uOffsetRGB.dwPacked		=		0x00000000;

	tri[3].ParamControlWord 	=       KM_VERTEXPARAM_ENDOFSTRIP;
	tri[3].fX				=       300.f;
	tri[3].fY				=       200.f;
	tri[3].u.fZ				=		1.f;
	tri[3].fU				=		1.f;
	tri[3].fV				=		1.f;
	tri[3].uBaseRGB.dwPacked			=		0xff0000ff;
	tri[3].uOffsetRGB.dwPacked		=		0x00000000;
 

}

void InitOpaqueStripContext03( PKMSTRIPCONTEXT pStripContext, PKMSTRIPHEAD pStripHead, PKMSURFACEDESC pTextureDesc)
{
	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_NOCULLING;//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_DECAL;
	pStripContext->ImageControl[KM_IMAGE_PARAM1].pTextureSurfaceDesc	= pTextureDesc;

	kmGenerateStripHead03( pStripHead,pStripContext );
}

void InitTransStripContext03( PKMSTRIPCONTEXT pStripContext, PKMSTRIPHEAD pStripHead, PKMSURFACEDESC pTextureDesc)
{
	pStripContext->nSize = sizeof(KMSTRIPCONTEXT);
	pStripContext->StripControl.nListType		 						= KM_TRANS_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_SRCALPHA;
	pStripContext->ImageControl[KM_IMAGE_PARAM1].nDSTBlendingMode		= KM_INVSRCALPHA;
	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_TRUE;
	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_ALPHA;
	pStripContext->ImageControl[KM_IMAGE_PARAM1].pTextureSurfaceDesc	= pTextureDesc;

	kmGenerateStripHead03( pStripHead,pStripContext );
}


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


void InitSystem( void )
{
	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;

	/* Setup system configuration */	
	SystemConfig.dwSize					=	sizeof(KMSYSTEMCONFIGSTRUCT);
	SystemConfig.flags					=	KM_CONFIGFLAG_ENABLE_CLEAR_FRAMEBUFFER;
	// for Frame buffer 
	SystemConfig.ppSurfaceDescArray		=	psurface;		// 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(0x200000) & 0x0FFFFFFFUL) | 0xA0000000);//(void *)((((int)syMalloc(2*sizeof(KMDWORD)*VBUFFER_SIZE)&0x3FFFFFE0)|0xA0000000));   
	SystemConfig.nVertexBufferSize		=	0x100000*2;//VBUFFER_SIZE*2;	// 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;

	// Set system configuration 
	kmSetSystemConfiguration(&SystemConfig);			
}


/**************************************************************
 *      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;		 /* new versions of pvrconv this should be changed to 4 */
	}

	/* 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 main( int argc, char *argv[ ], char *envp[ ] )
 *      
 **************************************************************/
const PDS_PERIPHERAL    *per;


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

	InitSystem();

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

	InitOpaqueStripContext03(&opaque_sc, &opaque_sh, &texture1);
	InitTransStripContext03(&trans_sc, &trans_sh, &texture1);		

	definetriangle(triangle);

	/* 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  -=      16.0f;
			triangle[1].fX  -=      16.0f;
			triangle[2].fX  -=      16.0f;
			triangle[3].fX  -=      16.0f;
		}

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

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

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

		}

		kmBeginScene(&SystemConfig);
		kmBeginPass(&vertex_buffer);
	
		kmxxGetCurrentPtr(&vertex_buffer);
		kmxxStartStrip(&vertex_buffer, &opaque_sh);

//		m=0;
//		n=0;
		
		for(m=0;m<20;m+=2)
		{
			for(n=0;n<100;n+=2)
			{	
				kmxxSetVertex_3( KM_VERTEXPARAM_NORMAL,     triangle[0].fX+n, triangle[0].fY+m, 0.5f, 0.0f,0.0f,0xffff0000,0x00000000 );
				kmxxSetVertex_3( KM_VERTEXPARAM_NORMAL,     triangle[1].fX+n, triangle[1].fY+m, 0.5f, 0.0f,1.0f,0xff00ff00,0x00000000 );
				kmxxSetVertex_3( KM_VERTEXPARAM_NORMAL,     triangle[2].fX+n, triangle[2].fY+m, 0.5f, 1.0f,0.0f,0xff0000ff,0x00000000 );
				kmxxSetVertex_3( KM_VERTEXPARAM_ENDOFSTRIP, triangle[3].fX+n, triangle[3].fY+m, 0.5f, 1.0f,1.0f,0xff0000ff,0x00000000 );
			}
		}	
		kmxxReleaseCurrentPtr(&vertex_buffer);
		kmEndStrip(&vertex_buffer);
			
		kmxxGetCurrentPtr(&vertex_buffer);
		kmxxStartStrip(&vertex_buffer, &trans_sh);
		
		m=40;
		n=40;
		
		kmxxSetVertex_3( KM_VERTEXPARAM_NORMAL,     triangle[0].fX+n, triangle[0].fY+m, 1.f, 0.0f,0.0f,0x7fffffff,0x00000000 );
		kmxxSetVertex_3( KM_VERTEXPARAM_NORMAL,     triangle[1].fX+n, triangle[1].fY+m, 1.f, 0.0f,1.0f,0x7fffffff,0x00000000 );
		kmxxSetVertex_3( KM_VERTEXPARAM_NORMAL,     triangle[2].fX+n, triangle[2].fY+m, 1.f, 1.0f,0.0f,0x7fffffff,0x00000000 );
		kmxxSetVertex_3( KM_VERTEXPARAM_ENDOFSTRIP, triangle[3].fX+n, triangle[3].fY+m, 1.f, 1.0f,1.0f,0x7fffffff,0x00000000 );
		
		kmxxReleaseCurrentPtr(&vertex_buffer);
		kmEndStrip(&vertex_buffer);
		
		kmEndPass(&vertex_buffer);
		kmRender(KM_RENDER_FLIP);
		
		/* must call this straight after flip frame buffer */
		pdExecPeripheralServer(); 

		kmEndScene(&SystemConfig); 
   	}

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

	QuitSystem();

}
