ARGoS  3
A parallel, multi-engine simulator for swarm robotics
plugins/simulator/visualizations/qt-opengl/qtopengl_widget.cpp
Go to the documentation of this file.
00001 
00007 #include "qtopengl_widget.h"
00008 #include "qtopengl_main_window.h"
00009 #include "qtopengl_user_functions.h"
00010 
00011 #include <argos3/core/utility/logging/argos_log.h>
00012 #include <argos3/core/utility/math/plane.h>
00013 #include <argos3/core/simulator/simulator.h>
00014 #include <argos3/core/simulator/space/space.h>
00015 #include <argos3/core/simulator/entity/floor_entity.h>
00016 #include <argos3/core/simulator/entity/composable_entity.h>
00017 
00018 #include <QDir>
00019 #include <QToolTip>
00020 #include <QTimerEvent>
00021 #include <QMouseEvent>
00022 #include <QPainter>
00023 
00024 #ifndef GL_MULTISAMPLE
00025 #define GL_MULTISAMPLE 0x809D
00026 #endif
00027 
00028 namespace argos {
00029 
00030    static const Real ASPECT_RATIO         = 4.0f / 3.0f;
00031    static const UInt32 SELECT_BUFFER_SIZE = 128;
00032    
00033    /****************************************/
00034    /****************************************/
00035 
00036    CQTOpenGLWidget::CQTOpenGLWidget(const QGLFormat& c_format,
00037                                     QWidget* pc_parent,
00038                                     CQTOpenGLMainWindow* pc_main_window,
00039                                     CQTOpenGLUserFunctions& c_user_functions) :
00040       QGLWidget(c_format, pc_parent),
00041       pcMainWindow(pc_main_window),
00042       m_cUserFunctions(c_user_functions),
00043       nTimerId(-1),
00044       m_bAntiAliasing(false),
00045       m_bFastForwarding(false),
00046       m_nDrawFrameEvery(1),
00047       m_nFrameCounter(0),
00048       m_bMouseGrabbed(false),
00049       m_bShiftPressed(false),
00050       m_bInvertMouse(false),
00051       m_cSimulator(CSimulator::GetInstance()),
00052       m_cSpace(m_cSimulator.GetSpace()),
00053       m_bUsingFloorTexture(false),
00054       m_punSelectionBuffer(new GLuint[SELECT_BUFFER_SIZE])
00055 #ifdef QTOPENGL_WITH_SDL
00056       , m_cJoystick(this)
00057 #endif
00058    {
00059       m_cUserFunctions.SetOpenGLWidget(*this);
00060       setAutoFillBackground(false);
00061       QSizePolicy cSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
00062       cSizePolicy.setHeightForWidth(true);
00063       setSizePolicy(cSizePolicy);
00064       setFocusPolicy(Qt::ClickFocus);
00065       updateGeometry();
00066       /* Light data */
00067       m_pfLightAmbient = new GLfloat[4];
00068       m_pfLightDiffuse = new GLfloat[4];
00069       m_pfLight0Position = new GLfloat[4];
00070       m_pfLight1Position = new GLfloat[4];
00071       m_pfLightAmbient[0] = 0.1f;
00072       m_pfLightAmbient[1] = 0.1f;
00073       m_pfLightAmbient[2] = 0.1f;
00074       m_pfLightAmbient[3] = 1.0f;
00075       m_pfLightDiffuse[0] = 0.6f;
00076       m_pfLightDiffuse[1] = 0.6f;
00077       m_pfLightDiffuse[2] = 0.6f;
00078       m_pfLightDiffuse[3] = 1.0f;
00079       m_pfLight0Position[0] = 50.0f;
00080       m_pfLight0Position[1] = 50.0f;
00081       m_pfLight0Position[2] = 2.0f;
00082       m_pfLight0Position[3] = 1.0f;
00083       m_pfLight1Position[0] = -50.0f;
00084       m_pfLight1Position[1] = -50.0f;
00085       m_pfLight1Position[2] = 2.0f;
00086       m_pfLight1Position[3] = 1.0f;
00087       /* Keys */
00088       m_mapPressedKeys[DIRECTION_UP]        = false;
00089       m_mapPressedKeys[DIRECTION_DOWN]      = false;
00090       m_mapPressedKeys[DIRECTION_LEFT]      = false;
00091       m_mapPressedKeys[DIRECTION_RIGHT]     = false;
00092       m_mapPressedKeys[DIRECTION_FORWARDS]  = false;
00093       m_mapPressedKeys[DIRECTION_BACKWARDS] = false;
00094       /* Antialiasing */
00095       m_bAntiAliasing = format().sampleBuffers();
00096 #ifdef QTOPENGL_WITH_SDL
00097       /* Joystick support */
00098       if(m_cJoystick.connected()) {
00099          m_cJoystick.open(0);
00100       }
00101 #endif
00102       /* Initialize the arena */
00103       makeCurrent();
00104       initializeGL();
00105       resizeGL(width(), height());
00106       InitializeArena();
00107    }
00108 
00109    /****************************************/
00110    /****************************************/
00111 
00112    CQTOpenGLWidget::~CQTOpenGLWidget() {
00113 #ifdef QTOPENGL_WITH_SDL
00114       m_cJoystick.close();
00115 #endif
00116       deleteTexture(m_unGroundTexture);
00117       glDeleteLists(1, m_unArenaList);
00118       if(m_bUsingFloorTexture) {
00119          deleteTexture(m_unFloorTexture);
00120          glDeleteLists(1, m_unFloorList);
00121       }
00122       delete[] m_punSelectionBuffer;
00123       delete[] m_pfLightAmbient;
00124       delete[] m_pfLightDiffuse;
00125       delete[] m_pfLight0Position;
00126       delete[] m_pfLight1Position;
00127    }
00128 
00129    /****************************************/
00130    /****************************************/
00131 
00132    void CQTOpenGLWidget::initializeGL() {
00133       glShadeModel(GL_SMOOTH);
00134       glEnable(GL_LINE_SMOOTH);
00135       glEnable(GL_LIGHTING);
00136       glEnable(GL_CULL_FACE);
00137       glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
00138       glHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST);
00139       glEnable(GL_DEPTH_TEST);
00140       qglClearColor(Qt::darkCyan);
00141       glClearAccum(0.0, 0.0, 0.0, 0.0);
00142       /* Place the lights */
00143       glLightfv(GL_LIGHT0, GL_AMBIENT,  m_pfLightAmbient);
00144       glLightfv(GL_LIGHT0, GL_DIFFUSE,  m_pfLightDiffuse);
00145       glLightfv(GL_LIGHT0, GL_POSITION, m_pfLight0Position);
00146       glLightfv(GL_LIGHT1, GL_AMBIENT,  m_pfLightAmbient);
00147       glLightfv(GL_LIGHT1, GL_DIFFUSE,  m_pfLightDiffuse);
00148       glLightfv(GL_LIGHT1, GL_POSITION, m_pfLight1Position);
00149       glEnable(GL_LIGHT0);
00150       glEnable(GL_LIGHT1);
00151    }
00152 
00153    /****************************************/
00154    /****************************************/
00155 
00156    void CQTOpenGLWidget::paintEvent(QPaintEvent*) {
00157       if(!isValid()) return;
00158       DrawScene();
00159    }
00160 
00161    /****************************************/
00162    /****************************************/
00163 
00164    void CQTOpenGLWidget::DrawAxes() {
00165       // @TODO
00166    }
00167 
00168    /****************************************/
00169    /****************************************/
00170 
00171    void CQTOpenGLWidget::DrawScene() {
00172       makeCurrent();
00173       resizeGL(width(), height());
00174       initializeGL();
00175       /* Calculate the perspective */
00176       glMatrixMode(GL_PROJECTION);
00177       glLoadIdentity();
00178       gluPerspective(m_cCamera.GetActiveSettings().YFieldOfView.GetValue(),
00179                      ASPECT_RATIO,
00180                      0.1f, 1000.0f);
00181       /* Set up the right matrix mode */
00182       glMatrixMode(GL_MODELVIEW);
00183       glLoadIdentity();
00184       /* Clear color buffer and depth buffer */
00185       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00186       /* Place the camera */
00187       m_cCamera.Look();
00188       /* Switch anti-aliasing on */
00189       if(m_bAntiAliasing) {
00190          glEnable(GL_MULTISAMPLE);
00191       }
00192       /* Draw the arena */
00193       DrawArena();
00194       /* Draw the objects */
00195       CEntity::TVector& vecEntities = m_cSpace.GetRootEntityVector();
00196       for(CEntity::TVector::iterator itEntities = vecEntities.begin();
00197           itEntities != vecEntities.end();
00198           ++itEntities) {
00199          glPushMatrix();
00200          CallEntityOperation<CQTOpenGLOperationDrawNormal, CQTOpenGLWidget, void>(*this, **itEntities);
00201          m_cUserFunctions.Call(**itEntities);
00202          glPopMatrix();
00203       }
00204       /* Draw the selected object, if necessary */
00205       if(m_sSelectionInfo.IsSelected) {
00206          glPushMatrix();
00207          CallEntityOperation<CQTOpenGLOperationDrawSelected, CQTOpenGLWidget, void>(*this, *vecEntities[m_sSelectionInfo.Index]);
00208          glPopMatrix();
00209       }
00210       /* Draw in world */
00211       glPushMatrix();
00212       m_cUserFunctions.DrawInWorld();
00213       glPopMatrix();
00214       /* Switch anti-aliasing off */
00215       if(m_bAntiAliasing) {
00216          glDisable(GL_MULTISAMPLE);
00217       }
00218       /* Draw axes */
00219       DrawAxes();
00220       /* Execute overlay drawing */
00221       glShadeModel(GL_FLAT);
00222       glDisable(GL_LIGHTING);
00223       glDisable(GL_CULL_FACE);
00224       glDisable(GL_DEPTH_TEST);
00225       glMatrixMode(GL_MODELVIEW);
00226       QPainter cPainter(this);
00227       if(m_bAntiAliasing) {
00228          cPainter.setRenderHint(QPainter::Antialiasing);
00229          cPainter.setRenderHint(QPainter::TextAntialiasing);
00230       }
00231       m_cUserFunctions.DrawOverlay(cPainter);
00232       cPainter.end();
00233       /* Grab frame, if necessary */
00234       if(m_sFrameGrabData.Grabbing) {
00235          QString strFileName = QString("%1/%2%3.%4")
00236             .arg(m_sFrameGrabData.Directory)
00237             .arg(m_sFrameGrabData.BaseName)
00238             .arg(m_cSpace.GetSimulationClock(), 5, 10, QChar('0'))
00239             .arg(m_sFrameGrabData.Format);
00240          QToolTip::showText(pos() + geometry().center(), "Stored frame to \"" + strFileName);
00241          grabFrameBuffer()
00242             .save(
00243                strFileName,
00244                0,
00245                m_sFrameGrabData.Quality);
00246       }
00247    }
00248 
00249    /****************************************/
00250    /****************************************/
00251 
00252    void CQTOpenGLWidget::SelectInScene(UInt32 un_x,
00253                                        UInt32 un_y) {
00254       /* Used to store the viewport size */
00255       GLint nViewport[4];
00256       /* Set the selection buffer */
00257       glSelectBuffer(SELECT_BUFFER_SIZE, m_punSelectionBuffer);
00258       /* Switch to select mode */
00259       glRenderMode(GL_SELECT);
00260       /* Set the projection matrix */
00261       glMatrixMode(GL_PROJECTION);
00262       glPushMatrix();
00263       glLoadIdentity();
00264       /* Set the viewport */
00265       glGetIntegerv(GL_VIEWPORT, nViewport);
00266       gluPickMatrix(un_x,
00267                     nViewport[3]-un_y,
00268                     5, 5,
00269                     nViewport);
00270       gluPerspective(m_cCamera.GetActiveSettings().YFieldOfView.GetValue(),
00271                      ASPECT_RATIO,
00272                      0.1f, 1000.0f);
00273       glMatrixMode(GL_MODELVIEW);
00274       /* Prepare name stack */
00275       glInitNames();
00276       /* Draw the objects */
00277       CEntity::TVector& vecEntities = m_cSpace.GetRootEntityVector();
00278       for(size_t i = 0; i < vecEntities.size(); ++i) {
00279          glPushName(i);
00280          glPushMatrix();
00281          CallEntityOperation<CQTOpenGLOperationDrawNormal, CQTOpenGLWidget, void>(*this, *vecEntities[i]);
00282          glPopMatrix();
00283          glPopName();
00284       }
00285       /* Restore the original projection matrix */
00286       glMatrixMode(GL_PROJECTION);
00287       glPopMatrix();
00288       glMatrixMode(GL_MODELVIEW);
00289       glFlush();
00290       /* Return to normal rendering mode and get hit count */
00291       bool bWasSelected = m_sSelectionInfo.IsSelected;
00292       UInt32 unHits = glRenderMode(GL_RENDER);
00293       if (unHits == 0) {
00294          /* No hits, deselect what was selected */
00295          m_sSelectionInfo.IsSelected = false;
00296          if(bWasSelected) {
00297             emit EntityDeselected(m_sSelectionInfo.Index);
00298          }
00299       }
00300       else {
00301          /* There are hits!
00302           * Process them, keeping the closest hit
00303           */
00304          GLuint unNames;
00305          GLuint* punByte;
00306          GLuint unMinZ;
00307          GLuint* punName;
00308          punByte = m_punSelectionBuffer;
00309          unMinZ = 0xffffffff;
00310          for (UInt32 i = 0; i < unHits; i++) {  
00311             unNames = *punByte;
00312             ++punByte;
00313             if (*punByte < unMinZ) {
00314                unMinZ = *punByte;
00315                punName = punByte+2;
00316             }
00317             punByte += unNames+2;
00318          }
00319          /* Now *punName contains the closest hit */
00320          if(bWasSelected &&
00321             (m_sSelectionInfo.Index == *punName)) {
00322             /* The user clicked on the selected entity, deselect it */
00323             emit EntityDeselected(m_sSelectionInfo.Index);
00324             m_sSelectionInfo.IsSelected = false;
00325          }
00326          if(bWasSelected &&
00327             (m_sSelectionInfo.Index != *punName)) {
00328             /* The user clicked on a different entity from the selected one */
00329             emit EntityDeselected(m_sSelectionInfo.Index);
00330             m_sSelectionInfo.Index = *punName;
00331             emit EntitySelected(m_sSelectionInfo.Index);
00332          }
00333          else {
00334             /* There was nothing selected, and the user clicked on an entity */
00335             m_sSelectionInfo.IsSelected = true;
00336             m_sSelectionInfo.Index = *punName;
00337             emit EntitySelected(m_sSelectionInfo.Index);
00338          }
00339       }
00340       DrawScene();
00341    }
00342 
00343    /****************************************/
00344    /****************************************/
00345 
00346    void CQTOpenGLWidget::DrawPositionalEntity(CPositionalEntity& c_entity) {
00347       /* Get the position of the entity */
00348       const CVector3& cPosition = c_entity.GetPosition();
00349       /* Get the orientation of the entity */
00350       const CQuaternion& cOrientation = c_entity.GetOrientation();
00351       CRadians cZAngle, cYAngle, cXAngle;
00352       cOrientation.ToEulerAngles(cZAngle, cYAngle, cXAngle);
00353       /* First, translate the entity */
00354       glTranslatef(cPosition.GetX(), cPosition.GetY(), cPosition.GetZ());
00355       /* Second, rotate the entity */
00356       glRotatef(ToDegrees(cXAngle).GetValue(), 1.0f, 0.0f, 0.0f);
00357       glRotatef(ToDegrees(cYAngle).GetValue(), 0.0f, 1.0f, 0.0f);
00358       glRotatef(ToDegrees(cZAngle).GetValue(), 0.0f, 0.0f, 1.0f);
00359    }
00360 
00361    /****************************************/
00362    /****************************************/
00363 
00364    void CQTOpenGLWidget::DrawRays(CControllableEntity& c_entity) {
00365       if(! c_entity.GetCheckedRays().empty()) {
00366          glDisable(GL_LIGHTING);
00367          glBegin(GL_LINES);
00368          for(UInt32 i = 0; i < c_entity.GetCheckedRays().size(); ++i) {
00369             if(c_entity.GetCheckedRays()[i].first) {
00370                glColor3f(1.0, 0.0, 1.0);
00371             }
00372             else {
00373                glColor3f(0.0, 1.0, 1.0);
00374             }
00375             const CVector3& cStart = c_entity.GetCheckedRays()[i].second.GetStart();
00376             const CVector3& cEnd = c_entity.GetCheckedRays()[i].second.GetEnd();
00377             glVertex3f(cStart.GetX(), cStart.GetY(), cStart.GetZ());
00378             glVertex3f(cEnd.GetX(), cEnd.GetY(), cEnd.GetZ());
00379          }
00380          glEnd();
00381          glPointSize(5.0);
00382          glColor3f(0.0, 0.0, 0.0);
00383          glBegin(GL_POINTS);
00384          for(UInt32 i = 0; i < c_entity.GetIntersectionPoints().size(); ++i) {
00385             const CVector3& cPoint = c_entity.GetIntersectionPoints()[i];
00386             glVertex3f(cPoint.GetX(), cPoint.GetY(), cPoint.GetZ());
00387          }
00388          glEnd();
00389          glPointSize(1.0);
00390          glEnable(GL_LIGHTING);
00391       }
00392    }
00393 
00394    /****************************************/
00395    /****************************************/
00396 
00397    void CQTOpenGLWidget::DrawBoundingBox(CEmbodiedEntity& c_entity) {
00398       const SBoundingBox& sBBox = c_entity.GetBoundingBox();
00399       glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00400       glDisable(GL_LIGHTING);
00401       glLineWidth(3.0f);
00402       glColor3f(1.0f, 1.0f, 1.0f);
00403       /* This part covers the top and bottom faces (parallel to XY) */
00404       glBegin(GL_QUADS);
00405       /* Bottom face */
00406       glNormal3f(0.0f, 0.0f, -1.0f);
00407       glVertex3f(sBBox.MinCorner.GetX(), sBBox.MinCorner.GetY(), sBBox.MinCorner.GetZ());
00408       glVertex3f(sBBox.MinCorner.GetX(), sBBox.MaxCorner.GetY(), sBBox.MinCorner.GetZ());
00409       glVertex3f(sBBox.MaxCorner.GetX(), sBBox.MaxCorner.GetY(), sBBox.MinCorner.GetZ());
00410       glVertex3f(sBBox.MaxCorner.GetX(), sBBox.MinCorner.GetY(), sBBox.MinCorner.GetZ());
00411       /* Top face */
00412       glNormal3f(0.0f, 0.0f, 1.0f);
00413       glVertex3f(sBBox.MinCorner.GetX(), sBBox.MinCorner.GetY(), sBBox.MaxCorner.GetZ());
00414       glVertex3f(sBBox.MaxCorner.GetX(), sBBox.MinCorner.GetY(), sBBox.MaxCorner.GetZ());
00415       glVertex3f(sBBox.MaxCorner.GetX(), sBBox.MaxCorner.GetY(), sBBox.MaxCorner.GetZ());
00416       glVertex3f(sBBox.MinCorner.GetX(), sBBox.MaxCorner.GetY(), sBBox.MaxCorner.GetZ());
00417       glEnd();
00418       /* This part covers the faces (South, East, North, West) */
00419       glBegin(GL_QUADS);
00420       /* South face */
00421       glNormal3f(-1.0f, 0.0f, 0.0f);
00422       glVertex3f(sBBox.MinCorner.GetX(), sBBox.MinCorner.GetY(), sBBox.MinCorner.GetZ());
00423       glVertex3f(sBBox.MinCorner.GetX(), sBBox.MinCorner.GetY(), sBBox.MaxCorner.GetZ());
00424       glVertex3f(sBBox.MinCorner.GetX(), sBBox.MaxCorner.GetY(), sBBox.MaxCorner.GetZ());
00425       glVertex3f(sBBox.MinCorner.GetX(), sBBox.MaxCorner.GetY(), sBBox.MinCorner.GetZ());
00426       /* East face */
00427       glNormal3f(0.0f, -1.0f, 0.0f);
00428       glVertex3f(sBBox.MinCorner.GetX(), sBBox.MinCorner.GetY(), sBBox.MinCorner.GetZ());
00429       glVertex3f(sBBox.MaxCorner.GetX(), sBBox.MinCorner.GetY(), sBBox.MinCorner.GetZ());
00430       glVertex3f(sBBox.MaxCorner.GetX(), sBBox.MinCorner.GetY(), sBBox.MaxCorner.GetZ());
00431       glVertex3f(sBBox.MinCorner.GetX(), sBBox.MinCorner.GetY(), sBBox.MaxCorner.GetZ());
00432       /* North face */
00433       glNormal3f(1.0f, 0.0f, 0.0f);
00434       glVertex3f(sBBox.MaxCorner.GetX(), sBBox.MinCorner.GetY(), sBBox.MinCorner.GetZ());
00435       glVertex3f(sBBox.MaxCorner.GetX(), sBBox.MaxCorner.GetY(), sBBox.MinCorner.GetZ());
00436       glVertex3f(sBBox.MaxCorner.GetX(), sBBox.MaxCorner.GetY(), sBBox.MaxCorner.GetZ());
00437       glVertex3f(sBBox.MaxCorner.GetX(), sBBox.MinCorner.GetY(), sBBox.MaxCorner.GetZ());
00438       /* West face */
00439       glNormal3f(0.0f, 1.0f, 0.0f);
00440       glVertex3f(sBBox.MinCorner.GetX(), sBBox.MaxCorner.GetY(), sBBox.MinCorner.GetZ());
00441       glVertex3f(sBBox.MinCorner.GetX(), sBBox.MaxCorner.GetY(), sBBox.MaxCorner.GetZ());
00442       glVertex3f(sBBox.MaxCorner.GetX(), sBBox.MaxCorner.GetY(), sBBox.MaxCorner.GetZ());
00443       glVertex3f(sBBox.MaxCorner.GetX(), sBBox.MaxCorner.GetY(), sBBox.MinCorner.GetZ());
00444       glEnd();
00445       glEnable(GL_LIGHTING);
00446       glLineWidth(1.0f);
00447       glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00448    }
00449 
00450    /****************************************/
00451    /****************************************/
00452 
00453    void CQTOpenGLWidget::resizeGL(int n_width,
00454                                   int n_height) {
00455       glViewport(0, 0, n_width, n_height);
00456    }
00457 
00458    /****************************************/
00459    /****************************************/
00460 
00461    void CQTOpenGLWidget::PlayPauseSimulation(bool b_play) {
00462       m_bFastForwarding = false;
00463       if(b_play) {
00464          if(nTimerId != -1) killTimer(nTimerId);
00465          nTimerId = startTimer(100);
00466       }
00467       else {
00468          killTimer(nTimerId);
00469          nTimerId = -1;
00470       }
00471    }
00472 
00473    /****************************************/
00474    /****************************************/
00475 
00476    void CQTOpenGLWidget::FastForwardPauseSimulation(bool b_play) {
00477       m_nFrameCounter = 0;
00478       if(b_play) {
00479          m_bFastForwarding = true;
00480          if(nTimerId != -1) killTimer(nTimerId);
00481          nTimerId = startTimer(1);
00482       }
00483       else {
00484          m_bFastForwarding = false;
00485          killTimer(nTimerId);
00486          nTimerId = -1;
00487       }
00488    }
00489 
00490    /****************************************/
00491    /****************************************/
00492 
00493    void CQTOpenGLWidget::StepSimulation() {
00494       if(!m_cSimulator.IsExperimentFinished()) {
00495          m_cSimulator.UpdateSpace();
00496          if(m_bFastForwarding) {
00497             /* Frame dropping happens only in fast-forward */
00498             m_nFrameCounter = m_nFrameCounter % m_nDrawFrameEvery;
00499             if(m_nFrameCounter == 0) {
00500                DrawScene();
00501             }
00502             ++m_nFrameCounter;
00503          } else {
00504             DrawScene();
00505          }
00506          emit StepDone(m_cSpace.GetSimulationClock());
00507       }
00508       else {
00509          killTimer(nTimerId);
00510          nTimerId = -1;
00511          emit SimulationDone();
00512       }
00513    }
00514 
00515    /****************************************/
00516    /****************************************/
00517 
00518    void CQTOpenGLWidget::StopSimulation() {
00519       m_bFastForwarding = false;
00520       killTimer(nTimerId);
00521       nTimerId = -1;
00522    }
00523 
00524    /****************************************/
00525    /****************************************/
00526 
00527    void CQTOpenGLWidget::ResetSimulation() {
00528       m_cSimulator.Reset();
00529       InitializeArena();
00530       DrawScene();
00531    }
00532 
00533    /****************************************/
00534    /****************************************/
00535 
00536    void CQTOpenGLWidget::SetAntiAliasing(bool b_antialias_on) {
00537       QGLFormat cGLFormat = format();
00538       cGLFormat.setSampleBuffers(b_antialias_on);
00539       setFormat(cGLFormat);
00540       m_bAntiAliasing = b_antialias_on;
00541       DrawScene();
00542    }
00543 
00544    /****************************************/
00545    /****************************************/
00546 
00547    void CQTOpenGLWidget::SetDrawFrameEvery(SInt32 n_every) {
00548       m_nDrawFrameEvery = n_every;
00549    }
00550 
00551    /****************************************/
00552    /****************************************/
00553 
00554    void CQTOpenGLWidget::SetGrabFrame(bool b_grab_on) {
00555       m_sFrameGrabData.Grabbing = b_grab_on;
00556    }
00557 
00558    /****************************************/
00559    /****************************************/
00560 
00561    void CQTOpenGLWidget::SetCamera(int n_camera) {
00562       m_cCamera.SetActiveSettings(n_camera);
00563       DrawScene();
00564       QToolTip::showText(pos() + geometry().center(), QString("Current camera: #%1").arg(n_camera+1));
00565    }
00566 
00567    /****************************************/
00568    /****************************************/
00569 
00570    void CQTOpenGLWidget::SetCameraFocalLength(double f_length) {
00571       m_cCamera.GetActiveSettings().LensFocalLength = f_length / 1000.0f;
00572       m_cCamera.GetActiveSettings().CalculateYFieldOfView();
00573       m_cCamera.GetActiveSettings().CalculateSensitivity();
00574       QToolTip::showText(pos() + geometry().center(), QString("Motion sens = %1").arg(m_cCamera.GetActiveSettings().MotionSensitivity));
00575       DrawScene();
00576    }
00577 
00578    /****************************************/
00579    /****************************************/
00580 
00581    void CQTOpenGLWidget::InitializeArena() {
00582       /* Set up the texture parameters for the floor plane
00583          (here we refer to the standard floor, not the floor entity) */
00584       glEnable(GL_TEXTURE_2D);
00585       QImage cGroundTexture(pcMainWindow->GetTextureDir() + "/ground.png");
00586       m_unGroundTexture = bindTexture(cGroundTexture,
00587                                       GL_TEXTURE_2D,
00588                                       GL_RGB,
00589                                       QGLContext::MipmapBindOption | QGLContext::LinearFilteringBindOption);
00590       /* Now take care of the floor entity */
00591       try {
00592          /* Create an image to use as texture */
00593          m_cSpace.GetFloorEntity().SaveAsImage("/tmp/argos_floor.png");
00594          m_bUsingFloorTexture = true;
00595          /* Use the image as texture */
00596          m_unFloorTexture = bindTexture(QImage("/tmp/argos_floor.png"),
00597                                         GL_TEXTURE_2D,
00598                                         GL_RGB,
00599                                         QGLContext::MipmapBindOption | QGLContext::LinearFilteringBindOption);
00600          m_cSpace.GetFloorEntity().ClearChanged();
00601       }
00602       catch(CARGoSException& ex) {}
00603    }
00604 
00605    /****************************************/
00606    /****************************************/
00607 
00608    void CQTOpenGLWidget::DrawArena() {
00609       CVector3 cArenaSize(m_cSpace.GetArenaSize());
00610       CVector3 cArenaMinCorner(m_cSpace.GetArenaCenter().GetX() - cArenaSize.GetX() * 0.5f,
00611                                m_cSpace.GetArenaCenter().GetY() - cArenaSize.GetY() * 0.5f,
00612                                m_cSpace.GetArenaCenter().GetZ() - cArenaSize.GetZ() * 0.5f);
00613       CVector3 cArenaMaxCorner(m_cSpace.GetArenaCenter().GetX() + cArenaSize.GetX() * 0.5f,
00614                                m_cSpace.GetArenaCenter().GetY() + cArenaSize.GetY() * 0.5f,
00615                                m_cSpace.GetArenaCenter().GetZ() + cArenaSize.GetZ() * 0.5f);
00616       /* Disable lighting - no funny color effects */
00617       glDisable(GL_LIGHTING);
00618       /* Enable textures */
00619       glEnable(GL_TEXTURE_2D);
00620       /* Take care of the floor entity if necessary */
00621       /* The texture covers the object like a decal */
00622       glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
00623       if(m_bUsingFloorTexture) {
00624          /* Use the image as texture */
00625          if(m_cSpace.GetFloorEntity().HasChanged()) {
00626             deleteTexture(m_unFloorTexture);
00627             /* Create an image to use as texture */
00628             m_cSpace.GetFloorEntity().SaveAsImage("/tmp/argos_floor.png");
00629             m_unFloorTexture = bindTexture(QImage("/tmp/argos_floor.png"),
00630                                            GL_TEXTURE_2D,
00631                                            GL_RGB,
00632                                            QGLContext::MipmapBindOption | QGLContext::LinearFilteringBindOption);
00633             /* Clear the 'changed' flag on the floor entity */
00634             m_cSpace.GetFloorEntity().ClearChanged();
00635          }
00636          glBindTexture(GL_TEXTURE_2D, m_unFloorTexture);
00637          /* Draw the floor entity along with its texture */
00638          glBegin(GL_QUADS);
00639          glTexCoord2d(0.0f, 1.0f); glVertex3f(cArenaMinCorner.GetX(), cArenaMinCorner.GetY(), 0.0f);
00640          glTexCoord2d(1.0f, 1.0f); glVertex3f(cArenaMaxCorner.GetX(), cArenaMinCorner.GetY(), 0.0f);
00641          glTexCoord2d(1.0f, 0.0f); glVertex3f(cArenaMaxCorner.GetX(), cArenaMaxCorner.GetY(), 0.0f);
00642          glTexCoord2d(0.0f, 0.0f); glVertex3f(cArenaMinCorner.GetX(), cArenaMaxCorner.GetY(), 0.0f);
00643          glEnd();
00644       }
00645       else {
00646          /* Wrap the texture at the edges, which in this case means that it is repeated */
00647          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
00648          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
00649          glBindTexture(GL_TEXTURE_2D, m_unGroundTexture);
00650          /* Draw the floor along with its texture */
00651          glBegin(GL_QUADS);
00652          glTexCoord2f(0.0f, cArenaSize.GetY());              glVertex3f(cArenaMinCorner.GetX(), cArenaMinCorner.GetY(), 0.0f);
00653          glTexCoord2f(cArenaSize.GetX(), cArenaSize.GetY()); glVertex3f(cArenaMaxCorner.GetX(), cArenaMinCorner.GetY(), 0.0f);
00654          glTexCoord2f(cArenaSize.GetX(), 0.0f);              glVertex3f(cArenaMaxCorner.GetX(), cArenaMaxCorner.GetY(), 0.0f);
00655          glTexCoord2f(0.0f, 0.0f);                           glVertex3f(cArenaMinCorner.GetX(), cArenaMaxCorner.GetY(), 0.0f);
00656          glEnd();
00657       }
00658       /* Disable the textures */
00659       glDisable(GL_TEXTURE_2D);
00660       /* Draw walls */
00661       glDisable(GL_CULL_FACE);
00662       glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00663       glLineWidth(3.0f);
00664       glColor3f(0.0f, 0.0f, 0.0f);
00665       /* This part covers the top and bottom faces (parallel to XY) */
00666       glBegin(GL_QUADS);
00667       /* Top face */
00668       glVertex3f(cArenaMinCorner.GetX(), cArenaMinCorner.GetY(), cArenaMaxCorner.GetZ());
00669       glVertex3f(cArenaMaxCorner.GetX(), cArenaMinCorner.GetY(), cArenaMaxCorner.GetZ());
00670       glVertex3f(cArenaMaxCorner.GetX(), cArenaMaxCorner.GetY(), cArenaMaxCorner.GetZ());
00671       glVertex3f(cArenaMinCorner.GetX(), cArenaMaxCorner.GetY(), cArenaMaxCorner.GetZ());
00672       glEnd();
00673       /* This part covers the faces (South, East, North, West) */
00674       glBegin(GL_QUADS);
00675       /* South face */
00676       glVertex3f(cArenaMinCorner.GetX(), cArenaMinCorner.GetY(), cArenaMinCorner.GetZ());
00677       glVertex3f(cArenaMinCorner.GetX(), cArenaMinCorner.GetY(), cArenaMaxCorner.GetZ());
00678       glVertex3f(cArenaMinCorner.GetX(), cArenaMaxCorner.GetY(), cArenaMaxCorner.GetZ());
00679       glVertex3f(cArenaMinCorner.GetX(), cArenaMaxCorner.GetY(), cArenaMinCorner.GetZ());
00680       /* East face */
00681       glVertex3f(cArenaMinCorner.GetX(), cArenaMinCorner.GetY(), cArenaMinCorner.GetZ());
00682       glVertex3f(cArenaMaxCorner.GetX(), cArenaMinCorner.GetY(), cArenaMinCorner.GetZ());
00683       glVertex3f(cArenaMaxCorner.GetX(), cArenaMinCorner.GetY(), cArenaMaxCorner.GetZ());
00684       glVertex3f(cArenaMinCorner.GetX(), cArenaMinCorner.GetY(), cArenaMaxCorner.GetZ());
00685       /* North face */
00686       glVertex3f(cArenaMaxCorner.GetX(), cArenaMinCorner.GetY(), cArenaMinCorner.GetZ());
00687       glVertex3f(cArenaMaxCorner.GetX(), cArenaMaxCorner.GetY(), cArenaMinCorner.GetZ());
00688       glVertex3f(cArenaMaxCorner.GetX(), cArenaMaxCorner.GetY(), cArenaMaxCorner.GetZ());
00689       glVertex3f(cArenaMaxCorner.GetX(), cArenaMinCorner.GetY(), cArenaMaxCorner.GetZ());
00690       /* West face */
00691       glVertex3f(cArenaMinCorner.GetX(), cArenaMaxCorner.GetY(), cArenaMinCorner.GetZ());
00692       glVertex3f(cArenaMinCorner.GetX(), cArenaMaxCorner.GetY(), cArenaMaxCorner.GetZ());
00693       glVertex3f(cArenaMaxCorner.GetX(), cArenaMaxCorner.GetY(), cArenaMaxCorner.GetZ());
00694       glVertex3f(cArenaMaxCorner.GetX(), cArenaMaxCorner.GetY(), cArenaMinCorner.GetZ());
00695       glEnd();
00696       glLineWidth(1.0f);
00697       glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00698       glEnable(GL_CULL_FACE);
00699       /* Restore lighting */
00700       glEnable(GL_LIGHTING);
00701    }
00702 
00703    /****************************************/
00704    /****************************************/
00705 
00706    void CQTOpenGLWidget::timerEvent(QTimerEvent* pc_event) {
00707       StepSimulation();
00708    }
00709 
00710    /****************************************/
00711    /****************************************/
00712 
00713    void CQTOpenGLWidget::mouseMoveEvent(QMouseEvent* pc_event) {
00714       if(m_bMouseGrabbed) {
00715          if(! (pc_event->modifiers() & Qt::ControlModifier)) {
00716             /*
00717              * Camera movement
00718              */
00719             if(pc_event->buttons() == Qt::LeftButton) {
00720                if (m_bInvertMouse) m_cCamera.Rotate( pc_event->pos() - m_cMouseGrabPos);
00721                else m_cCamera.Rotate( m_cMouseGrabPos - pc_event->pos());
00722                m_cMouseGrabPos = pc_event->pos();
00723                DrawScene();
00724             }
00725             else if(pc_event->buttons() == Qt::RightButton) {
00726                QPoint cDelta(pc_event->pos() - m_cMouseGrabPos);
00727                m_cCamera.Move(-cDelta.y(), cDelta.x(), 0);
00728                m_cMouseGrabPos = pc_event->pos();
00729                DrawScene();
00730             }
00731             else if(pc_event->buttons() == Qt::MidButton) {
00732                QPoint cDelta(pc_event->pos() - m_cMouseGrabPos);
00733                m_cCamera.Move(0, 0, cDelta.y());
00734                m_cMouseGrabPos = pc_event->pos();
00735                DrawScene();
00736             }
00737          }
00738       }
00739    }
00740 
00741    /****************************************/
00742    /****************************************/
00743 
00744    void CQTOpenGLWidget::mousePressEvent(QMouseEvent* pc_event) {
00745       if(! (pc_event->modifiers() & Qt::ShiftModifier)) {
00746          m_bMouseGrabbed = true;
00747          m_cMouseGrabPos = pc_event->pos();
00748       }
00749       else {
00750          m_bMouseGrabbed = false;
00751          SelectInScene(pc_event->pos().x(),
00752                        pc_event->pos().y());
00753       }
00754    }
00755 
00756    /****************************************/
00757    /****************************************/
00758 
00759    void CQTOpenGLWidget::mouseReleaseEvent(QMouseEvent* pc_event) {
00760       if(m_bMouseGrabbed &&
00761          m_sSelectionInfo.IsSelected &&
00762          pc_event->modifiers() & Qt::ControlModifier) {
00763          m_bMouseGrabbed = false;
00764          CPositionalEntity* pcPosEntity = dynamic_cast<CPositionalEntity*>(
00765             m_cSpace.GetRootEntityVector()[m_sSelectionInfo.Index]);
00766          if(pcPosEntity == NULL) {
00767             CComposableEntity* pcCompEntity = dynamic_cast<CComposableEntity*>(
00768                m_cSpace.GetRootEntityVector()[m_sSelectionInfo.Index]);
00769             if(pcCompEntity->HasComponent("position")) {
00770                pcPosEntity = &pcCompEntity->GetComponent<CPositionalEntity>("position");
00771             }
00772             else if(pcCompEntity->HasComponent("body")) {
00773                pcPosEntity = &pcCompEntity->GetComponent<CPositionalEntity>("body");
00774             }
00775             else {
00776                return;
00777             }
00778          }
00779          CPlane cXYPlane(pcPosEntity->GetPosition(), CVector3::Z);
00780          CRay3 cMouseRay = GetCamera().
00781             ProjectRayFromMousePosIntoWorld(pc_event->pos().x(),
00782                                             pc_event->pos().y());
00783          CVector3 cNewPos;
00784          if(cMouseRay.Intersects(cXYPlane, cNewPos)) {
00785             pcPosEntity->MoveTo(cNewPos,
00786                                 pcPosEntity->GetOrientation());
00787             DrawScene();
00788          }
00789       }
00790       else {
00791          m_bMouseGrabbed = false;
00792       }
00793    }
00794 
00795    /****************************************/
00796    /****************************************/
00797 
00798    void CQTOpenGLWidget::keyPressEvent(QKeyEvent* pc_event) {
00799       switch(pc_event->key()) {
00800          case Qt::Key_W:
00801          case Qt::Key_Up:
00802             /* Forwards */
00803             m_mapPressedKeys[DIRECTION_UP] = true;
00804             reactToKeyEvent();
00805             break;
00806          case Qt::Key_S:
00807          case Qt::Key_Down:
00808             /* Backwards */
00809             m_mapPressedKeys[DIRECTION_DOWN] = true;
00810             reactToKeyEvent();
00811             break;
00812          case Qt::Key_A:
00813          case Qt::Key_Left:
00814             /* Left */
00815             m_mapPressedKeys[DIRECTION_LEFT] = true;
00816             reactToKeyEvent();
00817             break;
00818          case Qt::Key_D:
00819          case Qt::Key_Right:
00820             /* Right */
00821             m_mapPressedKeys[DIRECTION_RIGHT] = true;
00822             reactToKeyEvent();
00823             break;
00824          case Qt::Key_E:
00825             /* Up */
00826             m_mapPressedKeys[DIRECTION_FORWARDS] = true;
00827             reactToKeyEvent();
00828             break;
00829          case Qt::Key_Q:
00830             /* Up */
00831             m_mapPressedKeys[DIRECTION_BACKWARDS] = true;
00832             reactToKeyEvent();
00833             break;
00834          default:
00835             /* Unknown key */
00836             QGLWidget::keyPressEvent(pc_event);
00837             break;
00838       }
00839    }
00840 
00841    /****************************************/
00842    /****************************************/
00843 
00844    void CQTOpenGLWidget::keyReleaseEvent(QKeyEvent* pc_event) {
00845       switch(pc_event->key()) {
00846          case Qt::Key_Up:
00847             /* Forwards */
00848             m_mapPressedKeys[DIRECTION_UP] = false;
00849             reactToKeyEvent();
00850             break;
00851          case Qt::Key_Down:
00852             /* Backwards */
00853             m_mapPressedKeys[DIRECTION_DOWN] = false;
00854             reactToKeyEvent();
00855             break;
00856          case Qt::Key_Left:
00857             /* Left */
00858             m_mapPressedKeys[DIRECTION_LEFT] = false;
00859             reactToKeyEvent();
00860             break;
00861          case Qt::Key_Right:
00862             /* Right */
00863             m_mapPressedKeys[DIRECTION_RIGHT] = false;
00864             reactToKeyEvent();
00865             break;
00866          default:
00867             /* Unknown key */
00868             QGLWidget::keyPressEvent(pc_event);
00869             break;
00870       }
00871    }
00872 
00873    /****************************************/
00874    /****************************************/
00875 
00876    void CQTOpenGLWidget::resizeEvent(QResizeEvent* pc_event) {
00877       QToolTip::showText(pos() + geometry().center(), QString("Size: %1 x %2").arg(pc_event->size().width()).arg(pc_event->size().height()));
00878    }
00879 
00880    /****************************************/
00881    /****************************************/
00882 
00883    void CQTOpenGLWidget::reactToKeyEvent() {
00884       SInt32 nForwardsBackwards = 0;
00885       SInt32 nSideways = 0;
00886       SInt32 nUpDown = 0;
00887 
00888       if(m_mapPressedKeys[DIRECTION_UP])        nUpDown++;
00889       if(m_mapPressedKeys[DIRECTION_DOWN])      nUpDown--;
00890       if(m_mapPressedKeys[DIRECTION_LEFT])      nSideways++;
00891       if(m_mapPressedKeys[DIRECTION_RIGHT])     nSideways--;
00892       if(m_mapPressedKeys[DIRECTION_FORWARDS])  nForwardsBackwards++;
00893       if(m_mapPressedKeys[DIRECTION_BACKWARDS]) nForwardsBackwards--;
00894 
00895       if(nForwardsBackwards != 0 ||
00896          nSideways != 0 ||
00897          nUpDown != 0) {
00898          m_cCamera.Move(nForwardsBackwards, nSideways, nUpDown);
00899          DrawScene();
00900       }
00901    }
00902 
00903    /****************************************/
00904    /****************************************/
00905 
00906    void CQTOpenGLWidget::SFrameGrabData::Init(TConfigurationNode& t_tree) {
00907       if(NodeExists(t_tree, "frame_grabbing")) {
00908          TConfigurationNode& tNode = GetNode(t_tree, "frame_grabbing");
00909          std::string strBuffer;
00910          /* Parse directory, removing trailing '/' */
00911          strBuffer = ".";
00912          GetNodeAttributeOrDefault(tNode, "directory", strBuffer, strBuffer);
00913          size_t unEndPos = strBuffer.find_last_not_of("/ \t");
00914          if(unEndPos != std::string::npos) {
00915             strBuffer = strBuffer.substr(0, unEndPos+1);
00916          }
00917          Directory = strBuffer.c_str();
00918          QDir cDirectory(Directory);
00919          if(!cDirectory.exists()) {
00920             THROW_ARGOSEXCEPTION("QTOpenGL: frame grabbing directory \"" << strBuffer << "\" does not exist. Create it first!");
00921          }
00922          /* Parse base name */
00923          strBuffer = "frame_";
00924          GetNodeAttributeOrDefault(tNode, "base_name", strBuffer, strBuffer);
00925          BaseName = strBuffer.c_str();
00926          /* Parse format */
00927          strBuffer = "png";
00928          GetNodeAttributeOrDefault(tNode, "format", strBuffer, strBuffer);
00929          Format = strBuffer.c_str();
00930          /* Parse quality */
00931          GetNodeAttributeOrDefault(tNode, "quality", Quality, Quality);
00932       }
00933    }
00934 
00935    /****************************************/
00936    /****************************************/
00937 
00938 }