/******************************************************************************************
	CRTest PS   (c) 1999-2001 ISL

	map_view.c:			Map Flyabout
******************************************************************************************/

// No objects, no sky, no nothing.
// The quick & simple way to view maps.

// Set this to "1", and you'll need to define "map_scale_adjust" in map_draw
// Set it to match the shifts in "MAP_SCALE_DEPTH_DOWN" value in map_draw, and map_scale_adjust in map_draw can be removed
//#define MAP_SCALE_ADJUST 1
#define MAP_SCALE_ADJUST 8


#include "global.h"
#include "main.h"
#include "menu.h"
#include "map_draw.h"
#include "bff_load.h"
#include "collide.h"
#include "debris.h"
#include "lights.h"
#include "timer.h"
#include "maths.h"
#include "inventory.h"
#include "enemies.h"

#include "puzzles.h"
#include "platform.h"

#include "global.h"
#include "scenics.h"
#include "overlays.h"
#include "sound.h"

#include <psitypes.h>

//#define MOVE_SHIFT (6+12)
#define MOVE_SHIFT (3+12)

// ============================================

void mapviewDraw();
void mapviewCycle();

TextureBankType	*mapview_textures = 0;
BFF_Header *mapview_level_bff = NULL;
FMA_WORLD *mapview_fma_world = NULL;
FMA_WORLD *mapview_sky_world = NULL;


int	mapview_camera_ya = 0;
int	mapview_camera_xa = 512;
int	mapview_camera_range = 1500 * MAP_SCALE_ADJUST;



/*
	Map flyabout bits
*/

void mapviewReleaseMap()
{
	int i;

	psiDestroy();
	scenicEnd();

	BFF_ReleaseFile(mapview_level_bff);
	textureUnloadBank(mapview_textures);
	mapview_level_bff = NULL;

	debrisFree();

	EXLIGHT_Shutdown();

	// The PC version re-compiles the models and level meshes at level-load time. The pointers to these
	// new meshes are stored in a list, so we can free them when we unload the level...kinda like now.
#ifdef _WINDOWS
	activeTPL_Destroy();
#endif

	for(i=originalTexCount;i<DCKnumTextures;i++)
	{
		kmFreeTexture(DCKtextureList[i].surfacePtr);
	} 

	DCKnumTextures = originalTexCount;

}

void mapviewLoadMap(char *leafname)
{
	char name[40];

	if(mapview_level_bff)
	{
		mapviewReleaseMap();
	}

	enemyInitialiseList();

	if(streamed_bank)
	{
		streamed_bank = textureTidyBank(streamed_bank);
	}

	psiInitialise(10);
	actorInitialise();
	puzzleInitLevel();

	texanimInit();
	scenicInit();
	EXLIGHT_Initialise();
	debrisInit();

//	utilPrintf("Memory before SPT load\n");
//	memoryShow();

	{
#ifndef _WINDOWS
		sound_XA_EnsurePaused();
#endif
	}

	sprintf(name,"%s\\%s.SPT",leafname,leafname);
	mapview_textures = textureLoadInOneGo(name);

//	utilPrintf("Memory after SPT load\n");
//	memoryShow();



	DB("Loading BFF\n");
	sprintf(name,"%s\\%s.BFF",leafname,leafname);
	mapview_level_bff = BFF_LoadFile(name);
	ASSERT(mapview_level_bff);

	DB("BFF loaded OK\n");

	mapview_fma_world = (void *)BFF_FindObject(BFF_FMA_WORLD2_ID,0);
	if(!mapview_fma_world)
		mapview_fma_world = (void *)BFF_FindObject(BFF_FMA_WORLD_ID,0);	// Should only be one world in the BFF

	mapview_sky_world = (void *)BFF_FindObject(BFF_FMA_WORLD_ID,utilStr2CRC("SKY"));	// Should only be one world in the BFF

	platformSetup();
	EXLIGHT_PostBFF();
	scenicPostBFF();

	PSImodelctrl.lighting = DIRECTIONONLY;
	psiSetAmbient(512,512,512);	// norm is 1024, max is 4096

	psiAllocWorkspace();
	PSImodelctrl.depthShift = 3;
	PSImodelctrl.farclip = 32768;

	if (levinfo)
	{
// Start the subgame's tune going
// The options screen also calls mapview_loadmap, and does some extra loading afterwards, so don't do this on the options load
		if(levinfo->level_number != LEVNUMBER_A1_FOWLER 
			&& levinfo->level_number != LEVNUMBER_A2_FOWLER 
			&& levinfo->level_number != LEVNUMBER_A4_FOWLER 
			&& levinfo->level_number != LEVNUMBER_A4_CONSTRUCT
			)
		{
			sound_XA_Resume(levinfo->tune_number);
		}
		levinfoSetupBackground();
	}
}

// --------- Cycle & Draw with the scenics & other stuff --------

//  Everything except the character & the camera updates
void mapviewBasicMapCycle()
{
 	enemyProcessAll();
	debrisCycle();
	EXLIGHT_Update();
	platformCycle();
	texanimCycle();
	scenicCycle();
	puzzleCheckPuzzles();

}
// Version for the fma without enemys cos the dog killed you during some fmas
void mapviewBasicFmaMapCycle()
{
// 	enemyProcessAll();
	ventProccessAll();
	debrisCycle();
	EXLIGHT_Update();
	platformCycle();
	texanimCycle();
	scenicCycle();
	puzzleCheckPuzzles();

}


// No sky. No debug lights
void mapviewBasicMapDraw()
{
	debrisDraw();
  	enemyDrawAll();
	texanimDraw();
	platformDraw();
	scenicDrawAll();

	TIMER_START(TIMER_MAPREND);
	MapDraw_DrawFMA_World(mapview_fma_world);
	TIMER_STOP(TIMER_MAPREND);

	overlayPreviewOverlay();
}









// ------------- The Map Viewer -------------

void mapviewStart(char *fname)
{
	mapviewLoadMap(fname);
	draw_routine = mapviewDraw;
	cycle_routine = mapviewCycle;
}

void mapviewEnd()
{
	if(mapview_level_bff)
	{
		mapviewReleaseMap();
	}
	menuStart();
}

void mapviewDraw()
{
	char temp[80];
	mapviewBasicMapDraw();


	TIMER_START(TIMER_SKYREND);
	if(mapview_sky_world)
	{
		MapDraw_Draw_SkyWorld(mapview_sky_world);
	}
	TIMER_STOP(TIMER_SKYREND);

	sprintf(temp,"pos %ld %ld %ld\n",mycamera.vpx,mycamera.vpy,mycamera.vpz);
	fontPrint(font, -70,64+20, temp, 128,128,0);
}

void mapviewCycle()
{
	VECTOR fore;

	mapviewBasicMapCycle();



#if PREVIEW_VERSION == 0

	if(padData.digital[0] & PAD_R3)
	{
		mycamera.vpx += GsWSMATRIX.m[2][0] >> 6;
		mycamera.vpy += GsWSMATRIX.m[2][1] >> 6;
		mycamera.vpz += GsWSMATRIX.m[2][2] >> 6;
	}
//	else
	{
// Rotations
		if(padData.analogX2S[0])
		{
			static MATRIX yrot = { {{4096,0,0},  {0,4096,0},  {0,0,4096}},  {0,0,0}};
			MATRIX out;

			int ang;
			ang = padData.analogX2S[0] >> 8;
			yrot.m[0][0] = rcos(ang);
			yrot.m[2][0] = rsin(ang);
			yrot.m[0][2] = rsin(ang);
			yrot.m[2][2] = rcos(ang);

			gte_MulMatrix0(&yrot, &GsWSMATRIX, &out);
			GsWSMATRIX = out;
		}
		if(padData.analogY2S[0])
		{
			static MATRIX xrot = { {{4096,0,0},  {0,4096,0},  {0,0,4096}},  {0,0,0}};
			MATRIX out;

			int ang;
			ang = (-padData.analogY2S[0]) >> 8;
			xrot.m[1][1] = rcos(ang);
			xrot.m[2][1] = rsin(ang);
			xrot.m[1][2] = rsin(ang);
			xrot.m[2][2] = rcos(ang);

			gte_MulMatrix0(&xrot, &GsWSMATRIX, &out);
			GsWSMATRIX = out;
		}
	}


	if(padData.digital[0] & PAD_L3)
	{
// fore/back
		mycamera.vpx -= ((int)GsWSMATRIX.m[2][0] * padData.analogYS[0]) >> MOVE_SHIFT;
		mycamera.vpy -= ((int)GsWSMATRIX.m[2][1] * padData.analogYS[0]) >> MOVE_SHIFT;
		mycamera.vpz -= ((int)GsWSMATRIX.m[2][2] * padData.analogYS[0]) >> MOVE_SHIFT;
	}
	else
	{

// Map/CamYA relative side strafe. Direct up down
/*
		VECTOR h;
		h.vx = GsWSMATRIX.m[0][0];
		h.vy = 0;
		h.vz = GsWSMATRIX.m[0][2];
		MakeUnit(&h);

		mycamera.vpx += (h.vx * padData.analogXS[0]) >> MOVE_SHIFT;
		mycamera.vpy += 0;
		mycamera.vpz += (h.vz * padData.analogXS[0]) >> MOVE_SHIFT;

		mycamera.vpx += 0;
		mycamera.vpy += (4096 * padData.analogYS[0]) >> MOVE_SHIFT;
		mycamera.vpz += 0;
*/
// Cam-relative strafe

		mycamera.vpx += ((int)GsWSMATRIX.m[0][0] * padData.analogXS[0]) >> MOVE_SHIFT;
		mycamera.vpy += ((int)GsWSMATRIX.m[0][1] * padData.analogXS[0]) >> MOVE_SHIFT;
		mycamera.vpz += ((int)GsWSMATRIX.m[0][2] * padData.analogXS[0]) >> MOVE_SHIFT;

		mycamera.vpx += ((int)GsWSMATRIX.m[1][0] * padData.analogYS[0]) >> MOVE_SHIFT;
		mycamera.vpy += ((int)GsWSMATRIX.m[1][1] * padData.analogYS[0]) >> MOVE_SHIFT;
		mycamera.vpz += ((int)GsWSMATRIX.m[1][2] * padData.analogYS[0]) >> MOVE_SHIFT;
	}


	mycamera.vrx = mycamera.vpx + GsWSMATRIX.m[2][0];
	mycamera.vry = mycamera.vpy + GsWSMATRIX.m[2][1];
	mycamera.vrz = mycamera.vpz + GsWSMATRIX.m[2][2];

#else
	{
		static int xa = 0;
		static int ya = 0;
		static int za = 0;

		xa = (xa + 5) & 4095;
		ya = (ya + 2) & 4095;
		za = (za + 9) & 4095;

		mycamera.vpx = rsin(xa) * 3;
		mycamera.vpy = -4000;	//rsin(ya)/4 - 500;
		mycamera.vpz = rsin(za) * 3;

		mycamera.vrx = 0;
		mycamera.vry = 0;
		mycamera.vrz = 0;
	}
#endif
	if(padData.debounce[0] & PAD_START)
	{
		mapviewEnd();
	}

// when setting the camera in the game, you must call this
	mapCamSetRefView2L(&mycamera);
}


