1 module evael.graphics.Environment;
2 
3 import evael.graphics.GL;
4 
5 import evael.graphics.GraphicsDevice;
6 import evael.graphics.shaders.BasicLightShader;
7 import evael.graphics.lights;
8 
9 import evael.utils.Math;
10 
11 import dnogc.DynamicArray;
12 
13 /**
14  * Environment.
15  */
16 class Environment
17 {
18 	enum MAX_POINTS_LIGHTS = 50;
19 
20 	private GraphicsDevice m_graphicsDevice;
21 
22 	/// Ambient light
23 	private AmbientLight m_ambientLight;
24 
25 	/// Sun
26 	private DirectionalLight m_sun;
27 
28 	private mat4 m_sunProjection;
29 	private mat4 m_sunView;
30 
31 	/// Lights
32 	private DynamicArray!PointLight m_pointsLights;
33 
34 	/**
35 	 * Environment constructor.
36 	 * Params:
37 	 *      graphics : graphics device
38 	 */
39 	@nogc @safe
40 	public this(GraphicsDevice graphics) pure nothrow
41 	{
42 		this.m_graphicsDevice = graphics;
43 
44 		this.m_sunProjection = orthoMatrix(-300.0f, 300.0f, -300.0f, 300.0f, -300.0f, 300.0f);
45 	}
46 
47 	/**
48 	 * Environment destructor.
49 	 */
50 	public void dispose()
51 	{
52 		this.m_pointsLights.dispose();
53 	}
54 
55 	/**
56 	 * Adds a point light to the scene.
57 	 * Params:
58 	 *		light : point light
59 	 */
60 	@nogc @safe
61 	public void addPointLight(PointLight light) pure nothrow
62 	{
63 		this.m_pointsLights ~= light;
64 	}
65 
66 
67 	/**
68 	 * Sets environment for the next frame.
69 	 */
70 	@nogc
71 	public void set() nothrow
72 	{
73 		this.setSun();
74 		this.setPointsLights();
75 		this.setAmbientLight();
76 	}
77 
78 	/**
79 	 * Sets sun.
80 	 */
81 	@nogc
82 	private void setSun() nothrow
83 	{
84 		auto lightShader = cast(BasicLightShader) this.m_graphicsDevice.currentShader;
85 
86 		gl.Uniform3fv(lightShader.dirLightDirectionLocation, 1, this.m_sun.direction.arrayof.ptr);
87 		gl.Uniform3fv(lightShader.dirLightAmbientLocation, 1, this.m_sun.ambient.arrayof.ptr);
88 		gl.Uniform3fv(lightShader.dirLightDiffuseLocation, 1, this.m_sun.diffuse.arrayof.ptr);
89 		gl.Uniform3fv(lightShader.dirLightSpecularLocation, 1, this.m_sun.specular.arrayof.ptr);
90 	}
91 
92 	/**
93 	 * Sets ambient light.
94 	 */
95 	@nogc
96 	private void setAmbientLight() nothrow
97 	{
98 		auto lightShader = cast(BasicLightShader) this.m_graphicsDevice.currentShader;
99 
100 		gl.Uniform3fv(lightShader.ambientLightValueLocation, 1, this.m_ambientLight.value.arrayof.ptr);
101 	}
102 
103 	/**
104 	 * Sets points lights.
105 	 */
106 	@nogc
107 	private void setPointsLights() nothrow
108 	{
109 		if (this.m_pointsLights.length == 0)
110 			return;
111 
112 		auto lightShader = cast(BasicLightShader) this.m_graphicsDevice.currentShader;
113 
114 		gl.Uniform1i(lightShader.pointsLightsNumberLocation, this.m_pointsLights.length);
115 		
116 		foreach (i, light; this.m_pointsLights)
117 		{
118 			gl.Uniform3fv(lightShader.pointsLightsLocation + (i * 1), 1, light.position.arrayof.ptr);
119 			gl.Uniform3fv(lightShader.pointsLightsLocation + MAX_POINTS_LIGHTS + (i * 1), 1, light.color.arrayof.ptr);
120 			gl.Uniform1f(lightShader.pointsLightsLocation + MAX_POINTS_LIGHTS * 2 + (i * 1), light.ambient);		
121 			gl.Uniform1f(lightShader.pointsLightsLocation + MAX_POINTS_LIGHTS * 3 + (i * 1), light.constant);
122 			gl.Uniform1f(lightShader.pointsLightsLocation + MAX_POINTS_LIGHTS * 4 + (i * 1), light.linear);
123 			gl.Uniform1f(lightShader.pointsLightsLocation + MAX_POINTS_LIGHTS * 5 + (i * 1), light.quadratic);
124 			gl.Uniform1i(lightShader.pointsLightsLocation + MAX_POINTS_LIGHTS * 6 + (i * 1), light.isEnabled);
125 		}
126 	}
127 
128 	@nogc @safe
129 	@property pure nothrow
130 	{
131 		public void sun(DirectionalLight value)
132 		{
133 			this.m_sun = value;
134 		}
135 
136 		public DirectionalLight sun()
137 		{
138 			return this.m_sun;
139 		}
140 
141 		public void ambientLight(AmbientLight value)
142 		{
143 			this.m_ambientLight = value;
144 		}
145 
146 		public AmbientLight ambientLight()
147 		{
148 			return this.m_ambientLight;
149 		}
150 		
151 		public void sunView()(in auto ref mat4 value)
152 		{
153 			this.m_sunView = value;
154 		}
155 
156 		public mat4 sunView()
157 		{
158 			return this.m_sunView;
159 		}
160 
161 		public DynamicArray!PointLight pointsLights()
162 		{
163 			return this.m_pointsLights;
164 		}
165 	}
166 }