/*********************************************************************************************/
/*                                                                                           */
/* Initialisation Code                                                                       */
/*                                                                                           */
/*********************************************************************************************/
								 
#include "standard.h"
#include "global.h"
#include "init.h"
#include "output.h"
#include "../3dsystem/3d_gen.h"
#include <time.h>

#include "winmain.h" // RF
#include "math.h"
/********************************* GLOBAL VARIABLES ******************************************/

SETUP	game_setup = {320,200,25,25,50,0,0};

char*	malloc_buffer=NULL;
int		malloc_size;			 
char*	malloc_ptr;
int		malloc_used,malloc_free;

char*	game_malloc_strings[NUM_MALLOC_TYPES]=
	{
	"Temp Alloc",
	"Texture Pages",
	"Mesh Pointers",
	"Meshes",
	"Anims",
	"Structs",
	"Ranges",
	"Commands",
	"Bones",
	"Frames",
	"Room Textures",
	"Room Infos",
	"Room Mesh",
	"Room Door",
	"Room Floor",
	"Room Lights",
	"Room Static Mesh Infos",
	"Floor Data",
	"ITEMS!!",
	"Cameras",
	"Sound FX",
	"Boxes",
	"Overlaps",
	"GroundZone",
	"FlyZone",
	"Animating Texture Ranges",
	"Cinematic Frames",
	"LoadDemo Buffer",
	"SaveDemo Buffer",
	"Cinematic Effects",
	"Mummy Head Turn",
	"Extra Door stuff",
	"Effects_Array",
	"Creature Data",
	"Creature LOT",
	"Sample Infos",
	"Samples",
	"Sample Offsets",
	"Rolling Ball Stuff",
	"Skidoo Stuff",
	"Load Piccy Buffer",
	"FMV Buffers",
	"Polygon Buffers",
	"Order Tables",
	"CLUTs",
	"Texture Infos",
	"Sprite Infos"
	};

local int LanGameMallocTotals[NUM_MALLOC_TYPES];


int SqrTable[1024];
unsigned int RColorTable[33][33][33];
unsigned int GColorTable[33][33][33];
unsigned int BColorTable[33][33][33];
WATERTAB	WaterTable[22][64];


static unsigned short GetRandom(WATERTAB *w, int n)
{
	int i;
	unsigned short random;

	do {
		random  = rand() & 0xfc;

		for ( i=0 ; i<n ; i++ )
		{
			if (w[i].random == random)
				break;
		}

		if (i == n)
			return random;

	} while(1);

	return 0;		// to stop warning
}

void	init_water_table()
{
	long	lp;

	srand(121197);

	for ( lp=0 ; lp<64 ; lp++ )
	{
		int i, j, k;
		short sin = rcossin_tbl[(lp<<7)];

	/* -------- underwater/swamp table */

		WaterTable[0][lp].shimmer = (sin*63) >> (12+3);
		WaterTable[0][lp].choppy  = (sin*16) >> 12;
		WaterTable[0][lp].random  = GetRandom(&WaterTable[0][0], lp);
		WaterTable[0][lp].abs	 = 0;

	/* -------- mist tables */

		WaterTable[1][lp].shimmer = (sin*32) >> (12+3);
		WaterTable[1][lp].choppy  = 0;
		WaterTable[1][lp].random  = GetRandom(&WaterTable[1][0], lp);
		WaterTable[1][lp].abs	 = -3;

		WaterTable[2][lp].shimmer = (sin*64) >> (12+3);
		WaterTable[2][lp].choppy  = 0;
		WaterTable[2][lp].random  = GetRandom(&WaterTable[2][0], lp);
		WaterTable[2][lp].abs	 = 0;

		WaterTable[3][lp].shimmer = (sin*96) >> (12+3);
		WaterTable[3][lp].choppy  = 0;
		WaterTable[3][lp].random  = GetRandom(&WaterTable[3][0], lp);
		WaterTable[3][lp].abs	 = 4;

		WaterTable[4][lp].shimmer = (sin*127) >> (12+3);
		WaterTable[4][lp].choppy  = 0;
		WaterTable[4][lp].random  = GetRandom(&WaterTable[4][0], lp);
		WaterTable[4][lp].abs	 = 8;

	/* -------- shimmer/ripple tables */

		for ( i=0,j=5 ; i<4 ; i++,j+=4 )
		{
			for ( k=0 ; k<4 ; k++ )
			{
				static unsigned char off[4] = { 4, 8, 12, 16 };
				static short shim[4] = { 31, 63, 95, 127 };
				static short chop[4] = { 16, 53, 90, 127 };

				WaterTable[j+k][lp].shimmer = -((sin*shim[k]) >> 15);
				WaterTable[j+k][lp].choppy  = (sin*chop[i]) >> 12;
				WaterTable[j+k][lp].random  = GetRandom(&WaterTable[j+k][0], lp);
				WaterTable[j+k][lp].abs	   = off[k];
			}
		}
	}

}


/*********************************** FUNCTION CODE *******************************************/

extern "C" void BuildOutsideTable();

int S_InitialiseSystem(void)
{
#ifdef GAMEDEBUG
// Should have something like this I should suspect...
//	CheckSellByDate();
#endif

	S_SeedRandom();							// Seed random numbers

	game_setup.dump_x = 0;
	game_setup.dump_y = 0;
	game_setup.dump_width = DXDisplayMode(App.DeviceInfoPtr,App.DXConfigPtr).w;  // RF G_RenderInfo.nWidth;
	game_setup.dump_height = DXDisplayMode(App.DeviceInfoPtr,App.DXConfigPtr).h; // RF G_RenderInfo.nHeight;


	init_water_table();
	
	CalculateWibbleTable();

	InitZTable();
	InitUVTable();

	for(int n=0;n<1024;n++)
		SqrTable[n] = (int) sqrt(float(n));


	for(int i=1;i<33;i++)
	{
		for(int j=1;j<33;j++)
		{
			for(int k=1;k<33;k++)
			{
				RColorTable[i][j][k] = (((k*(i-j))/i))<<10;
				GColorTable[i][j][k] = (((k*(i-j))/i))<<5;
				BColorTable[i][j][k] = (((k*(i-j))/i));
			}
		}
	}



	malloc_size = MALLOC_SIZE;             // Allocate Memory for Linear Buffer..
/* 

Only do this now if ESCAPE video thing can be made to work

	malloc_buffer = malloc(malloc_size);
	if ( malloc_buffer==NULL )
		S_ExitSystem("ERROR: Unable to allocate enough memory to run");
*/

	return (1);
}


void ShutdownGame(void)
{
	/* Free everything we can think of */
	if (malloc_buffer)
		GlobalFree((HGLOBAL)malloc_buffer);
}

/*****************************************************************************
 *				Initialise In Game Malloc Array....
 ****************************************************************************/

void init_game_malloc(void)
	{
	malloc_ptr=malloc_buffer;
	malloc_free=malloc_size;
	malloc_used=0;
#ifdef GAMEDEBUG
	ZeroArray(LanGameMallocTotals);
	Log(LT_Info,"init_game_malloc: size=%dK",malloc_size>>10);
#endif
	}

void* game_malloc(int size,int type)
	{
	char* ptr;

	size=(size+3)&0xfffffffc;		// LongWord Align....
	if (size<=malloc_free)
		{
#ifdef GAMEDEBUG
		LanGameMallocTotals[type]+=size;
#endif
		ptr=malloc_ptr;
		malloc_free-=size;
		malloc_used+=size;
		malloc_ptr+=size;
		return ptr;
		}
	
	wsprintf(exit_message,"game_malloc(): OUT OF MEMORY %s %d",game_malloc_strings[type],size);
	S_ExitSystem(exit_message);
	return 0;	// S_ExitSystem doesn't return...
	}

void game_free(int size,int type)
	{
	size=(size+3)&(~3);		// fuck Fuck FUck FUCk FUCK !FUCK!
#ifdef GAMEDEBUG
	LanGameMallocTotals[type]-=size;
#endif
	malloc_ptr-=size;
	malloc_free+=size;
	malloc_used-=size;
	}

void show_game_malloc_totals(void)
	{
#ifdef GAMEDEBUG
	for (int i=0;i<NUM_MALLOC_TYPES;++i)
		Log("%s: %d",game_malloc_strings[i],LanGameMallocTotals[i]);
	Log("malloc_used=%dK; malloc_free=%dK; malloc_size=%dK",malloc_used>>10,malloc_free>>10,malloc_size>>10);
#endif
	}

/*****************************************************************************
 *			Calculate Water Wibble Tables
 ****************************************************************************/
void CalculateWibbleTable(void)
	{
	/* Calculate the wibbling for the water effect */
	int i, j, sn;
	PHD_ANGLE angle;

	for (i=0; i<WIBBLE_SIZE; i++)
		{
		angle = (i * 65536)/WIBBLE_SIZE;
		sn = phd_sin(angle);

		wibble_table[i] =(float) (sn * MAX_WIBBLE >> W2V_SHIFT);
		shade_table[i] = sn * MAX_SHADE >> W2V_SHIFT;
		rand_table[i] = (GetRandomDraw() >> 5) - 0x01ff;

		/* Wibble tables for dynamic lighting of rooms */
		for (j=0; j<31; j++)
			wibble_light[i][j] = ((j-16) * i << 9)/(WIBBLE_SIZE-1); // linear ramp
//			wibble_light[i][j] = (sn+(1<<W2V_SHIFT)) * (j-16) >> (W2V_SHIFT+1-9);
		}
	}

/******************************************************************************
 *			Seed Random numbers Uses current time!!!
 *****************************************************************************/
void S_SeedRandom( void )
	{
	struct tm	*tptr;
	time_t		lt;

	lt = time(NULL);
	tptr = localtime(&lt);
	SeedRandomControl( tptr->tm_sec+(tptr->tm_min*57)+(tptr->tm_hour*3543) );
	SeedRandomDraw( tptr->tm_sec+(tptr->tm_min*43)+(tptr->tm_hour*3477) );
	}

void CheckSellByDate(void)
	{
/* Some sort of WIN95 style preproduction copy protect may be in order */
#ifdef THE_REST
	struct tm	*tptr;
	time_t		lt;
	char		date[128];
	FILE *file;

	/* Gav: team members (especially artists) don't need this kind of shit when they arrive in the morning */
	file = fopen("tombraid.er", "r");
	if (file)
		{
		fclose(file);
		return;
		}

	lt = time(NULL);
	tptr = localtime(&lt);

	strftime( date,128,"%b %d %Y",tptr );
	if ( strcmp( date,__DATE__ ) )
		{
		printf("\nFATAL ERROR: See Paul....\n");
		exit(0);
		}
#endif
	}


