// Misc.c

#include "ult_64.h"
#include "define.h"
#include "file.h"

#include "misc.h"


s32
	FileSize;

Gfx
	ColModeCombine,
	TexModeCombine;

s32
	ColorDiff,
	Paused = FALSE;


/********************************************************************/

static u32
	Seed = -1;


void srand( const u32 seed )
{
	Seed = seed;
}


s32 rand()
{
	Seed *= 214013;
	Seed += 2531011;
	return( (Seed >> 16) & 0x7fff );
}


s32 random( const s32 range )
{
	return( (rand() * range) >> 15 );
}


/********************************************************************/

void MatToN64( matrix *src, Mtx *dst )
{
	/*
	 * convert mat to N64 form
	 */

#if 1

	s16
		*i,
		*f;
	s32
		x,
		y,
		num,
		*lfp;

	lfp = (s32 *)src;
	i = (s16 *)dst;
	f = &i[4*4];

	for (y=0; y<3; y++)
	{
		for (x=0; x<3; x++)
		{
			num = *lfp++;
			*i++ = (s16)(num >> 14);
			*f++ = (s16)(num << 2);
		}

		*i++ = 0;
		*f++ = 0;
	}

	for (x=0; x<3; x++)
	{
		*i++ = 0;
		*f++ = 0;
	}

	*i++ = 1;
	*f++ = 0;

#else

	s32
		i,
		j,
		*rmat = (s32 *)src;
	s16
		*m2 = (s16 *)dst;

	for(i=0;i<3;i++)
	{
		for(j=0;j<3;j++)
		{
			m2[i*4+j]=(rmat[i*3+j]*4)>>16;
			m2[16+i*4+j]=(rmat[i*3+j]*4) & 0xFFFF;
		}
		m2[i*4+3]=0;
		m2[16+i*4+3]=0;
		m2[12+i]=0;
		m2[16+12+i]=0;
	}
	m2[15]=1;
	m2[16+15]=0;

#endif
}


void SetTransN64( Mtx *mat, s16 x, s16 y, s16 z )
{
	s16
		*ptr = (s16 *)mat;

	ptr[12] = x;
	ptr[13] = y;
	ptr[14] = z;

	ptr[(4*4)+12] = 0;
	ptr[(4*4)+13] = 0;
	ptr[(4*4)+14] = 0;
}


void *AllocAndLoadFile( char *filename, const s32 mem_type )
{
	FH
		file;
	void
		*mem = NULL;

	file = FileOpen( filename, "rb" );
	if (file)
	{
		FileSeek( file, 0, SEEK_END );
		FileSize = FileTell( file );
		FileSeek( file, 0, SEEK_SET );

		mem = MemMalloc( FileSize, mem_type );
		FileRead( mem, FileSize, 1, file );

		FileClose( file );
	}

	return( mem );
}


Gfx *DrawObject( Gfx *gp, u8 *object, void *ml )
{
	SMaterial
		*mat,
		*mat_list;
	s16
		*ptr,
		count,
		command;
	u8
		*vtx;
	s32
		tex = 0;

	mat_list = (SMaterial *)ml;
	ptr = (s16 *)&object[6*4];
	vtx = &object[*(s32 *)&object[5*4]];

	while (*ptr)
	{
		command = ptr[0];
		count = ptr[1];
		ptr += 2;

		switch (command)
		{
			case CMD_TEXTURE:
				if (count < 0)
				{
					if (tex != 1)
					{
						tex = 1;
						gDPPipeSync( gp++ );
						gSPTexture( gp++, 0x8000, 0x8000, 0, 0, G_OFF );
						*gp++ = ColModeCombine;
					}
				}
				else
				{
					mat = &mat_list[count];

					if (tex != 2)
					{
						tex = 2;
						gDPPipeSync( gp++ );
						gSPTexture( gp++, 0x8000, 0x8000, 0, G_TX_RENDERTILE, G_ON );
						*gp++ = TexModeCombine;
					}

					switch (mat->Flags.Format)
					{
						case FORMAT_CI4:
							if (mat->Texture)
							{
								gDPLoadTextureBlock_4b( gp++,
																				mat->Texture,
																				G_IM_FMT_CI,
																				mat->Width, mat->Height,
																				mat->Flags.PalNum,
																				mat->Flags.Xflags,
																				mat->Flags.Yflags,
																				mat->Flags.Xmask,
																				mat->Flags.Ymask,
																				G_TX_NOLOD, G_TX_NOLOD );
								gDPSetTextureLUT( gp++, G_TT_RGBA16 );
							}
							if (mat->Palette)
							{
								gDPLoadTLUT_pal16( gp++, 0, mat->Palette );
							}
							break;

						case FORMAT_IA4:
							gDPLoadTextureBlock_4b( gp++,
																			mat->Texture,
																			G_IM_FMT_IA,
																			mat->Width, mat->Height,
																			0,
																			mat->Flags.Xflags,
																			mat->Flags.Yflags,
																			mat->Flags.Xmask,
																			mat->Flags.Ymask,
																			G_TX_NOLOD, G_TX_NOLOD );
							gDPSetTextureLUT( gp++, G_TT_NONE );
							break;

						case FORMAT_IA8:
							gDPLoadTextureBlock( gp++,
																	 mat->Texture,
																	 G_IM_FMT_IA, G_IM_SIZ_8b,
																	 mat->Width, mat->Height,
																	 0,
																	 mat->Flags.Xflags,
																	 mat->Flags.Yflags,
																	 mat->Flags.Xmask,
																	 mat->Flags.Ymask,
																	 G_TX_NOLOD, G_TX_NOLOD );
							gDPSetTextureLUT( gp++, G_TT_NONE );
							break;

						case FORMAT_CI8:
							if (mat->Texture)
							{
								gDPLoadTextureBlock( gp++,
																		 mat->Texture,
																		 G_IM_FMT_CI, G_IM_SIZ_8b,
																		 mat->Width, mat->Height,
																		 0,
																		 mat->Flags.Xflags,
																		 mat->Flags.Yflags,
																		 mat->Flags.Xmask,
																		 mat->Flags.Ymask,
																		 G_TX_NOLOD, G_TX_NOLOD );
							}
								gDPSetTextureLUT( gp++, G_TT_RGBA16 );
							if (mat->Palette)
							{
								gDPLoadTLUT_pal256( gp++, mat->Palette );
							}
							break;
					}
				}
				break;

			case CMD_VERTICES:
				gSPVertex( gp++, vtx, count, 0 );
				vtx += (count * 16);
				break;

			case CMD_FACES:
#if 0
				while (count > 0)
				{
					gSP1Triangle( gp++, ptr[0], ptr[1], ptr[2], 0 );
					ptr += 3;
					count--;
				}
#else
				while (count >= 2)
				{
					gSP2Triangles( gp++,
												 ptr[0], ptr[1], ptr[2], 0,
												 ptr[3], ptr[4], ptr[5], 0 );
					ptr += 2*3;
					count -= 2;
				}
				if (count > 0)
				{
					gSP1Triangle( gp++, ptr[0], ptr[1], ptr[2], 0 );
					ptr += 3;
				}
#endif
				break;
		}
	}

	return( gp );
}


void Obj_CalcExtents( void *_obj, vector16 *min, vector16 *max )
{
	VertexN64
		*vtx;
	u8
		*object;
	s16
		n,
		xmin = 32767,
		ymin = 32767,
		zmin = 32767,
		xmax = -32768,
		ymax = -32768,
		zmax = -32768,
		*ptr,
		count,
		command;

	object = (u8 *)_obj;
	ptr = (s16 *)&object[6*4];
	vtx = (VertexN64 *)&object[*(s32 *)&object[5*4]];

	while (*ptr)
	{
		command = ptr[0];
		count = ptr[1];
		ptr += 2;

		switch (command)
		{
			case CMD_VERTICES:
				while (count)
				{
					n = vtx->x;
					if (n < xmin) xmin = n;
					if (n > xmax) xmax = n;

					n = vtx->y;
					if (n < ymin) ymin = n;
					if (n > ymax) ymax = n;

					n = vtx->z;
					if (n < zmin) zmin = n;
					if (n > zmax) zmax = n;

					vtx++;
					count--;
				}
				break;

			case CMD_FACES:
				ptr += count * 3;
				break;
		}
	}

	min->x = xmin;
	min->y = ymin;
	min->z = zmin;

	max->x = xmax;
	max->y = ymax;
	max->z = zmax;
}


s32 DotProduct( vector16 *va, vector16 *vb )
{
	s32
		dp;

	dp  = (s32)va->x * (s32)vb->x;
	dp += (s32)va->y * (s32)vb->y;
	dp += (s32)va->z * (s32)vb->z;
	dp >>= 14;

	return( dp );
}


u8 Pal_FindColor( const u32 r, const u32 g, const u32 b, const RGBA16 *pal, const u32 count )
{
	s32
		i,
		d,
		diff,
		which = 0,
		prev = 0x7fffffff;

	for (i=0; i<count; i++)
	{
		diff = 0;

		d = (s32)pal->r - (s32)r;
		diff += (d * d);

		d = (s32)pal->g - (s32)g;
		diff += (d * d);

		d = (s32)pal->b - (s32)b;
		diff += (d * d);

		if (diff < prev)
		{
			which = i;
			prev = diff;
		}

		pal++;
	}

	ColorDiff = prev;

	return( (u8)which );
}


void Pal_SetAlpha( RGBA16 *pal, const u8 alpha, s32 count )
{
	while (count)
	{
		pal->a = (alpha >> 7) & 1;

		pal++;
		count--;
	}
}
