11 #include <argos3/core/utility/logging/argos_log.h>
12 #include <argos3/core/utility/math/plane.h>
13 #include <argos3/core/simulator/simulator.h>
14 #include <argos3/core/simulator/loop_functions.h>
15 #include <argos3/core/simulator/space/space.h>
16 #include <argos3/core/simulator/entity/floor_entity.h>
17 #include <argos3/core/simulator/entity/composable_entity.h>
18 #include <argos3/core/simulator/entity/positional_entity.h>
22 #include <QTimerEvent>
23 #include <QMouseEvent>
26 #ifndef GL_MULTISAMPLE
27 #define GL_MULTISAMPLE 0x809D
32 static const Real ASPECT_RATIO = 4.0f / 3.0f;
33 static const UInt32 SELECT_BUFFER_SIZE = 128;
41 QOpenGLWidget(pc_parent),
42 m_cMainWindow(c_main_window),
43 m_cUserFunctions(c_user_functions),
45 m_bFastForwarding(false),
48 m_bMouseGrabbed(false),
49 m_bShiftPressed(false),
50 m_bInvertMouse(false),
52 m_cSpace(m_cSimulator.GetSpace()),
53 m_bUsingFloorTexture(false),
54 m_pcFloorTexture(NULL),
55 m_pcGroundTexture(NULL),
56 m_punSelectionBuffer(new GLuint[SELECT_BUFFER_SIZE])
59 QSizePolicy cSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
60 cSizePolicy.setHeightForWidth(
true);
61 setSizePolicy(cSizePolicy);
63 setFocusPolicy(Qt::ClickFocus);
67 m_mapPressedKeys[DIRECTION_UP] =
false;
68 m_mapPressedKeys[DIRECTION_DOWN] =
false;
69 m_mapPressedKeys[DIRECTION_LEFT] =
false;
70 m_mapPressedKeys[DIRECTION_RIGHT] =
false;
71 m_mapPressedKeys[DIRECTION_FORWARDS] =
false;
72 m_mapPressedKeys[DIRECTION_BACKWARDS] =
false;
80 delete m_pcGroundTexture;
81 glDeleteLists(1, m_unArenaList);
82 if(m_bUsingFloorTexture) {
83 delete m_pcFloorTexture;
84 glDeleteLists(1, m_unFloorList);
86 delete[] m_punSelectionBuffer;
95 initializeOpenGLFunctions();
97 glClearColor(0, .5, .5, 255);
100 m_pcGroundTexture =
new QOpenGLTexture(QImage(m_cMainWindow.
GetTextureDir() +
"/ground.png"));
101 m_pcGroundTexture->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear,
102 QOpenGLTexture::Linear);
103 #ifdef ARGOS_WITH_FREEIMAGE
108 m_bUsingFloorTexture =
true;
110 m_pcFloorTexture =
new QOpenGLTexture(QImage(
"/tmp/argos_floor.png"));
111 m_pcFloorTexture->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear,
112 QOpenGLTexture::Linear);
118 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
119 glHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST);
121 GLfloat pfLightAmbient[] = { .2, .2, .2, 1. };
122 GLfloat pfLightDiffuse[] = { .8, .8, .8, 1. };
123 GLfloat pfLightPosition[] = { 50. , 50. , 2. , 1. };
124 glLightfv(GL_LIGHT0, GL_AMBIENT, pfLightAmbient);
125 glLightfv(GL_LIGHT0, GL_DIFFUSE, pfLightDiffuse);
126 glLightfv(GL_LIGHT0, GL_POSITION, pfLightPosition);
135 glClearAccum(0.0, 0.0, 0.0, 0.0);
137 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
139 glEnable(GL_LINE_SMOOTH);
140 glShadeModel(GL_SMOOTH);
142 glEnable(GL_DEPTH_TEST);
144 glEnable(GL_CULL_FACE);
146 glEnable(GL_LIGHTING);
148 glMatrixMode(GL_PROJECTION);
154 glMatrixMode(GL_MODELVIEW);
161 for(CEntity::TVector::iterator itEntities = vecEntities.begin();
162 itEntities != vecEntities.end();
165 CallEntityOperation<CQTOpenGLOperationDrawNormal, CQTOpenGLWidget, void>(*
this, **itEntities);
166 m_cUserFunctions.
Call(**itEntities);
172 CallEntityOperation<CQTOpenGLOperationDrawSelected, CQTOpenGLWidget, void>(*
this, *vecEntities[m_sSelectionInfo.
Index]);
182 glDisable(GL_LIGHTING);
185 glColor3f(1.0, 0.0, 0.0);
188 glVertex3f(cStart.
GetX(), cStart.
GetY(), cStart.
GetZ());
191 glEnable(GL_LIGHTING);
193 glShadeModel(GL_FLAT);
194 glDisable(GL_LIGHTING);
195 glDisable(GL_CULL_FACE);
196 glDisable(GL_DEPTH_TEST);
197 glMatrixMode(GL_MODELVIEW);
198 QPainter cPainter(
this);
199 cPainter.setRenderHint(QPainter::Antialiasing);
200 cPainter.setRenderHint(QPainter::TextAntialiasing);
206 QString strFileName = QString(
"%1/%2%3.%4")
210 .arg(m_sFrameGrabData.
Format);
211 QToolTip::showText(pos() + geometry().center(),
"Stored frame to \"" + strFileName);
228 n_x *= devicePixelRatio();
229 n_y *= devicePixelRatio();
232 glGetIntegerv(GL_VIEWPORT, nViewport);
234 GLdouble fModelViewMatrix[16];
235 GLdouble fProjectionMatrix[16];
236 glGetDoublev(GL_MODELVIEW_MATRIX, fModelViewMatrix);
237 glGetDoublev(GL_PROJECTION_MATRIX, fProjectionMatrix);
244 GLfloat fWinY = nViewport[3] - n_y;
249 GLdouble fRayStartX, fRayStartY, fRayStartZ;
250 gluUnProject(fWinX, fWinY, 0.0f,
251 fModelViewMatrix, fProjectionMatrix, nViewport,
252 &fRayStartX, &fRayStartY, &fRayStartZ);
257 GLdouble fRayEndX, fRayEndY, fRayEndZ;
258 gluUnProject(fWinX, fWinY, 1.0f,
259 fModelViewMatrix, fProjectionMatrix, nViewport,
260 &fRayEndX, &fRayEndY, &fRayEndZ);
263 CVector3(fRayEndX, fRayEndY, fRayEndZ));
274 n_x *= devicePixelRatio();
275 n_y *= devicePixelRatio();
278 glGetIntegerv(GL_VIEWPORT, nViewport);
280 GLdouble fModelViewMatrix[16];
281 GLdouble fProjectionMatrix[16];
282 glGetDoublev(GL_MODELVIEW_MATRIX, fModelViewMatrix);
283 glGetDoublev(GL_PROJECTION_MATRIX, fProjectionMatrix);
290 GLfloat fWinY = nViewport[3] - n_y;
293 glReadBuffer(GL_BACK);
294 glReadPixels(n_x, (GLint)fWinY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &fWinZ);
296 GLdouble fWorldX, fWorldY, fWorldZ;
297 gluUnProject(fWinX, fWinY, fWinZ,
298 fModelViewMatrix, fProjectionMatrix, nViewport,
299 &fWorldX, &fWorldY, &fWorldZ);
305 return CVector3(fWorldX, fWorldZ, fWorldY);
329 if(m_sSelectionInfo.
Index == unIdx)
return;
340 m_sSelectionInfo.
Index = unIdx;
368 un_x *= devicePixelRatio();
369 un_y *= devicePixelRatio();
373 glSelectBuffer(SELECT_BUFFER_SIZE, m_punSelectionBuffer);
375 glRenderMode(GL_SELECT);
377 glMatrixMode(GL_PROJECTION);
380 glGetIntegerv(GL_VIEWPORT, nViewport);
388 glMatrixMode(GL_MODELVIEW);
395 for(
size_t i = 0; i < vecEntities.size(); ++i) {
398 CallEntityOperation<CQTOpenGLOperationDrawNormal, CQTOpenGLWidget, void>(*
this, *vecEntities[i]);
404 bool bWasSelected = m_sSelectionInfo.
IsSelected;
405 UInt32 unHits = glRenderMode(GL_RENDER);
419 GLuint* punByte = m_punSelectionBuffer;
420 GLuint unMinZ = 0xffffffff;
421 GLuint* punName = NULL;
422 for (
UInt32 i = 0; i < unHits; i++) {
423 GLuint unNames = *punByte;
425 if (*punByte < unMinZ) {
429 punByte += unNames+2;
433 (m_sSelectionInfo.
Index == *punName)) {
441 (m_sSelectionInfo.
Index != *punName)) {
446 m_sSelectionInfo.
Index = *punName;
454 m_sSelectionInfo.
Index = *punName;
476 glTranslatef(cPosition.
GetX(), cPosition.
GetY(), cPosition.
GetZ());
478 glRotatef(
ToDegrees(cXAngle).GetValue(), 1.0f, 0.0f, 0.0f);
479 glRotatef(
ToDegrees(cYAngle).GetValue(), 0.0f, 1.0f, 0.0f);
480 glRotatef(
ToDegrees(cZAngle).GetValue(), 0.0f, 0.0f, 1.0f);
494 glTranslatef(cPosition.
GetX(), cPosition.
GetY(), cPosition.
GetZ());
496 glRotatef(
ToDegrees(cXAngle).GetValue(), 1.0f, 0.0f, 0.0f);
497 glRotatef(
ToDegrees(cYAngle).GetValue(), 0.0f, 1.0f, 0.0f);
498 glRotatef(
ToDegrees(cZAngle).GetValue(), 0.0f, 0.0f, 1.0f);
506 glDisable(GL_LIGHTING);
511 glColor3f(1.0, 0.0, 1.0);
514 glColor3f(0.0, 1.0, 1.0);
518 glVertex3f(cStart.
GetX(), cStart.
GetY(), cStart.
GetZ());
523 glColor3f(0.0, 0.0, 0.0);
527 glVertex3f(cPoint.
GetX(), cPoint.
GetY(), cPoint.
GetZ());
531 glEnable(GL_LIGHTING);
540 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
541 glDisable(GL_LIGHTING);
543 glColor3f(1.0f, 1.0f, 1.0f);
547 glNormal3f(0.0f, 0.0f, -1.0f);
553 glNormal3f(0.0f, 0.0f, 1.0f);
562 glNormal3f(-1.0f, 0.0f, 0.0f);
568 glNormal3f(0.0f, -1.0f, 0.0f);
574 glNormal3f(1.0f, 0.0f, 0.0f);
580 glNormal3f(0.0f, 1.0f, 0.0f);
586 glEnable(GL_LIGHTING);
588 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
595 m_bFastForwarding =
false;
596 if(nTimerId != -1) killTimer(nTimerId);
605 m_bFastForwarding =
true;
606 if(nTimerId != -1) killTimer(nTimerId);
607 nTimerId = startTimer(1);
614 m_bFastForwarding =
false;
615 if(nTimerId != -1) killTimer(nTimerId);
625 if(m_bFastForwarding) {
627 m_nFrameCounter = m_nFrameCounter % m_nDrawFrameEvery;
628 if(m_nFrameCounter == 0) {
647 m_cSimulator.
Reset();
648 delete m_pcGroundTexture;
649 if(m_bUsingFloorTexture)
delete m_pcFloorTexture;
658 m_nDrawFrameEvery = n_every;
665 m_sFrameGrabData.
Grabbing = b_grab_on;
674 QToolTip::showText(pos() + geometry().center(), QString(
"Current camera: #%1").arg(n_camera+1));
692 switch(pc_event->key()) {
696 m_mapPressedKeys[DIRECTION_FORWARDS] =
true;
702 m_mapPressedKeys[DIRECTION_BACKWARDS] =
true;
708 m_mapPressedKeys[DIRECTION_LEFT] =
true;
714 m_mapPressedKeys[DIRECTION_RIGHT] =
true;
719 m_mapPressedKeys[DIRECTION_UP] =
true;
724 m_mapPressedKeys[DIRECTION_DOWN] =
true;
729 QOpenGLWidget::keyPressEvent(pc_event);
738 switch(pc_event->key()) {
742 m_mapPressedKeys[DIRECTION_FORWARDS] =
false;
748 m_mapPressedKeys[DIRECTION_BACKWARDS] =
false;
754 m_mapPressedKeys[DIRECTION_LEFT] =
false;
760 m_mapPressedKeys[DIRECTION_RIGHT] =
false;
765 m_mapPressedKeys[DIRECTION_UP] =
false;
770 m_mapPressedKeys[DIRECTION_DOWN] =
false;
775 QOpenGLWidget::keyPressEvent(pc_event);
792 glDisable(GL_LIGHTING);
794 glEnable(GL_TEXTURE_2D);
797 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
798 #ifdef ARGOS_WITH_FREEIMAGE
799 if(m_bUsingFloorTexture) {
803 m_pcFloorTexture->destroy();
804 m_pcFloorTexture->create();
806 m_pcFloorTexture->setData(QImage(
"/tmp/argos_floor.png"));
807 m_pcFloorTexture->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear,
808 QOpenGLTexture::Linear);
813 m_pcFloorTexture->bind();
815 glTexCoord2d(0.0f, 1.0f); glVertex3f(cArenaMinCorner.
GetX(), cArenaMinCorner.
GetY(), 0.0f);
816 glTexCoord2d(1.0f, 1.0f); glVertex3f(cArenaMaxCorner.
GetX(), cArenaMinCorner.
GetY(), 0.0f);
817 glTexCoord2d(1.0f, 0.0f); glVertex3f(cArenaMaxCorner.
GetX(), cArenaMaxCorner.
GetY(), 0.0f);
818 glTexCoord2d(0.0f, 0.0f); glVertex3f(cArenaMinCorner.
GetX(), cArenaMaxCorner.
GetY(), 0.0f);
824 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
825 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
826 m_pcGroundTexture->bind();
829 glTexCoord2f(0.0f, cArenaSize.
GetY()); glVertex3f(cArenaMinCorner.
GetX(), cArenaMinCorner.
GetY(), 0.0f);
830 glTexCoord2f(cArenaSize.
GetX(), cArenaSize.
GetY()); glVertex3f(cArenaMaxCorner.
GetX(), cArenaMinCorner.
GetY(), 0.0f);
831 glTexCoord2f(cArenaSize.
GetX(), 0.0f); glVertex3f(cArenaMaxCorner.
GetX(), cArenaMaxCorner.
GetY(), 0.0f);
832 glTexCoord2f(0.0f, 0.0f); glVertex3f(cArenaMinCorner.
GetX(), cArenaMaxCorner.
GetY(), 0.0f);
834 #ifdef ARGOS_WITH_FREEIMAGE
838 glDisable(GL_TEXTURE_2D);
840 glDisable(GL_CULL_FACE);
841 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
843 glColor3f(0.0f, 0.0f, 0.0f);
847 glVertex3f(cArenaMinCorner.
GetX(), cArenaMinCorner.
GetY(), cArenaMaxCorner.
GetZ());
848 glVertex3f(cArenaMaxCorner.
GetX(), cArenaMinCorner.
GetY(), cArenaMaxCorner.
GetZ());
849 glVertex3f(cArenaMaxCorner.
GetX(), cArenaMaxCorner.
GetY(), cArenaMaxCorner.
GetZ());
850 glVertex3f(cArenaMinCorner.
GetX(), cArenaMaxCorner.
GetY(), cArenaMaxCorner.
GetZ());
855 glVertex3f(cArenaMinCorner.
GetX(), cArenaMinCorner.
GetY(), cArenaMinCorner.
GetZ());
856 glVertex3f(cArenaMinCorner.
GetX(), cArenaMinCorner.
GetY(), cArenaMaxCorner.
GetZ());
857 glVertex3f(cArenaMinCorner.
GetX(), cArenaMaxCorner.
GetY(), cArenaMaxCorner.
GetZ());
858 glVertex3f(cArenaMinCorner.
GetX(), cArenaMaxCorner.
GetY(), cArenaMinCorner.
GetZ());
860 glVertex3f(cArenaMinCorner.
GetX(), cArenaMinCorner.
GetY(), cArenaMinCorner.
GetZ());
861 glVertex3f(cArenaMaxCorner.
GetX(), cArenaMinCorner.
GetY(), cArenaMinCorner.
GetZ());
862 glVertex3f(cArenaMaxCorner.
GetX(), cArenaMinCorner.
GetY(), cArenaMaxCorner.
GetZ());
863 glVertex3f(cArenaMinCorner.
GetX(), cArenaMinCorner.
GetY(), cArenaMaxCorner.
GetZ());
865 glVertex3f(cArenaMaxCorner.
GetX(), cArenaMinCorner.
GetY(), cArenaMinCorner.
GetZ());
866 glVertex3f(cArenaMaxCorner.
GetX(), cArenaMaxCorner.
GetY(), cArenaMinCorner.
GetZ());
867 glVertex3f(cArenaMaxCorner.
GetX(), cArenaMaxCorner.
GetY(), cArenaMaxCorner.
GetZ());
868 glVertex3f(cArenaMaxCorner.
GetX(), cArenaMinCorner.
GetY(), cArenaMaxCorner.
GetZ());
870 glVertex3f(cArenaMinCorner.
GetX(), cArenaMaxCorner.
GetY(), cArenaMinCorner.
GetZ());
871 glVertex3f(cArenaMinCorner.
GetX(), cArenaMaxCorner.
GetY(), cArenaMaxCorner.
GetZ());
872 glVertex3f(cArenaMaxCorner.
GetX(), cArenaMaxCorner.
GetY(), cArenaMaxCorner.
GetZ());
873 glVertex3f(cArenaMaxCorner.
GetX(), cArenaMaxCorner.
GetY(), cArenaMinCorner.
GetZ());
876 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
877 glEnable(GL_CULL_FACE);
879 glEnable(GL_LIGHTING);
903 if(! (pc_event->modifiers() & Qt::ShiftModifier)) {
904 m_bMouseGrabbed =
true;
905 m_cMouseGrabPos = pc_event->pos();
911 m_bMouseGrabbed =
false;
913 pc_event->pos().y());
924 if(m_bMouseGrabbed &&
926 (pc_event->modifiers() & Qt::ControlModifier)) {
930 if(pcEntity == NULL) {
934 if(pcCompEntity != NULL && pcCompEntity->
HasComponent(
"body")) {
939 m_bMouseGrabbed =
false;
952 pc_event->pos().y());
966 m_bMouseGrabbed =
false;
976 if(m_bMouseGrabbed) {
977 if(! (pc_event->modifiers() & Qt::ControlModifier)) {
981 if(pc_event->buttons() == Qt::LeftButton) {
982 if (m_bInvertMouse) m_cCamera.
Rotate( pc_event->pos() - m_cMouseGrabPos);
983 else m_cCamera.
Rotate( m_cMouseGrabPos - pc_event->pos());
984 m_cMouseGrabPos = pc_event->pos();
987 else if(pc_event->buttons() == Qt::RightButton) {
988 QPoint cDelta(pc_event->pos() - m_cMouseGrabPos);
989 m_cCamera.
Move(-cDelta.y(), cDelta.x(), 0);
990 m_cMouseGrabPos = pc_event->pos();
993 else if(pc_event->buttons() == Qt::MidButton) {
994 QPoint cDelta(pc_event->pos() - m_cMouseGrabPos);
995 m_cCamera.
Move(0, 0, cDelta.y());
996 m_cMouseGrabPos = pc_event->pos();
1021 SInt32 nForwardsBackwards = 0;
1025 if(m_mapPressedKeys[DIRECTION_UP]) nUpDown++;
1026 if(m_mapPressedKeys[DIRECTION_DOWN]) nUpDown--;
1027 if(m_mapPressedKeys[DIRECTION_LEFT]) nSideways++;
1028 if(m_mapPressedKeys[DIRECTION_RIGHT]) nSideways--;
1029 if(m_mapPressedKeys[DIRECTION_FORWARDS]) nForwardsBackwards++;
1030 if(m_mapPressedKeys[DIRECTION_BACKWARDS]) nForwardsBackwards--;
1032 if(nForwardsBackwards != 0 ||
1035 m_cCamera.
Move(15 * nForwardsBackwards,
1047 QOpenGLWidget::resizeEvent(pc_event);
1049 QToolTip::showText(pos() + geometry().center(), QString(
"Size: %1 x %2").arg(pc_event->size().width()).arg(pc_event->size().height()));
1058 std::string strBuffer;
1062 size_t unEndPos = strBuffer.find_last_not_of(
"/ \t");
1063 if(unEndPos != std::string::npos) {
1064 strBuffer = strBuffer.substr(0, unEndPos+1);
1068 if(!cDirectory.exists()) {
1069 THROW_ARGOSEXCEPTION(
"QTOpenGL: frame grabbing directory \"" << strBuffer <<
"\" does not exist. Create it first!");
1072 strBuffer =
"frame_";
1078 Format = strBuffer.c_str();