/* -----------------------------------------------------------------------------
	GSFramework
	Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */


		#include "gpu/gpu_renderer.h"
		#include "metafile/nml_object.h"
		#include "log/log.h"

		using namespace GS::GPU;
		using GS::NML::Tag;


//------------------------------------------------------------------------------
Tag				*Renderer::GetPCFShaderTag() const
{
	const char *pcf_tag[] = { "PCF:3x3GaussianDithered;", "PCF:3x3;", "PCF:2x2;", "PCF:1x1;" };
	int pcf_q = GS::Types::Clamp(registry.GetInteger("ShadowMapping:PCF:Quality", 1), 0, 3);
	return shader_dict.GetTag(pcf_tag[pcf_q]);
}
Tag				*Renderer::GetPSMShaderTag() const
{	return shader_dict.GetTag("PSM;");	}
Tag				*Renderer::GetPSSMShaderTag() const
{
	const char *pssm_tag[] = {	"PSSM:2Split;", "PSSM:3Split;", "PSSM:4Split;" };
	int split_count = GS::Types::Clamp(registry.GetInteger("ShadowMapping:PSSM:Split", 3), 2, 4);
	return shader_dict.GetTag(pssm_tag[split_count - 2]);
}
void			Renderer::MarshallCoreShader(GS::String &source)
{
	if	(Tag *t = shader_dict.GetTag("UnpackGBuffer:Float;"))
		source.Replace("#(UnpackNormalDepth)", t->GetString());
	if	(Tag *t = GetPCFShaderTag())
		source.Replace("#(ComputePCF)", t->GetString());
	if	(Tag *t = GetPSSMShaderTag())
		source.Replace("#(DispatchPSSM)", t->GetString());
}
Shader			*Renderer::SetupCoreShader(const char *name)
{
	Core::Shader shader;
	if	(!NML::LoadFromFile(shader, name))
		return NULL;

	shader.name = name;

	// Note: Marshalling is only done on core shaders.
	MarshallCoreShader(shader.vertex);
	MarshallCoreShader(shader.pixel);

	AutoPtr <Shader> gpu_shader((Shader *)NewShader());
	if	(gpu_shader.IsNull() || !gpu_shader->Create(*core_resource_factory, shader))
		return NULL;
	return gpu_shader.Detach();
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
bool				Renderer::LoadCoreShaders(bool support_3d)
{
	__LOG_FUNC__

	// Load the shader dictionaries.
	if	(!NML::Parser::Load("@core/shaders/gpu/dict.txt", shader_dict))
		__ERR__(__LOG_E__ << "Shader dictionnary missing.\n", false)
	if	(!NML::Parser::Load("@core/shaders/gpu/dict_material.txt", material_dict))
		__ERR__(__LOG_E__ << "Material dictionnary missing.\n", false)

	// Load core shaders.
	single_texture_color_program = SetupCoreShader("@core/shaders/gpu/single_texture_color.nsa");
	single_texture_program = SetupCoreShader("@core/shaders/gpu/single_texture.nsa");
	single_color_program = SetupCoreShader("@core/shaders/gpu/single_color.nsa");
	simple_program = SetupCoreShader("@core/shaders/gpu/simple.nsa");

	if	(support_3d)
	{
		single_texture_cutoff_program = SetupCoreShader("@core/shaders/gpu/single_texture_cutoff.nsa");
		single_texture_fx_program = SetupCoreShader("@core/shaders/gpu/single_texture_fx.nsa");
		tone_mapping_program = SetupCoreShader("@core/shaders/gpu/tone_mapping.nsa");

		ambient_program = SetupCoreShader("@core/shaders/gpu/ambient.nsa");

		spotlight_program = SetupCoreShader("@core/shaders/gpu/deferred/spotlight.nsa");
		spotlight_shadow_program = SetupCoreShader("@core/shaders/gpu/deferred/spotlight_shadow.nsa");
		pointlight_program = SetupCoreShader("@core/shaders/gpu/deferred/pointlight.nsa");
		pointlight_shadow_program = SetupCoreShader("@core/shaders/gpu/deferred/pointlight_shadow.nsa");
		linearlight_program = SetupCoreShader("@core/shaders/gpu/deferred/linearlight.nsa");
		linearlight_shadow_program = SetupCoreShader("@core/shaders/gpu/deferred/linearlight_shadow.nsa");
		ds_fog_program = SetupCoreShader("@core/shaders/gpu/deferred/ds_fog.nsa");

		fx_blur_program = SetupCoreShader("@core/shaders/gpu/fx_blur.nsa");
		noise_program = SetupCoreShader("@core/shaders/gpu/noise.nsa");
		sharpen_program = SetupCoreShader("@core/shaders/gpu/sharpen.nsa");
		hsl_program = SetupCoreShader("@core/shaders/gpu/hsl.nsa");
		chromatic_dispersion_program = SetupCoreShader("@core/shaders/gpu/chromatic_dispersion.nsa");

		ssaa_program = SetupCoreShader("@core/shaders/gpu/ssaa.nsa");
		ssao_program = SetupCoreShader("@core/shaders/gpu/ssao.nsa");
		ssao_blur_program = SetupCoreShader("@core/shaders/gpu/ssao_blur.nsa");

		motion_blur_program = SetupCoreShader("@core/shaders/gpu/motion_blur.nsa");
		radial_blur_program = SetupCoreShader("@core/shaders/gpu/radial_blur.nsa");

		resolve_msaa_depth_program = SetupCoreShader("@core/shaders/gpu/resolve_msaa_depth.nsa");

		skybox_program = SetupCoreShader("@core/shaders/gpu/skybox.nsa");
	}
	return true;
}
void				Renderer::UnloadCoreShaders()
{
	single_texture_color_program = NULL;
	single_texture_program = NULL;
	single_color_program = NULL;
	simple_program = NULL;

	single_texture_cutoff_program = NULL;
	single_texture_fx_program = NULL;
	tone_mapping_program = NULL;

	ambient_program = NULL;

	spotlight_program = NULL;
	spotlight_shadow_program = NULL;
	pointlight_program = NULL;
	pointlight_shadow_program = NULL;
	linearlight_program = NULL;
	linearlight_shadow_program = NULL;
	ds_fog_program = NULL;

	fx_blur_program = NULL;
	noise_program = NULL;
	sharpen_program = NULL;
	hsl_program = NULL;
	chromatic_dispersion_program = NULL;

	ssaa_program = NULL;
	ssao_program = NULL;
	ssao_blur_program = NULL;

	motion_blur_program = NULL;
	radial_blur_program = NULL;

	resolve_msaa_depth_program = NULL;

	skybox_program = NULL;
}
//------------------------------------------------------------------------------
