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


		#include "gpu/gpu_renderer.h"
		#include "gpu/gpu_geometry.h"
		#include "gpu/gpu_draw_context.h"
		#include "core/renderer_environment_interface.h"
		#include "core/camera.h"
		#include "core/light.h"

		using namespace GS::GPU;


//------------------------------------------------------------------------------
void				Renderer::RenderGBufferPass(const GS::Stack <RenderPrimitive *> &display_lists)
{
	SetCurrentFBO(buffer_fbo);
	Clear(0, 0, 0, 0);

	DrawContext	dc(DrawContext::Deferred, DrawContext::Base, MaterialShader::DS_GBufferMRT4);
	DrawList(display_lists, dc);
}
void				Renderer::RenderDeferredLightPass(const GS::Stack <RenderPrimitive *> &)
{
	SetCurrentFBO(resolve_fbo);

	DrawContext	dc(DrawContext::Deferred, DrawContext::Light);

	// Clear to ambient.
	EnableDepthWrite(false);
	RenderFullscreenQuad(*ambient_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y);
	EnableDepthWrite(true);

	// For each light in frustum, render affected primitives with a light specific shader.
	SetBlendFunc(BlendOne, BlendOne);

	List <Core::Light *> light_list;
	environment_interface->GetLightsInFrustum(view_item->GetMatrix().GetRow(3), frustum, light_list);

	ListForeachPtr(Core::Light *, l, light_list)
	{
		// Render shadow map.
		if	(gpu_config.enable_shadow && l->shadow == Core::Light::Shadow_Map)
		{
			if	(PrepareShadowMap(*l, true))	// TODO move to job
				RenderShadowMap(*l);

			SetCurrentFBO(resolve_fbo);
			SetBlendFunc(BlendOne, BlendOne);
		}

		// Compose light.
		EnableDepthWrite(false);
		EnableBlending(true);

		switch (l->model)
		{
			case Core::Light::Model_Point:	RenderPointLight(*l, dc);	break;
			case Core::Light::Model_Linear:	RenderLinearLight(*l, dc);	break;
			case Core::Light::Model_Spot:	RenderSpotLight(*l, dc);	break;
		}

		EnableBlending(false);
		EnableDepthWrite(true);
		stats.light_processed++;
	}

	SetBlendFunc(BlendSrcAlpha, BlendOneMinusSrcAlpha);
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				Renderer::RenderListDeferred(const GS::Stack <RenderPrimitive *> &display_lists)
{
	RenderGBufferPass(display_lists);
	if	(environment_interface)
		RenderDeferredLightPass(display_lists);
}
//------------------------------------------------------------------------------
