Code_TYMPAN  4.4.0
Industrial site acoustic simulation
TYOpenGLRenderer.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) <2012-2024> <EDF-DTG> <FRANCE>
3  * This file is part of Code_TYMPAN (R).
4  * Code_TYMPAN (R) is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * Code_TYMPAN (R) is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  * See the GNU General Public License for more details.
12  * You should have received a copy of the GNU General Public License along
13  * with Code_TYMPAN (R). If not, see <https://www.gnu.org/licenses/>.
14  */
15 
23 #include <cstdio>
24 #include <qmatrix4x4.h>
25 #include <qopenglbuffer.h>
26 #include <qopenglcontext.h>
27 #include <qopenglfunctions_4_3_core.h>
28 #include <qopenglshaderprogram.h>
29 #include <qopenglvertexarrayobject.h>
30 #include <qtransform.h>
31 #include <qvector3d.h>
32 #include <stdexcept>
33 
34 #include "TYOpenGLRenderer.h"
37 #include "gui/tools/OGLBoxMesh.h"
40 
41 #if TY_USE_IHM
43  #include <QOpenGLFunctions_4_3_Core>
44 #endif
45 
46 void drawBoundingBox(const QVector3D& boxDimensions, QOpenGLShaderProgram* shaderProgram,
47  const QMatrix4x4& model, const QMatrix4x4& view, const QMatrix4x4& projection)
48 {
49  QOpenGLFunctions_4_3_Core gl;
50  gl.initializeOpenGLFunctions();
51  OGLBoxMesh bboxMesh(boxDimensions);
53 
54  QOpenGLBuffer vbo(QOpenGLBuffer::VertexBuffer);
55  vbo.create();
56  vbo.bind();
57  vbo.allocate(bboxMesh.vertices().data(), bboxMesh.vertices().size() * sizeof(QVector3D));
58 
59  QOpenGLVertexArrayObject vao;
60  vao.create();
61  vao.bind();
62 
63  int vertexLocation = shaderProgram->attributeLocation("pos");
64  shaderProgram->enableAttributeArray(vertexLocation);
65  shaderProgram->setAttributeBuffer(vertexLocation, GL_FLOAT, 0, 3, 0);
66 
67  int modelLocation = shaderProgram->uniformLocation("model");
68  shaderProgram->setUniformValue(modelLocation, model);
69  int viewLocation = shaderProgram->uniformLocation("view");
70  shaderProgram->setUniformValue(viewLocation, view);
71  int projectionLocation = shaderProgram->uniformLocation("projection");
72  shaderProgram->setUniformValue(projectionLocation, projection);
73 
74  int colorLocation = shaderProgram->uniformLocation("color");
75  QColor color = bboxMesh.material().color;
76  QVector3D vectorColor = QVector3D(color.redF(), color.greenF(), color.blueF());
77  shaderProgram->setUniformValue(colorLocation, vectorColor);
78 
79  QOpenGLBuffer indexBuffer(QOpenGLBuffer::IndexBuffer);
80  indexBuffer.create();
81  indexBuffer.bind();
82  indexBuffer.allocate(bboxMesh.indices().data(), bboxMesh.indices().size() * sizeof(unsigned int));
83 
84  gl.glDrawElements(GL_LINES, 24, GL_UNSIGNED_INT, 0);
85  gl.glDrawArrays(GL_POINTS, 0, 8);
86  indexBuffer.release(QOpenGLBuffer::IndexBuffer);
87  indexBuffer.destroy();
88  vbo.release(QOpenGLBuffer::VertexBuffer);
89  vbo.destroy();
90  vao.release();
91  vao.destroy();
92 }
93 
95 {
96  _displayList = 0; // az++
97  _displayListOverlay = 0; // az++
98  _pActiveCamera = nullptr;
99  _pBackgroundColor = new double[3];
100  m_renderType = 0;
102 
103  _boundingBoxScaleMatrix = QMatrix4x4();
104  _boundingBoxScaleMatrix.scale(1.1);
105 }
106 
108 {
109  if (_displayList) // az++
110  {
111  glDeleteLists(_displayList, 1);
112  }
113  if (_displayListOverlay) // az++
114  {
115  glDeleteLists(_displayListOverlay, 1);
116  }
117  delete[] _pBackgroundColor;
118 }
119 
121 {
122  _displayList = glGenLists(1);
123  _displayListOverlay = glGenLists(1);
124 }
125 
127 {
128  // glClearColor(1.0, 1.0, 1.0, 1.0);
129  glClearColor(_pBackgroundColor[0], _pBackgroundColor[1], _pBackgroundColor[2], 1.0);
130  glColor3f(1.0, 0.0, 0.0);
131 
133  {
134  glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
135  }
137  {
138  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
139  }
141  {
142  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
143  }
145  {
146  glShadeModel(GL_FLAT);
147  }
149  {
150  glShadeModel(GL_SMOOTH);
151  }
152 
153  // Lights
154  glEnable(GL_LIGHTING);
155  glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
156 
157  static GLfloat ambient[] = {0.1f, 0.1f, 0.1f, 1.0f};
158  static GLfloat ambientBIS[] = {0.8f, 0.8f, 0.8f, 0.8f};
159  static GLfloat diffuse[] = {0.8f, 0.8f, 0.8f, 1.0f};
160  static GLfloat specular[] = {0.8f, 0.8f, 0.8f, 1.0f};
161  static GLfloat shininess = 50.;
162  glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientBIS);
163  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient);
164  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
165  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
166  glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
167 
168  glMatrixMode(GL_PROJECTION);
169  glLoadIdentity();
170 }
171 
173 {
174  _renderMode = mode;
175 }
176 
178 {
179  return _renderMode;
180 }
181 
183  TYGeometryNode* pDansCeRepere)
184 {
185  if (pElement)
186  {
187  // Chercher le GeoNode correspondant a pElement (le repere dans lequel est exprime pElement)
188  TYGeometryNode* pGeoNode = pElement;
189  if (pElement->isA("TYGeometryNode"))
190  {
191  pGeoNode = (TYGeometryNode*)pElement;
192  }
193  else
194  {
195  pGeoNode = (TYGeometryNode*)pElement->GetGeoNodeParent();
196  }
197 
198  if (pGeoNode)
199  {
200  LPTYElementGraphic pTYElementGraphic = pGeoNode->getGraphicObject();
201  TYGeometryNodeGraphic* pGeoNodeGraphic =
202  (TYGeometryNodeGraphic*)pTYElementGraphic.getRealPointer();
203  pGeoNodeGraphic->displayPushingParentMatrix(renderContext, pDansCeRepere);
204  }
205  }
206 }
207 
209 {
211 }
212 
214 {
215  if (!_sceneRenderCacheIsDirty) // az++
216  {
217  glCallList(_displayList);
218  return;
219  }
220  else
221  {
222  // Affectation de la displayList principale:
223  glNewList(_displayList, GL_COMPILE_AND_EXECUTE);
224  drawElement(renderContext);
225  glEndList();
226  _sceneRenderCacheIsDirty = false;
227  }
228 }
229 
230 void TYOpenGLRenderer::OpenGLRender(TYRenderContext& renderContext, int x /* = 0*/, int y /* = 0*/)
231 {
232  GLint polygon_mode[2];
233  glGetIntegerv(GL_POLYGON_MODE, polygon_mode);
234 
235  // do the render library specific stuff
236  const OGLCamera* currentCamera = renderContext.viewport.camera();
237  if (currentCamera)
238  {
239  glMatrixMode(GL_PROJECTION);
240  glLoadMatrixf(currentCamera->projectionMatrix().constData());
241  glMatrixMode(GL_MODELVIEW);
242  glLoadMatrixf(currentCamera->viewMatrix().constData());
243  }
244 
245  // set matrix mode for actors
246  glMatrixMode(GL_MODELVIEW);
247 
248  // Gestion des lumieres
249  if (currentCamera)
250  {
251  // place la lumiere 0 sur la camera
252  double xc, yc, zc;
253  currentCamera->getPosition(xc, yc, zc);
254  _tabLights[0]->setPosition(OPoint3D(xc, yc, zc));
255  }
256  for (int il = 0; il < _tabLights.size(); il++)
257  {
258  _tabLights[il]->render();
259  }
260 
261  // Materials
262  float colorSpec[] = {0.0, 0.0, 0.0, 1.0};
263  float colorShine[] = {127.0};
264  glMaterialfv(GL_FRONT, GL_SPECULAR, colorSpec);
265  glMaterialfv(GL_FRONT, GL_SHININESS, colorShine);
266  glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
267  glEnable(GL_COLOR_MATERIAL);
268 
269  // Antialiasing
270  glEnable(GL_LINE_SMOOTH);
271  glEnable(GL_BLEND);
272  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
273  glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
274 
275  glEnable(GL_NORMALIZE);
276  glEnable(GL_DEPTH_TEST);
277  glDepthRange(0, 1);
278 
279  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
280 
281  if (renderContext.type == TYRenderType::Picking)
282  {
283  GLint viewport[4];
284  GLfloat proj[16];
285 
286  glGetFloatv(GL_PROJECTION_MATRIX, proj);
287 
288  glGetIntegerv(GL_VIEWPORT, viewport);
289 
290  glMatrixMode(GL_PROJECTION);
291  glPushMatrix();
292  glLoadIdentity();
293  gluPickMatrix((GLdouble)x, (GLdouble)y, 5, 5, viewport);
294  glMultMatrixf(proj);
295 
296  glMatrixMode(GL_MODELVIEW);
297  glPushMatrix();
298  drawElement(renderContext);
299  glPopMatrix();
300  glMatrixMode(GL_PROJECTION);
301  glPopMatrix();
302  }
303  else /* renderType == TYOpenGLRenderer::DisplayRenderer */
304  {
305  // CLM-NT35: Init la liste avant d'ajouter les elements
306  // display overlay text for selected elements (localized)
307  TYRenderContext overlayRenderContext = {renderContext.type, TYRenderPass::Overlay,
308  renderContext.viewport, renderContext.modelerElement};
309  glNewList(_displayListOverlay, GL_COMPILE);
310  std::vector<TYElement*>::iterator iterElements;
311  for (iterElements = _tabSelectedElements.begin(); iterElements < _tabSelectedElements.end();
312  iterElements++)
313  {
314  TYGeometryNode* pGeoNode = TYGeometryNode::GetGeoNode(*iterElements);
315  TYGeometryNode* pRootGeometryNode = TYGeometryNode::GetGeoNode(renderContext.modelerElement);
316  // For elements without GeoNode like TYPointControl, display in GL_COMPILE mode the
317  // correponding graphic object
318  if (!pGeoNode)
319  {
320  if (*iterElements != nullptr)
321  {
322  LPTYElementGraphic pTYElementGraphic = (*iterElements)->getGraphicObject();
323  if (pTYElementGraphic != nullptr)
324  {
325  pTYElementGraphic->display(overlayRenderContext);
326  }
327  }
328  }
329  updateDisplayListOverlay(overlayRenderContext, pGeoNode, pRootGeometryNode);
330  }
331  glEndList();
332  }
333 
334  glMatrixMode(GL_MODELVIEW);
335  if (renderContext.type == TYRenderType::Display)
336  {
337  glPushMatrix();
338  _renderScene(renderContext);
339  glCallList(_displayListOverlay);
340  renderBoundingBoxes(renderContext);
341  glPopMatrix();
342  }
343 
344  // render the TYAtcor2D list
345  glDisable(GL_LIGHTING);
346  std::vector<OGLElement*>::iterator iter;
347  for (iter = _tabOGLElement.begin(); iter < _tabOGLElement.end(); iter++)
348  {
349  glPushMatrix();
350  (*iter)->render();
351  glPopMatrix();
352  }
353 
354  glPolygonMode(GL_FRONT_AND_BACK, polygon_mode[0]);
355 }
356 
358 {
359  LPTYElementGraphic pGraphObj = NULL;
360  if (renderContext.modelerElement)
361  {
362  pGraphObj = renderContext.modelerElement->getGraphicObject();
363 
364  if (dynamic_cast<TYSiteNode*>(renderContext.modelerElement) != nullptr)
365  {
366  TYElement* pParent = renderContext.modelerElement->getParent();
367  if (pParent && pParent->isA("TYProjet"))
368  {
369  pGraphObj = pParent->getGraphicObject();
370  }
371  }
372 
373  glRotatef(-90.0, 1.0, 0.0, 0.0);
374  if (pGraphObj)
375  {
376  pGraphObj->display(renderContext);
377  }
378  }
379 }
380 
382 {
383  bool _bFinded = false;
384  std::vector<OGLElement*>::iterator iter;
385  for (iter = _tabOGLElement.begin(); !_bFinded && (iter < _tabOGLElement.end()); iter++)
386  {
387  if ((OGLElement*)(*iter) == pOGLElement)
388  {
389  _bFinded = true;
390  }
391  }
392  if (!_bFinded)
393  {
394  _tabOGLElement.push_back(pOGLElement);
395  }
396 }
397 
399 {
400  _tabLights.push_back(pOGLElement);
401 }
402 
404 {
405  _tabLights.clear();
406 }
407 
408 std::vector<OGLLightElement*> TYOpenGLRenderer::getLights()
409 {
410  return _tabLights;
411 }
412 
414 {
415  std::vector<OGLElement*>::iterator iter;
416  bool _bFinded = false;
417  for (iter = _tabOGLElement.begin(); !_bFinded && (iter < _tabOGLElement.end()); iter++)
418  {
419  if ((OGLElement*)(*iter) == pOGLElement)
420  {
421  _bFinded = true;
422  _tabOGLElement.erase(iter);
423  break;
424  }
425  }
426 }
427 
429 {
430  bool _bFinded = false;
431  std::vector<TYElement*>::iterator iter;
432  for (iter = _tabSelectedElements.begin(); !_bFinded && (iter < _tabSelectedElements.end()); iter++)
433  {
434  if ((TYElement*)(*iter) == pElement)
435  {
436  _bFinded = true;
437  }
438  }
439  if (!_bFinded)
440  {
441  _tabSelectedElements.push_back(pElement);
442  }
443 }
444 
446 {
447  std::vector<TYElement*>::iterator iter;
448  bool _bFinded = false;
449  for (iter = _tabSelectedElements.begin(); !_bFinded && (iter < _tabSelectedElements.end()); iter++)
450  {
451  if ((TYElement*)(*iter) == pElement)
452  {
453  _bFinded = true;
454  _tabSelectedElements.erase(iter);
455  break;
456  }
457  }
458 }
459 
461 {
462  _tabSelectedElements.clear();
463 }
464 
465 void gluPickMatrix(GLdouble x, GLdouble y, GLdouble deltax, GLdouble deltay, GLint viewport[4])
466 {
467  if (deltax <= 0 || deltay <= 0)
468  {
469  return;
470  }
471 
472  /* Translate and scale the picked region to the entire window */
473  glTranslated((viewport[2] - 2 * (x - viewport[0])) / deltax,
474  (viewport[3] - 2 * (y - viewport[1])) / deltay, 0);
475  glScaled(viewport[2] / deltax, viewport[3] / deltay, 1.0);
476 }
477 
479 {
480  if (renderContext.modelerElement == nullptr)
481  {
482  return;
483  }
484  auto camera = renderContext.viewport.camera();
485  QMatrix4x4 viewMatrix = camera->viewMatrix();
486  // TODO: Tympan coordinate system is RHS with Z-up while camera is operated as if
487  // Y was UP. Rotating the view matrix before rendering fixes it (the same
488  // hack is used both in interactions and with legacy render pipeline).
489  viewMatrix.rotate(90, -1, 0, 0);
490 
491  QMatrix4x4 projectionMatrix = camera->projectionMatrix();
492 
493  TYElement* modelerElement = renderContext.modelerElement;
494  TYElementGraphic* modelerElementGraphic = modelerElement->getGraphicObject();
495  TYListPtrConstTYElementGraphic allModelerElementGraphics;
496  modelerElementGraphic->getChilds(allModelerElementGraphics, true);
497 
498  TYGeometryNode* modelerGeoNode = TYGeometryNode::GetGeoNode(modelerElement);
499  QMatrix4x4 invertedGlobalModelerMatrix{};
500  if (modelerGeoNode != nullptr)
501  invertedGlobalModelerMatrix =
502  dynamic_cast<TYGeometryNodeGraphic*>(modelerGeoNode->getGraphicObject().getRealPointer())
503  ->globalMatrix()
504  .inverted();
505  allModelerElementGraphics.push_back(modelerElementGraphic);
506 
507  QOpenGLShaderProgram* shaderProgram = OGLShaderManager::instance(QOpenGLContext::currentContext())
509  shaderProgram->bind();
510  for (auto element : allModelerElementGraphics)
511  {
512  if (element->isBoundingBoxVisible() && dynamic_cast<const TYGeometryNodeGraphic*>(element) == nullptr)
513  {
514  const OBox boundingBox = element->boundingBox();
515 
516  // TODO : understand how the map is constructed
517  TYGeometryNode* geoNode =
518  const_cast<TYGeometryNode*>(TYGeometryNode::GetGeoNode(element->getTYElement()));
519  const TYElement* parent = element->getTYElement();
520 
521  while (geoNode == nullptr && parent->getParent())
522  {
523  parent = parent->getParent();
524  geoNode = const_cast<TYGeometryNode*>(TYGeometryNode::GetGeoNode(parent));
525  }
526 
527  QMatrix4x4 globalMatrix{};
528  if (geoNode != nullptr)
529  {
530  globalMatrix =
531  dynamic_cast<TYGeometryNodeGraphic*>(geoNode->getGraphicObject().getRealPointer())
532  ->globalMatrix();
533  }
534 
535  QMatrix4x4 bboxTranslation;
536  bboxTranslation.translate(QVector3D((boundingBox._min._x + boundingBox._max._x),
537  (boundingBox._min._y + boundingBox._max._y),
538  (boundingBox._min._z + boundingBox._max._z)) /
539  2);
540 
541  QVector3D bboxDimensions(boundingBox._max._x - boundingBox._min._x,
542  boundingBox._max._y - boundingBox._min._y,
543  boundingBox._max._z - boundingBox._min._z);
544  QMatrix4x4 modelMatrix = invertedGlobalModelerMatrix * globalMatrix * bboxTranslation;
545  drawBoundingBox(bboxDimensions, shaderProgram, modelMatrix * _boundingBoxScaleMatrix, viewMatrix,
546  projectionMatrix);
547  }
548  }
549  shaderProgram->release();
550 }
Representation graphique d'un element de base (fichier header)
list< const TYElementGraphic * > TYListPtrConstTYElementGraphic
List de pointeur de TYElement.
Representation graphique d'un GeometryNode (fichier header)
void gluPickMatrix(GLdouble x, GLdouble y, GLdouble deltax, GLdouble deltay, GLint viewport[4])
void drawBoundingBox(const QVector3D &boxDimensions, QOpenGLShaderProgram *shaderProgram, const QMatrix4x4 &model, const QMatrix4x4 &view, const QMatrix4x4 &projection)
Realise le rendu VTK et le rendu OpenGL (fichier header)
Contexte de rendu utilisé par les fonctions d'affichage.
@ Display
The current render is intended to be displayed on screen.
@ Picking
The current render is only done for picking purpose.
@ Overlay
The current render pass is for overlay elements.
The box class.
Definition: 3d.h:1346
OPoint3D _min
Minimal coordinates of the OBox.
Definition: 3d.h:1423
OPoint3D _max
Maximal coordinates of the OBox.
Definition: 3d.h:1424
double _y
y coordinate of OCoord3D
Definition: 3d.h:283
double _z
z coordinate of OCoord3D
Definition: 3d.h:284
double _x
x coordinate of OCoord3D
Definition: 3d.h:282
void getPosition(double &x, double &y, double &z) const
Definition: OGLCamera.cpp:481
const QMatrix4x4 & projectionMatrix() const
Definition: OGLCamera.cpp:567
const QMatrix4x4 & viewMatrix() const
Definition: OGLCamera.cpp:558
const std::vector< unsigned int > & indices() const
Definition: OGLMesh.cpp:23
const std::vector< QVector3D > & vertices() const
Definition: OGLMesh.cpp:18
void setMaterial(const OGLSimpleMaterial &material)
Definition: OGLMesh.cpp:28
OGLSimpleMaterial material()
Definition: OGLMesh.cpp:33
static OGLShaderManager * instance(QOpenGLContext *context)
QOpenGLShaderProgram * getShaderProgram(ShaderId shaderId)
static OGLSimpleMaterial BOUNDING_BOX
The 3D point class.
Definition: 3d.h:487
bool isA(const char *className) const
Definition: TYElement.cpp:65
T * getRealPointer()
Definition: smartptr.h:291
classe graphique pour un element de base
virtual void getChilds(TYListPtrTYElementGraphic &childs, bool recursif=true)
virtual void display(TYRenderContext &renderContext)
TYElement * getParent() const
Definition: TYElement.h:706
classe graphique pour un GeometryNode
void displayPushingParentMatrix(TYRenderContext &renderContext, TYGeometryNode *pDansCeRepere)
TYGeometryNode * GetGeoNodeParent() const
static TYGeometryNode * GetGeoNode(TYElement *pElement)
std::vector< TYElement * > _tabSelectedElements
Elements selectionnes.
void _renderScene(TYRenderContext &renderContext) const
0 --> render all, 1 --> render 2D, 2 --> render 3D
void removeSelectedElement(TYElement *pElement)
void addLight(OGLLightElement *pOGLElementLight)
void addOGLElement(OGLElement *pOGLElement)
void invalidateScene(void)
void removeOGLElement(OGLElement *pOGLElement)
std::vector< OGLLightElement * > _tabLights
Liste des lumieres dans la scene 3D.
QMatrix4x4 _boundingBoxScaleMatrix
GLuint _displayList
Display liste globale.
void renderBoundingBoxes(TYRenderContext &renderContext) const
RenderMode _renderMode
Mode de rendu.
OGLCamera * _pActiveCamera
void updateDisplayListOverlay(TYRenderContext &renderContext, TYGeometryNode *pElement, TYGeometryNode *pDansCeRepere)
std::vector< OGLElement * > _tabOGLElement
void setRenderMode(RenderMode mode)
double * _pBackgroundColor
std::vector< OGLLightElement * > getLights()
GLuint _displayListOverlay
Display liste pour les deplacements.
void drawElement(TYRenderContext &renderContext) const
RenderMode getRenderMode()
void OpenGLRender(TYRenderContext &renderContext, int x=0, int y=0)
void addSelectedElement(TYElement *pElement)
const TYRenderViewport viewport
const TYRenderType type
TYElement *const modelerElement
const OGLCamera * camera() const