1 /* This file is part of Dilay
2  * Copyright © 2015-2018 Alexander Bau
3  * Use and redistribute under the terms of the GNU General Public License
4  */
5 #include <glm/glm.hpp>
6 #include "color.hpp"
7 #include "config.hpp"
8 #include "opengl.hpp"
9 #include "render-mode.hpp"
10 #include "renderer.hpp"
11 #include "util.hpp"
12 
13 namespace
14 {
15   const unsigned int numLights = 2;
16 
17   struct LightIds
18   {
19     int directionId;
20     int colorId;
21     int irradianceId;
22 
LightIds__anonf3ef77560111::LightIds23     LightIds ()
24       : directionId (0)
25       , colorId (0)
26       , irradianceId (0)
27     {
28     }
29   };
30 
31   struct ShaderIds
32   {
33     unsigned int programId;
34     int          modelId;
35     int          modelNormalId;
36     int          viewId;
37     int          projectionId;
38     int          colorId;
39     int          wireframeColorId;
40     int          eyePointId;
41     int          barycentricId;
42     LightIds     lightIds[numLights];
43 
ShaderIds__anonf3ef77560111::ShaderIds44     ShaderIds ()
45       : programId (0)
46       , modelId (0)
47       , modelNormalId (0)
48       , viewId (0)
49       , projectionId (0)
50       , colorId (0)
51       , wireframeColorId (0)
52       , eyePointId (0)
53       , barycentricId (0)
54     {
55     }
56   };
57 
58   struct GlobalLightUniforms
59   {
60     glm::vec3 direction;
61     Color     color;
62     float     irradiance;
63   };
64 
65   struct GlobalUniforms
66   {
67     GlobalLightUniforms lightUniforms[numLights];
68     glm::vec3           eyePoint;
69   };
70 };
71 
72 struct Renderer::Impl
73 {
74   static const unsigned int numShaders = 6;
75 
76   ShaderIds      shaderIds[Impl::numShaders];
77   ShaderIds*     activeShaderIndex;
78   GlobalUniforms globalUniforms;
79   Color          clearColor;
80 
ImplRenderer::Impl81   Impl (const Config& config)
82     : activeShaderIndex (nullptr)
83   {
84     this->runFromConfig (config);
85   }
86 
~ImplRenderer::Impl87   ~Impl ()
88   {
89     for (unsigned int i = 0; i < Impl::numShaders; i++)
90     {
91       OpenGL::safeDeleteProgram (this->shaderIds[i].programId);
92     }
93   }
94 
setupRenderingRenderer::Impl95   void setupRendering ()
96   {
97     OpenGL::glClearColor (this->clearColor.r (), this->clearColor.g (), this->clearColor.b (),
98                           0.0f);
99     OpenGL::glClearStencil (0);
100     OpenGL::glFrontFace (OpenGL::CCW ());
101     OpenGL::glEnable (OpenGL::CullFace ());
102     OpenGL::glCullFace (OpenGL::Back ());
103     OpenGL::glEnable (OpenGL::DepthTest ());
104     OpenGL::glDepthFunc (OpenGL::LEqual ());
105     OpenGL::glClear (OpenGL::ColorBufferBit () | OpenGL::DepthBufferBit ());
106   }
107 
shutdownRenderingRenderer::Impl108   void shutdownRendering ()
109   {
110     OpenGL::glDisable (OpenGL::DepthTest ());
111     OpenGL::glDisable (OpenGL::CullFace ());
112   }
113 
shaderIndexRenderer::Impl114   unsigned int shaderIndex (const RenderMode& renderMode)
115   {
116     if (renderMode.smoothShading ())
117     {
118       return renderMode.renderWireframe () ? 0 : 1;
119     }
120     else if (renderMode.flatShading ())
121     {
122       return renderMode.renderWireframe () ? 2 : 3;
123     }
124     else if (renderMode.constantShading ())
125     {
126       return renderMode.renderWireframe () ? 4 : 5;
127     }
128     else
129     {
130       DILAY_IMPOSSIBLE
131     }
132   }
133 
initalizeProgramRenderer::Impl134   void initalizeProgram (const RenderMode& renderMode)
135   {
136     assert (renderMode.renderWireframe () == false || OpenGL::hasGeometryShader ());
137 
138     const unsigned int id = OpenGL::loadProgram (
139       renderMode.vertexShader (), renderMode.fragmentShader (), renderMode.renderWireframe ());
140 
141     unsigned int index = this->shaderIndex (renderMode);
142     assert (this->shaderIds[index].programId == 0);
143 
144     ShaderIds* s = &this->shaderIds[index];
145 
146     s->programId = id;
147     s->modelId = OpenGL::glGetUniformLocation (id, "model");
148     s->modelNormalId = OpenGL::glGetUniformLocation (id, "modelNormal");
149     s->viewId = OpenGL::glGetUniformLocation (id, "view");
150     s->projectionId = OpenGL::glGetUniformLocation (id, "projection");
151     s->colorId = OpenGL::glGetUniformLocation (id, "color");
152     s->wireframeColorId = OpenGL::glGetUniformLocation (id, "wireframeColor");
153     s->eyePointId = OpenGL::glGetUniformLocation (id, "eyePoint");
154     s->barycentricId = OpenGL::glGetUniformLocation (id, "barycentric");
155     s->lightIds[0].directionId = OpenGL::glGetUniformLocation (id, "light1Direction");
156     s->lightIds[0].colorId = OpenGL::glGetUniformLocation (id, "light1Color");
157     s->lightIds[0].irradianceId = OpenGL::glGetUniformLocation (id, "light1Irradiance");
158     s->lightIds[1].directionId = OpenGL::glGetUniformLocation (id, "light2Direction");
159     s->lightIds[1].colorId = OpenGL::glGetUniformLocation (id, "light2Color");
160     s->lightIds[1].irradianceId = OpenGL::glGetUniformLocation (id, "light2Irradiance");
161   }
162 
setProgramRenderer::Impl163   void setProgram (const RenderMode& renderMode)
164   {
165     const unsigned int index = this->shaderIndex (renderMode);
166 
167     if (this->shaderIds[index].programId == 0)
168     {
169       this->initalizeProgram (renderMode);
170     }
171     assert (this->shaderIds[index].programId);
172 
173     this->activeShaderIndex = &this->shaderIds[index];
174     OpenGL::glUseProgram (this->activeShaderIndex->programId);
175 
176     OpenGL::glUniformVec3 (this->activeShaderIndex->eyePointId, this->globalUniforms.eyePoint);
177 
178     for (unsigned int i = 0; i < numLights; i++)
179     {
180       OpenGL::glUniformVec3 (this->activeShaderIndex->lightIds[i].directionId,
181                              this->globalUniforms.lightUniforms[i].direction);
182       OpenGL::glUniformVec3 (this->activeShaderIndex->lightIds[i].colorId,
183                              this->globalUniforms.lightUniforms[i].color.vec3 ());
184       OpenGL::glUniform1f (this->activeShaderIndex->lightIds[i].irradianceId,
185                            this->globalUniforms.lightUniforms[i].irradiance);
186     }
187   }
188 
setModelRenderer::Impl189   void setModel (const float* model, const float* modelNormal)
190   {
191     assert (this->activeShaderIndex);
192     OpenGL::glUniformMatrix4fv (this->activeShaderIndex->modelId, 1, false, model);
193     OpenGL::glUniformMatrix3fv (this->activeShaderIndex->modelNormalId, 1, false, modelNormal);
194   }
195 
setViewRenderer::Impl196   void setView (const float* view)
197   {
198     assert (this->activeShaderIndex);
199     OpenGL::glUniformMatrix4fv (this->activeShaderIndex->viewId, 1, false, view);
200   }
201 
setProjectionRenderer::Impl202   void setProjection (const float* projection)
203   {
204     assert (this->activeShaderIndex);
205     OpenGL::glUniformMatrix4fv (this->activeShaderIndex->projectionId, 1, false, projection);
206   }
207 
setColorRenderer::Impl208   void setColor (const Color& c, bool withOpacity)
209   {
210     assert (this->activeShaderIndex);
211 
212     if (withOpacity)
213     {
214       OpenGL::glUniformVec4 (this->activeShaderIndex->colorId, c.vec4 ());
215     }
216     else
217     {
218       OpenGL::glUniformVec3 (this->activeShaderIndex->colorId, c.vec3 ());
219     }
220   }
221 
setWireframeColorRenderer::Impl222   void setWireframeColor (const Color& c, bool withOpacity)
223   {
224     assert (this->activeShaderIndex);
225 
226     if (withOpacity)
227     {
228       OpenGL::glUniformVec4 (this->activeShaderIndex->wireframeColorId, c.vec4 ());
229     }
230     else
231     {
232       OpenGL::glUniformVec3 (this->activeShaderIndex->wireframeColorId, c.vec3 ());
233     }
234   }
235 
setEyePointRenderer::Impl236   void setEyePoint (const glm::vec3& e) { this->globalUniforms.eyePoint = e; }
237 
setLightDirectionRenderer::Impl238   void setLightDirection (unsigned int i, const glm::vec3& d)
239   {
240     assert (i < numLights);
241     this->globalUniforms.lightUniforms[i].direction = d;
242   }
243 
setLightColorRenderer::Impl244   void setLightColor (unsigned int i, const Color& c)
245   {
246     assert (i < numLights);
247     this->globalUniforms.lightUniforms[i].color = c;
248   }
249 
setLightIrradianceRenderer::Impl250   void setLightIrradiance (unsigned int i, float irr)
251   {
252     assert (i < numLights);
253     this->globalUniforms.lightUniforms[i].irradiance = irr;
254   }
255 
runFromConfigRenderer::Impl256   void runFromConfig (const Config& config)
257   {
258     this->clearColor = config.get<Color> ("editor/background");
259 
260     for (unsigned int i = 0; i < numLights; i++)
261     {
262       const std::string key = "editor/light/light" + std::to_string (i + 1) + "/";
263 
264       const glm::vec3 dir = config.get<glm::vec3> (key + "direction");
265       this->setLightDirection (i, glm::normalize (dir));
266       this->setLightColor (i, config.get<Color> (key + "color"));
267       this->setLightIrradiance (i, config.get<float> (key + "irradiance"));
268     }
269   }
270 };
271 
272 DELEGATE1_BIG3 (Renderer, const Config&)
273 
274 DELEGATE (void, Renderer, setupRendering)
275 DELEGATE (void, Renderer, shutdownRendering)
276 DELEGATE1 (void, Renderer, setProgram, const RenderMode&)
277 DELEGATE2 (void, Renderer, setModel, const float*, const float*)
278 DELEGATE1 (void, Renderer, setView, const float*)
279 DELEGATE1 (void, Renderer, setProjection, const float*)
280 DELEGATE2 (void, Renderer, setColor, const Color&, bool)
281 DELEGATE2 (void, Renderer, setWireframeColor, const Color&, bool)
282 DELEGATE1 (void, Renderer, setEyePoint, const glm::vec3&)
283 DELEGATE2 (void, Renderer, setLightDirection, unsigned int, const glm::vec3&)
284 DELEGATE2 (void, Renderer, setLightColor, unsigned int, const Color&)
285 DELEGATE2 (void, Renderer, setLightIrradiance, unsigned int, float)
286 DELEGATE1 (void, Renderer, runFromConfig, const Config&)
287