Molecule Viewer
 All Classes Functions Variables Enumerations Pages
AppMain.cpp
1 #include "AppMain.hpp"
2 
3 
5  _errorMessage = "";
6 }
7 
8 
9 AppMain::~AppMain(void) {
10 
11  //free shaders
12  ShaderMap::const_iterator itr;
13  for(itr = _shaders.begin(); itr != _shaders.end(); ++itr) {
14  delete itr->second;
15  _shaders[itr->first] = NULL;
16  }
17 
18  if (_molecule != NULL)
19  delete _molecule;
20  if (_camera != NULL)
21  delete _camera;
22  if (_light != NULL)
23  delete _light;
24  if (_loader != NULL)
25  delete _loader;
26  if (_occlusionDirections != NULL)
27  delete _occlusionDirections;
28 
29  glDeleteTextures(1,&_shadowTex);
30  glDeleteTextures(1,&_ambientOcclusionTex);
31  glDeleteFramebuffers(1,&_FBO);
32 
33 
34 }
35 
36 
37 void AppMain::GenerateShaders() {
38  //private function, called at the end of PrepareScene()
39 
40  //main shader for drawing molecule to the screen
41  _shaders["main"] = new Shader("../Shaders/main");
42 
43  //shadow shader for drawing molecule to a depth buffer
44  //(used for ambient occlusion computation and also molecule shadows)
45  _shaders["shadow"] = new Shader("../Shaders/shadow");
46 
47  //atlas shader used to compute ambient occlusion and write result to the texture atlas
48  _shaders["atlas"] = new Shader("../Shaders/atlas");
49 
50  if (!_shaders["main"] || !_shaders["shadow"] || !_shaders["atlas"] ) {
51  throw "Could not compile minimal shader program.";
52  }
53 
54  _shaders["atlas"]->bind_frag_data_location("out_color");
55  _shaders["main"]->bind_frag_data_location("out_color");
56 
57 }
58 
59 
60 
62 
63  _molecule = new SceneObject();
64  _loader = new Loader();
65  _occlusionDirections = new Directions();
66  _camera = new Camera(GetWindowWidth(),GetWindowHeight());
67  _light = new Light();
68 
69 
70  //ATTENTION: TEXTURE SIZE HARD CODED IN SHADER (main.frag)!
71  _aoTextureSize = 2048;
72  //currently they have to be the same size! otherwise switch viewport size while drawing!
73  _shadowTextureSize = _aoTextureSize;
74  _loader ->SetTextureSize(_aoTextureSize);
75 
76  //Generate FBO and textures
77  glGenFramebuffers(1, &_FBO);
78  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _FBO);
79  glGenTextures(1, &_shadowTex);
80  glBindTexture(GL_TEXTURE_2D, _shadowTex);
81  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
82  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
83  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
84  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
85  glTexImage2D (GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24,_shadowTextureSize, _shadowTextureSize, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
86  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _shadowTex, 0);
87  glReadBuffer(GL_NONE);
88  glBindTexture(GL_TEXTURE_2D, 0);
89  glGenTextures(1, &_ambientOcclusionTex);
90  glBindTexture(GL_TEXTURE_2D, _ambientOcclusionTex);
91  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
92  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
93  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
94  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
95 
96  //if the occlusion quality is set very high, a high precision texture is needed, otherwise numerical problems
97  if (GetOcclusionQuality()>2)
98  glTexImage2D (GL_TEXTURE_2D, 0, GL_R16, _aoTextureSize, _aoTextureSize, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
99  else
100  glTexImage2D (GL_TEXTURE_2D, 0, GL_RED, _aoTextureSize, _aoTextureSize, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
101 
102  glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _ambientOcclusionTex, 0);
103  glBindTexture(GL_TEXTURE_2D, 0);
104  glBindFramebuffer(GL_FRAMEBUFFER, 0);
105 
106  GenerateShaders();
107 
108 }
109 
110 
111 
113 
114  //if no molecule is loaded, set the background color gray and stop drawing
115  if (!_loader->LoadedFirstTime()) {
116  glClearColor(0.3,0.3,0.3,1);
117  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
118  return;
119  }
120 
121  //otherwise bind vao, render depth map if needed, then render molecule to screen
122  glBindVertexArray(_vao);
123 
124 
125  if (_shadowsActive) {
126 
128  //only if shadows are activated
129 
130  glBindFramebuffer(GL_FRAMEBUFFER, _FBO);
131  glDrawBuffer(GL_NONE);
132  glViewport(0,0,_aoTextureSize,_aoTextureSize);
133  glClearColor(0,0,0,1);
134  glClear(GL_DEPTH_BUFFER_BIT);
135 
136  _shaders["shadow"]->bind();
137 
138  glUniformMatrix4fv(_shaders["shadow"]->GetAddress(Shader::ShadowPMatrix), 1, GL_FALSE, glm::value_ptr(*(_light->GetProjectionMatrix())));
139  glUniformMatrix4fv(_shaders["shadow"]->GetAddress(Shader::ShadowMVMatrix), 1, GL_FALSE, glm::value_ptr( _light->GetInverseModelMatrix()* _molecule->GetModelMatrix()));
140  glDrawArrays(GL_POINTS, 0, _numberOfSpheres);
141 
142  _shaders["shadow"]->unbind();
143 
144  glDrawBuffer(GL_COLOR_ATTACHMENT0);
145 
147  }
148 
149 
151 
152  glBindFramebuffer(GL_FRAMEBUFFER, 0);
153  glViewport(0, 0, GetWindowWidth(),GetWindowHeight());
154  glClearColor(0.3,0.3,0.3,1);
155  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
156 
157  //Bind
158  _shaders["main"]->bind();
159  glBindTexture(GL_TEXTURE_2D, _shadowTex);
160  glUniform1i(_shaders["main"]->GetAddress(Shader::ShadowTex), 0);
161  glActiveTexture(GL_TEXTURE0 + 1);
162  glBindTexture(GL_TEXTURE_2D, _ambientOcclusionTex);
163 
164  //Pass uniforms to shader
165  glUniform1i(_shaders["main"]->GetAddress(Shader::OcclusionTexture), 1);
166  glUniformMatrix4fv(_shaders["main"]->GetAddress(Shader::ProjectionMatrix), 1, GL_FALSE, glm::value_ptr(_camera->GetProjectionMatrix()));
167  glUniform4fv(_shaders["main"]->GetAddress(Shader::LightPosition), 1, glm::value_ptr(_camera->GetViewMatrix()*glm::vec4(_light->GetPosition(),1)));
168  glUniformMatrix4fv(_shaders["main"]->GetAddress(Shader::ModelViewMatrix), 1, GL_FALSE, glm::value_ptr(_camera->GetViewMatrix()* _molecule->GetModelMatrix()));
169  glUniformMatrix4fv(_shaders["main"]->GetAddress(Shader::ShadowMVMatrix), 1, GL_FALSE, glm::value_ptr(_light->GetInverseModelMatrix()*_molecule->GetModelMatrix()));
170  glUniformMatrix4fv(_shaders["main"]->GetAddress(Shader::ShadowPMatrix), 1, GL_FALSE, glm::value_ptr(*(_light->GetProjectionMatrix())));
171 
172 
173  //Draw molecule to screen
174  glDrawArrays(GL_POINTS, 0, _numberOfSpheres);
175 
176  //Unbind
177  glBindTexture(GL_TEXTURE_2D, 0);
178  glActiveTexture(GL_TEXTURE0 + 0);
179  glBindTexture(GL_TEXTURE_2D, 0);
180  glBindVertexArray(0);
181  _shaders["main"]->unbind();
182 
183 
184 }
185 
186 void AppMain::ComputeAmbientOcclusion() {
187 
188  glClearColor(0,0,0,1);
189 
190  glViewport(0,0,_aoTextureSize,_aoTextureSize);
191  glBindVertexArray(_vao);
192  //draw to framebuffer for shadow mapping
193  glBindFramebuffer(GL_FRAMEBUFFER, _FBO);
194  glClear(GL_COLOR_BUFFER_BIT);
195 
196  for (int i = 0; i<_occlusionDirections->GetDirectionNumber() ; i++ ) {
197 
199  glEnable(GL_DEPTH_TEST);
200  glDrawBuffer(GL_NONE);
201  glClear(GL_DEPTH_BUFFER_BIT);
202 
203  _shaders["shadow"]->bind();
204 
205  glUniformMatrix4fv(_shaders["shadow"]->GetAddress(Shader::ShadowPMatrix), 1, GL_FALSE, glm::value_ptr(_orthoMatrix));
206  glUniformMatrix4fv(_shaders["shadow"]->GetAddress(Shader::ShadowMVMatrix), 1, GL_FALSE, glm::value_ptr(_occlusionDirections->GetViewMatrix(i)));
207 
208  glDrawArrays(GL_POINTS, 0, _numberOfSpheres);
209 
210  _shaders["shadow"]->unbind();
211 
213 
215  glDrawBuffer(GL_COLOR_ATTACHMENT0);
216  glEnable(GL_BLEND);
217  glBindTexture(GL_TEXTURE_2D, _shadowTex);
218  glDisable(GL_DEPTH_TEST);
219 
220  _shaders["atlas"]->bind();
221 
222  glUniform1i(_shaders["atlas"]->GetAddress(Shader::OcclusionTexture), 0);
223  glUniform1f(_shaders["atlas"]->GetAddress(Shader::OcclusionDirections),_occlusionDirections->GetDirectionNumber());
224  glUniformMatrix4fv(_shaders["atlas"]->GetAddress(Shader::ShadowPMatrix), 1, GL_FALSE, glm::value_ptr(_orthoMatrix));
225  glUniformMatrix4fv(_shaders["atlas"]->GetAddress(Shader::ShadowMVMatrix), 1, GL_FALSE, glm::value_ptr(_occlusionDirections->GetViewMatrix(i)));
226 
227  glDrawArrays(GL_POINTS, 0, _numberOfSpheres);
228 
229  glDisable(GL_BLEND);
230 
231  _shaders["atlas"]->unbind();
232  glBindTexture(GL_TEXTURE_2D, 0);
233 
235  }
236 
237  glEnable(GL_DEPTH_TEST);
238 
239  glBindVertexArray(0);
240  glBindFramebuffer(GL_FRAMEBUFFER, 0);
241 
242 }
243 
244 void AppMain::RotateMolecule(const double x, const double y) {
245  //Molecule Rotation (Move mouse with pressed left button to rotate molecule around center)
246  _molecule->RotateY_world(x);
247  _molecule->RotateX_world(y);
248 }
249 
250 void AppMain::MoveLight(const double x, const double y) {
251  //Move Light around Molecule (Move mouse with pressed right button to rotate light around molecule)
252  _light->RotateXY(y,x,4*_loader ->GetBoundingSphere());
253 }
254 
255 void AppMain::MoveCamera(const double x, const double y) {
256  //Camera movement (Move mouse with pressed middle button to move camera left/right or up/down)
257  glm::vec4 pos = _camera->GetModelMatrix() * glm::vec4(0,0,0,1);
258 
259  //prevents that camera can be moved to far away from the molecule (in both directions)
260  //so that the molecule is always visible
261  if (x<0 && pos.x> -_loader ->GetBoundingSphere())
262  _camera->Translate(0.01 * x * pos.z, 0.0f, 0.0f);
263  else if (x>0 && pos.x < _loader ->GetBoundingSphere())
264  _camera->Translate(0.01 * x * pos.z, 0.0f, 0.0f);
265 
266  if (y<0 && pos.y> -_loader ->GetBoundingSphere())
267  _camera->Translate(0.0f, 0.01 * y * pos.z, 0.0f);
268  else if (y>0 && pos.y < _loader ->GetBoundingSphere())
269  _camera->Translate(0.0f, 0.01 * y * pos.z, 0.0f);
270 
271 }
272 
273 
274 
275 void AppMain::ZoomInOut(const double z) {
276 
277  //prevents that camera can be moved to far away from the molecule
278  //so that the molecule is always visible (not clipped by near or far plane)
279  glm::vec4 pos = _camera->GetModelMatrix() * glm::vec4(0,0,0,1);
280  if (z<0 && pos.z <= 0)
281  return;
282 
283  if (z>0 && pos.z >= 4*_loader ->GetBoundingSphere())
284  return;
285 
286  _camera->Translate(0.0f, 0.0f, (1/z) * _loader->GetBoundingSphere());
287 }
288 
289 
290 
292  //when the window size is changed, the projection matrix of the camera has to be updated
293  _camera->UpdateProjectionMatrix(GetWindowWidth(),GetWindowHeight(), 5.5f * _loader ->GetBoundingSphere());
294 }
295 
296 
297 
298 bool AppMain::LoadMolecule(const string filename) {
299 
300 
301  if (!_loader->LoadMolecule(filename))
302  return false;
303 
304  _numberOfSpheres = _loader->GetAtomNumber();
305 
306  //if a new molecule is loaded, reset light, camera and molecule back to the starting position and orientation
307  //also update near and far planes etc to size of new molecule
308  _light->Reset(2.5f * _loader ->GetBoundingSphere(), 4.8f * _loader ->GetBoundingSphere());
309 
310 
311  MoveLight(20,-60);
312  _molecule->Reset();
313  _camera->Reset();
314  _camera->Translate(0,0,2*_loader ->GetBoundingSphere());
315  _camera->UpdateProjectionMatrix(GetWindowWidth(),GetWindowHeight(), 5.5f * _loader ->GetBoundingSphere());
316  _shaders["main"]->bind();
317  glUniform1f(_shaders["main"]->GetAddress(Shader::FarPlane),5.5f * _loader ->GetBoundingSphere());
318  _shaders["main"]->unbind();
319  float f = 4.2*_loader ->GetBoundingSphere();
320  float n = -f;
321  float right = 1.3*_loader ->GetBoundingSphere();
322  float left = -right;
323  float top = right;
324  float bottom = -top;
325  _orthoMatrix = glm::ortho(left,right,bottom,top,n,f); //Is this correct?! check far and near planes...
326 
327  _vao = _loader->GetVAO();
328 
329  _occlusionDirections->generateViewMatrices(3*_loader ->GetBoundingSphere());
330 
331  //update ambient occlusion for new mol
332  ComputeAmbientOcclusion();
333 
334  return true;
335 }
336 
337 
338 
339 
341 //Settings functions
342 //pass changed variables to gpu
344 
345 void AppMain::ChangeColorMode(int colorMode) {
346  _loader->UpdateColorMode(colorMode, false);
347 }
348 
349 void AppMain::ChangeOcclusionQuality(int occlusionQuality) {
350 
351  SetOcclusionQuality(occlusionQuality);
352 
353  delete _occlusionDirections;
354  _occlusionDirections = new Directions();
355 
356  glBindTexture(GL_TEXTURE_2D, _ambientOcclusionTex);
357 
358  //if the occlusion quality is set very high, a high precision texture is needed, otherwise numerical problems
359  if (GetOcclusionQuality()>2)
360  glTexImage2D (GL_TEXTURE_2D, 0, GL_R16, _aoTextureSize, _aoTextureSize, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
361  else
362  glTexImage2D (GL_TEXTURE_2D, 0, GL_RED, _aoTextureSize, _aoTextureSize, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
363  glBindTexture(GL_TEXTURE_2D, 0);
364 
365  if (_loader->LoadedFirstTime()) {
366  _occlusionDirections->generateViewMatrices(3*_loader ->GetBoundingSphere());
367  ComputeAmbientOcclusion();
368  }
369 
370 }
371 
372 void AppMain::ChangeLightIntensity(const int pointLightIntensity) {
373  _shaders["main"]->bind();
374  glUniform1f(_shaders["main"]->GetAddress(Shader::DirectIntensity),(float)pointLightIntensity*(4.0f/255.0f));
375  _shaders["main"]->unbind();
376 }
377 void AppMain::ChangeAmbientIntensity(const int ambientIntensity) {
378  _shaders["main"]->bind();
379  glUniform1f(_shaders["main"]->GetAddress(Shader::AmbientIntensity),(float)ambientIntensity*(4.0f/255.0f));
380  _shaders["main"]->unbind();
381 }
382 void AppMain::ChangeGlossiness(const int glossiness) {
383  _shaders["main"]->bind();
384  glUniform1f(_shaders["main"]->GetAddress(Shader::Glossiness),10 + glossiness/3.0f);
385  _shaders["main"]->unbind();
386 }
387 void AppMain::ToggleShadow(const bool shadows) {
388  _shaders["main"]->bind();
389  glUniform1f(_shaders["main"]->GetAddress(Shader::ShadowActive),shadows);
390  _shaders["main"]->unbind();
391  _shadowsActive = shadows;
392 }
393 void AppMain::ChangeBorder(const int borderWidth, const int borderVariance) {
394  _shaders["main"]->bind();
395  glUniform2f(_shaders["main"]->GetAddress(Shader::ContourData),(float)borderWidth*(3.0f/255.0f),(float)borderVariance*(20.0f/255.0f));
396  _shaders["main"]->unbind();
397 }
398 
399 void AppMain::ToggleAmbientOcclusion(const bool ambientOcclusionActive) {
400  _shaders["main"]->bind();
401  glUniform1f(_shaders["main"]->GetAddress(Shader::OcclusionActive),ambientOcclusionActive);
402  _shaders["main"]->unbind();
403 }
404 
405 
406 
407 
408 const string& AppMain::GetErrorMessage() const {
409  return _errorMessage;
410 }
411 
412