/*******************************************************************************
 *  The most useful SET5.16 program in the world!
 *  ---------------------------------------------
 *	Thomas Szirtes / Sega Europe
 *	Version 2
 *  Re-engineered for : Set 5.16, KAMUI 1.3 or above
 *
 *	Demonstrates kamui initialization and simple test program
 *  System malloc and file handling
 *  Please also look at new modified sbinit.c
 *  Demonstrates use of new fast kamui macros
 *
 *******************************************************************************/


/* new macro stuff - use level 3 */
#define		_KM_USE_VERTEX_MACRO_
#define		_KM_USE_VERTEX_MACRO_L3_

#include	<shinobi.h>
#include	"kamui.h"

#define VBUFFER_SIZE 	8*3*2000

#include		"kamuix.h"
#include		"file.h"

KMVERTEX0               triangle[3];
KMVERTEXBUFFDESC        vertex_buffer;
KMVERTEXCONTEXT         global_vc;

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

/* System Configuration */

KMSYSTEMCONFIGSTRUCT kmsc = {
		sizeof(KMSYSTEMCONFIGSTRUCT),
		KM_CONFIGFLAG_ENABLE_CLEAR_FRAMEBUFFER,	/* set any special flags = clear frame buffer */
		psurface,						/* pointer to array of surface pointers */
		2,							/* number of buffers = 2 */
		640,480,						/* width and height of surface */
		KM_DSPBPP_RGB565,					/* bits per pixel */
		0x100000,						/* allocate amount of VRAM for texture = 4MB */
		&vertex_buffer,					/* pointer to vertex buffer descriptor */
		0,							/* pointer to vertex buffer - ** malloc now on application side */
		2*VBUFFER_SIZE,							/* size in DWORDS of vertex buffer - must be multiple of 32 */
		{60.f,0.f,40.f,0.f,0.f},			/* percentage of vbuf to use for each type of vertex */
		0,0,0,0,0,0,0,					/* reserved */
		KM_VERTEXBUFMODEL_NORMAL,			/* latency model = 3VB */
	};


void definetriangle(KMVERTEX0 *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].uBaseRGB.dwPacked	=       0xffff0000;

	tri[1].ParamControlWord		=       KM_VERTEXPARAM_NORMAL;
	tri[1].fX					=       400.f;
	tri[1].fY					=       100.f;
	tri[1].u.fZ					=       1.f;
	tri[1].uBaseRGB.dwPacked	=       0xff0000ff;

	tri[2].ParamControlWord 	=       KM_VERTEXPARAM_ENDOFSTRIP;
	tri[2].fX					=       400.f;
	tri[2].fY					=       400.f;
	tri[2].u.fZ					=       1.f;
	tri[2].uBaseRGB.dwPacked	=       0xff00ff00;
}



void    InitVertexContext(PKMVERTEXCONTEXT pVertexContext)
{
	pVertexContext->RenderState = KM_DEPTHMODE					| KM_CULLINGMODE                                                                                        | KM_SCREENCOORDINATION | KM_SHADINGMODE
								| KM_MODIFIER                   | KM_ZWRITEDISABLE
								| KM_SRCBLENDINGMODE    		| KM_DSTBLENDINGMODE
								| KM_SRCSELECT                  | KM_DSTSELECT
								| KM_FOGMODE                    | KM_USESPECULAR
								| KM_USEALPHA                   | KM_IGNORETEXTUREALPHA
								| KM_FLIPUV                     | KM_CLAMPUV
								| KM_FILTERMODE                 | KM_SUPERSAMPLE
								| KM_MIPMAPDADJUST              | KM_TEXTURESHADINGMODE
								| KM_PARAMTYPE                  | KM_LISTTYPE
								| KM_COLORTYPE                  | KM_USESPECULAR
								| KM_UVFORMAT;

	pVertexContext->ParamType				= KM_POLYGON;
	pVertexContext->ListType				= KM_OPAQUE_POLYGON;
	pVertexContext->ColorType				= KM_PACKEDCOLOR;
	pVertexContext->bUseSpecular            = FALSE;
	pVertexContext->UVFormat				= KM_32BITUV;

	pVertexContext->DepthMode				= KM_GREATER;
	pVertexContext->CullingMode				= KM_NOCULLING;
	pVertexContext->ScreenCoordination      = KM_SCREEN;
	pVertexContext->ShadingMode				= KM_NOTEXTUREGOURAUD;
	pVertexContext->SelectModifier          = KM_NOMODIFIER;
	pVertexContext->bZWriteDisable          = FALSE;

	pVertexContext->SRCBlendingMode         = KM_ONE;
	pVertexContext->DSTBlendingMode         = KM_ZERO;
	pVertexContext->bSRCSel					= FALSE;
	pVertexContext->bDSTSel					= FALSE;
	pVertexContext->FogMode					= KM_NOFOG;
	pVertexContext->bUseSpecular            = FALSE;
	pVertexContext->bUseAlpha				= FALSE;
	pVertexContext->FlipUV					= KM_NOFLIP;
	pVertexContext->ClampUV					= KM_NOCLAMP;
	pVertexContext->FilterMode				= KM_POINT_SAMPLE;
	pVertexContext->bSuperSample            = FALSE;
	pVertexContext->MipMapAdjust            = 0x00000004;           /* D=1.00 */
	pVertexContext->TextureShadingMode      = KM_MODULATE;


	pVertexContext->bColorClamp             = FALSE;
	pVertexContext->PaletteBank             = 0;

	pVertexContext->fFaceColorAlpha         = 1.0f;
	pVertexContext->fFaceColorRed           = 1.0f;
	pVertexContext->fFaceColorGreen         = 1.0f;
	pVertexContext->fFaceColorBlue          = 1.0f;
	pVertexContext->fOffsetColorAlpha       = 1.0f;
	pVertexContext->fOffsetColorRed         = 1.0f;
	pVertexContext->fOffsetColorGreen       = 1.0f;
	pVertexContext->fOffsetColorBlue        = 1.0f;

	kmProcessVertexRenderState(pVertexContext);
}




/**************************************************************
 *      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 */
	kmsc.pVertexBuffer	=	(void *)((((int)syMalloc(2*sizeof(KMDWORD)*VBUFFER_SIZE)&0x3FFFFFE0)|0xA0000000)+32);

	ks		=	kmSetSystemConfiguration(&kmsc);			/* Set system configuration */

	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	(kmsc.pVertexBuffer);

	sbExitSystem();
}


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

Uint8	*buffer;

void main( void )
{
	KMSTATUS                        ks;
	int                             frame=0;
	GDFS                            fd;

	InitSystem();

	definetriangle(triangle);

#if 1
	/* allocate memory */

    buffer  =   syMalloc(1024);

	/*
	 *		Quick example of using file access - this actually calls my routines in file.c
	 *		I wrote these to allow simple porting from native DOS version - since this allows byte
	 *		access to files instead of just sector access that Shinobi supports. Its just a simple buffer routine.
	 */
	fd  =  t_fopen("test.txt",NULL);

	/*	Read in 32 bytes */
	t_fread( buffer, sizeof(Uint8), 32, fd );
	/* and read in the next 8 bytes */
	t_fread( buffer+32, sizeof(Uint8), 8, fd );

	/* close the file - you should now have a little text message in the buffer[] array - look in the debugger!  */
	t_fclose(fd);
#endif

	/* 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;
		}

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

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

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


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

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

			kmxxStartVertexStrip(&vertex_buffer);
			kmxxSetVertex_0( KM_VERTEXPARAM_NORMAL,     triangle[0].fX, triangle[0].fY, 1.f, triangle[0].uBaseRGB.dwPacked );
			kmxxSetVertex_0( KM_VERTEXPARAM_NORMAL,     triangle[1].fX, triangle[1].fY, 1.f, triangle[1].uBaseRGB.dwPacked );
			kmxxSetVertex_0( KM_VERTEXPARAM_ENDOFSTRIP, triangle[2].fX, triangle[2].fY, 1.f, triangle[2].uBaseRGB.dwPacked );

		kmxxReleaseCurrentPtr(&vertex_buffer);


		/* go away and render */
  		kmRender();

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

   	}


    ks      =       kmDiscardVertexBuffer(&vertex_buffer);

	/*	Free memory */

	QuitSystem();


}