Documentation


viewer.cpp

Go to the documentation of this file.
00001 
00002 //                            viewer.cpp                                      //
00004 //#include <stdio.h>
00005 #include <qimage.h>
00006 #include <qfileinfo.h>
00007 
00008 #include <animal/X3DTK/Qt/mainControllerGUI/MainController.h>
00009 #include "viewer.h"
00010 
00011 using namespace qglviewer;
00012 
00013 namespace X3DTK
00014 {
00015   namespace Qt
00016   {
00017 
00018     Viewer::Viewer()
00019         : QGLViewer()
00020         , mainController(NULL)
00021         , snapshot(false)
00022         , snapshotFilename("")
00023         , snapshotCounter(0)
00024         , videoMode(DISPLAY)
00025         , selectedPoint(0)
00026     {
00027       viewerGUI = new ViewerQt(this);
00028       viewerGUI->hide();
00029       setManipulatedFrame( new ManipulatedFrame() );
00030     }
00031 
00032     Viewer::Viewer(QWidget* q, const char * c)
00033         : QGLViewer(q, c)
00034         , mainController(NULL)
00035         , snapshot(false)
00036         , snapshotFilename("")
00037         , snapshotCounter(0)
00038         , videoMode(DISPLAY)
00039         , selectedPoint(0)
00040     {
00041       viewerGUI = new ViewerQt(this);
00042       viewerGUI->hide();
00043       setManipulatedFrame( new ManipulatedFrame() );
00044     }
00045 
00046     Viewer::~Viewer()
00047     {
00048       if (viewerGUI)
00049       {
00050         delete viewerGUI;
00051         viewerGUI = NULL;
00052       }
00053     }
00054 
00055     void Viewer::init()
00056     {
00057       // Restore previous viewer state.
00058       restoreFromFile();
00059 
00060       // Redefine keyboard events
00061       // The default SAVE_SCREENSHOT shortcut is Ctrl+S and this shortcut is used to
00062       // save x3d file in the MainController. So we need to change it:
00063       setShortcutKey(QGLViewer::SAVE_SCREENSHOT, Qt::Key_I, Qt::NoButton);
00064 
00065       //portability with other OpenGL versions
00066 #ifdef GL_RESCALE_NORMAL
00067 
00068       glEnable(GL_RESCALE_NORMAL);
00069 #endif
00070       // GL_LIGHT1 is a directionnal ligth
00071       glEnable(GL_LIGHT1);
00072       const GLfloat light_ambient1[4]  =
00073         {
00074           0.2, 0.2, 0.2, 1.0
00075         };
00076       const GLfloat light_specular1[4] =
00077         {
00078           0.3, 0.3, 0.3, 1.0
00079         };
00080       const GLfloat light_diffuse1[4]  =
00081         {
00082           0.5, 0.5, 0.5, 1.0
00083         };
00084       glLightfv(GL_LIGHT1, GL_AMBIENT,  light_ambient1);
00085       glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular1);
00086       glLightfv(GL_LIGHT1, GL_DIFFUSE,  light_diffuse1);
00087 
00088       // GL_LIGHT1 follows the camera
00089       glMatrixMode(GL_MODELVIEW);
00090       glPushMatrix();
00091       glLoadIdentity();
00092       const GLfloat pos1[4] =
00093         {
00094           0.0,0.0,0.0,1.0
00095         };
00096       glLightfv(GL_LIGHT1, GL_POSITION, pos1);
00097       glPopMatrix();
00098 
00099       viewAll();
00100 
00101     }
00102 
00103     void Viewer::viewAll()
00104     {
00105       updateFrustum();
00106       showEntireScene();
00107     }
00108 
00109     void Viewer::updateFrustum()
00110     {
00111       if (mainController)
00112       {
00113         if ((mainController->getMainScene())->computeBbox())
00114         {
00115           setSceneBoundingBox(  (mainController->getMainScene())->getBboxMin().f_data(),
00116                                 (mainController->getMainScene())->getBboxMax().f_data());
00117         }
00118       }
00119     }
00120 
00125     bool Viewer::viewCapture()
00126     {
00127       QString videoName = getVideoName();
00128       if (!(snapshot || !QFile::exists(videoName)))
00129       {
00130         // View the video with xine
00131         QString path = videoName.section('/', 0, -2);
00132         QString command = "xine " + videoName + " >> " + path + "/xine.log &";
00133         std::cerr<< "--------------------------------------------------------------"<<std::endl;
00134         std::cerr<<" Background command: "<<command<<std::endl;
00135         std::cerr<< "--------------------------------------------------------------"<<std::endl;
00136         if (!system(command.ascii()))
00137           return true;
00138         else
00139           return false;
00140       }
00141       else
00142         return false;
00143     }
00144 
00146     void Viewer::drawAfterAnimation()
00147     {
00148       updateGL();
00149 
00150 
00151       // Snapshot are done every animation
00152       if (snapshot && videoMode==ANIMATION)
00153       {
00154         static QImage snapshot;
00155         snapshot = grabFrameBuffer(true);
00156         char filename[100];
00157         sprintf(filename, snapshotFilename.latin1(), snapshotCounter++);
00158         snapshot.save(filename, snapshotFormat);
00159         std::cerr<< "--------------------------------------------------------------"<<std::endl;
00160         std::cerr<< " SNAPSHOT saved in "<< filename<<std::endl;
00161         std::cerr<< "--------------------------------------------------------------"<<std::endl;
00162       }
00163     }
00164 
00172     bool Viewer::mpeg2encode()
00173     {
00174       QString filename_par = snapshotFilename.section('%', 0, 0) + ".par";
00175 
00176       // Count the number of files
00177       int filesNumber = 0;
00178       char filename[100];
00179       sprintf(filename, snapshotFilename.latin1(), filesNumber);
00180       while (QFile::exists(QString(filename)))
00181         sprintf(filename, snapshotFilename.latin1(), filesNumber++);
00182       filesNumber--;
00183 
00184       if (!(  filesNumber==0                  ||
00185               width()%16!=0 || height()%16!=0 ||
00186               snapshotFormat!="PPM"           ||
00187               filename_par.isEmpty()          ||
00188               QFile::exists(filename_par)     ||
00189               QFile::exists(getVideoName())))
00190       {
00191 
00192 
00193         QString filepattern  = snapshotFilename.section('.', 0, 0) ;
00194         std::FILE *f = fopen(filename_par, "w");
00195         fprintf(f,"\
00196                 MPEG-2 stream 30 frames/sec\n\
00197                 %s        /* name of source files */\n\
00198                 -         /* name of reconstructed images (-: don't store) */\n\
00199                 -         /* name of intra quant matrix file     (-: default matrix) */\n\
00200                 -         /* name of non intra quant matrix file (-: default matrix) */\n\
00201                 -         /* name of statistics file (-: stdout ) */\n\
00202                 2         /* input picture file format: 0=*.Y,*.U,*.V, 1=*.yuv, 2=*.ppm */\n\
00203                 %d        /* number of frames */\n\
00204                 0         /* number of first frame */\n\
00205                 00:00:00:00/* timecode of first frame */\n\
00206                 12        /* N (# of frames in GOP) */\n\
00207                 3         /* M (I/P frame distance) */\n\
00208                 0         /* ISO/IEC 11172-2 stream */\n\
00209                 0         /* 0:frame pictures, 1:field pictures */\n\
00210                 %d        /* horizontal_size */\n\
00211                 %d        /* vertical_size */\n\
00212                 2         /* aspect_ratio_information 1=square pel, 2=4:3, 3=16:9, 4=2.11:1 */\n\
00213                 5         /* frame_rate_code 1=23.976, 2=24, 3=25, 4=29.97, 5=30 frames/sec. */\n\
00214                 3000000.0 /* bit_rate (bits/s) */\n\
00215                 112       /* vbv_buffer_size (in multiples of 16 kbit) */\n\
00216                 0         /* low_delay  */\n\
00217                 0         /* constrained_parameters_flag */\n\
00218                 4         /* Profile ID: Simple = 5, Main = 4, SNR = 3, Spatial = 2, High = 1 */\n\
00219                 8         /* Level ID:   Low = 10, Main = 8, High 1440 = 6, High = 4          */\n\
00220                 0         /* progressive_sequence */\n\
00221                 1         /* chroma_format: 1=4:2:0, 2=4:2:2, 3=4:4:4 */\n\
00222                 1         /* video_format: 0=comp., 1=PAL, 2=NTSC, 3=SECAM, 4=MAC, 5=unspec. */\n\
00223                 5         /* color_primaries */\n\
00224                 5         /* transfer_characteristics */\n\
00225                 5         /* matrix_coefficients */\n\
00226                 %d        ""/* display_horizontal_size */\n\
00227                 %d        /* display_vertical_size */\n\
00228                 0         /* intra_dc_precision (0: 8 bit, 1: 9 bit, 2: 10 bit, 3: 11 bit */\n\
00229                 1         /* top_field_first */\n\
00230                 0 0 0     /* frame_pred_frame_dct (I P B) */\n\
00231                 0 0 0     /* concealment_motion_vectors (I P B) */\n\
00232                 1 1 1     /* q_scale_type  (I P B) */\n\
00233                 1 0 0     /* intra_vlc_format (I P B)*/\n\
00234                 0 0 0     /* alternate_scan (I P B) */\n\
00235                 0         /* repeat_first_field */\n\
00236                 0         /* progressive_frame */\n\
00237                 0         /* P distance between complete intra slice refresh */\n\
00238                 0         /* rate control: r (reaction parameter) */\n\
00239                 0         /* rate control: avg_act (initial average activity) */\n\
00240                 0         /* rate control: Xi (initial I frame global complexity measure) */\n\
00241                 0         /* rate control: Xp (initial P frame global complexity measure) */\n\
00242                 0         /* rate control: Xb (initial B frame global complexity measure) */\n\
00243                 0         /* rate control: d0i (initial I frame virtual buffer fullness) */\n\
00244                 0         /* rate control: d0p (initial P frame virtual buffer fullness) */\n\
00245                 0         /* rate control: d0b (initial B frame virtual buffer fullness) */\n\
00246                 2 2 11 11 /* P:  forw_hor_f_code forw_vert_f_code search_width/height */\n\
00247                 1 1 3  3  /* B1: forw_hor_f_code forw_vert_f_code search_width/height */\n\
00248                 1 1 7  7  /* B1: back_hor_f_code back_vert_f_code search_width/height */\n\
00249                 1 1 7  7  /* B2: forw_hor_f_code forw_vert_f_code search_width/height */\n\
00250                 1 1 3  3  /* B2: back_hor_f_code back_vert_f_code search_width/height */\n\
00251                 "
00252                 , filepattern.latin1(), filesNumber, width(), height(), width(), height() );
00253         fclose(f);
00254 
00255         // Generation of the video with mpeg2encode
00256         QString path = filename_par.section('/', 0, -2);
00257         // Command: mpeg2encode parameterFile.par videoFile.mpg >> videoPath/mpeg2encode.log &
00258         QString command = "mpeg2encode " + filename_par + " " + getVideoName() + " >> " + path + "/mpeg2encode.log &";
00259         std::cerr<< "--------------------------------------------------------------"<<std::endl;
00260         std::cerr<<" Background command: "<<command<<std::endl;
00261         std::cerr<< "--------------------------------------------------------------"<<std::endl;
00262         if (system(command.ascii()))
00263           return false;
00264         else
00265           return true;
00266       }
00267       else
00268         return false;
00269       //std::cerr<<" Warning: the snapshot files format has to be PPM to create a video with mpeg2encode !"<<std::endl;
00270     }
00271 
00274     bool Viewer::xvidcap()
00275     {
00276       if (videoMode==SCREEN)
00277       {
00278         // Verify the name of the files and if they existe
00279         char filename[100];
00280         sprintf(filename, snapshotFilename.latin1(), 0);
00281         if (  snapshotFilename.isEmpty()  ||
00282               snapshotFormat.isEmpty()    ||
00283               QFile::exists(QString(filename)))
00284           return false;
00285 
00286         // Command: xvidcap --fps 25 --file "video/video%04d.ppm" --cap_size 320x240 --time 0 &
00287         char command[500];
00288         sprintf(command, "xvidcap --fps 25 --file \"%s\" --cap_geometry %dx%d --time 0 &", snapshotFilename.latin1(), this->width(), this->height());
00289         std::cerr<< "--------------------------------------------------------------"<<std::endl;
00290         std::cerr<<" Background command: "<<command<<std::endl;
00291         std::cerr<< "--------------------------------------------------------------"<<std::endl;
00292         if (system(command))
00293           return false;
00294         else
00295           return true;
00296       }
00297       return false;
00298     }
00299 
00300 
00301     void Viewer::setMainController(::MainController * mainController)
00302     {
00303       this->mainController = mainController;
00304       viewerGUI->reparent(mainController, ::Qt::WType_Dialog, QPoint(0,0));
00305     }
00306 
00307     void Viewer::draw()
00308     {
00309       //std::cerr<< "Viewer::draw()"<<std::endl;
00310 
00311       //drawLight(GL_LIGHT1);
00312 
00313       //  this->show();
00314       //  this->raise();
00315 
00316       // Draws the scene.
00317       if (mainController)
00318       {
00319         (mainController->getMainScene())->draw();
00320     }
00321 
00322     if( selectedPoint )
00323     {
00324         selectedPoint->draw();
00325     }
00326     
00327       //   if( manipulatedFrame() ){
00328       //    // Save the current model view matrix
00329       //    glPushMatrix();
00330       //    // Multiply matrix to get in the frame coordinate system.
00331       //    glMultMatrixd(manipulatedFrame()->matrix());
00332       //    // Scale the drawings
00333       //    glScalef(3, 3, 3);
00334       //    // Draw an axis using the QGLViewer static function
00335       //    drawAxis();
00336       //    // Restore the original (world) coordinate system
00337       //    glPopMatrix();
00338       //    }
00339 
00340     }
00341 
00342     void Viewer::postDraw()
00343     {
00344       QGLViewer::postDraw();
00345 
00346       // Snapshot are done every display
00347       if (snapshot && videoMode==DISPLAY)
00348       {
00349         static QImage snapshot;
00350         snapshot = grabFrameBuffer(true);
00351         char filename[100];
00352         sprintf(filename, snapshotFilename.latin1(), snapshotCounter++);
00353         snapshot.save(filename, snapshotFormat);
00354         std::cerr<< "--------------------------------------------------------------"<<std::endl;
00355         std::cerr<< " SNAPSHOT saved in "<< filename<<std::endl;
00356         std::cerr<< "--------------------------------------------------------------"<<std::endl;
00357       }
00358     }
00359 
00360     QString Viewer::helpString() const
00361     {
00362       QString text("<h2>X 3 D T K :: Q t :: V i e w e r</h2>");
00363       text += "Use the mouse to move the camera around the object. ";
00364       text += "You can revolve around, zoom and translate with the three buttons. ";
00365       text += "Left and middle buttons pressed together rotate around the camera z axis<br><br>";
00366 
00367       text += "Press <b>F</b> to display the frame rate, <b>A</b> for the world axis, ";
00368       text += "<b>Alt+Return</b> for full screen mode and <b>I</b> to save a single snapshot.<br><br>";
00369 
00370       text += "Press <b>R</b> to display the viewer property where you can set:<br>";
00371       text += "       - the viewer's size and,<br>";
00372       text += "       - the video capture.<br><br>";
00373 
00374       text += "Press <b>V</b> to view all the x3d scene.<br><br>";
00375 
00376       text += "A double click aligns the closer axis with the camera (left, if close enough), fits ";
00377       text += "the zoom of the camera (middle) or re-center the scene (right).<br>";
00378       text += "A left double click while right button is pressed defines the <i>revolveAroundPoint</i>.";
00379       text += "With middle button pressed instead, it zooms on the pixel.<br><br>";
00380 
00381       text += "See also the <b>Shortcuts</b> and <b>Mouse</b> tabs and the documentation web pages:<br>";
00382       text += "               http://artis.imag.fr/Members/Gilles.Debunne/QGLViewer/index.html<br>";
00383       return text;
00384     }
00385 
00386     //-----------Mouse and key board events-------------
00387     void Viewer::keyPressEvent(QKeyEvent *e)
00388     {
00389       if (e->key()==Qt::Key_V)
00390         viewAll();
00391       else if( e->key()==Qt::Key_Control  )
00392       {
00393         interactionMode = SELECT_OBJECT;
00394         //std::cout<<"Viewer::keyPressEvent switch to SELECT_OBJECT mode"<<std::endl;
00395         e->accept();
00396       }
00397       else if( e->key()==Qt::Key_F  )
00398         std::cerr<<" Sorry: the key F (to display the frame rate on the QGLViewer window) makes the program abort. So it is temporaly disabled !"<< std::endl;
00399       else
00400         QGLViewer::keyPressEvent(e);
00401 
00402       //mainController->keyPressEvent(e);
00403     }
00404 
00405     void Viewer::keyReleaseEvent(QKeyEvent *e)
00406     {
00407       QGLViewer::keyReleaseEvent(e);
00408       if ( e->key()==Qt::Key_Control  )
00409       {
00410         interactionMode = MOVE_CAMERA;
00411         e->accept();
00412         //std::cout<<"Viewer::keyReleaseEvent switch to MOVE_CAMERA mode"<<std::endl;
00413       }
00414       
00415       //mainController->keyReleaseEvent(e);
00416     }
00417 
00418     void Viewer::mouseDoubleClickEvent(QMouseEvent * e)
00419     {
00420       QGLViewer::mouseDoubleClickEvent(e);
00421 
00422       //mainController->mouseDoubleClickEvent(e);
00423     }
00424 
00425     void Viewer::mouseMoveEvent(QMouseEvent * e)
00426     {
00427       //std::cout<<"Viewer::mouseMoveEvent"<<std::endl;
00428       QGLViewer::mouseMoveEvent(e);
00429       if( selectedPoint && interactionMode == SELECT_OBJECT )
00430       {
00431         //if( ! manipulatedFrame() ) std::cerr<<" selectedPoint but no manipulatedFrame() !!!"<< std::endl;
00432         float x,y,z;
00433         manipulatedFrame()->getPosition(x,y,z);
00434         //std::cout<<"Viewer::mouseMoveEvent, new manipulatedFrame origin: " <<  x <<", "<< y <<", "<< z << std::endl;
00435         selectedPoint->moveTo(x,y,z);
00436         e->accept();
00437       }
00438 
00439       //  // The viewer do not handle the event
00440       //  e->ignore();
00441       //mainController->mouseMoveEvent(e);
00442     }
00443 
00444     void Viewer::mousePressEvent(QMouseEvent * e)
00445     {
00446       //std::cout<<"Viewer::mousePressEvent"<<std::endl;
00447       QGLViewer::mousePressEvent(e);
00448       if( interactionMode == SELECT_OBJECT && e->button()==Qt::RightButton)
00449       {
00450         float dir[3], orig[3], threshold=0.001;
00451         camera()->convertClickToLine(e->x(), e->y(), orig, dir );
00452         if( (selectedPoint = mainController->pickPoint(orig,dir,threshold)) )
00453         {
00454           //std::cout<<"Viewer::mousePressEvent selected an object, "<< std::endl;
00455           selectedPoint->print();
00456 
00457           // check if the item is already manipulated, to avoid redundancy.
00458           ItemList::const_iterator
00459           i=manipulatedObjects.begin(),
00460             iend = manipulatedObjects.end();
00461           while( i != iend && !(**i == selectedPoint ) )
00462             ++i;
00463           if( i==iend ) // not in the list
00464           {
00465             manipulatedObjects.push_back(selectedPoint);
00466           }
00467           else // use the Item already in the list
00468           {
00469             delete selectedPoint;
00470             selectedPoint = *i;
00471           }
00472 
00473           // manipulate the item
00474           float x,y,z;
00475           selectedPoint->getPoint(x,y,z);
00476           selectedPoint->moveTo(x,y,z);
00477           manipulatedFrame()->setTranslation(x,y,z);
00478           e->accept();
00479         }
00480         //else std::cout<<"Viewer::mousePressEvent selected no object, "<< std::endl;
00481       }
00482       //else std::cout<<"interactionMode is not SELECT_OBJECT"<<std::endl;
00483       //mainController->mousePressEvent(e);
00484     }
00485 
00486     void Viewer::mouseReleaseEvent(QMouseEvent * e)
00487     {
00488       QGLViewer::mouseReleaseEvent(e);
00489       if( interactionMode == SELECT_OBJECT && e->button()==Qt::RightButton && selectedPoint)
00490       {
00491         manipulatedObjects.remove( selectedPoint );
00492         delete selectedPoint;
00493         selectedPoint = 0;
00494         e->accept();
00495       }
00496       //mainController->mouseReleaseEvent(e);
00497     }
00498     //-----------End of mouse and key board events-------------
00499 
00502     bool Viewer::setSnapshot(bool b)
00503     {
00504 
00505       if(b)
00506       {
00507         snapshot = true;
00508         snapshotCounter=0;
00509         char filename[100];
00510         sprintf(filename, snapshotFilename.latin1(), 0);
00511         if (  snapshotFilename.isEmpty()  ||
00512               snapshotFormat.isEmpty()    ||
00513               QFile::exists(QString(filename)))
00514           snapshot = false;
00515 
00516       }
00517       else
00518         snapshot=false;
00519 
00520       return snapshot;
00521     }
00522 
00525     void Viewer::setSnapshotFilename(QString s)
00526     {
00527       snapshotFilename = s;
00528       if (snapshotFilename.isEmpty())
00529       {
00530         std::cerr<<" Warning: the snapshot file name is empty !"<< std::endl;
00531         return;
00532       }
00533 
00534       // Get the extension
00535       QString sQt(s);
00536       QFileInfo info(sQt);
00537       snapshotFormat = (info.extension(false)).upper();
00538 
00539       // Check that extension has been provided and is an available format handled by Qt
00540       QStringList formatList = QImage::outputFormatList();
00541       if (!formatList.contains(snapshotFormat))
00542       {
00543         std::cerr<<" Warning: the extension is not valid !"<< std::endl;
00544         snapshotFormat = "";
00545       }
00546 
00547     }
00548 
00550     QString Viewer::getVideoName()
00551     {
00552       QString prefix(snapshotFilename.section('%', 0, 0));
00553       if(prefix.isEmpty())
00554         return "";
00555       else
00556         return prefix+".mpg";
00557     }
00558 
00560     void Viewer::setVideoName(QString fileName)
00561     {
00562       fileName = fileName.remove(".mpg");
00563       fileName = fileName.remove(".MPG");
00564       setSnapshotFilename(fileName+"%04d.ppm");
00565     }
00566 
00567   }// Qt
00568 }// X3DTK

Generated on Thu Dec 23 13:52:27 2004 by doxygen 1.3.6