/***********************************************************************************
           Copyright 1998, NEC Electronics Inc. All rights reserved.

Information and source code samples contained herein are provided "as-is",
without representations or warranties, and are subject to change without notice.
NEC Electronics Inc. cannot support modifications or derivative works created from
the sample source code provided. Developers may use, reproduce, and modify portions
or entire sections of the sample source code for the purposes of creating Dreamcast
applications.  Developers may only commercially distribute the executable or binary
portions of the sample source code.  Sample source code contained herein may not be
appropriate for use under all circumstances.  Please consult Developer documentation
provided along with your Dreamcast unit for additional information and suggestions.
************************************************************************************/


/***********************************************************************************
** File:     Main.c
** Purpose:  Example of how to use the ScrnGrab.c module
** Author:   Kevin Kralian
** Created:  December 17, 1998
**
** Version:  1.0
**
** Description:
**    This is a simple example that shows the use of the ScrnGrab() function
**    provided by the ScrnGrab.c module.
**
**    While running, you can press the <START> button to cause the display to
**    be captured and written to disk. It will appear as:
**    katana\utl\dev\codescape\EXAMPLE.BMP
**
***********************************************************************************/

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

#include "ScrnGrab.h"		/* Screen-grab function */
#include "DrawText.h"		/* Text-output routines */



#define CTX_MASK_ALL   (KM_PARAMTYPE | KM_LISTTYPE | KM_COLORTYPE | KM_UVFORMAT |       \
                        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_CLAMPUV | KM_FLIPUV |                \
                        KM_FILTERMODE | KM_SUPERSAMPLE | KM_MIPMAPDADJUST |             \
                        KM_TEXTURESHADINGMODE | KM_COLORCLAMP | KM_PALETTEBANK)

KMVERTEXCONTEXT OpaqueFlatGouraudContext =
{
    CTX_MASK_ALL, KM_POLYGON, KM_OPAQUE_POLYGON, KM_PACKEDCOLOR, KM_32BITUV,
    KM_GREATER, KM_CULLCW, KM_SCREEN, KM_NOTEXTUREGOURAUD, KM_NOMODIFIER,
    FALSE, KM_ONE, KM_ZERO, FALSE, FALSE, KM_NOFOG, FALSE, FALSE, FALSE,
    KM_NOCLAMP, KM_NOFLIP, KM_BILINEAR, FALSE, 0x4, KM_MODULATE, FALSE,
    0, 0, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
    0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0.0f
};

/* Size of vertex buffer. */
#define VBUFFER_SIZE    8*3*2000

/* System Configuration */
PKMSURFACEDESC          psurface[2];            /* array of pointers to surfaces */
KMVERTEXBUFFDESC		VertexBufferDesc;		/* Vertex-buffer */

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_RGB888,                       /* bits per pixel */
    0x100000,                               /* allocate amount of VRAM for texture = 4MB */
    &VertexBufferDesc,                      /* 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 */
    {20.f,20.f,20.f,20.f,20.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 */
};


#define DEGREES_TO_RADIANS(d)	((d)*3.14159/180.0)
#define RGBA(r,g,b,a)   		( (int)((a)<<24) + (int)((r)<<16) + (int)((g)<<8) + (int)(b) )
#define RGB(r,g,b) 				( (0xff<<24) + ((int)(r)<<16) + ((int)(g)<<8) + (int)(b) )

int main (void)
{
    KMSURFACEDESC       PrimarySurfaceDesc;     /* Primary framebuffer. */
    KMSURFACEDESC       BackSurfaceDesc;        /* Back framebuffer surface. */
    KMVERTEX_00         CurrentStrip[16];    /* Strip of textured triangles. */
    int                 i,x,y, step;
	KMPACKEDARGB		packedARGB;

	float				fRotation = 0.0;
	float				fRotationDelta = 4.0;
	float				fScale = 220.0;
	float				fVal;

#ifdef __GNUC__
	shinobi_workaround();
#endif
	/* Initialize the display device and set the frame buffer mode. */

    /* Check the cable for NTSC/PAL or VGA */
    switch (syCblCheckCable())
	{
        /* Initialize the display device and set the frame buffer based on the video mode. */
        case SYE_CBL_CABLE_NTSC:    /* Note: SYE_CBL_CABLE_NTSC/PAL defined as same value. */
            switch (syCblCheckBroadcast())
            {
                case SYE_CBL_BROADCAST_NTSC:    /* U.S./North America NTSC (60Hz). */
                case SYE_CBL_BROADCAST_PALM:    /* Brazil PAL-M (60Hz). */
                    sbInitSystem (KM_DSPMODE_NTSCNI640x480, KM_DSPBPP_RGB565, 1);
                    break;
                case SYE_CBL_BROADCAST_PAL:     /* Europe PAL (50Hz). */
                case SYE_CBL_BROADCAST_PALN:    /* Argentina PAL-N (50Hz). */
                    sbInitSystem (KM_DSPMODE_PALNI640x480, KM_DSPBPP_RGB565, 1);
                    break;
            }
            break;
        case SYE_CBL_CABLE_VGA:
            sbInitSystem (KM_DSPMODE_VGA, KM_DSPBPP_RGB565, 1);
            break;
	}

	/* setup border color */
	packedARGB.dwPacked	=	0x00000000;
	kmSetBorderColor(packedARGB);


	/* setup front & back framebuffer structs */
    psurface[0]         =   &PrimarySurfaceDesc;
    psurface[1]         =   &BackSurfaceDesc;

    /* generate vertex buffer */
	kmsc.pVertexBuffer	=	(void *)((((int)syMalloc(2*sizeof(KMDWORD)*VBUFFER_SIZE)&0x3FFFFFE0)|0xA0000000)+32);

	/* Submit system configuration */
    kmSetSystemConfiguration(&kmsc);

	kmProcessVertexRenderState (&OpaqueFlatGouraudContext);

    /* The main render loop. */
    while (TRUE)
    {
		/* Set Kamui's global render state for opaque gouraud */
        kmSetVertexRenderState (&OpaqueFlatGouraudContext);

        /* Start rendering opaque gouraud strips. */
        kmStartVertexStrip (&VertexBufferDesc);

		for (fVal = 0.0; fVal < 25.0; fVal++)
		{

	        /* Set the vertices in the current strip to draw a textured square. */
	        CurrentStrip[0].ParamControlWord     = KM_VERTEXPARAM_NORMAL;
	        CurrentStrip[0].fX                   = 320.0 + cos( DEGREES_TO_RADIANS(fRotation-fVal) ) * fScale;
	        CurrentStrip[0].fY                   = 240.0 - sin( DEGREES_TO_RADIANS(fRotation-fVal) ) * fScale;
	        CurrentStrip[0].u.fInvW              = 1.0/(fVal+1);
	        CurrentStrip[0].uBaseRGB.dwPacked    = RGB(255-fVal*10,0,0);

	        CurrentStrip[1].ParamControlWord     = KM_VERTEXPARAM_NORMAL;
	        CurrentStrip[1].fX                   = 320.0 + cos( DEGREES_TO_RADIANS(fRotation+120.0-fVal) ) * fScale;
	        CurrentStrip[1].fY                   = 240.0 - sin( DEGREES_TO_RADIANS(fRotation+120.0-fVal) ) * fScale;
	        CurrentStrip[1].u.fInvW              = 1.0/(fVal+1);
	        CurrentStrip[1].uBaseRGB.dwPacked    = RGB(0,255-fVal*10,0);

	        CurrentStrip[2].ParamControlWord     = KM_VERTEXPARAM_ENDOFSTRIP;
	        CurrentStrip[2].fX                   = 320.0 + cos( DEGREES_TO_RADIANS(fRotation+240.0-fVal) ) * fScale;
	        CurrentStrip[2].fY                   = 240.0 - sin( DEGREES_TO_RADIANS(fRotation+240.0-fVal) ) * fScale;
	        CurrentStrip[2].u.fInvW              = 1.0/(fVal+1);
	        CurrentStrip[2].uBaseRGB.dwPacked    = RGB(0,0,255-fVal*10);

	        kmSetVertex(&VertexBufferDesc, CurrentStrip+0, KM_VERTEXTYPE_00, sizeof (KMVERTEX_00));
	        kmSetVertex(&VertexBufferDesc, CurrentStrip+1, KM_VERTEXTYPE_00, sizeof (KMVERTEX_00));
	        kmSetVertex(&VertexBufferDesc, CurrentStrip+2, KM_VERTEXTYPE_00, sizeof (KMVERTEX_00));
		}

	  	fRotation += fRotationDelta;

        /* Render the polygons */
        kmRender();

		/* And print text (this is SLOW) */
		diagUseTransparentBackground();
		diagSetScreenMargin(2);
		diagSetPixelDoubling( 1,1 );   /* 32x32 text, easier to read on 640x480 interlace */
		diagSetXY( 0, 0 );
		diagSetFGColor(200,200,200);
		diagPrintf("Press <START> to capture screen...\n\n");
		diagSetFGColor(100,100,100);
		diagPrintf("(Will take ~10 seconds)\n");

		/* Done drawing text, now we can flip the display */
		kmFlipFrameBuffer();


		/* Check controller */
		{
			PDS_PERIPHERAL *pJoy;
			pdExecPeripheralServer();

			pJoy = (PDS_PERIPHERAL *) pdGetPeripheral(PDD_PORT_A0);

			if ( pJoy->press & PDD_DGT_ST )
			{
				/********* Save Display Buffer *********/
				SaveFrontBufferAsBMP( "Example.bmp" );
			}
		}

    } 


    /* Free vertex buffers. */
    kmDiscardVertexBuffer (&VertexBufferDesc);

    /* Free the frame buffers. */
    kmFreeTexture (&PrimarySurfaceDesc);
    kmFreeTexture (&BackSurfaceDesc);

    return 0;
}
