#include "Rune.h"

#pragma unmanaged

#define RuShaderSys_CreateShader(shaderName)										\
	{																				\
		shaderName *shader = ruNEW shaderName(engine);								\
		g_ruResourceManager->AddShader(shader);										\
		shader->Release();															\
	}

BOOL				g_ruObjectFactoryInitialized = FALSE;
char				g_ruGlobalMessage[2048] = "";

void RuInitializeObjectFactory()
{
	// Do not initialize the object factory a second time
	if(g_ruObjectFactoryInitialized)
		return;

	// Initialize object factory
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Material());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_MorphTarget());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Mesh());

	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Entity());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Entity_Light());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Entity_Container());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Entity_Decal());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Frame());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_LinkFrame());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_FrameHierarchy());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Entity_Renderable());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Model());

	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_CompositeModelTemplate());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_PaperdollTemplate());

	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_ACTEntity());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_ACTTemplate());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_ACTTemplateNode());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_ACTTemplateModifier());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_ACTMotion());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_ACTMotionNode());

	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Controller_Decal());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Controller_Entity());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Controller_EventTrigger());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Controller_Frame());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Controller_GhostTrail());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Controller_GlobalAlpha());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Controller_GlobalColor());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Controller_Hierarchy());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Controller_Morph());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Controller_ParticleSystem());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Controller_Particle_Emitter());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Controller_Particle_Visualizer_Entity());
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Controller_Particle_Visualizer_Sprite());

	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Container_Portal());

	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_MeshCollision_Simple);
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_MeshCollision_Quadtree);
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_MeshCollision_kdTree);

	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_SplatIDMap);

	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_OptimalTerrain_Chunk);

	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Entity_Water);
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_PolySoup_Quadtree);

	// Collision modules
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Collision_kdTree);
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Collision_kdTree_16);
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Collision_Simple);

	// PathEngine modules
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_PathGraph_AStar);

	// Particle system modules
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Entity_Particle_Emitter);
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Entity_Particle_Visualizer_Entity);
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Entity_Particle_Visualizer_Sprite);

	// Noise generator modules
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Noise_Perlin);
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Noise_Texture);
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Noise_Value);
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Noise_Worley);

	// Fractal modules
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Fractal_Composite);
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Fractal_fBm);
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Fractal_HeteroTerrain);
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Fractal_HybridMultifractal);
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Fractal_Multifractal);
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Fractal_RidgedMultifractal);
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Fractal_Shapes);

	// Fractal post-process modules
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Fractal_PostFX_ABS);
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Fractal_PostFX_Cutoff);
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Fractal_PostFX_Gain);
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Fractal_PostFX_Remap);
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Fractal_PostFX_Square);

	// World system modules
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_RuWorld_EntityDescriptor);
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_RuWorld_Trigger);

	// Deprecated
	g_ruObjectFactory.AttachModule(ruNEW CRuObjectModule_Entity_Particle_Sprite);

}

BOOL RuInitialize_Minimal()
{
	// Initialize object factory
	RuInitializeObjectFactory();

	// Initialize resource manager
	g_ruResourceManager = ruNEW CRuResourceManagerD3D();

	return TRUE;
}

IRuSwapChain* RuInitialize(HWND primaryWindow, HWND focusWindow, UINT32 resourceArenaSize)
{
	CRuEngineD3D *engine = NULL;
	IRuSwapChain *swapChain = NULL;

	// Initialize and startup engine
	engine = ruNEW CRuEngineD3D();
	engine->Startup(primaryWindow);

	// Initialize profiler
	RUPROFILE_INITIALIZE

	// Initialize object factory
	RuInitializeObjectFactory();

	// Enumerate display modes
	if(engine->EnumerateAdapters() && engine->SelectInitialDisplaySettings(FALSE))
	{
		// Create a default swap chain
		swapChain = engine->CreateSwapChain(800, 600, focusWindow);

		if(swapChain)
		{
			// Set engine into global
			g_ruEngine = engine;
			g_ruEngineD3D = engine;

			// Initialize the resource arena
			engine->SetResourceArenaSize(resourceArenaSize);

			// Initialize instance manager
			g_ruInstanceManager = ruNEW CRuInstanceManagerD3D();
			((CRuInstanceManagerD3D *) g_ruInstanceManager)->SetEngine(engine);

			// Initialize resource manager
			g_ruResourceManager = ruNEW CRuResourceManagerD3D();
			((CRuResourceManagerD3D *) g_ruResourceManager)->SetEngine(engine);

			// Initialize scene renderer
			g_ruSceneRenderer = ruNEW CRuSceneRenderer();
			g_ruSceneRenderer->SetInstanceManager(g_ruInstanceManager);

			// Initialize 2D shaders
			RuShaderSys_CreateShader(CRuShader_ru2DFXTYPE_FLAT);
			RuShaderSys_CreateShader(CRuShader_ru2DFXTYPE_BLIT);
			RuShaderSys_CreateShader(CRuShader_ru2DFXTYPE_BLIT_ADD);
			RuShaderSys_CreateShader(CRuShader_ru2DFXTYPE_BLIT_FILTER);
			RuShaderSys_CreateShader(CRuShader_ru2DFXTYPE_BLIT_FILTER_CUBIC);
			RuShaderSys_CreateShader(CRuShader_ru2DFXTYPE_BLIT_MASK);
			RuShaderSys_CreateShader(CRuShader_ru2DFXTYPE_BLIT_MASKED);
			RuShaderSys_CreateShader(CRuShader_ru2DFXTYPE_BLIT_LUMINANCE);
			RuShaderSys_CreateShader(CRuShader_ru2DFXTYPE_DARKEN);
			RuShaderSys_CreateShader(CRuShader_ru2DFXTYPE_GAUSSIAN);
			RuShaderSys_CreateShader(CRuShader_ru2DFXTYPE_MODULATE);
			RuShaderSys_CreateShader(CRuShader_ru2DFXTYPE_SPLAT_PS11);
			RuShaderSys_CreateShader(CRuShader_ru2DFXTYPE_SPLAT_PS20);

			// Initialize NULL shader
			RuShaderSys_CreateShader(CRuShader_NULL);

			// Initialize gizmo shader
			RuShaderSys_CreateShader(CRuShader_Gizmo);

			// Initialize default shaders
			RuShaderSys_CreateShader(CRuShader_Static_Flat);
			RuShaderSys_CreateShader(CRuShader_Static_SH9);
			RuShaderSys_CreateShader(CRuShader_Static_SH9_Gloss);
			RuShaderSys_CreateShader(CRuShader_Static_Prelit);
			RuShaderSys_CreateShader(CRuShader_Static_SH9_Translucent);
			RuShaderSys_CreateShader(CRuShader_Static_Prelit_Translucent);
			RuShaderSys_CreateShader(CRuShader_Static_FX);
			RuShaderSys_CreateShader(CRuShader_Static_Fader);
			RuShaderSys_CreateShader(CRuShader_Static_Highlight);
			RuShaderSys_CreateShader(CRuShader_Skin_Flat);
			RuShaderSys_CreateShader(CRuShader_Skin_SH9);

			RuShaderSys_CreateShader(CRuShader_Paperdoll_SH9_Gloss);

			// Initialize terrain shaders
			RuShaderSys_CreateShader(CRuShader_Terrain);
			RuShaderSys_CreateShader(CRuShader_Terrain_Highlight);
			RuShaderSys_CreateShader(CRuShader_Terrain_Brush);
			RuShaderSys_CreateShader(CRuShader_Terrain_Packed);
			RuShaderSys_CreateShader(CRuShader_Terrain_Packed_Flat);
			RuShaderSys_CreateShader(CRuShader_Terrain_Packed_Projection);
			RuShaderSys_CreateShader(CRuShader_Terrain_Packed_Backdrop);

			// Initialize sky and environment shaders
			RuShaderSys_CreateShader(CRuShader_SkyDome);
			RuShaderSys_CreateShader(CRuShader_SkyFX);
			RuShaderSys_CreateShader(CRuShader_CloudPlane);

			// Initialize water shaders
			RuShaderSys_CreateShader(CRuShader_Water_PS20_Full);
			RuShaderSys_CreateShader(CRuShader_Water_PS20_Diffuse);

			// Other shaders
			RuShaderSys_CreateShader(CRuShader_Static_DepthMap);
			RuShaderSys_CreateShader(CRuShader_Static_Shadow);
			RuShaderSys_CreateShader(CRuShader_Terrain_Packed_DepthMap);
			RuShaderSys_CreateShader(CRuShader_Terrain_Packed_Shadow);

			// Initialize particle system shaders
			RuShaderSys_CreateShader(CRuShader_Particle_Doodad);
			RuShaderSys_CreateShader(CRuShader_Particle_Grass);
			RuShaderSys_CreateShader(CRuShader_Particle_Grass_Optimized);
			RuShaderSys_CreateShader(CRuShader_Particle_Sprite);
			RuShaderSys_CreateShader(CRuShader_Particle_SpriteEx);

			RuShaderSys_CreateShader(CRuShader_Widget_Label);

			RuShaderSys_CreateShader(CRuShader_FX_Decal);
			RuShaderSys_CreateShader(CRuShader_FX_GhostTrail);

			// Initialize editor shaders
			RuShaderSys_CreateShader(CRuShader_Editor_PolyHighlight);
			RuShaderSys_CreateShader(CRuShader_Editor_ColVis);
			RuShaderSys_CreateShader(CRuShader_Editor_Translucent);
		}

		return swapChain;
	}

	return NULL;
}

IRuSwapChain* RuCreateSwapChain(UINT32 width, UINT32 height, HWND focusWindow)
{
	if(g_ruEngine)
	{
		return g_ruEngine->CreateSwapChain(width, height, focusWindow);
	}

	return NULL;
}

BOOL RuSetResolution(IRuSwapChain *swapChain, UINT32 width, UINT32 height, BOOL fullscreen)
{
	if(g_ruEngine && swapChain)
	{
		if(g_ruEngine->SetResolution(swapChain, width, height, fullscreen))
		{
			g_ruEngine->ClearStateCache();

			return TRUE;
		}
	}

	return FALSE;
}

BOOL RuShutdown()
{
	delete g_ruSceneRenderer;
	delete g_ruResourceManager;
	delete g_ruInstanceManager;
	delete g_ruEngine;

	return TRUE;
}

BOOL RuSymphony_Initialize()
{
	if(g_ruSymphony == NULL)
	{
		g_ruSymphony = ruNEW CRuSymphony();
		g_ruSymphony->Startup();
	}

	return TRUE;
}

BOOL RuSymphony_Shutdown()
{
	if(g_ruSymphony)
	{
		g_ruSymphony->Shutdown();
		ruSAFE_RELEASE(g_ruSymphony);
	}

	return TRUE;
}

#pragma managed
