//
// Asura_MainLoop.cpp
//
// Created by RWM - 31/03/2009
//
// Copyright (C) 2009 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"

// This file's header
#include "Core/Asura_MainLoop.h"

// Asura Headers
#include "AI/Asura_AI_Navigation.h"
#ifdef ASURA_BOTANICAL_SUPPORT_STATES
	#include "Botanicals/Asura_Botanical_Game_Render_Manager.h"
#endif
#ifdef ASURA_USE_BOTANICALS
	#include "Botanicals/Asura_Botanicals_InstanceManager.h"
#endif
#ifdef ASURA_USE_CARPET
	#include "Carpet/Asura_Carpet_MeshManager.h"
#endif
#include "Cutscene/Asura_Cutscene_System.h"
#include "Debugging/Asura_CPUProfile.h"
#include "Entity/Asura_Entity_System.h"
#ifdef ASURA_USE_MOVEMENT_SYSTEM
	#include "Entity/PhysicalObject/Moves/Asura_Movement_System.h"
#endif
#ifdef ASURA_USE_DEBUG_MESSAGE_TRIGGER
	#include "Entity/Triggers/Asura_ServerEntity_DebugMessageTrigger.h"
	#include "Entity/Triggers/Asura_ServerEntity_DebugWaypointTrigger.h"
#endif
#ifdef ASURA_USE_VIDEO_TO_TEXTURE_SYSTEM
	#include "FMV/Asura_VideoToTexture_System.h"
#endif
#ifdef ASURA_USE_GUI_MENU_SYSTEM
	#include "GUIMenu/Asura_GUIMenu_System.h"
#endif
#include "Input/Asura_ControlManager.h"
#ifdef ASURA_USE_NEW_INPUT
	#include "Input/Asura_Input.h"
#endif
#ifdef ASURA_SUPPORT_CONTROLLER_RUMBLE
	#include "Input/Asura_Rumble_System.h"
#endif
#ifdef ASURA_SUPPORT_COMMAND_CONSOLE
	#include "Interface/Asura_CommandConsole.h"
#endif
#if defined(ASURA_TOOLS) || defined(ASURA_USE_CURSOR)
	#include "Interface/Asura_Cursor.h"
#endif
#ifdef ASURA_TOOLS
	#include "Interface/Asura_Overlay_System.h"
#endif
#include "Mesh/Asura_Env_System.h"
#ifdef ASURA_SUPPORT_EXTERNAL_NETWORK
	#include "Network/Asura_NetLinkManager.h"
#endif
#include "Physics/Asura_Physics.h"
#ifdef ASURA_TARGET_SM3
	#include "Rendering/Asura_AmbientOcclusion.h"
	#include "Rendering/Asura_DeferredShading.h"
#endif
#include "Rendering/Asura_Module.h"
#include "Rendering/Asura_Render.h"
#ifdef ASURA_TARGET_SM3
	#include "Rendering/Asura_SortedRender.h"
#endif
#ifdef ASURA_USE_CSM
	#include "Shadows/Asura_CSM.h"
#endif
#if defined(ASURA_USE_INDEPENDENT_SHADOW_SYSTEM) && !defined(ASURA_TARGET_SM3)
	#include "Shadows/Asura_Shadow_System.h"
#endif
#ifdef ASURA_USE_AUDIO_SYSTEM
	#include "Sound/Asura_Audio_Systems_Manager.h"
#else
	#include "Sound/Asura_Sound.h"
#endif
#ifdef ASURA_USE_COLLISIONFX
	#include "SpecialFX/Asura_CollisionFX_System.h"
#endif
#ifdef ASURA_USE_STATIC_DECAL_SYSTEM
	#include "SpecialFX/Asura_Decal_System.h"
#endif
#include "SpecialFX/Asura_Skybox.h"
#include "SpecialFX/Asura_SpecialFX.h"
#ifdef ASURA_USE_STREAMING
	#include "Streaming/Asura_Streaming_System.h"
#endif
#if !defined(ASURA_DONT_USE_TELEPORTERS)
	#include "Teleport/Asura_Teleport_System.h"
#endif

// Axon headers
#ifdef ASURA_USE_AXON
	#include "Core/Axon_System.h"
#endif


Asura_FunctionSequencer Asura_MainLoop::s_xRenderSequence;
Asura_FunctionSequencer Asura_MainLoop::s_xUpdateSequence;

void Asura_MainLoop::Initialise()
{
	CreateDefaultRenderSequence();
	CreateDefaultUpdateSequence();
}

void Asura_MainLoop::Shutdown()
{
	s_xUpdateSequence.Reset();
	s_xRenderSequence.Reset();
}

void Asura_MainLoop::CreateDefaultRenderSequence()
{
	s_xRenderSequence.Reset();

	// fill sequencer
	s_xRenderSequence.AFS_ADD_HEAD(&Asura_Render::BeginFrame, "Begin Frame", ASURA_CPU_PROFILE__MISC_RENDER);

#ifdef ASURA_USE_VIDEO_TO_TEXTURE_SYSTEM
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_VideoToTexture_System::Render, "VideoToTexture Render", ASURA_CPU_PROFILE__MISC_RENDER);
#endif

#ifdef ASURA_USE_CSM
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_CSM::CreateShadowMaps, "Create Cascading Shadow Maps", ASURA_CPU_PROFILE__MISC_RENDER);
#endif

#ifdef ASURA_TARGET_SM3
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_Render::BeginMRT, "Begin MRT", ASURA_CPU_PROFILE__MISC_RENDER);
#endif

	s_xRenderSequence.AFS_ADD_TAIL(&Asura_Skybox::Render, "Skybox Render", ASURA_CPU_PROFILE__WORLD_RENDER);
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_SpecialFX_System::RenderSkyboxEffects, "Skybox PFX Render", ASURA_CPU_PROFILE__SPECIALFX_RENDER);

#ifdef ASURA_USE_STREAMING
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_Streaming_System::RenderEnvironment, "Environment Render", ASURA_CPU_PROFILE__WORLD_RENDER);
#else //#ifdef ASURA_USE_STREAMING
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_Module_System::Render, "Module Render", ASURA_CPU_PROFILE__WORLD_RENDER);
#endif //#else //#ifdef ASURA_USE_STREAMING

#ifdef ASURA_USE_BOTANICALS
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_Botanicals_InstanceManager::Render, "Botanical Render", ASURA_CPU_PROFILE__BOTANICALS_RENDER);
#endif

#ifdef ASURA_USE_CARPET
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_Carpet_MeshManager::Render, "Carpet Render", ASURA_CPU_PROFILE__CARPET_RENDER);
#endif

#ifdef ASURA_USE_STATIC_DECAL_SYSTEM
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_Decal_System::RenderStaticDecals, "Static Decal Render", ASURA_CPU_PROFILE__MISC_RENDER);
#endif

	s_xRenderSequence.AFS_ADD_TAIL(&Asura_SpecialFX_System::RenderDecals, "Decal Render", ASURA_CPU_PROFILE__SPECIALFX_RENDER);

#ifdef ASURA_USE_STREAMING
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_Streaming_System::RenderEntities, "Entity Render", ASURA_CPU_PROFILE__ENTITY_RENDER);
#else //#ifdef ASURA_USE_STREAMING
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_Entity_System::Render, "Entity Render", ASURA_CPU_PROFILE__ENTITY_RENDER);
#endif //#else //#ifdef ASURA_USE_STREAMING

#ifdef ASURA_TARGET_SM3
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_Render::EndMRT, "End MRT", ASURA_CPU_PROFILE__MISC_RENDER);
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_AmbientOcclusion::PrepareDepthData, "Prepare Ambient Occlusion Depth Data", ASURA_CPU_PROFILE__MISC_RENDER);
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_DeferredShading::Render, "Deferred Shading Render", ASURA_CPU_PROFILE__DEFERRED_LIGHTS);
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_AmbientOcclusion::Render, "Ambient Occlusion Render", ASURA_CPU_PROFILE__MISC_RENDER);
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_Module_System::RenderLate, "Transparent Environment Render", ASURA_CPU_PROFILE__WORLD_RENDER);
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_SortedRender::RenderTransparentItems, "Transparent Entity Render", ASURA_CPU_PROFILE__ENTITY_RENDER);
#elif defined ASURA_USE_INDEPENDENT_SHADOW_SYSTEM
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_Shadow_System::Render, "Shadow Render", ASURA_CPU_PROFILE__MISC_RENDER);
#endif

#ifdef ASURA_USE_STREAMING
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_Streaming_System::RenderSpecialFX, "Special Effects Render", ASURA_CPU_PROFILE__SPECIALFX_RENDER);
#else //#ifdef ASURA_USE_STREAMING
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_SpecialFX_System::Render, "Special Effects Render", ASURA_CPU_PROFILE__SPECIALFX_RENDER);
#endif //#else //#ifdef ASURA_USE_STREAMING

	s_xRenderSequence.AFS_ADD_TAIL(&Asura_SpecialFX_System::Render2DEffects, "2D Effects Render", ASURA_CPU_PROFILE__SPECIALFX_RENDER);

#if !defined(ASURA_DONT_USE_TELEPORTERS)
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_Teleport_System::Render, "Teleport Render", ASURA_CPU_PROFILE__MISC_RENDER);
#endif	// !defined(ASURA_DONT_USE_TELEPORTERS)

	s_xRenderSequence.AFS_ADD_TAIL(&Asura_Physics_System::DebuggingRender, "Physics Debug Render", ASURA_CPU_PROFILE__MISC_RENDER);

#ifdef ASURA_USE_DEBUG_MESSAGE_TRIGGER
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_DebugMessageTrigger_Messages::Render, "Debug Message Trigger Render", ASURA_CPU_PROFILE__MISC_RENDER);
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_DebugWaypointTrigger_Messages::Render, "Debug Waypoint Trigger Render", ASURA_CPU_PROFILE__MISC_RENDER);
#endif // #ifdef ASURA_USE_DEBUG_MESSAGE_TRIGGER

#if defined ASURA_TARGET_SM3
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_DeferredShading::RenderDebugOutput, "Deferred Shading Debug Render", ASURA_CPU_PROFILE__MISC_RENDER);
#endif

#ifdef ASURA_USE_GUI_MENU_SYSTEM
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_GUIMenu_System::Render, "GUI Menu Render", ASURA_CPU_PROFILE__MISC_RENDER);
#endif

#ifdef ASURA_TOOLS
//if(Asura_Overlay_System::AreAnyOverlaysVisible())
//{
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_Overlay_System::Render, "Overlay Render", ASURA_CPU_PROFILE__MISC_RENDER);
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_Cursor::Render, "Cursor Render", ASURA_CPU_PROFILE__MISC_RENDER);
//}
#else
#ifdef ASURA_USE_CURSOR
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_Cursor::Render, "Cursor Render", ASURA_CPU_PROFILE__MISC_RENDER);
#endif
#endif

#ifdef ASURA_SUPPORT_COMMAND_CONSOLE
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_CommandConsole::Render, "Command Console Render", ASURA_CPU_PROFILE__MISC_RENDER);
#endif

	s_xRenderSequence.AFS_ADD_TAIL(&Asura_Render::EndFrame, "End Frame", ASURA_CPU_PROFILE__MISC_RENDER);

#ifdef ASURA_SUPPORT_EXTERNAL_NETWORK
	s_xUpdateSequence.AFS_ADD_TAIL( &Asura_NetLinkManager::Update_PostRender, "Net Link Manager PostRender Update", ASURA_CPU_PROFILE__NETWORKMESSAGES);
#endif

	Platform_ModifyDefaultRenderSequence();
}

void Asura_MainLoop::CreateDefaultUpdateSequence()
{
	s_xUpdateSequence.Reset();

	// fill sequencer
#ifdef ASURA_USE_NEW_INPUT
	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_Input::Update, "Input Update", ASURA_CPU_PROFILE__MISC_UPDATE);
#else
	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_UserInput::Update, "Input Update", ASURA_CPU_PROFILE__MISC_UPDATE);
#endif

	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_ControlManager::Update, "Control Manager Update", ASURA_CPU_PROFILE__MISC_UPDATE);

#ifdef ASURA_SUPPORT_EXTERNAL_NETWORK
	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_NetLinkManager::Update, "Net Link Manager Update", ASURA_CPU_PROFILE__NETWORKMESSAGES);
#endif

#ifdef ASURA_SUPPORT_LOBBY
	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_Lobby_System::Update, "Lobby System Update", ASURA_CPU_PROFILE__NETWORKMESSAGES);
#endif

	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_Network::Update, "Network Update", ASURA_CPU_PROFILE__NETWORKMESSAGES);

	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_Cutscene_System::Update, "Cutscene Update", ASURA_CPU_PROFILE__MISC_UPDATE);

#ifdef ASURA_SUPPORT_CONTROLLER_RUMBLE
	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_Rumble_System::Update, "Rumble Update", ASURA_CPU_PROFILE__MISC_UPDATE);
#endif

#ifdef ASURA_USE_VIDEO_TO_TEXTURE_SYSTEM
	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_VideoToTexture_System::Update, "Video To Texture Update", ASURA_CPU_PROFILE__MISC_UPDATE);
#endif

#if !defined(ASURA_DONT_USE_TELEPORTERS)
	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_Teleport_System::Update, "Teleport Update", ASURA_CPU_PROFILE__MISC_UPDATE);
#endif

#ifdef ASURA_USE_STREAMING
	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_Streaming_System::UpdateEntities, "Entity Update", ASURA_CPU_PROFILE__ENTITY_UPDATE);
#else
	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_Entity_System::Update, "Entity Update", ASURA_CPU_PROFILE__ENTITY_UPDATE);
#endif

#ifdef ASURA_USE_MOVEMENT_SYSTEM
	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_Movement_System::DeferredUpdate, "Movement System Update", ASURA_CPU_PROFILE__MISC_UPDATE);
#endif

#ifdef ASURA_USE_AXON
	s_xUpdateSequence.AFS_ADD_TAIL(&Axon_System::Update, "Axon Update", ASURA_CPU_PROFILE__AXON_UPDATE);
#endif

	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_AI_Navigation_System::Update, "AI Navigation System Update", ASURA_CPU_PROFILE__AXON_UPDATE);

	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_SpecialFX_System::Update, "Special FX Update", ASURA_CPU_PROFILE__SPECIALFX_UPDATE);
	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_Physics_System::Update, "Physics Update", ASURA_CPU_PROFILE__DYNAMICS);

#ifdef ASURA_USE_COLLISIONFX
	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_CollisionFX_System::Update, "Collision FX Update", ASURA_CPU_PROFILE__SPECIALFX_UPDATE);
#endif

#ifdef ASURA_BOTANICAL_SUPPORT_STATES
	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_BGR_Manager::Update, "Botanical Game Render Manager Update", ASURA_CPU_PROFILE__BOTANICALS_UPDATE);
#endif

#ifdef ASURA_USE_GUI_MENU_SYSTEM
	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_GUIMenu_System::Update, "Menu Update", ASURA_CPU_PROFILE__MISC_UPDATE);
#endif

#ifdef ASURA_TOOLS
	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_Cursor::OncePerFrameUpdate, "Cursor Update", ASURA_CPU_PROFILE__MISC_UPDATE);
	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_Overlay_System::Update, "Overlay Update", ASURA_CPU_PROFILE__MISC_UPDATE);
#else
#ifdef ASURA_USE_CURSOR
	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_Cursor::OncePerFrameUpdate, "Cursor Update", ASURA_CPU_PROFILE__MISC_UPDATE);
#endif
#endif

	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_Network::BeginClientToServerUpdates, "Begin Client/Server Updates", ASURA_CPU_PROFILE__MISC_UPDATE);
	// Project specific Player Update usually goes here
	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_Network::EndClientToServerUpdates, "End Client/Server Updates", ASURA_CPU_PROFILE__MISC_UPDATE);
	// Project specific camera setting usually goes here

#ifdef ASURA_SUPPORT_COMMAND_CONSOLE
	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_CommandConsole::Update, "Command Console Update", ASURA_CPU_PROFILE__MISC_UPDATE);
#endif

#ifdef ASURA_USE_STREAMING
#error "FIX LATER: Asura_Streaming_System::Update takes a boolean argument but function sequencer cannot take fns with arguments at present"
	//s_xUpdateSequence.AFS_ADD_TAIL(&Asura_Streaming_System::Update, "Streaming Update", ASURA_CPU_PROFILE__MISC_UPDATE);
#endif

	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_Network::EndOfFrameUpdate, "Network End Of Frame Update", ASURA_CPU_PROFILE__NETWORKMESSAGES);

	s_xRenderSequence.AFS_ADD_TAIL(&Asura_Module_System::Update, "Module System Update", ASURA_CPU_PROFILE__MISC_RENDER);
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_Environment_System::Update, "Environment System Update", ASURA_CPU_PROFILE__MISC_RENDER);

#ifdef ASURA_USE_STREAMING
	s_xRenderSequence.AFS_ADD_TAIL(&Asura_Streaming_System::PreRenderUpdate, "Streaming system pre-render update", ASURA_CPU_PROFILE__MISC_RENDER);
#endif //#ifdef ASURA_USE_STREAMING

	// Project specific render function usually goes here

#ifdef ASURA_USE_AUDIO_SYSTEM
	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_Audio_Systems_Manager::Update, "Sound Update", ASURA_CPU_PROFILE__SOUND_UPDATE);
#else
	s_xUpdateSequence.AFS_ADD_TAIL(&Asura_Sound_System::Update, "Sound Update", ASURA_CPU_PROFILE__SOUND_UPDATE);
#endif

#ifdef ASURA_USE_STREAMING
#error "FIX LATER: Asura_Streaming_System::EndOfFrameUpdate takes two floats as arguments, but function sequencer cannot handle fns with arguments at present"
	//s_xUpdateSequence.AFS_ADD_TAIL(&Asura_Streaming_System::EndOfFrameUpdate, "Streaming EndOfFrame Update", ASURA_CPU_PROFILE__MISC_UPDATE);
#endif
}

void Asura_MainLoop::Render()
{
	s_xRenderSequence.Execute();
}

void Asura_MainLoop::Update()
{
	s_xUpdateSequence.Execute();
}




