// **************************************************************************
// *				Sporting Clays for the Nintendo 64						*
// *					   (C) 1999 Charles Doty                           	*
// *	 	   Display Source file contains screen related code				*
// **************************************************************************

#include "display.h"
#include "main.h"
#include "scene3d.h"
#include "static.h"

BOOL				Is_NTSC;						// is the display in NTSC mode?
long 				ActiveBuffer 	= 0;
dynamic_stuff   	dynamic[3];
OSTask          	task[3];
u64 				dram_stack[SP_DRAM_STACK_SIZE64];// Used for matrix stack
dynamic_stuff		*generate;
RECT				Mouse;
RECT				Shots[MAXSHOTS];
BOOL				DrawText = FALSE;
BYTE				TextMap[SCREENHEIGHT / FONTSIZE][SCREENWIDTH / FONTSIZE];

extern BOOL 		MouseUsed;
extern BOOL 		PadUsed;
extern BOOL 		Shot[2];						// Draw shot (miss) 1/2
extern OSMesgQueue	rdpMessageQ;
extern OSMesgQueue	rspMessageQ;
extern OSMesgQueue	retraceMessageQ;
extern Gfx			BackgroundGfx[NUM_DL(BACKGROUNDBLOCKS)];
extern Sprite 		BackgroundImage;
extern Gfx			MouseGfx[NUM_DL(1)];
extern Sprite 		MouseImage;
extern Sprite 		ShotsImage[MAXSHOTS];
extern Gfx			ShotsGfx[MAXSHOTS][NUM_DL(1)];
extern Sprite 		TextImage[300];
extern Gfx			TextGfx[300][NUM_DL(1)];
extern char   		*staticSegment;
extern WORD    		FrontBuffer[SCREENWIDTH * SCREENHEIGHT];
extern WORD    		BackBuffer[SCREENWIDTH * SCREENHEIGHT];
extern Bitmap 		Levels[][48];					// Background Bitmaps
extern Bitmap 		Font[49];						// Font Bitmaps

DWORD DisplayInitialize()
{
	long	loop;

	Scene3DInitialize();
	InitializeTextDisplay();

  	osViBlack(0);

	for (loop = 1; loop < 300; loop++)
	{
		memcpy(&TextImage[loop], &TextImage[0], sizeof(Sprite));
	}

	return ERR_NOERROR;
}

DWORD Flip()
{
    long		loop;
    long		outerloop;
    long		innerloop;
    OSTask		*gentask;
    Gfx			*GfxList0;
	Gfx			*GfxList;
	Gfx			*DisplayList;
	Sprite 		*sp;

  	generate 	= &(dynamic[(ActiveBuffer ? 0 : 1)]);
  	GfxList0  	= &(generate->glist[0]);
  	GfxList   	= GfxList0;

  	// Tell RCP where each segment is
  	gSPSegment(GfxList++, 0, 0);
  	gSPSegment(GfxList++, STATIC_SEGMENT, osVirtualToPhysical(staticSegment));

  	// Clear ZBuffer
  	gSPDisplayList(GfxList++, ClearZBuffer);

  	// Select surface to write to
  	gDPSetColorImage(GfxList++, G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREENWIDTH,
  		OS_K0_TO_PHYSICAL(ActiveBuffer ? FrontBuffer : BackBuffer));

  	// Initialize RSP and RDP state
  	gSPDisplayList(GfxList++, Initialize);

	gDPPipeSync(GfxList++);
	gDPSetCycleType(GfxList++, G_CYC_1CYCLE);
	gDPSetScissor(GfxList++, G_SC_NON_INTERLACE, 0, 0, SCREENWIDTH, SCREENHEIGHT);

	spInit(&GfxList);

	sp 				= &BackgroundImage;
	sp->rsp_dl 		= BackgroundGfx;
	sp->rsp_dl_next	= NULL;

  	DisplayList		= spDraw(sp);

 	gSPDisplayList(GfxList++, DisplayList);

	spFinish(&GfxList);
  	GfxList--;

 	gDPPipeSync(GfxList++);

	Render(&GfxList);

	gDPPipeSync(GfxList++);

	for (loop = 0; loop < MAXSHOTS; loop++)
	{
    	if (TRUE == Shot[loop])
    	{
			spInit(&GfxList);

			sp 				= &ShotsImage[loop];
			sp->rsp_dl 		= ShotsGfx[loop];
			sp->rsp_dl_next	= NULL;
  			sp->x			= Shots[loop].x;
  			sp->y			= Shots[loop].y;

	  		DisplayList		= spDraw(sp);

  			gSPDisplayList(GfxList++, DisplayList);

			spFinish(&GfxList);
			GfxList--;
    	}
	}

    if (TRUE == PadUsed)
    {
		spInit(&GfxList);

		sp 				= &MouseImage;
		sp->rsp_dl 		= MouseGfx;
		sp->rsp_dl_next	= NULL;
  		sp->x			= Mouse.x;
  		sp->y			= Mouse.y;

  		DisplayList		= spDraw(sp);

  		gSPDisplayList(GfxList++, DisplayList);

		spFinish(&GfxList);
		GfxList--;
    }

  	if (TRUE == DrawText)
  	{
		spInit(&GfxList);

		for (outerloop = 0; outerloop < SCREENHEIGHT / FONTSIZE; outerloop++)
		{
			for (innerloop = 0; innerloop < SCREENWIDTH / FONTSIZE; innerloop++)
			{
				sp 				= &TextImage[outerloop * 20 + innerloop];
				sp->rsp_dl 		= TextGfx[outerloop * 20 + innerloop];
				sp->rsp_dl_next	= NULL;
  				sp->x			= innerloop * FONTSIZE;
	  			sp->y			= outerloop * FONTSIZE;
	            sp->bitmap		= &Font[TextMap[outerloop][innerloop]];

  				DisplayList		= spDraw(sp);

  				gSPDisplayList(GfxList++, DisplayList);
        	}
        }

		spFinish(&GfxList);
        GfxList--;
  	}

  	gDPPipeSync(GfxList++);
	gDPFullSync(GfxList++);
  	gSPEndDisplayList(GfxList++);

  	// Build graphics task to execute the display list we just built
  	gentask 					= &(task[ActiveBuffer ? 0 : 1]);
  	gentask->t.type            	= M_GFXTASK;
  	gentask->t.flags           	= 0x0;
  	gentask->t.ucode_boot      	= (u64 *)rspbootTextStart;
  	gentask->t.ucode_boot_size 	= ((int)rspbootTextEnd - (int)rspbootTextStart);
  	gentask->t.ucode           	= (u64 *)gspFast3DTextStart;
  	gentask->t.ucode_data      	= (u64 *)gspFast3DDataStart;
  	gentask->t.ucode_size      	= 4096;
  	gentask->t.ucode_data_size 	= 2048;
  	gentask->t.dram_stack      	= (u64 *)dram_stack;
  	gentask->t.dram_stack_size 	= 1024;
  	gentask->t.output_buff     	= (u64 *)NULL;
  	gentask->t.output_buff_size	= (u64 *)NULL;
  	gentask->t.yield_data_ptr  	= (u64 *)NULL;
  	gentask->t.yield_data_size 	= 0x0;
  	gentask->t.data_ptr        	= (u64 *)GfxList0;
  	gentask->t.data_size       	= ((int)GfxList - (int)GfxList0);

  	// Write back dirty cache lines that need to be read by the RCP
  	osWritebackDCache(generate, sizeof(dynamic_stuff));

  	// Fire up SP task
  	osSpTaskStart(gentask);

  	// wait for SP completion
  	osRecvMesg(&rspMessageQ, NULL, OS_MESG_BLOCK);
  	osRecvMesg(&rdpMessageQ, NULL, OS_MESG_BLOCK);

  	// setup to swap buffers
  	osViSwapBuffer(ActiveBuffer ? FrontBuffer : BackBuffer);

  	// Make sure there isn't an old retrace in queue
  	if (MQ_IS_FULL(&retraceMessageQ))
  	{
    	osRecvMesg(&retraceMessageQ, NULL, OS_MESG_BLOCK);
    }

  	// Wait for Vertical retrace to finish swap buffers
  	osRecvMesg(&retraceMessageQ, NULL, OS_MESG_BLOCK);

  	ActiveBuffer ^= 1;

	return ERR_NOERROR;
}

DWORD SelectPicture(long scene)
{
	BackgroundImage.bitmap = Levels[scene];

	return ERR_NOERROR;
}

DWORD SetMousePosition(long x, long y)
{
	Mouse.x = x;
	Mouse.y = y;

	return ERR_NOERROR;
}

DWORD SetShotPosition(long x, long y, long shot)
{
	Shots[shot].x   = x;
	Shots[shot].y   = y;

	return ERR_NOERROR;
}

BOOL IsNTSC()
{
	return Is_NTSC;
}

DWORD InitializeTextDisplay()
{
	return ClearText();
}

DWORD ClearText()
{
	DrawText = FALSE;

	memset(&TextMap, 48, sizeof(TextMap));

	return ERR_NOERROR;
}

DWORD DrawTextString(char *string, long x, long y)
{
	DWORD	length;
	DWORD 	loop;
	char	value;

	if (NULL == string || y < 0 || y >= SCREENHEIGHT / FONTSIZE || x < 0 ||
		x >= SCREENWIDTH / FONTSIZE)
	{
		return ERR_BADPARAMS;
	}

	length 	= strlen(string);

	if (length + x > SCREENWIDTH / FONTSIZE)
	{
		length = SCREENWIDTH / FONTSIZE - x;
	}

	for (loop = 0; loop < length; loop++)
	{
		value = string[loop];

		if (value < 48)
		{
            TextMap[y][x++] = 48;
		}

		else
		{
            TextMap[y][x++] = value - 48;
		}
	}

	DrawText = TRUE;

	return ERR_NOERROR;
}

