00001
00002
00004
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
00058 restoreFromFile();
00059
00060
00061
00062
00063 setShortcutKey(QGLViewer::SAVE_SCREENSHOT, Qt::Key_I, Qt::NoButton);
00064
00065
00066 #ifdef GL_RESCALE_NORMAL
00067
00068 glEnable(GL_RESCALE_NORMAL);
00069 #endif
00070
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
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
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
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
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
00256 QString path = filename_par.section('/', 0, -2);
00257
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
00270 }
00271
00274 bool Viewer::xvidcap()
00275 {
00276 if (videoMode==SCREEN)
00277 {
00278
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
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
00310
00311
00312
00313
00314
00315
00316
00317 if (mainController)
00318 {
00319 (mainController->getMainScene())->draw();
00320 }
00321
00322 if( selectedPoint )
00323 {
00324 selectedPoint->draw();
00325 }
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340 }
00341
00342 void Viewer::postDraw()
00343 {
00344 QGLViewer::postDraw();
00345
00346
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
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
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
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
00413 }
00414
00415
00416 }
00417
00418 void Viewer::mouseDoubleClickEvent(QMouseEvent * e)
00419 {
00420 QGLViewer::mouseDoubleClickEvent(e);
00421
00422
00423 }
00424
00425 void Viewer::mouseMoveEvent(QMouseEvent * e)
00426 {
00427
00428 QGLViewer::mouseMoveEvent(e);
00429 if( selectedPoint && interactionMode == SELECT_OBJECT )
00430 {
00431
00432 float x,y,z;
00433 manipulatedFrame()->getPosition(x,y,z);
00434
00435 selectedPoint->moveTo(x,y,z);
00436 e->accept();
00437 }
00438
00439
00440
00441
00442 }
00443
00444 void Viewer::mousePressEvent(QMouseEvent * e)
00445 {
00446
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
00455 selectedPoint->print();
00456
00457
00458 ItemList::const_iterator
00459 i=manipulatedObjects.begin(),
00460 iend = manipulatedObjects.end();
00461 while( i != iend && !(**i == selectedPoint ) )
00462 ++i;
00463 if( i==iend )
00464 {
00465 manipulatedObjects.push_back(selectedPoint);
00466 }
00467 else
00468 {
00469 delete selectedPoint;
00470 selectedPoint = *i;
00471 }
00472
00473
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
00481 }
00482
00483
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
00497 }
00498
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
00535 QString sQt(s);
00536 QFileInfo info(sQt);
00537 snapshotFormat = (info.extension(false)).upper();
00538
00539
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 }
00568 }