1 /* -*-c++-*- Present3D - Copyright (C) 1999-2006 Robert Osfield
2 *
3 * This software is open source and may be redistributed and/or modified under
4 * the terms of the GNU General Public License (GPL) version 2.0.
5 * The full license is in LICENSE.txt file included with this distribution,.
6 *
7 * This software is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * include LICENSE.txt for more details.
11 */
12
13 #include <osg/Geometry>
14 #include <osg/Texture2D>
15 #include <osg/AutoTransform>
16 #include <osg/Notify>
17 #include <osg/io_utils>
18
19
20 #include <osgDB/ReadFile>
21 #include <osgDB/WriteFile>
22 #include <osgDB/FileNameUtils>
23 #include <osgUtil/Optimizer>
24
25 #include <osgViewer/Viewer>
26 #include <osgViewer/ViewerEventHandlers>
27
28 #include <OpenThreads/Thread>
29
30 #include <osgGA/GUIEventHandler>
31 #include <osgGA/TrackballManipulator>
32 #include <osgGA/FlightManipulator>
33 #include <osgGA/DriveManipulator>
34 #include <osgGA/KeySwitchMatrixManipulator>
35 #include <osgGA/AnimationPathManipulator>
36 #include <osgGA/TerrainManipulator>
37 #include <osgGA/AnimationPathManipulator>
38 #include <osgGA/StateSetManipulator>
39 #include <osgGA/MultiTouchTrackballManipulator>
40
41 #include <osgPresentation/SlideEventHandler>
42 #include <osgPresentation/Cursor>
43
44 #include "ReadShowFile.h"
45 #include "PointsEventHandler.h"
46 #include "Cluster.h"
47 #include "ExportHTML.h"
48 #include "SpellChecker.h"
49
50 #include <sstream>
51 #include <fstream>
52 #include <iostream>
53
54
55 #include <string.h>
56
57 #ifdef USE_SDL
58 #include "SDLIntegration.h"
59 #endif
60
61 #ifdef OSG_LIBRARY_STATIC
62
63 // include the plugins we need
64 USE_OSGPLUGIN(ive)
65 USE_OSGPLUGIN(osg)
66 USE_OSGPLUGIN(osg2)
67 USE_OSGPLUGIN(p3d)
68 USE_OSGPLUGIN(paths)
69 USE_OSGPLUGIN(rgb)
70 USE_OSGPLUGIN(OpenFlight)
71 USE_OSGPLUGIN(obj)
72
73 #ifdef USE_FREETYPE
74 USE_OSGPLUGIN(freetype)
75 #endif
76
77 #ifdef USE_PNG
78 USE_OSGPLUGIN(png)
79 #endif
80
81 #ifdef USE_JPEG
82 USE_OSGPLUGIN(jpeg)
83 #endif
84
85 #ifdef USE_FFMPEG
86 USE_OSGPLUGIN(ffmpeg)
87 #endif
88
89 #ifdef USE_POPPLER_CAIRO
90 USE_OSGPLUGIN(pdf)
91 #endif
92
93 #ifdef USE_CURL
94 USE_OSGPLUGIN(curl)
95 #endif
96
97 USE_DOTOSGWRAPPER_LIBRARY(osg)
98 USE_DOTOSGWRAPPER_LIBRARY(osgFX)
99 USE_DOTOSGWRAPPER_LIBRARY(osgParticle)
100 USE_DOTOSGWRAPPER_LIBRARY(osgShadow)
101 USE_DOTOSGWRAPPER_LIBRARY(osgSim)
102 USE_DOTOSGWRAPPER_LIBRARY(osgTerrain)
103 USE_DOTOSGWRAPPER_LIBRARY(osgText)
104 USE_DOTOSGWRAPPER_LIBRARY(osgViewer)
105 USE_DOTOSGWRAPPER_LIBRARY(osgVolume)
106 USE_DOTOSGWRAPPER_LIBRARY(osgWidget)
107
108 USE_SERIALIZER_WRAPPER_LIBRARY(osg)
109 USE_SERIALIZER_WRAPPER_LIBRARY(osgAnimation)
110 USE_SERIALIZER_WRAPPER_LIBRARY(osgFX)
111 USE_SERIALIZER_WRAPPER_LIBRARY(osgManipulator)
112 USE_SERIALIZER_WRAPPER_LIBRARY(osgParticle)
113 USE_SERIALIZER_WRAPPER_LIBRARY(osgShadow)
114 USE_SERIALIZER_WRAPPER_LIBRARY(osgSim)
115 USE_SERIALIZER_WRAPPER_LIBRARY(osgTerrain)
116 USE_SERIALIZER_WRAPPER_LIBRARY(osgText)
117 USE_SERIALIZER_WRAPPER_LIBRARY(osgVolume)
118
119 // include the platform specific GraphicsWindow implementation.
120 USE_GRAPHICSWINDOW()
121
122 #endif
123
124 static const char* s_version = "1.4 beta";
125
setViewer(osgViewer::Viewer & viewer,float width,float height,float distance)126 void setViewer(osgViewer::Viewer& viewer, float width, float height, float distance)
127 {
128 double vfov = osg::RadiansToDegrees(atan2(height/2.0f,distance)*2.0);
129 // double hfov = osg::RadiansToDegrees(atan2(width/2.0f,distance)*2.0);
130
131 viewer.getCamera()->setProjectionMatrixAsPerspective( vfov, width/height, 0.1, 1000.0);
132
133 OSG_INFO<<"setProjectionMatrixAsPerspective( "<<vfov<<", "<<width/height<<", "<<0.1<<", "<<1000.0<<");"<<std::endl;
134 }
135
136 class ForwardToDeviceEventHandler : public osgGA::GUIEventHandler {
137 public:
ForwardToDeviceEventHandler(osgGA::Device * device,bool format_mouse_events)138 ForwardToDeviceEventHandler(osgGA::Device* device, bool format_mouse_events) : osgGA::GUIEventHandler(), _device(device), _forwardMouseEvents(format_mouse_events) {}
139
handle(const osgGA::GUIEventAdapter & ea,osgGA::GUIActionAdapter & aa,osg::Object *,osg::NodeVisitor *)140 virtual bool handle (const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa, osg::Object *, osg::NodeVisitor *)
141 {
142 switch (ea.getEventType())
143 {
144 case osgGA::GUIEventAdapter::PUSH:
145 case osgGA::GUIEventAdapter::RELEASE:
146 case osgGA::GUIEventAdapter::MOVE:
147 case osgGA::GUIEventAdapter::DRAG:
148 case osgGA::GUIEventAdapter::SCROLL:
149 if (_forwardMouseEvents)
150 _device->sendEvent(ea);
151 break;
152
153 default:
154 _device->sendEvent(ea);
155 break;
156 }
157 return false;
158 }
159
160
handle(osgGA::Event * event,osg::Object * object,osg::NodeVisitor * nv)161 bool handle(osgGA::Event* event, osg::Object* object, osg::NodeVisitor* nv)
162 {
163 if (event->asGUIEventAdapter())
164 return osgGA::GUIEventHandler::handle(event, object, nv);
165 else
166 {
167 _device->sendEvent(*event);
168 return false;
169 }
170 }
171
172
173 private:
174 osg::ref_ptr<osgGA::Device> _device;
175 bool _forwardMouseEvents;
176 };
177
178
179 class DumpEventHandler : public osgGA::GUIEventHandler {
180 public:
DumpEventHandler()181 DumpEventHandler() : osgGA::GUIEventHandler() {}
182
handle(const osgGA::GUIEventAdapter & ea,osgGA::GUIActionAdapter & aa,osg::Object *,osg::NodeVisitor *)183 virtual bool handle (const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa, osg::Object *, osg::NodeVisitor *)
184 {
185 switch (ea.getEventType())
186 {
187 case osgGA::GUIEventAdapter::FRAME:
188 return false;
189 break;
190 case osgGA::GUIEventAdapter::PUSH:
191 std::cout << "PUSH: ";
192 break;
193 case osgGA::GUIEventAdapter::RELEASE:
194 std::cout << "RELEASE: ";
195 break;
196 case osgGA::GUIEventAdapter::MOVE:
197 std::cout << "MOVE: ";
198 break;
199 case osgGA::GUIEventAdapter::DRAG:
200 std::cout << "DRAG: ";
201 break;
202 case osgGA::GUIEventAdapter::SCROLL:
203 std::cout << "SCROLL: ";
204 break;
205 break;
206
207 default:
208 std::cout << ea.getEventType() << " ";
209 break;
210 }
211 std::cout << ea.getX() << "/" << ea.getY() << " " << ea.isMultiTouchEvent() << std::endl;
212 return false;
213 }
214
215
handle(osgGA::Event * event,osg::Object * object,osg::NodeVisitor * nv)216 bool handle(osgGA::Event* event, osg::Object* object, osg::NodeVisitor* nv)
217 {
218 if (event->asGUIEventAdapter())
219 return osgGA::GUIEventHandler::handle(event, object, nv);
220 else
221 {
222 return false;
223 }
224 }
225
226
227 private:
228 };
229
230
231
232 enum P3DApplicationType
233 {
234 VIEWER,
235 MASTER,
236 SLAVE
237 };
238
239
processLoadedModel(osg::ref_ptr<osg::Node> & loadedModel,int optimizer_options,const std::string & cursorFileName)240 void processLoadedModel(osg::ref_ptr<osg::Node>& loadedModel, int optimizer_options, const std::string& cursorFileName)
241 {
242 if (!loadedModel) return;
243
244 #if !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE)
245
246 // add back in enabling of the GL_ALPHA_TEST to get around the core OSG no longer setting it by default for opaque bins.
247 // the alpha test is required for the volume rendering alpha clipping to work.
248 loadedModel->getOrCreateStateSet()->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
249 #endif
250
251 // optimize the scene graph, remove redundant nodes and state etc.
252 osgUtil::Optimizer optimizer;
253 optimizer.optimize(loadedModel.get(), optimizer_options);
254
255 if (!cursorFileName.empty())
256 {
257 osg::ref_ptr<osg::Group> group = new osg::Group;
258 group->addChild(loadedModel.get());
259
260 OSG_NOTICE<<"Creating Cursor"<<std::endl;
261 group->addChild(new osgPresentation::Cursor(cursorFileName, 20.0f));
262
263 loadedModel = group;
264 }
265 }
266
addDeviceTo(osgViewer::Viewer & viewer,const std::string & device_name,bool forward_mouse_events)267 void addDeviceTo(osgViewer::Viewer& viewer, const std::string& device_name, bool forward_mouse_events)
268 {
269 osg::ref_ptr<osgGA::Device> dev = osgDB::readRefFile<osgGA::Device>(device_name);
270 if (dev.valid())
271 {
272 OSG_INFO << "Adding Device : " << device_name << std::endl;
273 viewer.addDevice(dev.get());
274
275 if ((dev->getCapabilities() & osgGA::Device::SEND_EVENTS))
276 viewer.getEventHandlers().push_front(new ForwardToDeviceEventHandler(dev.get(), forward_mouse_events));
277 }
278 else
279 {
280 OSG_WARN << "could not open device: " << device_name << std::endl;
281 }
282 }
283
284
main(int argc,char ** argv)285 int main( int argc, char **argv )
286 {
287 // use an ArgumentParser object to manage the program arguments.
288 osg::ArgumentParser arguments(&argc,argv);
289
290 // set up the usage document, in case we need to print out how to use this program.
291 arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
292 arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the application for presenting 3D interactive slide shows.");
293 arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
294 arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
295 arguments.getApplicationUsage()->addCommandLineOption("-a","Turn auto stepping on by default");
296 arguments.getApplicationUsage()->addCommandLineOption("-d <float>","Time duration in seconds between layers/slides");
297 arguments.getApplicationUsage()->addCommandLineOption("-s <float> <float> <float>","width, height, distance and of the screen away from the viewer");
298 arguments.getApplicationUsage()->addCommandLineOption("--viewer","Start Present3D as the viewer version.");
299 arguments.getApplicationUsage()->addCommandLineOption("--authoring","Start Present3D as the authoring version, license required.");
300 arguments.getApplicationUsage()->addCommandLineOption("--master","Start Present3D as the master version, license required.");
301 arguments.getApplicationUsage()->addCommandLineOption("--slave","Start Present3D as the slave version, license required.");
302 arguments.getApplicationUsage()->addCommandLineOption("--publishing","Start Present3D as the publishing version, license required.");
303 arguments.getApplicationUsage()->addCommandLineOption("--timeDelayOnNewSlideWithMovies","Set the time delay on new slide with movies, done to allow movie threads to get in sync with rendering thread.");
304 arguments.getApplicationUsage()->addCommandLineOption("--targetFrameRate","Set the target frame rate, defaults to 80Hz.");
305 arguments.getApplicationUsage()->addCommandLineOption("--version","Report the Present3D version.");
306 arguments.getApplicationUsage()->addCommandLineOption("--print <filename>","Print out slides to a series of image files.");
307 arguments.getApplicationUsage()->addCommandLineOption("--html <filename>","Print out slides to a series of html & image files.");
308 arguments.getApplicationUsage()->addCommandLineOption("--loop","Switch on looping of presentation.");
309 arguments.getApplicationUsage()->addCommandLineOption("--devices","Print the Video input capability via QuickTime and exit.");
310 arguments.getApplicationUsage()->addCommandLineOption("--forwardMouseEvents","forward also mouse/touch-events to the devices");
311 arguments.getApplicationUsage()->addCommandLineOption("--suppressEnvTags", "suppresses all found ENV-tags in the presentation");
312
313 // add alias from xml to p3d to provide backwards compatibility for old p3d files.
314 osgDB::Registry::instance()->addFileExtensionAlias("xml","p3d");
315
316 // if user requests devices video capability.
317 if (arguments.read("-devices") || arguments.read("--devices"))
318 {
319 // Force load QuickTime plugin, probe video capability, exit
320 osgDB::readRefImageFile("devices.live");
321 return 1;
322 }
323
324 bool suppress_env_tags = false;
325 if (arguments.read("--suppressEnvTags"))
326 suppress_env_tags = true;
327
328 // read any env vars from presentations before we create viewer to make sure the viewer
329 // utilises these env vars
330 if (!suppress_env_tags && p3d::readEnvVars(arguments))
331 {
332 osg::DisplaySettings::instance()->readEnvironmentalVariables();
333 }
334
335 // set up any logins required for http access
336 std::string url, username, password;
337 while(arguments.read("--login",url, username, password))
338 {
339 if (!osgDB::Registry::instance()->getAuthenticationMap())
340 {
341 osgDB::Registry::instance()->setAuthenticationMap(new osgDB::AuthenticationMap);
342 osgDB::Registry::instance()->getAuthenticationMap()->addAuthenticationDetails(
343 url,
344 new osgDB::AuthenticationDetails(username, password)
345 );
346 }
347 }
348
349
350
351 #ifdef USE_SDL
352 SDLIntegration sdlIntegration;
353
354 osg::notify(osg::INFO)<<"USE_SDL"<<std::endl;
355 #endif
356
357 bool doSetViewer = true;
358 std::string configurationFile;
359
360 // check env vars for configuration file
361 const char* str = getenv("PRESENT3D_CONFIG_FILE");
362 if (!str) str = getenv("OSG_CONFIG_FILE");
363 if (str) configurationFile = str;
364
365 // check command line parameters for configuration file.
366 while (arguments.read("-c",configurationFile)) {}
367
368 osg::Vec4 clearColor(0.0f,0.0f,0.0f,0.0f);
369
370 while (arguments.read("--clear-color",clearColor[0],clearColor[1],clearColor[2],clearColor[3])) {}
371
372 std::string filename;
373 if (arguments.read("--spell-check",filename))
374 {
375 p3d::SpellChecker spellChecker;
376 spellChecker.checkP3dXml(filename);
377 return 1;
378 }
379
380 if (arguments.read("--strip-text",filename))
381 {
382 p3d::XmlPatcher patcher;
383 // patcher.stripP3dXml(filename, osg::notify(osg::NOTICE));
384
385 osg::ref_ptr<osgDB::XmlNode> newNode = patcher.simplifyP3dXml(filename);
386 if (newNode.valid())
387 {
388 newNode->write(std::cout);
389 }
390 return 1;
391 }
392
393 std::string lhs_filename, rhs_filename;
394 if (arguments.read("--merge",lhs_filename, rhs_filename))
395 {
396 p3d::XmlPatcher patcher;
397 osg::ref_ptr<osgDB::XmlNode> newNode = patcher.mergeP3dXml(lhs_filename, rhs_filename);
398 if (newNode.valid())
399 {
400 newNode->write(std::cout);
401 }
402 return 1;
403 }
404
405
406 // construct the viewer.
407 osgViewer::Viewer viewer(arguments);
408
409 // set clear colour to black by default.
410 viewer.getCamera()->setClearColor(clearColor);
411
412 if (!configurationFile.empty())
413 {
414 viewer.readConfiguration(configurationFile);
415 doSetViewer = false;
416 }
417
418 bool forwardMouseEvents = false;
419 if (arguments.read("--forwardMouseEvents"))
420 forwardMouseEvents = true;
421
422 const char* p3dDevice = getenv("P3D_DEVICE");
423 if (p3dDevice)
424 {
425 osgDB::StringList devices;
426 osgDB::split(p3dDevice, devices);
427 for(osgDB::StringList::iterator i = devices.begin(); i != devices.end(); ++i)
428 {
429 addDeviceTo(viewer, *i, forwardMouseEvents);
430 }
431 }
432
433
434 std::string device;
435 while (arguments.read("--device", device))
436 {
437 addDeviceTo(viewer, device, forwardMouseEvents);
438
439 }
440
441 if (arguments.read("--http-control"))
442 {
443
444 std::string server_address = "localhost";
445 std::string server_port = "8080";
446 std::string document_root = "htdocs";
447
448 while (arguments.read("--http-server-address", server_address)) {}
449 while (arguments.read("--http-server-port", server_port)) {}
450 while (arguments.read("--http-document-root", document_root)) {}
451
452 osg::ref_ptr<osgDB::Options> device_options = new osgDB::Options("documentRegisteredHandlers");
453
454 osg::ref_ptr<osgGA::Device> rest_http_device = osgDB::readRefFile<osgGA::Device>(server_address+":"+server_port+"/"+document_root+".resthttp", device_options.get());
455 if (rest_http_device.valid())
456 {
457 viewer.addDevice(rest_http_device.get());
458 }
459 }
460
461 // set up stereo masks
462
463 viewer.getCamera()->setCullMaskLeft(0x00000001);
464 viewer.getCamera()->setCullMaskRight(0x00000002);
465
466 bool assignLeftCullMaskForMono = true;
467 if (assignLeftCullMaskForMono)
468 {
469 viewer.getCamera()->setCullMask(viewer.getCamera()->getCullMaskLeft());
470 }
471 else
472 {
473 viewer.getCamera()->setCullMask(0xffffffff);
474 }
475
476 // set up the camera manipulators.
477 {
478 osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
479
480 keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::MultiTouchTrackballManipulator() );
481 keyswitchManipulator->addMatrixManipulator( '2', "Flight", new osgGA::FlightManipulator() );
482 keyswitchManipulator->addMatrixManipulator( '3', "Drive", new osgGA::DriveManipulator() );
483 keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() );
484
485 std::string pathfile;
486 char keyForAnimationPath = '5';
487 while (arguments.read("-p",pathfile))
488 {
489 osgGA::AnimationPathManipulator* apm = new osgGA::AnimationPathManipulator(pathfile);
490 if (apm || !apm->valid())
491 {
492 unsigned int num = keyswitchManipulator->getNumMatrixManipulators();
493 keyswitchManipulator->addMatrixManipulator( keyForAnimationPath, "Path", apm );
494 keyswitchManipulator->selectMatrixManipulator(num);
495 ++keyForAnimationPath;
496 }
497 }
498
499 viewer.setCameraManipulator( keyswitchManipulator.get() );
500 }
501
502 //viewer.getEventHandlers().push_front(new DumpEventHandler());
503
504 // add the state manipulator
505 osg::ref_ptr<osgGA::StateSetManipulator> ssManipulator = new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet());
506 ssManipulator->setKeyEventToggleTexturing('e');
507 viewer.addEventHandler( ssManipulator.get() );
508
509 // add the state manipulator
510 viewer.addEventHandler( new osgViewer::StatsHandler() );
511
512 viewer.addEventHandler( new osgViewer::WindowSizeHandler() );
513
514 // neeed to address.
515 // viewer.getScene()->getUpdateVisitor()->setTraversalMode(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN);
516
517
518 const char* p3dCursor = getenv("P3D_CURSOR");
519 std::string cursorFileName( p3dCursor ? p3dCursor : "");
520 while (arguments.read("--cursor",cursorFileName)) {}
521
522 const char* p3dShowCursor = getenv("P3D_SHOW_CURSOR");
523 std::string showCursor( p3dShowCursor ? p3dShowCursor : "YES");
524 while (arguments.read("--show-cursor")) { showCursor="YES"; }
525 while (arguments.read("--hide-cursor")) { showCursor="NO"; }
526
527 bool hideCursor = (showCursor=="No" || showCursor=="NO" || showCursor=="no");
528
529 while (arguments.read("--set-viewer")) { doSetViewer = true; }
530
531 while (arguments.read("--no-set-viewer")) { doSetViewer = false; }
532
533 // if we want to hide the cursor override the custom cursor.
534 if (hideCursor) cursorFileName.clear();
535
536
537 // cluster related entries.
538 int socketNumber=8100;
539 while (arguments.read("-n",socketNumber)) {}
540
541 float camera_fov=-1.0f;
542 while (arguments.read("-f",camera_fov)) {}
543
544 float camera_offset=45.0f;
545 while (arguments.read("-o",camera_offset)) {}
546
547
548 std::string exportName;
549 while (arguments.read("--print",exportName)) {}
550
551 while (arguments.read("--html",exportName)) {}
552
553 // read any time delay argument.
554 float timeDelayBetweenSlides = 1.0f;
555 while (arguments.read("-d",timeDelayBetweenSlides)) {}
556
557 bool autoSteppingActive = false;
558 while (arguments.read("-a")) autoSteppingActive = true;
559
560 bool loopPresentation = false;
561 while (arguments.read("--loop")) loopPresentation = true;
562
563 {
564 // set update hte default traversal mode settings for update visitor
565 // default to osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN.
566 osg::NodeVisitor::TraversalMode updateTraversalMode = osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN; // viewer.getUpdateVisitor()->getTraversalMode();
567
568 const char* p3dUpdateStr = getenv("P3D_UPDATE");
569 if (p3dUpdateStr)
570 {
571 std::string updateStr(p3dUpdateStr);
572 if (updateStr=="active" || updateStr=="Active" || updateStr=="ACTIVE") updateTraversalMode = osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN;
573 else if (updateStr=="all" || updateStr=="All" || updateStr=="ALL") updateTraversalMode = osg::NodeVisitor::TRAVERSE_ALL_CHILDREN;
574 }
575
576 while(arguments.read("--update-active")) updateTraversalMode = osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN;
577 while(arguments.read("--update-all")) updateTraversalMode = osg::NodeVisitor::TRAVERSE_ALL_CHILDREN;
578
579 viewer.getUpdateVisitor()->setTraversalMode(updateTraversalMode);
580 }
581
582
583 // register the slide event handler - which moves the presentation from slide to slide, layer to layer.
584 osg::ref_ptr<osgPresentation::SlideEventHandler> seh = new osgPresentation::SlideEventHandler(&viewer);
585 viewer.addEventHandler(seh.get());
586
587 seh->setAutoSteppingActive(autoSteppingActive);
588 seh->setTimeDelayBetweenSlides(timeDelayBetweenSlides);
589 seh->setLoopPresentation(loopPresentation);
590
591 double targetFrameRate = 80.0;
592 while (arguments.read("--targetFrameRate",targetFrameRate)) {}
593
594
595 // set the time delay
596 float timeDelayOnNewSlideWithMovies = 0.4f;
597 while (arguments.read("--timeDelayOnNewSlideWithMovies",timeDelayOnNewSlideWithMovies)) {}
598 seh->setTimeDelayOnNewSlideWithMovies(timeDelayOnNewSlideWithMovies);
599
600 // set up optimizer options
601 unsigned int optimizer_options = osgUtil::Optimizer::DEFAULT_OPTIMIZATIONS;
602 bool release_and_compile = false;
603 while (arguments.read("--release-and-compile"))
604 {
605 release_and_compile = true;
606 }
607 seh->setReleaseAndCompileOnEachNewSlide(release_and_compile);
608 if (release_and_compile)
609 {
610 // make sure that imagery stays around after being applied to textures.
611 viewer.getDatabasePager()->setUnrefImageDataAfterApplyPolicy(true,false);
612 optimizer_options &= ~osgUtil::Optimizer::OPTIMIZE_TEXTURE_SETTINGS;
613 }
614 //
615 // osgDB::Registry::instance()->getOrCreateDatabasePager()->setUnrefImageDataAfterApplyPolicy(true,false);
616 // optimizer_options &= ~osgUtil::Optimizer::OPTIMIZE_TEXTURE_SETTINGS;
617 // osg::Texture::getTextureObjectManager()->setExpiryDelay(0.0f);
618 // osgDB::Registry::instance()->getOrCreateDatabasePager()->setExpiryDelay(1.0f);
619
620 // register the handler for modifying the point size
621 osg::ref_ptr<PointsEventHandler> peh = new PointsEventHandler;
622 viewer.addEventHandler(peh.get());
623
624 // add the screen capture handler
625 std::string screenCaptureFilename = "screen_shot.jpg";
626 while(arguments.read("--screenshot", screenCaptureFilename)) {}
627 osg::ref_ptr<osgViewer::ScreenCaptureHandler::WriteToFile> writeFile = new osgViewer::ScreenCaptureHandler::WriteToFile(
628 osgDB::getNameLessExtension(screenCaptureFilename),
629 osgDB::getFileExtension(screenCaptureFilename) );
630 osg::ref_ptr<osgViewer::ScreenCaptureHandler> screenCaptureHandler = new osgViewer::ScreenCaptureHandler(writeFile.get());
631 screenCaptureHandler->setKeyEventTakeScreenShot('m');//osgGA::GUIEventAdapter::KEY_Print);
632 screenCaptureHandler->setKeyEventToggleContinuousCapture('M');
633 viewer.addEventHandler(screenCaptureHandler.get());
634
635 // osg::DisplaySettings::instance()->setSplitStereoAutoAjustAspectRatio(false);
636
637 float width = osg::DisplaySettings::instance()->getScreenWidth();
638 float height = osg::DisplaySettings::instance()->getScreenHeight();
639 float distance = osg::DisplaySettings::instance()->getScreenDistance();
640 while (arguments.read("-s", width, height, distance))
641 {
642 osg::DisplaySettings::instance()->setScreenDistance(distance);
643 osg::DisplaySettings::instance()->setScreenHeight(height);
644 osg::DisplaySettings::instance()->setScreenWidth(width);
645 }
646
647 std::string outputFileName;
648 while(arguments.read("--output",outputFileName)) {}
649
650
651 // get details on keyboard and mouse bindings used by the viewer.
652 viewer.getUsage(*arguments.getApplicationUsage());
653
654 // if user request help write it out to cout.
655 unsigned int helpType = 0;
656 if ((helpType = arguments.readHelpType()))
657 {
658 arguments.getApplicationUsage()->write(std::cout, helpType);
659 return 1;
660 }
661
662 P3DApplicationType P3DApplicationType = VIEWER;
663
664 str = getenv("PRESENT3D_TYPE");
665 if (str)
666 {
667 if (strcmp(str,"viewer")==0) P3DApplicationType = VIEWER;
668 else if (strcmp(str,"master")==0) P3DApplicationType = MASTER;
669 else if (strcmp(str,"slave")==0) P3DApplicationType = SLAVE;
670 }
671
672 while (arguments.read("--viewer")) { P3DApplicationType = VIEWER; }
673 while (arguments.read("--master")) { P3DApplicationType = MASTER; }
674 while (arguments.read("--slave")) { P3DApplicationType = SLAVE; }
675
676 while (arguments.read("--version"))
677 {
678 std::string appTypeName = "invalid";
679 switch(P3DApplicationType)
680 {
681 case(VIEWER): appTypeName = "viewer"; break;
682 case(MASTER): appTypeName = "master"; break;
683 case(SLAVE): appTypeName = "slave"; break;
684 }
685
686 osg::notify(osg::NOTICE)<<std::endl;
687 osg::notify(osg::NOTICE)<<"Present3D "<<appTypeName<<" version : "<<s_version<<std::endl;
688 osg::notify(osg::NOTICE)<<std::endl;
689
690 return 0;
691 }
692
693 // any option left unread are converted into errors to write out later.
694 //arguments.reportRemainingOptionsAsUnrecognized();
695
696 // report any errors if they have ocured when parsing the program aguments.
697 if (arguments.errors())
698 {
699 arguments.writeErrorMessages(osg::notify(osg::INFO));
700 return 1;
701 }
702
703
704 // read files name from arguments.
705 p3d::FileNameList xmlFiles, normalFiles;
706 if (!p3d::getFileNames(arguments, xmlFiles, normalFiles))
707 {
708 osg::notify(osg::NOTICE)<<std::endl;
709 osg::notify(osg::NOTICE)<<"No file specified, please specify and file to load."<<std::endl;
710 osg::notify(osg::NOTICE)<<std::endl;
711 return 1;
712 }
713
714
715
716 bool viewerInitialized = false;
717 if (!xmlFiles.empty())
718 {
719 osg::ref_ptr<osg::Node> holdingModel = p3d::readHoldingSlide(xmlFiles.front());
720
721 if (holdingModel.valid())
722 {
723 viewer.setSceneData(holdingModel.get());
724
725 seh->selectSlide(0);
726
727 if (!viewerInitialized)
728 {
729 // pass the global stateset to the point event handler so that it can
730 // alter the point size of all points in the scene.
731 peh->setStateSet(viewer.getCamera()->getOrCreateStateSet());
732
733 // create the windows and run the threads.
734 viewer.realize();
735
736 if (doSetViewer) setViewer(viewer, width, height, distance);
737
738 viewerInitialized = true;
739 }
740
741 seh->home();
742
743 // render a frame
744 viewer.frame();
745 }
746 }
747
748 osg::Timer timer;
749 osg::Timer_t start_tick = timer.tick();
750
751
752 osg::ref_ptr<osgDB::ReaderWriter::Options> cacheAllOption = new osgDB::ReaderWriter::Options;
753 if(suppress_env_tags)
754 cacheAllOption->setPluginStringData("suppressEnvTags", "true");
755
756 cacheAllOption->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_ALL);
757 osgDB::Registry::instance()->setOptions(cacheAllOption.get());
758
759 // read the scene from the list of file specified commandline args.
760 osg::ref_ptr<osg::Node> loadedModel = p3d::readShowFiles(arguments,cacheAllOption.get()); // osgDB::readNodeFiles(arguments, cacheAllOption.get());
761
762
763 osgDB::Registry::instance()->setOptions( 0 );
764
765
766 // if no model has been successfully loaded report failure.
767 if (!loadedModel)
768 {
769 osg::notify(osg::INFO) << arguments.getApplicationName() <<": No data loaded" << std::endl;
770 return 1;
771 }
772
773 osg::Timer_t end_tick = timer.tick();
774
775 osg::notify(osg::INFO) << "Time to load = "<<timer.delta_s(start_tick,end_tick)<<std::endl;
776
777
778 if (loadedModel->getNumDescriptions()>0)
779 {
780 for(unsigned int i=0; i<loadedModel->getNumDescriptions(); ++i)
781 {
782 const std::string& desc = loadedModel->getDescription(i);
783 if (desc=="loop")
784 {
785 osg::notify(osg::NOTICE)<<"Enabling looping"<<std::endl;
786 seh->setLoopPresentation(true);
787 }
788 else if (desc=="auto")
789 {
790 osg::notify(osg::NOTICE)<<"Enabling auto run"<<std::endl;
791 seh->setAutoSteppingActive(true);
792 }
793 }
794 }
795
796
797 processLoadedModel(loadedModel, optimizer_options, cursorFileName);
798
799 // set the scene to render
800 viewer.setSceneData(loadedModel.get());
801
802 if (!viewerInitialized)
803 {
804 // pass the global stateset to the point event handler so that it can
805 // alter the point size of all points in the scene.
806 peh->setStateSet(viewer.getCamera()->getOrCreateStateSet());
807
808 // create the windows and run the threads.
809 viewer.realize();
810
811 if (doSetViewer) setViewer(viewer, width, height, distance);
812
813 viewerInitialized = true;
814 }
815
816
817
818
819 // pass the model to the slide event handler so it knows which to manipulate.
820 seh->set(loadedModel.get());
821 seh->selectSlide(0);
822
823 seh->home();
824
825 if (!outputFileName.empty())
826 {
827 osgDB::writeNodeFile(*loadedModel,outputFileName);
828 return 0;
829 }
830
831
832 if (!cursorFileName.empty() || hideCursor)
833 {
834 // have to add a frame in here to avoid problems with X11 threading issue on switching off the cursor
835 // not yet sure why it makes a difference, but it at least fixes the crash that would otherwise occur
836 // under X11.
837 viewer.frame();
838
839 // switch off the cursor
840 osgViewer::Viewer::Windows windows;
841 viewer.getWindows(windows);
842 for(osgViewer::Viewer::Windows::iterator itr = windows.begin();
843 itr != windows.end();
844 ++itr)
845 {
846 (*itr)->useCursor(false);
847 }
848 }
849
850 osg::Timer_t startOfFrameTick = osg::Timer::instance()->tick();
851 double targetFrameTime = 1.0/targetFrameRate;
852
853 if (exportName.empty())
854 {
855 // objects for managing the broadcasting and recieving of camera packets.
856 CameraPacket cp;
857 Broadcaster bc;
858 Receiver rc;
859 bc.setPort(static_cast<short int>(socketNumber));
860 rc.setPort(static_cast<short int>(socketNumber));
861
862 bool masterKilled = false;
863 DataConverter scratchPad(1024);
864
865 while( !viewer.done() && !masterKilled)
866 {
867 // wait for all cull and draw threads to complete.
868 viewer.advance();
869
870 osg::Timer_t currentTick = osg::Timer::instance()->tick();
871 double deltaTime = osg::Timer::instance()->delta_s(startOfFrameTick, currentTick);
872
873
874 if (deltaTime<targetFrameTime)
875 {
876 OpenThreads::Thread::microSleep(static_cast<unsigned int>((targetFrameTime-deltaTime)*1000000.0));
877 }
878
879 startOfFrameTick = osg::Timer::instance()->tick();
880
881 #if 0
882 if (kmcb)
883 {
884 double time = kmcb->getTime();
885 viewer.getFrameStamp()->setReferenceTime(time);
886 }
887 #endif
888
889 #ifdef USE_SDL
890 sdlIntegration.update(viewer);
891 #endif
892
893 if (P3DApplicationType==MASTER)
894 {
895 // take camera zero as the guide.
896 osg::Matrix modelview(viewer.getCamera()->getViewMatrix());
897
898 cp.setPacket(modelview,viewer.getFrameStamp());
899
900 // cp.readEventQueue(viewer);
901
902 scratchPad.reset();
903 scratchPad.write(cp);
904
905 scratchPad.reset();
906 scratchPad.read(cp);
907
908 bc.setBuffer(scratchPad.startPtr(), scratchPad.numBytes());
909
910 std::cout << "bc.sync()"<<scratchPad.numBytes()<<std::endl;
911
912 bc.sync();
913 }
914 else if (P3DApplicationType==SLAVE)
915 {
916 rc.setBuffer(scratchPad.startPtr(), scratchPad.numBytes());
917
918 rc.sync();
919
920 scratchPad.reset();
921 scratchPad.read(cp);
922
923 // cp.writeEventQueue(viewer);
924
925 if (cp.getMasterKilled())
926 {
927 std::cout << "Received master killed."<<std::endl;
928 // break out of while (!done) loop since we've now want to shut down.
929 masterKilled = true;
930 }
931 }
932
933 // update the scene by traversing it with the update visitor which will
934 // call all node update callbacks and animations.
935 viewer.eventTraversal();
936
937 if (seh->getRequestReload())
938 {
939 OSG_INFO<<"Reload requested"<<std::endl;
940 seh->setRequestReload(false);
941 int previous_ActiveSlide = seh->getActiveSlide();
942 int previous_ActiveLayer = seh->getActiveLayer();
943
944 // reset time so any event key generate
945
946 loadedModel = p3d::readShowFiles(arguments,cacheAllOption.get());
947 processLoadedModel(loadedModel, optimizer_options, cursorFileName);
948
949 if (!loadedModel)
950 {
951 return 0;
952 }
953
954 viewer.setSceneData(loadedModel.get());
955 seh->set(loadedModel.get());
956 seh->selectSlide(previous_ActiveSlide, previous_ActiveLayer);
957
958 continue;
959
960 }
961
962 // update the scene by traversing it with the update visitor which will
963 // call all node update callbacks and animations.
964 viewer.updateTraversal();
965
966 if (P3DApplicationType==SLAVE)
967 {
968 osg::Matrix modelview;
969 cp.getModelView(modelview,camera_offset);
970
971 viewer.getCamera()->setViewMatrix(modelview);
972 }
973
974 // fire off the cull and draw traversals of the scene.
975 if(!masterKilled)
976 viewer.renderingTraversals();
977 }
978 }
979 else
980 {
981 ExportHTML::write(seh.get(), viewer, exportName);
982 }
983
984 return 0;
985 }
986
987