ARGoS
3
A parallel, multi-engine simulator for swarm robotics
|
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 }