/********************************************************************************
						Ultra 64 MARIO Brothers

				  	   Title BG drawing function.

			Copyright 1995 Nintendo co., ltd.  All rights reserved

				  This module was programmed by Y.Tanimoto

								1996.4.25
*********************************************************************************/
#include "headers.h"

#define		TM_FIX_FRAME	45

static ushort*	frameBuffer[3];

extern Gfx	 mario_screen_init[] ;
extern Gfx	 mario_screen_reset[];

extern ushort	dispFrame ;
extern ushort	drawFrame ;
extern Gfx		vibpack_draw[];


/* ============================================================================================
		: Static Gfx and its records to initialize and draw title BG [ Fixed ].
===============================================================================================	*/
extern Gfx titleBG_draw_init[]	;
extern Gfx titleBG_draw_on[]	;
extern Gfx titleBG_draw_tri0[]	;
extern Gfx titleBG_draw_tri1[]	;
extern Gfx titleBG_draw_tri2[]	;
extern Gfx titleBG_draw_tri3[]	;
extern Gfx titleBG_draw_reset[]	;
extern Gfx titleTM_draw[]		;
extern Gfx RCP_Nintendo[]		;
extern Gfx wipe_gfx_init[]		;

static Gfx*	titleBG_draw[] = {	titleBG_draw_tri0, titleBG_draw_tri1,
								titleBG_draw_tri2, titleBG_draw_tri3  };


/* ============================================================================================
		: 2D coordinate data [ Fixed ].
===============================================================================================	*/
static float	Xo[] = {    0.0,  80.0, 160.0, 240.0,  0.0, 80.0, 160.0, 240.0, 0.0, 80.0, 160.0, 240.0  };
static float	Yo[] = {  160.0, 160.0, 160.0, 160.0, 80.0, 80.0,  80.0,  80.0, 0.0,  0.0,   0.0,   0.0	 };


/* ============================================================================================
		: Ptr to real image data records and their record.
===============================================================================================	*/
extern ushort*	titleBG_A[];
extern ushort*	titleGm_O[];

static ushort**	titleBG[] = {	titleBG_A, titleGm_O  };


/* ============================================================================================
		: Back pattern data and its record.
===============================================================================================	*/
static char	 back_pattern_A[] = {	0, 0, 0, 0,				//	<--- Each is image No.
									0, 0, 0, 0,
									0, 0, 0, 0,	  };

static char* back_pattern_rec[] = {	  back_pattern_A   };


static int	gover_count ;
static int	gover_flag	;


/* ============================================================================================
		: Back pattern and its changing data for Game Over.
===============================================================================================	*/
static char	 back_pattern_GV[] = {	1, 1, 1, 1,				//	<--- Each is image No.
									1, 1, 1, 1,
									1, 1, 1, 1,	 };

static char	 back_change_proc[] = {	0, 1, 2, 3, 7, 11, 10, 9, 8, 4, 5, 6 };


/* ============================================================================================
		: Back pattern data of multi-screen.
===============================================================================================	*/
static char  pos[] = {	1,1,1,1,1,1,1,1,
						1,1,1,1,1,1,1,1,
						1,1,0,0,0,0,1,1,
						1,1,0,0,0,0,1,1,
						1,1,1,1,1,1,1,1,
						1,1,1,1,1,1,1,1	 };

static char	 pos_proc[] = {  0,1,2,3,4,5,6,7,15,23,31,39,47,46,45,44,43,42,41,40,32,24,16,
							 8,9,10,11,12,13,14,22,30,38,37,36,35,34,33,25,17  };

static char	 pos_procFlag = 0 ;



/* ============================================================================================
		: Trademark drawing.
===============================================================================================	*/
static short	logo_Count	;
static int		logo_Alpha	;
extern float	logo_start[];
extern float	logo_end[]	;


/* ------------------------------------------------------------------------------------------------------------	*/
/* ------------------------------------------------------------------------------------------------------------	*/


/* ============================================================================================
		: Title BG drawing function.
===============================================================================================	*/
extern ulong TitleLGDraw(int code, MapNode *node, void *data)
{
	MapCProg*	cprog  = (MapCProg *)node ;
	Gfx*  		gfxPtr = NULL ;
	Gfx*  		gfxTmp = NULL ;
	Mtx*		scale  ;
	float*		s_data = (float *)SegmentToVirtual(logo_start);
	float*		e_data = (float *)SegmentToVirtual(logo_end);
	float		sx_val ;
	float		sy_val ;
	float		sz_val ;

	if (code != MAP_CBACK_EXEC)	{

		logo_Count = 0 ;

	}else
	if (code == MAP_CBACK_EXEC)	{

		MapSetRenderMode(cprog, RM_SURF);

		scale  = (Mtx *)AllocDynamic(sizeof(Mtx));
		gfxPtr = (Gfx *)AllocDynamic(4*sizeof(Gfx));
		gfxTmp = gfxPtr ;

		if (logo_Count >=  0 && logo_Count <= 19)	{
			sx_val = s_data[3*logo_Count];
			sy_val = s_data[3*logo_Count+1];
			sz_val = s_data[3*logo_Count+2];
		}else
		if (logo_Count >= 20 && logo_Count <= TM_FIX_FRAME+29)	{
			sx_val = 1.0 ;
			sy_val = 1.0 ;
			sz_val = 1.0 ;
		}else
		if (logo_Count >= TM_FIX_FRAME+30 && logo_Count <= TM_FIX_FRAME+45)	{
			sx_val = e_data[3*(logo_Count-(TM_FIX_FRAME+30))];
			sy_val = e_data[3*(logo_Count-(TM_FIX_FRAME+30))+1];
			sz_val = e_data[3*(logo_Count-(TM_FIX_FRAME+30))+2];
		}else{
			sx_val = 0.0 ;
			sy_val = 0.0 ;
			sz_val = 0.0 ;
		}

		guScale(scale, sx_val, sy_val, sz_val);

		gSPMatrix(gfxTmp++, scale, G_MTX_MODELVIEW|G_MTX_MUL|G_MTX_PUSH);
		gSPDisplayList(gfxTmp++, RCP_Nintendo);
		gSPPopMatrix(gfxTmp++, G_MTX_MODELVIEW);
		gSPEndDisplayList(gfxTmp);

		logo_Count++ ;

	}

	return((ulong)gfxPtr);
}

/* ============================================================================================
		: Title trade mark drawing function.
===============================================================================================	*/
extern ulong TitleTMDraw(int code, MapNode *node, void *data)
{
	MapCProg*	cprog  = (MapCProg *)node ;
	Gfx*  		gfxPtr = NULL ;
	Gfx*  		gfxTmp = NULL ;

	if (code != MAP_CBACK_EXEC)	{

		logo_Alpha = 0 ;

	}else
	if (code == MAP_CBACK_EXEC)	{


		gfxPtr = (Gfx *)AllocDynamic(5*sizeof(Gfx));
		gfxTmp = gfxPtr ;

		gSPDisplayList(gfxTmp++, wipe_gfx_init);
		gDPSetEnvColor(gfxTmp++, 255, 255, 255, logo_Alpha);

		switch(logo_Alpha)
		{
			case  255 : MapSetRenderMode(cprog, RM_SURF);
						gDPSetRenderMode(gfxTmp++, G_RM_AA_OPA_SURF, G_RM_AA_OPA_SURF2);
						break ;

			default	  : MapSetRenderMode(cprog, RM_XSURF);
						gDPSetRenderMode(gfxTmp++, G_RM_AA_XLU_SURF, G_RM_AA_XLU_SURF2);
						break ;
		}

		gSPDisplayList(gfxTmp++, titleTM_draw);
		gSPEndDisplayList(gfxTmp);

		if (logo_Count >= 19)	{
			logo_Alpha += 26 ;
			if (logo_Alpha > 255)  {  logo_Alpha = 255 ;  }
		}

	}

	return((ulong)gfxPtr);
}

/* ============================================================================================
		: Draw one image in one position.
===============================================================================================	*/
static Gfx* TitleBGDrawEach(int positNo, char *ptrnXX)
{
	Mtx*	  transM = (Mtx *)AllocDynamic(sizeof(Mtx));
	Gfx*	  gfxPtr = (Gfx *)AllocDynamic(36*sizeof(Gfx));
	Gfx*	  gfxTmp = gfxPtr ;
	ushort**  image ;
	int		  i ;

	image = (ushort **)SegmentToVirtual(titleBG[(ptrnXX[positNo])]);

	guTranslate(transM, Xo[positNo], Yo[positNo], 0.0);

	gSPMatrix(gfxTmp++, transM, G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_PUSH );

	gSPDisplayList(gfxTmp++, titleBG_draw_on);

	for (i = 0 ; i < 4 ; i++)
	{
		gDPLoadTextureBlock(gfxTmp++, image[i], G_IM_FMT_RGBA, G_IM_SIZ_16b, 80, 20, 0,
								G_TX_CLAMP|G_TX_NOMIRROR, G_TX_CLAMP|G_TX_NOMIRROR,
								7, 6, G_TX_NOLOD, G_TX_NOLOD);

		gSPDisplayList(gfxTmp++, titleBG_draw[i]);
	}

	gSPPopMatrix(gfxTmp++, G_MTX_MODELVIEW);

	gSPEndDisplayList(gfxTmp);

	return(gfxPtr);
}

/* ============================================================================================
		: Title BG drawing function.
===============================================================================================	*/
extern ulong TitleBGDraw(int code, MapNode *node, void *data)
{
	MapCProg*	cprog  = (MapCProg *)node ;
	int			ptrnNo = (int)((cprog->refCon) & 0xff);
	char*		ptrnXX = back_pattern_rec[ptrnNo];
	Gfx*  		gfxPtr = NULL ;
	Gfx*  		gfxTmp = NULL ;
	int	  		position ;

	if (code == MAP_CBACK_EXEC)	{

		gfxPtr = (Gfx *)AllocDynamic(16*sizeof(Gfx));
		gfxTmp = gfxPtr ;

		MapSetRenderMode(cprog, RM_SURF);

		gSPDisplayList(gfxTmp++, wipe_gfx_init);
		gSPDisplayList(gfxTmp++, titleBG_draw_init);

		for (position = 0 ; position < 12 ; position++)
		{
			gSPDisplayList(gfxTmp++, TitleBGDrawEach(position, ptrnXX));
		}

		gSPDisplayList(gfxTmp++, titleBG_draw_reset);
		gSPEndDisplayList(gfxTmp);

	}

	return((ulong)gfxPtr);
}

/* ============================================================================================
		: Game Over BG drawing function.
===============================================================================================	*/
extern ulong GOverBGDraw(int code, MapNode *node, void *data)
{
	MapCProg*	cprog  = (MapCProg *)node ;
	Gfx*  		gfxPtr = NULL ;
	Gfx*  		gfxTmp = NULL ;
	int	  		position, i	  ;

	if (code != MAP_CBACK_EXEC)	{

		gover_count =  0 ;
		gover_flag  = -2 ;
		for (i = 0 ; i < 12 ; i++)
		{
			back_pattern_GV[i] = 1 ;
		}

	}else{

		gfxPtr = (Gfx *)AllocDynamic(16*sizeof(Gfx));
		gfxTmp = gfxPtr ;

		if (gover_flag == -2)	{
			if (gover_count == 180)	{
				gover_flag++ ;
				gover_count = 0 ;
			}
		}else
		if (gover_flag != 11)	{
			if ((gover_count % 2) == 0)	{
				gover_flag++ ;
				back_pattern_GV[(back_change_proc[gover_flag])] = 0 ;
			}
		}

		if (gover_flag != 11)	{  gover_count++ ;	}

		MapSetRenderMode(cprog, RM_SURF);

		gSPDisplayList(gfxTmp++, wipe_gfx_init);
		gSPDisplayList(gfxTmp++, titleBG_draw_init);

		for (position = 0 ; position < 12 ; position++)
		{
			gSPDisplayList(gfxTmp++, TitleBGDrawEach(position, back_pattern_GV));
		}

		gSPDisplayList(gfxTmp++, titleBG_draw_reset);
		gSPEndDisplayList(gfxTmp);
	}

	return((ulong)gfxPtr);
}


/* --------------------------------------------------------------------------------------------	*/
/* --------------------------------------------------------------------------------------------	*/


/* ============================================================================================
		: Generate gSPTextureRectangle() commands.
===============================================================================================	*/
static void GenTextureRect(Gfx **gfxTmp)
{
	int	  x, y ;

	for (y = 0 ; y < 6 ; y++)
	{
		for (x = 0 ; x < 8 ; x++)
		{
			if (pos[y*8+x])	{	gSPTextureRectangle((*gfxTmp)++, ((40*x) << 2), ((40*y) << 2),
													((40*x+39) << 2), ((40*y+39) << 2), 0,
										  	  		(0 << 5), (0 << 5),  (4 << 10), (1 << 10)  );	}
		}
	}
}

/* ============================================================================================
		: Copy image data block by copy-mode.
===============================================================================================	*/
static Gfx* DrawImageBlock(ushort *image, int imgW, int imgH)
{
	Gfx	 *gfxPtr ;
	Gfx	 *gfxTmp ;

	gfxPtr = (Gfx *)AllocDynamic(110*sizeof(Gfx));

	if (gfxPtr == NULL)	{	return(gfxPtr)	;	}else
						{	gfxTmp = gfxPtr ;	}
	
	gSPDisplayList(gfxTmp++, mario_screen_init);

	gDPLoadTextureBlock(gfxTmp++, K0_TO_PHYS(image), G_IM_FMT_RGBA, G_IM_SIZ_16b, imgW, imgH, 0,
									G_TX_CLAMP|G_TX_NOMIRROR, G_TX_CLAMP|G_TX_NOMIRROR,
									6, 6, G_TX_NOLOD, G_TX_NOLOD);

	GenTextureRect(&(gfxTmp));

	gSPDisplayList(gfxTmp++, mario_screen_reset);

 	gSPEndDisplayList(gfxTmp++);

	return(gfxPtr);
}

/* ============================================================================================
		: Get and shrink image data from the frame-buffer.
===============================================================================================	*/
static ushort* ShrinkImageData(int imgW, int imgH, int unitW, int unitH)
{
	ushort*	 fb_image	;
	ushort*	 dt_image	;
	int		 fb_offset	;
	int		 dt_offset	;
	int		 sx, sy		;
	int		 i, j, p, q	;
	ushort	 r_short, g_short, b_short ;
	float	 r_float, g_float, b_float ;
	float	 r_total, g_total, b_total ;
	float	 devide ;

	fb_image = frameBuffer[drawFrame];
	dt_image = (ushort *)AllocDynamic((imgW*imgH)*sizeof(ushort));

	if (dt_image == NULL)	{	return(dt_image);	}

	sx = 120 ;
	sy =  80 ;

	for (q = 0 ; q < imgH ; q++)
	{
		for (p = 0 ; p < imgW ; p++)
		{
			r_total = 0.0 ;
			g_total = 0.0 ;
			b_total = 0.0 ;

			for (j = 0 ; j < unitH ; j++)
			{
				for (i = 0 ; i < unitW ; i++)
				{
					fb_offset = 320*(sy + unitH*q + j) + (sx + unitW*p + i);

					r_short = fb_image[fb_offset];
					g_short = fb_image[fb_offset];
					b_short = fb_image[fb_offset];

					r_float = (float)((r_short >> 11) & 0x1f);
					g_float = (float)((g_short >>  6) & 0x1f);
					b_float = (float)((b_short >>  1) & 0x1f);

					r_total += r_float ;
					g_total += g_float ;
					b_total += b_float ;
				}
			}

			devide = (float)(unitW*unitH);

			r_short = (((ushort)((r_total / devide) + 0.5)) << 11) & 0xf800 ;
			g_short = (((ushort)((g_total / devide) + 0.5)) <<  6) & 0x07c0 ;
			b_short = (((ushort)((b_total / devide) + 0.5)) <<  1) & 0x003e ;

			dt_offset = imgH*q + p ;

			dt_image[dt_offset] = r_short + g_short + b_short + 1 ;

		}
	}

	return(dt_image);
}

/* ============================================================================================
		: Real time image change function.
===============================================================================================	*/
extern ulong ImageChangeFunc(int code, MapNode *node, void *data)
{
	MapCProg*	cprog  ;
	ushort*		imgPtr ;
	Gfx*		gfxPtr = NULL ;
	int			i ;

	if (code != MAP_CBACK_EXEC)	{

		frameBuffer[0] = (ushort *)(frameMemoryA);
		frameBuffer[1] = (ushort *)(frameMemoryB);
		frameBuffer[2] = (ushort *)(frameMemoryC);

		for (i = 0 ; i < 48 ; i++)
		{
			pos[i] = 0 ;
		}

	}else
	if (code == MAP_CBACK_EXEC)	{

		if (pos_procFlag == 0)	{

			if (cont1p->trigger & CONT_BACK)  {
				Na_FixSeFlagEntry(NA_SE2_SET);

				pos[0] ^= 1 ;
				pos_procFlag++ ;

			}

		}else{

			(pos[(pos_proc[pos_procFlag])]) ^= 1 ;

			pos_procFlag++ ;
			if (pos_procFlag >= 40)	 {	pos_procFlag = 0 ;	}

		}

		if ((pos[0] == 1) || (pos[17] == 1))  {
		
			if ((imgPtr = ShrinkImageData(40, 40, 2, 2)) != NULL)	{

				cprog = (MapCProg *)node ;
				MapSetRenderMode(cprog, RM_SURF);
				gfxPtr = DrawImageBlock(imgPtr, 40, 40);

			}

		}

	}

	return((ulong)gfxPtr);
}


/* --------------------------------------------------------------------------------------------	*/
/* --------------------------------------------------------------------------------------------	*/


/* ============================================================================================
		: Draw vibrate-pack logo.
===============================================================================================	*/
extern ulong VibLogoDraw(int code, MapNode *node, void *data)
{
	MapCProg*	cprog  ;
	Gfx*		gfxTmp ;
	Gfx*		gfxPtr ;
	int			flag   ;
	char		value  ;

	if (code != MAP_CBACK_EXEC)	{

		gfxPtr = NULL ;

	}else
	if (code == MAP_CBACK_EXEC)	{

		cprog = (MapCProg *)node ;
		MapSetRenderMode(cprog, RM_SURF);

		flag = (int)((cprog->refCon) & 0xff);

		if (flag == 0)	{  value = back_pattern_A[6] ;  }else
		if (flag == 1)	{  value = back_pattern_GV[6];	}

		if (value == 0)	 {

			gfxPtr = (Gfx *)AllocDynamic(3*sizeof(Gfx));

			if (gfxPtr != NULL)	{

				gfxTmp = gfxPtr ;

				gSPDisplayList(gfxTmp++, vibpack_draw);
			 	gSPEndDisplayList(gfxTmp);

			}

		}else{

			gfxPtr = NULL ;

		}

	}

	return((ulong)gfxPtr);
}
