//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------		
#include <Render/Scene.hpp>
#include <cassert>


namespace Render
{
	//-----------------------------------------------------------------
	// C/D-Tor
	//-----------------------------------------------------------------
	Scene::Scene( Primitive* _root,
 				  const TLightVector& _lights,
 				  const TMaterialVector& _materials,
				  SurfaceIntegrator* _integrator,
				  Film* _film,
				  Camera* _camera,
				  Sampler* _sampler):
	root(_root),
	lights(_lights),
	materials(_materials),
	integrator(_integrator),
	film(_film),
	camera(_camera),
	sampler(_sampler)
	{
		
	}
	//-----------------------------------------------------------------
	Scene::~Scene()
	{

	}
	//-----------------------------------------------------------------
	void Scene::Render()
	{
		assert(root != NULL);
		assert(integrator != NULL);
		assert(film != NULL);
		assert(camera != NULL);
		assert(sampler != NULL);

		Sample sample;
		Math::vec4 radianceWithAlpha;
		Ray ray;
		const int nSamples = sampler->NumSamples();
		int samplesDone	   = 0;
		int lastPrint	   = 0;
		while(sampler->GetNextSample(sample))
		{
			// Generate ray
			camera->GenerateRay(sample, ray);
	
			// Compute reflected radiance
			radianceWithAlpha = integrator->Li(*this, ray);
			
			// Set radiance in final image
			Math::ivec2 pixelCoord;
			pixelCoord.x = floor(sample.Position.x);
			pixelCoord.y = floor(sample.Position.y);
//printf("%s\n",Math::ToString(pixelCoord).c_str());

			// Accumulate radiance on film
			radianceWithAlpha *= sample.Weight;
			
			film->AccumulateRadiance(pixelCoord, radianceWithAlpha);

			if(samplesDone > (nSamples*0.01f+lastPrint))
			{
				printf("Progress : %f%% \n", 100 * samplesDone/static_cast<float>(nSamples));
				lastPrint = samplesDone;
			}
			++samplesDone;
		}

		// Apply tone mapping
		// TODO
	}
	//-----------------------------------------------------------------
	bool Scene::Intersect(const Ray& _ray, Intersection& _intersection) const
	{
		return root->Intersect(_ray,_intersection);
	}
	//-----------------------------------------------------------------
	bool Scene::Unoccluded(const VisibilityTester& _tester) const
	{
		return root->Unoccluded(_tester);
	}
	//-----------------------------------------------------------------
	const BSDF& Scene::GetMaterial(unsigned int _matID) const
	{
		//printf("matID:%d", _matID);
		assert(_matID>=0);
		assert(_matID<materials.size());
		assert(materials[_matID]!=NULL);
		return *materials[_matID];
	}
}
