/***************************************************************************
 *
 * Intro.c
 *
 ***************************************************************************/

/*
 * includes
 */

#include "ult_64.h"
#include "defs.h"
#include "ctrl.h"
#include "main.h"
#include "static_s.h"
#include "file.h"
#include "define.h"
#include "ml.h"
#include "memory.h"

#include "misc.h"


/*
 * defines
 */


/*
 * typedefs
 */


// externs...

extern int
	C3PT;


/*
 * globals
 */

static u8
	*Font;

static s32
	MenuPtr = 0;


/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/

#define CHUNK_SHIFT 4
#define TYPE_USED 1


struct MEMCHUNK_S;

typedef union MEMPTR_U
    {
    struct MEMCHUNK_S * link;
    char *              file;
    unsigned long       data;
    unsigned long       type;
    } MEMPTR_T;

typedef struct MEMCHUNK_S
    {
    MEMPTR_T            next;
    MEMPTR_T            last;
    unsigned long       size;
    unsigned long       csum;
    } MEMCHUNK_T;


extern MEMCHUNK_T
	*pcl__gHeapBtm,
	*pcl__gHeapTop;


static u8
	*UsedBlocks[8];


static void SetMemFree( void *mem, s32 size )
{
	s32
		off,
		block;

	off = (s32)mem - 0x80000000;
	block = off / (1024*1024);
	off &= (1024*1024)-1;
	off /= 512;
	while (size > 0)
	{
		UsedBlocks[block][off] = 0;
		off++;
		if (off >= (128*16))
		{
			off = 0;
			block++;
		}
		size -= 512;
	}
}


void InitUsedMem()
{
	MEMCHUNK_T
		*ptr;
	u8
		*mem;
	s32
		i,
		j;

	mem = MemMalloc( 8*128*16, MEM_ANY );
	memset( mem, -1, 8*128*16 );

	for (i=0; i<8; i++)
	{
		UsedBlocks[i] = mem;

		for (j=0; j<(128*16); j++)
			UsedBlocks[i][j] = 128;

		mem += (128*16);
	}

	ptr = pcl__gHeapBtm + 2;
	while (ptr < pcl__gHeapTop)
	{
		if ((ptr->last.type & TYPE_USED) == 0)
			SetMemFree( ptr, ptr->size << CHUNK_SHIFT );

		ptr += ptr->size;
	}
}


void DeinitUsedMem()
{
	MemFree( UsedBlocks[0] );
}


Gfx *ShowUsedMem( Gfx *gp, s32 x, s32 y )
{
	s32
		b;

	for (b=0; b<8; b++)
	{
		gDPLoadTextureBlock( gp++,
												 UsedBlocks[b],
												 G_IM_FMT_I,
												 G_IM_SIZ_8b,
												 16,
												 128,
												 0,
												 G_TX_CLAMP,
												 G_TX_CLAMP,
												 4,
												 7,
												 G_TX_NOLOD,
												 G_TX_NOLOD );

		gSPTextureRectangle( gp++, x<<2, y<<2, (x+16)<<2, (y+128)<<2, 0, 0<<5, 0<<5, (1<<10), (1<<10) );

		x += 32;
	}

	return( gp );
}


/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/

void Intro_Open( void *arg )
{
	Font = AllocAndLoadFile( "PHIL.FNT", MEM_ANY );

	InitUsedMem();
}


/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/

void Intro_Close( void *args )
{
	DeinitUsedMem();

	MemFree( Font );
}


/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/

void Intro_Process( signed int *p )
{
	static s32
		prev = 0;
	s32
		bits,
		held;

	bits = p[0];
	held = bits & ~prev;


	if (bits & (CTRL_START | CTRL_FIRE_A | CTRL_FIRE_B))
	{
		currentProcess->status = PROCESS_FREEING;

		C3PT = MenuPtr;
	}

	if (held & (CTRL_UP | CTRL_PAD_UP))
	{
		MenuPtr--;
		if (MenuPtr < 0)
			MenuPtr = 1;
	}

	if (held & (CTRL_DOWN | CTRL_PAD_DOWN))
	{
		MenuPtr++;
		if (MenuPtr >= 2)
			MenuPtr = 0;
	}


	prev = bits;
}

/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/

static Gfx *DrawChar( Gfx *gp, s8 c, s32 x, s32 y )
{
	s32
		s,
		t;

	x *= 8;
	y *= 8;

	c -= ' ';
	s = (s32)(c & 15) * 8;
	t = (s32)(c / 16) * 8;

	gSPTextureRectangle( gp++, x<<2, y<<2, (x+8)<<2, (y+8)<<2, 0, s<<5, t<<5, (1<<10), (1<<10) );

	return( gp );
}


static Gfx * DrawString(Gfx *gp, char *string, s32 x, s32 y)
{
	char
		c;

	while (*string)
	{
		c = *string++;
		if (c > 0x60)		c -= 0x20;

		gp = DrawChar( gp, c, x, y );
		x++;
	}

	return( gp );
}



static Gfx *DrawNumber( Gfx *gp, s32 number, s32 x, s32 y )
{
	s32
		s,
		t,
		digit,
		zero = FALSE,
		div = 1000000;

	if (number < 0)
	{
		gp = DrawChar( gp, '-', x, y );
		x++;
		number = -number;
	}

	while (div > 0)
	{
		digit = number / div;
		number -= (digit * div);
		div /= 10;

		if (digit == 0)
		{
			if (div == 0)
				zero = TRUE;
		}
		else
			zero = TRUE;

		if (digit || zero)
		{
			gp = DrawChar( gp, digit+'0', x, y );
			x++;
		}
	}

	return( gp );
}


static Gfx *DoMenu( Gfx *gp )
{
	static char
		*titles[] =
		{
			"Regular Game",
			"3 Point Game",
			""
		};
	s32
		i;

	i = 0;
	while (titles[i][0])
	{
		gp = DrawString( gp, titles[i], 26, 13+(i*2) );

		i++;
	}

	gp = DrawChar( gp, '>', 25, 13+(MenuPtr*2) );

	return( gp );
}


void Intro_Render( dyn *d, int draw_buffer, Gfx **gl )
{
	Gfx
		*gp;

	// copy ptr
	gp=(*gl);


	// initialise RCP
	gSPSegment(gp++, 0, 0x0);
	gSPDisplayList(gp++, DLInitRDP);
	gSPDisplayList(gp++, DLInitRSP);

	// set scissor rect
	gDPSetScissor(gp++,G_SC_NON_INTERLACE,0,0,(currentProcess->ScreenX),(currentProcess->ScreenY));

	// clear depth buffer
	gDPSetCycleType(gp++,G_CYC_FILL);

	// clear framebuffer
	gDPSetColorImage(gp++,G_IM_FMT_RGBA, G_IM_SIZ_16b, currentProcess->ScreenX,cfb[draw_buffer]);

	gDPSetFillColor(gp++,GPACK_RGBA5551(0,0,0,255) << 16 | GPACK_RGBA5551(0,0,0,255));
	gDPFillRectangle(gp++,0, 0, currentProcess->ScreenX-1, currentProcess->ScreenY-1);


	// misc setup
	gDPPipeSync(gp++);
	gDPSetCycleType(gp++,G_CYC_1CYCLE);
	gDPSetColorDither(gp++,G_CD_MAGICSQ);


	gDPSetRenderMode( gp++, G_RM_OPA_SURF, G_RM_OPA_SURF2 );
	gDPSetTextureLUT( gp++, G_TT_NONE );
	gDPSetCombineMode( gp++, G_CC_DECALRGBA, G_CC_DECALRGBA );
	gDPSetTexturePersp( gp++, G_TP_NONE );
	gDPSetTextureFilter( gp++, G_TF_POINT );

//	gp = ShowUsedMem( gp, 16, 16 );

	gDPLoadTextureBlock( gp++, Font, G_IM_FMT_I, G_IM_SIZ_8b, 128, 32, 0,
											 G_TX_WRAP, G_TX_WRAP, 7, 5, G_TX_NOLOD, G_TX_NOLOD );
	gDPSetAlphaCompare( gp++, G_AC_THRESHOLD );
//gDPSetAlphaCompare( gp++, G_AC_NONE );
	gDPSetBlendColor( gp++, 0, 0, 0, 128 );


	gp = DoMenu( gp );


	gDPPipeSync(gp++);


	// write back gfx ptr
	(*gl)=gp;
}


/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/



/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/



/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/

