//	Darkstar Engine  (c) UnderWorld Interactive Studio (all coding by Svarog    2008)
//
//      Данный файл является частью Darkstar Engine. Любое использование кода файла
//      без согласия компании, является нарушением закона об авторском праве (в слу-
//      чае если не оговорено обратное).
//
//      Имя файла: preetham_sky.hpp
//      Краткое описание: darkstar preetham sky representation
//

#ifndef DSE_NATURE_SKY_HPP
#define DSE_NATURE_SKY_HPP

#include <Darkstar/Nature/Sky/sun.hpp>
#include <Darkstar/Nature/Sky/star_database.hpp>
#include <Darkstar/Math/xyY.hpp>
#include <Darkstar/Math/XYZ.hpp>
#include <Darkstar/Resource System/Model/static_model.hpp>
#include <Darkstar/Graphic System/Camera/camera.hpp>
#include <Darkstar/Resource System/Model/SimpleModels/quad.hpp>
#include <Darkstar/Graphic System/Render Target/render_target.hpp>
#include <Darkstar/Kernel/timetable.hpp>

namespace nature
{
	// distribution coefficients for the luminance (Y)
	const float Y_dist_coeff[5][2] = 
	{
		{ 0.1787f, -1.4630f},
		{-0.3554f,  0.4275f},
		{-0.0227f,  5.3251f},
		{ 0.1206f, -2.5771f},
		{-0.0670f,  0.3703f},
	};

	// distribution coefficients for the x component
	const float x_dist_coeff[5][2] = 
	{
		{-0.0193f, -0.2592f},
		{-0.0665f,  0.0008f},
		{-0.0004f,  0.2125f},
		{-0.0641f, -0.8989f},
		{-0.0033f,  0.0452f},
	};

	// distribution coefficients for the y component
	const float y_dist_coeff[5][2] = 
	{
		{-0.0167f, -0.2608f},
		{-0.0950f,  0.0092f},
		{-0.0079f,  0.2102f},
		{-0.0441f, -1.6537f},
		{-0.0109f,  0.0529f},
	};

	// coefficients for zenith x component
	const float x_zenith_coeff[3][4] = 
	{
		{ 0.00166f, -0.00375f,  0.00209f, 0.00000f},
		{-0.02903f,  0.06377f, -0.03202f, 0.00394f},
		{ 0.11693f, -0.21196f,  0.06052f, 0.25886f},
	};
	// coefficients for zenith y component
	const float y_zenith_coeff[3][4] = 
	{
		{ 0.00275f, -0.00610f,  0.00317f, 0.00000f},
		{-0.04214f,  0.08970f, -0.04153f, 0.00516f},
		{ 0.15346f, -0.26756f,  0.06670f, 0.26688f},
	};

	// We assume that positive Oz - north, negative Oz - south, positive Ox - east, negative Ox - west

	class PreethamSky
	{
	private:
		shared_ptr<rs::StaticModel> sky_dome;

		shared_ptr<rs::Quad> fullscreen_quad;
		shared_ptr<gs::RenderTarget> sky_cubemap;
		unsigned int cubemap_size;
		bool is_cubemap_enable;

		// distribution's coefficients for the Perez's function
		math::xyY A_coeff, B_coeff, C_coeff, D_coeff, E_coeff;
		// turbidity
		float turbidity;
		// zenith distribution for each point on geosphere
		math::xyY zenith_distribution;
		// sun representation
		Sun sun;
		// sun intensity
		float sun_intensity;
		// star database
		shared_ptr<StarDatabase> stars;
		// is night sky enable
		bool is_night_sky_stars_enable;

		// current longitude and latitude. Longitude in degrees and latitude in radians
		float site_longitude, site_latitude;
		// current standard date
		ker::Date current_date;
		// current standard time
		ker::Time current_time;

		void _computePerezCoeff();
		void _computeZenitDistribution();

		// F(theta, gamma) = (1 + A*exp(B/cos(theta))*(1 + C*exp(D*gamma) + E*cos(gamma)*cos(gamma))
		float _PerezFunction(const float theta, const float gamma, const float A, const float B, const float C, const float D, const float E);
	public:
		PreethamSky(const shared_ptr<rs::StaticModel>& geosphere, const std::string& star_database_name = "", const std::string& stars_texture_name = "", const std::string& stars_effect_name = "");
		~PreethamSky();

		void setTurbidity(const float new_turbidity);
		void setSun(const float new_theta_sun, const float new_phi_sun);
		// both, longitude and latitude, are in degrees
		void setSiteCoordinates(const float site_longtitude, const float site_latitude);

		void setCubemapSize(const unsigned int new_size);
		void drawToCubemap(const bool is_enable);
		
		void setTime(const ker::Time& time);
		void setDate(const ker::Date& date);
		void setTimeAndDate(const ker::Time& time, const ker::Date& date);

		const Vect3& getSunDirection() const;
		float getSunIntensity() const;
		shared_ptr<rs::BaseTexture> getSkybox() const;
		
		void draw(const shared_ptr<gs::Camera>& camera);
	};		
};		

#endif


