/*******************************************************************************
 *  A useful SET4 program
 *  ---------------------
 *	Thomas Szirtes / Sega Europe
 *
 *	This is a really simple program that demonstrates pretty much everything
 *	you need to know about Set4 development with Kamui.
 *  It initializes the Shinobi library and then calls Kamui routines. This
 *  demonstrates Peripheral Access, File Access, and Memory Allocation.
 *
 *  You will need to use the GD Emulator to run this project. Copy the
 *  text.txt file into the root directory of a GDROM filesystem.
  *******************************************************************************/


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

KMVERTEXCONTEXT     context;
KMSURFACEDESC       front_buffer;
KMSURFACEDESC       back_buffer;

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

const PDS_PERIPHERAL    *per;     /* Peripheral data structure. */
Uint8 *buffer;                    /* Pointer to file load buffer. */


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                   = 200.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                   = 200.f;
    tri[2].fY                   = 200.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;
	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;

    /*  Initialize Shinobi system. */
    sbInitSystem (0, 0, 0);

    InitVertexContext (&global_vc);

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

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

    ks = kmSetCullingRegister (0.001f);
    if (ks != KMSTATUS_SUCCESS)
        return;

    ks = kmSetPixelClipping (0, 0, 640, 480);
    if (ks != KMSTATUS_SUCCESS)
        return;

    ks = kmCreateVertexBuffer (&vertex_buffer, 200000, 256, 100000, 256);
    if (ks != KMSTATUS_SUCCESS)
        return;
}


/**************************************************************
 *      void QuitSystem (void)
 **************************************************************/
void QuitSystem (void)
{
	sbExitSystem();
}


/**************************************************************
 *      void main()
 **************************************************************/

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

	InitSystem();

    definetriangle (triangle);

    /* Allocate memory */
    buffer = syMalloc(64);

	/*
	 *		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.
	 */
    fd = t_fopen ("test.txt", NULL);

    /* Read in 32 bytes. */
    t_fread (buffer, sizeof(Uint8), 32, fd);
    /* 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);

	/* main loop */
	while( TRUE )
	{
        /* this should be called pretty much first thing in your loop
           pdExecPeripheralServer() creates the peripheral structure. */
		pdExecPeripheralServer();

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

		ks = kmSetVertexRenderState(&global_vc);
		ks = kmStartVertexStrip(&vertex_buffer);

        ks = kmSetVertex (  &vertex_buffer,
							&triangle[0],
							KM_VERTEXTYPE_00,
							sizeof(KMVERTEX_00)
							);

        ks = kmSetVertex (  &vertex_buffer,
							&triangle[1],
							KM_VERTEXTYPE_00,
							sizeof(KMVERTEX_00)
							);

        ks = kmSetVertex (  &vertex_buffer,
							&triangle[2],
							KM_VERTEXTYPE_00,
							sizeof(KMVERTEX_00)
							);

        kmRender();
        kmFlipFrameBuffer();
	}

    ks = kmDiscardVertexBuffer (&vertex_buffer);

    /* Free memory. */
	syFree	(buffer);

	QuitSystem();
}