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 <osgPresentation/SlideShowConstructor>
14 #include <osgPresentation/AnimationMaterial>
15 #include <osgPresentation/PickEventHandler>
16 #include <osgPresentation/KeyEventHandler>
17 
18 
19 #include <osg/Geometry>
20 #include <osg/PolygonOffset>
21 #include <osg/Geode>
22 #include <osg/Texture2D>
23 #include <osg/TextureRectangle>
24 #include <osg/MatrixTransform>
25 #include <osg/PositionAttitudeTransform>
26 #include <osg/TexMat>
27 #include <osg/ShapeDrawable>
28 #include <osg/ImageSequence>
29 #include <osg/ImageUtils>
30 #include <osg/ClipNode>
31 #include <osg/ComputeBoundsVisitor>
32 #include <osg/Notify>
33 #include <osg/io_utils>
34 #include <osg/ValueObject>
35 
36 #include <osgUtil/TransformCallback>
37 
38 #include <osgDB/ReadFile>
39 #include <osgDB/WriteFile>
40 #include <osgDB/FileUtils>
41 #include <osgDB/Input>
42 #include <osgDB/FileNameUtils>
43 
44 #include <osgWidget/PdfReader>
45 
46 #include <osgUI/Widget>
47 
48 #include <osgViewer/ViewerEventHandlers>
49 
50 #include <osgText/Text>
51 
52 #include <osgFX/SpecularHighlights>
53 
54 #include <osgVolume/Volume>
55 #include <osgVolume/VolumeScene>
56 #include <osgVolume/RayTracedTechnique>
57 #include <osgVolume/FixedFunctionTechnique>
58 #include <osgVolume/MultipassTechnique>
59 
60 #include <sstream>
61 #include <algorithm>
62 
63 #include <osgManipulator/TabBoxDragger>
64 #include <osgManipulator/TabBoxTrackballDragger>
65 #include <osgManipulator/TrackballDragger>
66 
67 using namespace osgPresentation;
68 
69 #define USE_CLIENT_STORAGE_HINT 0
70 
71 
72 class SetToTransparentBin : public osg::NodeVisitor
73 {
74 public:
75 
SetToTransparentBin()76     SetToTransparentBin():
77         osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
78 
appply(osg::Node & node)79     virtual void appply(osg::Node& node)
80     {
81         if (node.getStateSet())
82         {
83             node.getStateSet()->setMode(GL_BLEND,osg::StateAttribute::ON);
84             node.getStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
85         }
86     }
87 
apply(osg::Geode & geode)88     virtual void apply(osg::Geode& geode)
89     {
90         if (geode.getStateSet())
91         {
92             geode.getStateSet()->setMode(GL_BLEND,osg::StateAttribute::ON);
93             geode.getStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
94         }
95         for(unsigned int i=0;i<geode.getNumDrawables();++i)
96         {
97             if (geode.getDrawable(i)->getStateSet())
98             {
99                 geode.getDrawable(i)->getStateSet()->setMode(GL_BLEND,osg::StateAttribute::ON);
100                 geode.getDrawable(i)->getStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
101             }
102         }
103     }
104 };
105 
106 
HUDTransform(HUDSettings * hudSettings)107 HUDTransform::HUDTransform(HUDSettings* hudSettings):
108     _hudSettings(hudSettings)
109 {
110     setDataVariance(osg::Object::DYNAMIC);
111     setReferenceFrame(osg::Transform::ABSOLUTE_RF);
112 }
113 
~HUDTransform()114 HUDTransform::~HUDTransform() {}
115 
computeLocalToWorldMatrix(osg::Matrix & matrix,osg::NodeVisitor * nv) const116 bool HUDTransform::computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const
117 {
118     return _hudSettings->getModelViewMatrix(matrix,nv);
119 }
120 
computeWorldToLocalMatrix(osg::Matrix & matrix,osg::NodeVisitor * nv) const121 bool HUDTransform::computeWorldToLocalMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const
122 {
123     return _hudSettings->getInverseModelViewMatrix(matrix,nv);
124 }
125 
SlideShowConstructor(osgDB::Options * options)126 SlideShowConstructor::SlideShowConstructor(osgDB::Options* options):
127     _options(options)
128 {
129     const osg::DisplaySettings* ds = osg::DisplaySettings::instance().get();
130 
131     _propertyManager = new osgPresentation::PropertyManager;
132     _propertyEventCallback = new osgPresentation::PropertyEventCallback(_propertyManager.get());
133 
134     _slideHeight = ds->getScreenHeight();
135     _slideWidth = ds->getScreenWidth();
136     _slideDistance = ds->getScreenDistance();
137     _leftEyeMask = 0x01;
138     _rightEyeMask = 0x02;
139 
140     _hudSettings = new HUDSettings(_slideDistance, ds->getEyeSeparation()*0.5, _leftEyeMask, _rightEyeMask);
141 
142     _backgroundColor.set(0.0f,0.0f,0.0f,0.0f);
143 
144     _presentationDuration = -1.0;
145 
146     // set up title defaults
147     _titleFontDataDefault.font = "fonts/arial.ttf";
148     _titleFontDataDefault.color.set(1.0f,1.0f,1.0f,1.0f);
149     _titleFontDataDefault.layout =osgText::Text::LEFT_TO_RIGHT;
150     _titleFontDataDefault.alignment = osgText::Text::CENTER_BASE_LINE;
151     _titleFontDataDefault.axisAlignment = osgText::Text::XZ_PLANE;
152     _titleFontDataDefault.characterSize = 0.06f;
153     _titleFontDataDefault.maximumWidth = 0.9f;
154 
155     _titlePositionDataDefault.position.set(0.5f,0.92f,0.0f);
156 
157     // set up text defaults
158     _textFontDataDefault.font = "fonts/arial.ttf";
159     _textFontDataDefault.color.set(1.0f,1.0f,1.0f,1.0f);
160     _textFontDataDefault.layout = osgText::Text::LEFT_TO_RIGHT;
161     _textFontDataDefault.alignment = osgText::Text::LEFT_BASE_LINE;
162     _textFontDataDefault.axisAlignment = osgText::Text::XZ_PLANE;
163     _textFontDataDefault.characterSize = 0.04f;
164     _textFontDataDefault.maximumWidth = 0.8f;
165 
166     _textPositionDataDefault.position.set(0.1f,0.85f,0.0f);
167 
168     _loopPresentation = false;
169     _autoSteppingActive = false;
170 
171     _slideBackgroundAsHUD = false;
172 
173     _layerToApplyEventCallbackTo = 0;
174     _currentEventCallbacksToApply.clear();
175 }
176 
setPresentationAspectRatio(float aspectRatio)177 void SlideShowConstructor::setPresentationAspectRatio(float aspectRatio)
178 {
179     _slideWidth = _slideHeight*aspectRatio;
180 }
181 
setPresentationAspectRatio(const std::string & str)182 void SlideShowConstructor::setPresentationAspectRatio(const std::string& str)
183 {
184     if (str=="Reality Theatre") setPresentationAspectRatio(3.0f);
185     else if (str=="Desktop") setPresentationAspectRatio(1280.0f/1024.0f);
186     else
187     {
188         float ratio = (float)atof(str.c_str());
189         if (ratio!=0.0) setPresentationAspectRatio(1280.0f/1024.0f);
190         else
191         {
192             OSG_WARN<<"Error: presentation aspect ratio incorrect type"<<std::endl;
193             OSG_WARN<<"       valid types are \"Reality Theatre\", \"Desktop\" or a numerical value."<<std::endl;
194         }
195     }
196 }
197 
createPresentation()198 void SlideShowConstructor::createPresentation()
199 {
200     _slideOrigin.set(-_slideWidth*0.5f,_slideDistance,-_slideHeight*0.5f);
201 
202 #if 0
203     _titleFontDataDefault.characterSize = 0.06f;
204     _titleFontDataDefault.maximumWidth = 0.9f;
205 
206     _textFontDataDefault.characterSize = 0.04f;
207     _textFontDataDefault.maximumWidth = 0.8f;
208 #endif
209 
210     OSG_INFO<<"_titlePositionDataDefault.position="<<_titlePositionDataDefault.position<<std::endl;
211 
212     _textPositionDataDefault.position.set(0.1f,_titlePositionDataDefault.position.y()-_titleFontDataDefault.characterSize,0.0f);
213     _imagePositionDataDefault.position.set(0.5f,0.5f,0.0f);
214     _modelPositionDataDefault.position.set(0.5f,0.5f,0.0f);
215 
216     _root = new osg::Group;
217 
218     _presentationSwitch = new osg::Switch;
219     _presentationSwitch->setName(std::string("Presentation_")+_presentationName);
220 
221     _root->addChild(_presentationSwitch.get());
222     _root->setName(std::string("Presentation_")+_presentationName);
223 
224     osg::Vec3 slideCenter = _slideOrigin + osg::Vec3(_slideWidth*0.5f,0.0f,_slideHeight*0.5f);
225 
226     HomePosition* hp = new HomePosition;
227     hp->eye.set(0.0f,0.0f,0.0f);
228     hp->center = slideCenter;
229     hp->up.set(0.0f,0.0f,1.0f);
230 
231     OSG_INFO<<" slideCenter "<<slideCenter<<std::endl;
232 
233     if (_presentationDuration>=0.0)
234     {
235         setDuration(_presentationSwitch.get(),_presentationDuration);
236     }
237 
238     _root->setUserData(hp);
239 
240     if (_loopPresentation) _root->addDescription("loop");
241     if (_autoSteppingActive) _root->addDescription("auto");
242 
243     //_root->addEventCallback(_propertyEventCallback.get());
244 
245     _presentationSwitch->setEventCallback(_propertyEventCallback.get());
246 
247     for(ScriptEngineMap::iterator itr = _scriptEngines.begin();
248         itr != _scriptEngines.end();
249         ++itr)
250     {
251         OSG_NOTICE<<"Assigning '"<<itr->first<<"' ScriptEngine to Presentation in createPresentation()."<<std::endl;
252         _presentationSwitch->getOrCreateUserDataContainer()->addUserObject(itr->second.get());
253     }
254 
255 }
256 
getOrCreateLayerAttributes(osg::Node * node)257 LayerAttributes* SlideShowConstructor::getOrCreateLayerAttributes(osg::Node* node)
258 {
259     LayerAttributes* la = dynamic_cast<LayerAttributes*>(node->getUserData());
260     if (!la)
261     {
262         if (node->getUserData())
263         {
264             OSG_NOTICE<<"UserData already assigned, overriding to set LayerAttributes."<<std::endl;
265         }
266 
267         la = new LayerAttributes;
268         node->setUserData(la);
269     }
270 
271     return la;
272 }
273 
setBackgroundColor(const osg::Vec4 & color,bool updateClearNode)274 void SlideShowConstructor::setBackgroundColor(const osg::Vec4& color, bool updateClearNode)
275 {
276     _backgroundColor = color;
277     if (updateClearNode && _slideClearNode.valid()) _slideClearNode->setClearColor(_backgroundColor);
278 }
279 
setTextColor(const osg::Vec4 & color)280 void SlideShowConstructor::setTextColor(const osg::Vec4& color)
281 {
282     _titleFontDataDefault.color = color;
283     _textFontDataDefault.color = color;
284 
285     _titleFontData.color = _titleFontDataDefault.color;
286     _textFontData.color = _textFontDataDefault.color;
287 
288 }
289 
setPresentationName(const std::string & name)290 void SlideShowConstructor::setPresentationName(const std::string& name)
291 {
292     _presentationName = name;
293     if (_presentationSwitch.valid()) _presentationSwitch->setName(std::string("Presentation_")+_presentationName);
294 }
295 
setPresentationDuration(double duration)296 void SlideShowConstructor::setPresentationDuration(double duration)
297 {
298     _presentationDuration = duration;
299     if (_presentationDuration>=0.0 && _presentationSwitch.valid())
300     {
301         setDuration(_presentationSwitch.get(),_presentationDuration);
302     }
303 }
304 
getOrCreateScriptEngine(const std::string & language)305 osg::ScriptEngine* SlideShowConstructor::getOrCreateScriptEngine(const std::string& language)
306 {
307     ScriptEngineMap::iterator itr = _scriptEngines.find(language);
308     if (itr==_scriptEngines.end())
309     {
310         addScriptEngine(language);
311         itr = _scriptEngines.find(language);
312     }
313 
314     return (itr!=_scriptEngines.end()) ? itr->second.get() : 0;
315 }
316 
addScriptEngine(const std::string & scriptEngineName)317 void SlideShowConstructor::addScriptEngine(const std::string& scriptEngineName)
318 {
319     if (_scriptEngines.count(scriptEngineName)!=0)
320     {
321         OSG_NOTICE<<"Script engine "<<scriptEngineName<<" already loaded."<<std::endl;
322     }
323 
324     osg::ref_ptr<osg::ScriptEngine> scriptEngine = osgDB::readRefFile<osg::ScriptEngine>(std::string("ScriptEngine.")+scriptEngineName);
325     if (scriptEngine.valid())
326     {
327         _scriptEngines[scriptEngineName] = scriptEngine;
328 
329         if (_presentationSwitch.valid())
330         {
331             _presentationSwitch->getOrCreateUserDataContainer()->addUserObject(scriptEngine.get());
332         }
333     }
334     else
335     {
336         OSG_NOTICE<<"Warning: Failed to load "<<scriptEngineName<<" engine, scripts will not work."<<std::endl;
337     }
338 }
339 
addScriptFile(const std::string & name,const std::string & filename)340 void SlideShowConstructor::addScriptFile(const std::string& name, const std::string& filename)
341 {
342     OSG_NOTICE<<"addScriptFile() name="<<name<<", filename = "<<filename<<std::endl;
343     osg::ref_ptr<osg::Script> script = osgDB::readRefFile<osg::Script>(filename);
344     if (script.valid())
345     {
346         _scripts[name] = script;
347     }
348 }
349 
addScript(const std::string & name,const std::string & language,const std::string & scriptContents)350 void SlideShowConstructor::addScript(const std::string& name, const std::string& language, const std::string& scriptContents)
351 {
352     OSG_NOTICE<<"addScript() language="<<language<<", name="<<name<<", script = "<<scriptContents<<std::endl;
353     osg::ref_ptr<osg::Script> script = new osg::Script;
354     script->setLanguage(language);
355     script->setScript(scriptContents);
356     _scripts[name] = script;
357 }
358 
addSlide()359 void SlideShowConstructor::addSlide()
360 {
361     if (!_presentationSwitch) createPresentation();
362 
363     // reset fonts
364     _titleFontData = _titleFontDataDefault;
365     _textFontData = _textFontDataDefault;
366 
367     // reset cursors
368     _titlePositionData = _titlePositionDataDefault;
369     _textPositionData = _textPositionDataDefault;
370     _imagePositionData =  _imagePositionDataDefault;
371     _modelPositionData =  _modelPositionDataDefault;
372 
373     _slide = new osg::Switch;
374     _slide->setName(std::string("Slide_")+_slideTitle);
375 
376     _slideClearNode = new osg::ClearNode;
377     _slideClearNode->setClearColor(_backgroundColor);
378     _slideClearNode->addChild(_slide.get());
379 
380     _presentationSwitch->addChild(_slideClearNode.get());
381 
382     _previousLayer = 0;
383     _currentLayer = 0;
384 
385 
386     _filePathData = new FilePathData(osgDB::getDataFilePathList());
387 
388     _slideClearNode->setUserData(_filePathData.get());
389 }
390 
selectSlide(int slideNum)391 void SlideShowConstructor::selectSlide(int slideNum)
392 {
393     if (slideNum<0)
394     {
395         addSlide();
396     }
397     else if (slideNum>=static_cast<int>(_presentationSwitch->getNumChildren()))
398     {
399         addSlide();
400     }
401     else
402     {
403         _slideClearNode = dynamic_cast<osg::ClearNode*>(_presentationSwitch->getChild(slideNum));
404         if (!_slideClearNode || _slideClearNode->getNumChildren()==0 || _slideClearNode->getChild(0)->asSwitch()==0)
405         {
406             addSlide();
407         }
408         else
409         {
410             _slide = _slideClearNode->getChild(0)->asSwitch();
411             _previousLayer = _slide->getChild(_slide->getNumChildren()-1)->asGroup();
412             _currentLayer = 0;
413         }
414     }
415 }
416 
setSlideDuration(double duration)417 void SlideShowConstructor::setSlideDuration(double duration)
418 {
419     if (!_slide) addSlide();
420 
421     if (_slide.valid())
422     {
423         setDuration(_slide.get(),duration);
424     }
425 }
426 
pushCurrentLayer(osg::Group * group)427 void SlideShowConstructor::pushCurrentLayer(osg::Group* group)
428 {
429     if (_currentLayer.valid())
430     {
431         _currentLayer->addChild(group);
432         _layerStack.push_back(_currentLayer.get());
433     }
434 
435     _currentLayer = group;
436 
437 }
438 
popCurrentLayer()439 void SlideShowConstructor::popCurrentLayer()
440 {
441     if (!_layerStack.empty())
442     {
443         _currentLayer = _layerStack.back();
444         _layerStack.pop_back();
445     }
446     else
447     {
448         _currentLayer = 0;
449     }
450 }
451 
addLayer(bool inheritPreviousLayers,bool defineAsBaseLayer)452 void SlideShowConstructor::addLayer(bool inheritPreviousLayers, bool defineAsBaseLayer)
453 {
454     if (!_slide) addSlide();
455 
456     _currentLayer = new osg::Group;
457     _currentLayer->setName("Layer");
458 
459     // OSG_NOTICE<<"addLayer"<<std::endl;
460 
461     if (!_previousLayer || !inheritPreviousLayers)
462     {
463         _textPositionData = _textPositionDataDefault;
464         _imagePositionData =  _imagePositionDataDefault;
465         _modelPositionData =  _modelPositionDataDefault;
466 
467         // OSG_NOTICE<<"   new layer background = "<<_slideBackgroundImageFileName<<std::endl;
468 
469         osg::ref_ptr<osg::Image> image = !_slideBackgroundImageFileName.empty() ?
470             osgDB::readRefImageFile(_slideBackgroundImageFileName, _options.get()) :
471             0;
472 
473         // create the background and title..
474         if (image.valid())
475         {
476             osg::Geode* background = new osg::Geode;
477 
478             osg::StateSet* backgroundStateSet = background->getOrCreateStateSet();
479             backgroundStateSet->setAttributeAndModes(
480                         new osg::PolygonOffset(1.0f,2.0f),
481                         osg::StateAttribute::ON);
482 
483 
484             bool useTextureRectangle = true;
485             float s = useTextureRectangle ? image->s() : 1.0;
486             float t = useTextureRectangle ? image->t() : 1.0;
487             osg::Geometry* backgroundQuad = osg::createTexturedQuadGeometry(_slideOrigin,
488                                                             osg::Vec3(_slideWidth,0.0f,0.0f),
489                                                             osg::Vec3(0.0f,0.0f,_slideHeight),
490                                                             s, t);
491             // OSG_NOTICE<<"Image loaded "<<image.get()<<"  "<<_slideBackgroundImageFileName<<std::endl;
492 
493             if (useTextureRectangle)
494             {
495                 osg::TextureRectangle* texture = new osg::TextureRectangle(image.get());
496                 backgroundStateSet->setTextureAttributeAndModes(0,
497                             texture,
498                             osg::StateAttribute::ON);
499             }
500             else
501             {
502                 osg::Texture2D* texture = new osg::Texture2D(image.get());
503                 texture->setResizeNonPowerOfTwoHint(false);
504                 texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR);
505                 texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR);
506 #if USE_CLIENT_STORAGE_HINT
507                 texture->setClientStorageHint(true);
508 #endif
509                 backgroundStateSet->setTextureAttributeAndModes(0,
510                             texture,
511                             osg::StateAttribute::ON);
512             }
513 
514             background->addDrawable(backgroundQuad);
515 
516             if (_slideBackgroundAsHUD)
517             {
518                 HUDTransform* hudTransform = new HUDTransform(_hudSettings.get());
519                 hudTransform->addChild(background);
520                 addToCurrentLayer(hudTransform);
521             }
522             else
523             {
524                 addToCurrentLayer(background);
525             }
526         }
527 
528         if (!_slideTitle.empty())
529         {
530             osg::Geode* geode = new osg::Geode;
531 
532             osg::Vec3 localPosition = computePositionInModelCoords(_titlePositionData);
533 
534             osgText::Text* text = new osgText::Text;
535             text->setFont(osgText::readRefFontFile(_titleFontData.font, _options.get()));
536             text->setColor(_titleFontData.color);
537             text->setCharacterSize(_titleFontData.characterSize*_slideHeight);
538             text->setFontResolution(110,120);
539             text->setMaximumWidth(_titleFontData.maximumWidth*_slideWidth);
540             text->setLayout(_titleFontData.layout);
541             text->setAlignment(_titleFontData.alignment);
542             text->setAxisAlignment(_titleFontData.axisAlignment);
543             //text->setPosition(_titlePositionData.position);
544             text->setPosition(localPosition);
545 
546             text->setText(_slideTitle);
547 
548             geode->addDrawable(text);
549 
550             addToCurrentLayer(decorateSubgraphForPosition(geode, _titlePositionData));
551         }
552 
553     }
554     else
555     {
556         // copy previous layer's children across into new layer.
557         for(unsigned int i=0;i<_previousLayer->getNumChildren();++i)
558         {
559             addToCurrentLayer(_previousLayer->getChild(i));
560         }
561     }
562 
563     if (!defineAsBaseLayer)
564     {
565         _slide->addChild(_currentLayer.get());
566     }
567 
568     _previousLayer = _currentLayer;
569 }
570 
selectLayer(int layerNum)571 void SlideShowConstructor::selectLayer(int layerNum)
572 {
573     if (!_slide)
574     {
575         addSlide();
576         addLayer();
577     }
578     else if (layerNum>=0 && layerNum<static_cast<int>(_slide->getNumChildren()) && _slide->getChild(layerNum)->asGroup())
579     {
580         _currentLayer = _slide->getChild(layerNum)->asGroup();
581         _previousLayer = _currentLayer;
582     }
583     else
584     {
585         addLayer();
586     }
587 
588 }
589 
590 
setLayerDuration(double duration)591 void SlideShowConstructor::setLayerDuration(double duration)
592 {
593     if (!_currentLayer) addLayer();
594 
595     if (_currentLayer.valid())
596     {
597         setDuration(_currentLayer.get(),duration);
598     }
599 }
600 
addToCurrentLayer(osg::Node * subgraph)601 void SlideShowConstructor::addToCurrentLayer(osg::Node* subgraph)
602 {
603     if (!subgraph) return;
604 
605     if (!_currentLayer) addLayer();
606 
607     if (!_currentEventCallbacksToApply.empty())
608     {
609         if (_layerToApplyEventCallbackTo==0 || _currentLayer==_layerToApplyEventCallbackTo)
610         {
611             OSG_INFO<<"Assigning event callbacks."<<std::endl;
612 
613             for(EventHandlerList::iterator itr = _currentEventCallbacksToApply.begin();
614                 itr != _currentEventCallbacksToApply.end();
615                 ++itr)
616             {
617                 subgraph->addEventCallback(itr->get());
618             }
619         }
620         else
621         {
622             OSG_INFO<<"Ignoring event callback from previous layer."<<std::endl;
623         }
624 
625         _currentEventCallbacksToApply.clear();
626     }
627     _currentLayer->addChild(subgraph);
628 }
629 
addEventHandler(PresentationContext presentationContext,osg::ref_ptr<osgGA::GUIEventHandler> handler)630 void SlideShowConstructor::addEventHandler(PresentationContext presentationContext, osg::ref_ptr<osgGA::GUIEventHandler> handler)
631 {
632     switch(presentationContext)
633     {
634         case(CURRENT_PRESENTATION):
635             OSG_NOTICE<<"Need to add event handler to presentation."<<std::endl;
636             break;
637         case(CURRENT_SLIDE):
638             OSG_NOTICE<<"Need to add event handler to slide."<<std::endl;
639             break;
640         case(CURRENT_LAYER):
641             OSG_INFO<<"Add event handler to layer."<<std::endl;
642             _layerToApplyEventCallbackTo = _currentLayer;
643             _currentEventCallbacksToApply.push_back(handler);
644             break;
645     }
646 }
647 
keyToDoOperation(PresentationContext presentationContext,int key,Operation operation,const JumpData & jumpData)648 void SlideShowConstructor::keyToDoOperation(PresentationContext presentationContext, int key, Operation operation, const JumpData& jumpData)
649 {
650     OSG_INFO<<"keyToDoOperation(key="<<key<<", operation="<<operation<<")"<<std::endl;
651     addEventHandler(presentationContext, new KeyEventHandler(key, operation, jumpData));
652 }
653 
654 
keyToDoOperation(PresentationContext presentationContext,int key,const std::string & command,Operation operation,const JumpData & jumpData)655 void SlideShowConstructor::keyToDoOperation(PresentationContext presentationContext, int key, const std::string& command, Operation operation, const JumpData& jumpData)
656 {
657     OSG_INFO<<"keyToDoOperation(key="<<key<<",command="<<command<<")"<<std::endl;
658     addEventHandler(presentationContext, new KeyEventHandler(key, command, operation, jumpData));
659 }
660 
661 
keyEventOperation(PresentationContext presentationContext,int key,const KeyPosition & keyPos,const JumpData & jumpData)662 void SlideShowConstructor::keyEventOperation(PresentationContext presentationContext, int key, const KeyPosition& keyPos,  const JumpData& jumpData)
663 {
664     OSG_INFO<<"keyEventOperation(key="<<key<<")"<<std::endl;
665     addEventHandler(presentationContext, new KeyEventHandler(key, keyPos, jumpData));
666 }
667 
668 
layerClickToDoOperation(Operation operation,const JumpData & jumpData)669 void SlideShowConstructor::layerClickToDoOperation(Operation operation, const JumpData& jumpData)
670 {
671     addEventHandler(CURRENT_LAYER, new PickEventHandler(operation, jumpData));
672 }
673 
674 
layerClickToDoOperation(const std::string & command,Operation operation,const JumpData & jumpData)675 void SlideShowConstructor::layerClickToDoOperation(const std::string& command, Operation operation, const JumpData& jumpData)
676 {
677     addEventHandler(CURRENT_LAYER, new PickEventHandler(command, operation, jumpData));
678 }
679 
680 
layerClickEventOperation(const KeyPosition & keyPos,const JumpData & jumpData)681 void SlideShowConstructor::layerClickEventOperation(const KeyPosition& keyPos, const JumpData& jumpData)
682 {
683     addEventHandler(CURRENT_LAYER, new PickEventHandler(keyPos, jumpData));
684 }
685 
686 
687 
addPropertyAnimation(PresentationContext presentationContext,PropertyAnimation * propertyAnimation)688 void SlideShowConstructor::addPropertyAnimation(PresentationContext presentationContext, PropertyAnimation* propertyAnimation)
689 {
690     switch(presentationContext)
691     {
692         case(CURRENT_PRESENTATION):
693             OSG_NOTICE<<"Need to add PropertyAnimation to presentation."<<std::endl;
694             if (!_presentationSwitch) createPresentation();
695             if (_presentationSwitch.valid()) _presentationSwitch->addUpdateCallback(propertyAnimation);
696             break;
697         case(CURRENT_SLIDE):
698             OSG_NOTICE<<"Need to add PropertyAnimation to slide."<<std::endl;
699             if (!_slide) addSlide();
700             if (_slide.valid()) _slide->addUpdateCallback(propertyAnimation);
701             break;
702         case(CURRENT_LAYER):
703             OSG_NOTICE<<"Need to add PropertyAnimation to layer."<<std::endl;
704             if (!_currentLayer) addLayer();
705             if (_currentLayer.valid())
706             {
707                 _currentLayer->addUpdateCallback(propertyAnimation);
708             }
709             break;
710     }
711 }
712 
addScriptCallback(PresentationContext presentationContext,ScriptCallbackType scriptCallbackType,const std::string & name)713 void SlideShowConstructor::addScriptCallback(PresentationContext presentationContext, ScriptCallbackType scriptCallbackType, const std::string& name)
714 {
715     switch(presentationContext)
716     {
717         case(CURRENT_PRESENTATION):
718             OSG_NOTICE<<"  Adding ScriptCallback to presentation."<<std::endl;
719             if (!_presentationSwitch) createPresentation();
720             if (_presentationSwitch.valid()) addScriptToNode(scriptCallbackType, name, _presentationSwitch.get());
721             break;
722         case(CURRENT_SLIDE):
723             OSG_NOTICE<<"  Adding ScriptCallback to slide."<<std::endl;
724             if (!_slide) addSlide();
725             if (_slide.valid()) addScriptToNode(scriptCallbackType, name, _slide.get());
726             break;
727         case(CURRENT_LAYER):
728             OSG_NOTICE<<"  Adding ScriptCallback to layer."<<std::endl;
729             if (!_currentLayer) addLayer();
730             if (_currentLayer.valid())
731             {
732                 addScriptToNode(scriptCallbackType, name, _currentLayer.get());
733             }
734             break;
735     }
736 }
737 
addScriptToNode(ScriptCallbackType scriptCallbackType,const std::string & name,osg::Node * node)738 void SlideShowConstructor::addScriptToNode(ScriptCallbackType scriptCallbackType, const std::string& name, osg::Node* node)
739 {
740     std::string::size_type colon_position = name.find(':');
741     std::string script_name = (colon_position==std::string::npos) ? name : name.substr(0, colon_position);
742     std::string entry_point = (colon_position==std::string::npos) ? std::string() : name.substr(colon_position+1,std::string::npos);
743     ScriptMap::iterator script_itr = _scripts.find(script_name);
744     if (script_itr!=_scripts.end())
745     {
746         switch(scriptCallbackType)
747         {
748             case(UPDATE_SCRIPT) :
749                 node->addUpdateCallback(new osg::ScriptNodeCallback(script_itr->second.get(), entry_point));
750                 break;
751             case(EVENT_SCRIPT) :
752                 node->addEventCallback(new osg::ScriptNodeCallback(script_itr->second.get(), entry_point));
753                 break;
754         }
755     }
756     else
757     {
758         OSG_NOTICE<<"Warning: script '"<<name<<"' not defined."<<std::endl;
759     }
760 }
761 
addScriptsToNode(const ScriptData & scriptData,osg::Node * node)762 void SlideShowConstructor::addScriptsToNode(const ScriptData& scriptData, osg::Node* node)
763 {
764     if (!node) return;
765 
766     for(ScriptData::Scripts::const_iterator itr = scriptData.scripts.begin();
767         itr != scriptData.scripts.end();
768         ++itr)
769     {
770         addScriptToNode(itr->first, itr->second, node);
771     }
772 }
773 
774 
775 
decorateSubgraphForPosition(osg::Node * node,PositionData & positionData)776 osg::Node* SlideShowConstructor::decorateSubgraphForPosition(osg::Node* node, PositionData& positionData)
777 {
778     osg::Node* subgraph = node;
779 
780     if (positionData.requiresMaterialAnimation())
781     {
782         subgraph = attachMaterialAnimation(subgraph,positionData);
783     }
784 
785     if (positionData.rotation[0]!=0.0)
786     {
787         osg::MatrixTransform* animation_transform = new osg::MatrixTransform;
788         animation_transform->setDataVariance(osg::Object::DYNAMIC);
789         animation_transform->setUpdateCallback(
790             new osgUtil::TransformCallback(subgraph->getBound().center(),
791                                            osg::Vec3(positionData.rotation[1],positionData.rotation[2],positionData.rotation[3]),
792                                            osg::DegreesToRadians(positionData.rotation[0])));
793         animation_transform->addChild(subgraph);
794 
795         subgraph = animation_transform;
796     }
797 
798     if (positionData.hud)
799     {
800         HUDTransform* hudTransform = new HUDTransform(_hudSettings.get());
801         hudTransform->addChild(subgraph);
802 
803         subgraph = hudTransform;
804     }
805     return subgraph;
806 }
807 
addBullet(const std::string & bullet,PositionData & positionData,FontData & fontData,const ScriptData & scriptData)808 void SlideShowConstructor::addBullet(const std::string& bullet, PositionData& positionData, FontData& fontData, const ScriptData& scriptData)
809 {
810     osg::Geode* geode = new osg::Geode;
811 
812     osgText::Text* text = new osgText::Text;
813 
814     osg::Vec3 localPosition = computePositionInModelCoords(positionData);
815 
816     text->setFont(osgText::readRefFontFile(fontData.font, _options.get()));
817     text->setColor(fontData.color);
818     text->setCharacterSize(fontData.characterSize*_slideHeight);
819     text->setCharacterSizeMode(fontData.characterSizeMode);
820     text->setFontResolution(110,120);
821     text->setMaximumWidth(fontData.maximumWidth*_slideWidth);
822     text->setLayout(fontData.layout);
823     text->setAlignment(fontData.alignment);
824     text->setAxisAlignment(fontData.axisAlignment);
825     text->setPosition(localPosition);
826 
827     if (positionData.autoRotate)
828     {
829         text->setAxisAlignment(osgText::Text::SCREEN);
830     }
831 
832     if (positionData.autoScale)
833     {
834         text->setCharacterSizeMode(osgText::Text::SCREEN_COORDS);
835     }
836 
837     text->setText(bullet);
838 
839     const osg::BoundingBox& bb = text->getBoundingBox();
840 
841     // note, this increment is only "correct" when text is on the plane of the slide..
842     // will need to make this more general later.
843     localPosition.z() = bb.zMin()-fontData.characterSize*_slideHeight*1.5;
844 
845     geode->addDrawable(text);
846 
847     addToCurrentLayer( decorateSubgraphForPosition(geode, positionData) );
848 
849     bool needToApplyPosition = (_textPositionData.position == positionData.position);
850     if (needToApplyPosition)
851     {
852         updatePositionFromInModelCoords(localPosition, _textPositionData);
853     }
854 
855     if (scriptData.hasScripts()) addScriptsToNode(scriptData, geode);
856 }
857 
addParagraph(const std::string & paragraph,PositionData & positionData,FontData & fontData,const ScriptData & scriptData)858 void SlideShowConstructor::addParagraph(const std::string& paragraph, PositionData& positionData, FontData& fontData, const ScriptData& scriptData)
859 {
860     osg::Geode* geode = new osg::Geode;
861 
862     osg::Vec3 localPosition = computePositionInModelCoords(positionData);
863 
864     osgText::Text* text = new osgText::Text;
865 
866     text->setFont(osgText::readRefFontFile(fontData.font, _options.get()));
867     text->setColor(fontData.color);
868     text->setCharacterSize(fontData.characterSize*_slideHeight);
869     text->setCharacterSizeMode(fontData.characterSizeMode);
870     text->setFontResolution(110,120);
871     text->setMaximumWidth(fontData.maximumWidth*_slideWidth);
872     text->setLayout(fontData.layout);
873     text->setAlignment(fontData.alignment);
874     text->setAxisAlignment(fontData.axisAlignment);
875     text->setPosition(localPosition);
876 
877     if (positionData.autoRotate)
878     {
879         text->setAxisAlignment(osgText::Text::SCREEN);
880     }
881 
882     if (positionData.autoScale)
883     {
884         text->setCharacterSizeMode(osgText::Text::SCREEN_COORDS);
885     }
886     text->setText(paragraph);
887 
888     const osg::BoundingBox& bb = text->getBoundingBox();
889 
890     // note, this increment is only "correct" when text is on the plane of the slide..
891     // will need to make this more general later.
892     localPosition.z() = bb.zMin()-fontData.characterSize*_slideHeight*1.5;
893 
894     geode->addDrawable(text);
895 
896     addToCurrentLayer( decorateSubgraphForPosition(geode, positionData) );
897 
898     bool needToApplyPosition = (_textPositionData.position == positionData.position);
899     if (needToApplyPosition)
900     {
901         updatePositionFromInModelCoords(localPosition, _textPositionData);
902     }
903 
904     if (scriptData.hasScripts()) addScriptsToNode(scriptData, geode);
905 }
906 
907 class FindImageStreamsVisitor : public osg::NodeVisitor
908 {
909 public:
FindImageStreamsVisitor()910     FindImageStreamsVisitor():
911         osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
912 
apply(osg::Node & node)913     virtual void apply(osg::Node& node)
914     {
915         if (node.getStateSet())
916         {
917                 process(node.getStateSet());
918         }
919         traverse(node);
920     }
921 
apply(osg::Geode & node)922     virtual void apply(osg::Geode& node)
923     {
924         if (node.getStateSet())
925         {
926                 process(node.getStateSet());
927         }
928 
929         for(unsigned int i=0;i<node.getNumDrawables();++i)
930         {
931             osg::Drawable* drawable = node.getDrawable(i);
932             if (drawable && drawable->getStateSet())
933             {
934                 process(drawable->getStateSet());
935             }
936         }
937     }
938 
process(osg::StateSet * ss)939     void process(osg::StateSet* ss)
940     {
941         for(unsigned int i=0;i<ss->getTextureAttributeList().size();++i)
942         {
943             osg::Texture* texture = dynamic_cast<osg::Texture*>(ss->getTextureAttribute(i,osg::StateAttribute::TEXTURE));
944             osg::Image* image = texture ? texture->getImage(0) : 0;
945             osg::ImageStream* imageStream = image ? dynamic_cast<osg::ImageStream*>(image) : 0;
946             if (imageStream)
947             {
948                 texture->setDataVariance(osg::Object::DYNAMIC);
949                 texture->setUnRefImageDataAfterApply(false);
950                 texture->setResizeNonPowerOfTwoHint(false);
951                 texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR);
952                 texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR);
953 #if USE_CLIENT_STORAGE_HINT
954                 texture->setClientStorageHint(true);
955 #endif
956             }
957         }
958     }
959 
960 };
961 
findImageStreamsAndAddCallbacks(osg::Node * node)962 void SlideShowConstructor::findImageStreamsAndAddCallbacks(osg::Node* node)
963 {
964     FindImageStreamsVisitor fisv;
965     node->accept(fisv);
966 }
967 
968 
createTexturedQuadGeometry(const osg::Vec3 & pos,const osg::Vec4 & rotation,float width,float height,osg::Image * image,bool & usedTextureRectangle)969 osg::Geometry* SlideShowConstructor::createTexturedQuadGeometry(const osg::Vec3& pos, const osg::Vec4& rotation, float width, float height, osg::Image* image, bool& usedTextureRectangle)
970 {
971     osg::Geometry* pictureQuad = 0;
972     osg::ref_ptr<osg::Texture> texture = 0;
973     osg::StateSet* stateset = 0;
974 
975     osg::Vec3 positionVec = pos;
976     osg::Vec3 widthVec(width,0.0f,0.0f);
977     osg::Vec3 heightVec(0.0f,0.0f,height);
978 
979     osg::Matrixd rotationMatrix = osg::Matrixd::rotate(osg::DegreesToRadians(rotation[0]),rotation[1],rotation[2],rotation[3]);
980     widthVec = widthVec*rotationMatrix;
981     heightVec = heightVec*rotationMatrix;
982 
983     osg::ImageStream* imageStream = dynamic_cast<osg::ImageStream*>(image);
984 
985     // let the video-plugin create a texture for us, if supported
986     if(imageStream && getenv("P3D_ENABLE_CORE_VIDEO"))
987     {
988         texture = imageStream->createSuitableTexture();
989     }
990 
991     bool flipYAxis = image->getOrigin()==osg::Image::TOP_LEFT;
992 
993 #if 1
994     bool useTextureRectangle = false;
995 #else
996     #ifdef __sgi
997         bool useTextureRectangle = false;
998     #else
999         bool useTextureRectangle = true;
1000     #endif
1001 #endif
1002 
1003     // pass back info on wether texture 2D is used.
1004     usedTextureRectangle = useTextureRectangle;
1005 
1006     if (!texture)
1007     {
1008         if (useTextureRectangle)
1009         {
1010             texture = new osg::TextureRectangle(image);
1011         }
1012         else
1013         {
1014             texture = new osg::Texture2D(image);
1015 
1016             texture->setResizeNonPowerOfTwoHint(false);
1017             texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR);
1018             texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR);
1019     #if USE_CLIENT_STORAGE_HINT
1020             texture->setClientStorageHint(true);
1021     #endif
1022 
1023         }
1024     }
1025     if (texture)
1026     {
1027         float t(0), l(0);
1028         float r = (texture->getTextureTarget() == GL_TEXTURE_RECTANGLE) ? image->s() : 1;
1029         float b = (texture->getTextureTarget() == GL_TEXTURE_RECTANGLE) ? image->t() : 1;
1030 
1031         if (flipYAxis)
1032             std::swap(t,b);
1033 
1034         pictureQuad = osg::createTexturedQuadGeometry(positionVec,
1035                                                widthVec,
1036                                                heightVec,
1037                                                l, t, r, b);
1038 
1039         stateset = pictureQuad->getOrCreateStateSet();
1040         stateset->setTextureAttributeAndModes(0,
1041                         texture.get(),
1042                         osg::StateAttribute::ON);
1043     }
1044 
1045     if (!pictureQuad) return 0;
1046 
1047     if (imageStream)
1048     {
1049         imageStream->pause();
1050 
1051         OSG_INFO<<"Reading video "<<imageStream->getFileName()<<std::endl;
1052 #if USE_CLIENT_STORAGE_HINT
1053         // make sure that OSX uses the client storage extension to accelerate peformance where possible.
1054         texture->setClientStorageHint(true);
1055 #endif
1056     }
1057 
1058 
1059     return pictureQuad;
1060 }
1061 
1062 
1063 
readImage(const std::string & filename,const ImageData & imageData)1064 osg::Image* SlideShowConstructor::readImage(const std::string& filename, const ImageData& imageData)
1065 {
1066     osg::ref_ptr<osgDB::Options> options = _options;
1067     if (!imageData.options.empty())
1068     {
1069         options = _options->cloneOptions();
1070         options->setOptionString(imageData.options);
1071     }
1072 
1073     osg::ref_ptr<osg::Image> image;
1074     osgDB::DirectoryContents filenames;
1075 
1076     std::string foundFile = filename;
1077 
1078     if (imageData.imageSequence)
1079     {
1080         // check for wild cards
1081         if (filename.find('*')!=std::string::npos)
1082         {
1083             OSG_INFO<<"Expanding wildcard "<<std::endl;
1084             filenames = osgDB::expandWildcardsInFilename(filename);
1085         }
1086         else
1087         {
1088             std::string foundFile = filename;
1089             osgDB::FileType fileType = osgDB::fileType(foundFile);
1090             if (fileType == osgDB::FILE_NOT_FOUND)
1091             {
1092                 foundFile = findFileAndRecordPath(foundFile);
1093                 fileType = osgDB::fileType(foundFile);
1094             }
1095 
1096             if (fileType == osgDB::DIRECTORY)
1097             {
1098                 OSG_INFO<<"Reading directory "<<foundFile<<std::endl;
1099 
1100                 filenames = osgDB::getDirectoryContents(foundFile);
1101 
1102                 // need to insert the directory path in front of the filenames so it's relative to the appropriate directory.
1103                 for(osgDB::DirectoryContents::iterator itr = filenames.begin();
1104                     itr != filenames.end();
1105                     ++itr)
1106                 {
1107                     *itr = foundFile + osgDB::getNativePathSeparator() + *itr;
1108                 }
1109 
1110                 // prune any directory entries from the list.
1111                 for(osgDB::DirectoryContents::iterator itr = filenames.begin();
1112                     itr != filenames.end();
1113                     )
1114                 {
1115                     if (osgDB::fileType(*itr)!=osgDB::REGULAR_FILE)
1116                     {
1117                         itr = filenames.erase(itr);
1118                     }
1119                     else
1120                     {
1121                         ++itr;
1122                     }
1123                 }
1124             }
1125             else
1126             {
1127                 filenames.push_back(foundFile);
1128             }
1129         }
1130     }
1131     else
1132     {
1133         std::string foundFile = filename;
1134         osgDB::FileType fileType = osgDB::fileType(foundFile);
1135         if (fileType == osgDB::FILE_NOT_FOUND)
1136         {
1137             foundFile = findFileAndRecordPath(foundFile);
1138             fileType = osgDB::fileType(foundFile);
1139         }
1140         filenames.push_back(foundFile);
1141     }
1142 
1143     if (filenames.empty())
1144     {
1145         OSG_NOTICE<<"Could not fine image file: "<<filename<<std::endl;
1146         return 0;
1147     }
1148 
1149     if (filenames.size()==1)
1150     {
1151         image = osgDB::readRefImageFile(filenames[0], options.get());
1152         if (image.valid()) recordOptionsFilePath(options.get() );
1153     }
1154     else
1155     {
1156         // make sure images are in alphabetical order.
1157         std::sort(filenames.begin(), filenames.end(), osgDB::FileNameComparator());
1158 
1159         osg::ref_ptr<osg::ImageSequence> imageSequence = new osg::ImageSequence;
1160 
1161         imageSequence->setMode(imageData.imageSequencePagingMode);
1162 
1163         bool firstLoad = true;
1164 
1165         for(osgDB::DirectoryContents::iterator itr = filenames.begin();
1166             itr != filenames.end();
1167             ++itr)
1168         {
1169             if (imageSequence->getMode()==osg::ImageSequence::PRE_LOAD_ALL_IMAGES)
1170             {
1171                 OSG_INFO<<"Attempting to read "<<*itr<<std::endl;
1172                 osg::ref_ptr<osg::Image> loadedImage = osgDB::readRefImageFile(*itr, options.get());
1173                 if (loadedImage.valid())
1174                 {
1175                     OSG_INFO<<"Loaded image "<<*itr<<std::endl;
1176                     imageSequence->addImage(loadedImage.get());
1177                 }
1178             }
1179             else
1180             {
1181                 OSG_INFO<<"Adding filename for load image on demand "<<*itr<<std::endl;
1182                 imageSequence->addImageFile(*itr);
1183                 if (firstLoad)
1184                 {
1185                     osg::ref_ptr<osg::Image> loadedImage = osgDB::readRefImageFile(*itr, options.get());
1186                     if (loadedImage.valid())
1187                     {
1188                         imageSequence->addImage(loadedImage.get());
1189                         firstLoad = false;
1190                     }
1191                 }
1192             }
1193         }
1194 
1195 #if 0
1196         if (imageSequence->getMode()==osg::ImageSequence::PAGE_AND_DISCARD_USED_IMAGES)
1197         {
1198 
1199             if (_options.valid())
1200             {
1201                 OSG_NOTICE<<"Object cache usage _options "<<options->getObjectCacheHint()<<std::endl;
1202             }
1203             else
1204             {
1205                 OSG_NOTICE<<"No Object _options assigned"<<std::endl;
1206             }
1207 
1208 
1209             osg::ref_ptr<osgDB::Options> options = _options.valid() ? _options->cloneOptions() : (new osgDB::Options);
1210             if (!imageData.options.empty())
1211             {
1212                 options->setOptionString(imageData.options);
1213             }
1214             OSG_NOTICE<<"Disabling object cache usage"<<std::endl;
1215             options->setObjectCacheHint(osgDB::Options::CACHE_NONE);
1216             imageSequence->setReadOptions(options);
1217         }
1218 #endif
1219         if (imageData.duration>0.0)
1220         {
1221             imageSequence->setLength(imageData.duration);
1222         }
1223         else
1224         {
1225             unsigned int maxNum = imageSequence->getNumImageData();
1226             imageSequence->setLength(double(maxNum)*(1.0/imageData.fps));
1227         }
1228 
1229         if (imageData.imageSequenceInteractionMode==ImageData::USE_MOUSE_X_POSITION)
1230         {
1231             imageSequence->setName("USE_MOUSE_X_POSITION");
1232         }
1233         else if (imageData.imageSequenceInteractionMode==ImageData::USE_MOUSE_Y_POSITION)
1234         {
1235             imageSequence->setName("USE_MOUSE_Y_POSITION");
1236         }
1237 
1238 
1239         imageSequence->play();
1240 
1241         image = imageSequence;
1242     }
1243     if (image.valid())
1244     {
1245         if (imageData.delayTime>0.0) image->setUserValue("delay",imageData.delayTime);
1246         if (imageData.startTime>0.0) image->setUserValue("start",imageData.startTime);
1247         if (imageData.stopTime>0.0) image->setUserValue("stop",imageData.stopTime);
1248     }
1249     else
1250     {
1251         OSG_NOTICE<<"Could not load image file: "<<filename<<std::endl;
1252     }
1253     return image.release();
1254 }
1255 
1256 struct VolumeCallback : public osg::NodeCallback
1257 {
1258 public:
VolumeCallbackVolumeCallback1259     VolumeCallback(osg::ImageStream* movie, const std::string& str):
1260         _movie(movie),
1261         _source(str) {}
1262 
operator ()VolumeCallback1263     virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
1264     {
1265         PropertyReader pr(nv->getNodePath(), _source);
1266 
1267         float volume=0.0f;
1268         pr>>volume;
1269 
1270         if (pr.ok())
1271         {
1272             OSG_NOTICE<<"VolumeCallback : volume="<<volume<<", from "<<_source<<std::endl;
1273             _movie->setVolume(volume);
1274         }
1275         else
1276         {
1277             OSG_NOTICE<<"Problem in reading, VolumeCallback : volume="<<volume<<std::endl;
1278         }
1279 
1280 
1281         // note, callback is responsible for scenegraph traversal so
1282         // they must call traverse(node,nv) to ensure that the
1283         // scene graph subtree (and associated callbacks) are traversed.
1284         traverse(node, nv);
1285     }
1286 
1287 protected:
1288 
1289     osg::ref_ptr<osg::ImageStream> _movie;
1290     std::string  _source;
1291 };
1292 
setUpMovieVolume(osg::Node * subgraph,osg::ImageStream * imageStream,const ImageData & imageData)1293 void SlideShowConstructor::setUpMovieVolume(osg::Node* subgraph, osg::ImageStream* imageStream, const ImageData& imageData)
1294 {
1295     if (containsPropertyReference(imageData.volume))
1296     {
1297         subgraph->addUpdateCallback(new VolumeCallback(imageStream, imageData.volume));
1298     }
1299     else
1300     {
1301         float volume;
1302         std::istringstream sstream(imageData.volume);
1303         sstream>>volume;
1304 
1305         if (!sstream.fail())
1306         {
1307             OSG_NOTICE<<"Setting volume "<<volume<<std::endl;
1308             imageStream->setVolume( volume );
1309         }
1310         else
1311         {
1312             OSG_NOTICE<<"Invalid volume setting: "<<imageData.volume<<std::endl;
1313         }
1314     }
1315 }
1316 
addImage(const std::string & filename,const PositionData & positionData,const ImageData & imageData,const ScriptData & scriptData)1317 void SlideShowConstructor::addImage(const std::string& filename, const PositionData& positionData, const ImageData& imageData, const ScriptData& scriptData)
1318 {
1319     osg::ref_ptr<osg::Image> image = readImage(filename, imageData);
1320     if (!image) return;
1321 
1322     bool isImageTranslucent = false;
1323 
1324     osg::ImageStream* imageStream = dynamic_cast<osg::ImageStream*>(image.get());
1325     if (imageStream)
1326     {
1327         imageStream->setLoopingMode(imageData.loopingMode);
1328 
1329         isImageTranslucent = imageStream->getPixelFormat()==GL_RGBA ||
1330                              imageStream->getPixelFormat()==GL_BGRA;
1331 
1332     }
1333     else
1334     {
1335         isImageTranslucent = image->isImageTranslucent();
1336     }
1337 
1338     if (imageData.blendingHint==ImageData::ON)
1339     {
1340         isImageTranslucent = true;
1341     }
1342     else if (imageData.blendingHint==ImageData::OFF)
1343     {
1344         isImageTranslucent = false;
1345     }
1346 
1347 
1348     float s = image->s();
1349     float t = image->t();
1350 
1351     float sx = imageData.region_in_pixel_coords ? 1.0f : s;
1352     float sy = imageData.region_in_pixel_coords ? 1.0f : t;
1353 
1354     float x1 = imageData.region[0]*sx;
1355     float y1 = imageData.region[1]*sy;
1356     float x2 = imageData.region[2]*sx;
1357     float y2 = imageData.region[3]*sy;
1358 
1359     float aspectRatio = (y2-y1)/(x2-x1);
1360 
1361     float image_width = _slideWidth*positionData.scale.x();
1362     float image_height = image_width*aspectRatio*positionData.scale.y()/positionData.scale.x();
1363     float offset = 0.0f;
1364 
1365     osg::Vec3 pos = computePositionInModelCoords(positionData);
1366     osg::Vec3 image_local_pos = osg::Vec3(-image_width*0.5f+offset,-offset,-image_height*0.5f-offset);
1367     osg::Vec3 image_pos = positionData.autoRotate ? image_local_pos : (pos+image_local_pos);
1368 
1369 
1370     bool usedTextureRectangle = false;
1371     osg::Geometry* pictureQuad = createTexturedQuadGeometry(image_pos, positionData.rotate, image_width, image_height, image.get(), usedTextureRectangle);
1372     osg::StateSet* pictureStateSet = pictureQuad->getOrCreateStateSet();
1373 
1374     attachTexMat(pictureStateSet, imageData, s, t, usedTextureRectangle);
1375 
1376     osg::Node* subgraph = 0;
1377 
1378     if (positionData.autoRotate)
1379     {
1380         osg::Billboard* picture = new osg::Billboard;
1381         picture->setMode(osg::Billboard::POINT_ROT_EYE);
1382         picture->setNormal(osg::Vec3(0.0f,-1.0f,0.0f));
1383         picture->setAxis(osg::Vec3(0.0f,0.0f,1.0f));
1384         picture->addDrawable(pictureQuad,pos);
1385         subgraph = picture;
1386     }
1387     else
1388     {
1389         osg::Geode* picture = new osg::Geode;
1390         picture->addDrawable(pictureQuad);
1391         subgraph = picture;
1392     }
1393 
1394     // attach any meterial animation.
1395     if (positionData.requiresMaterialAnimation())
1396         subgraph = attachMaterialAnimation(subgraph,positionData);
1397 
1398 
1399     if (isImageTranslucent)
1400     {
1401         SetToTransparentBin sttb;
1402         subgraph->accept(sttb);
1403         pictureStateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
1404     }
1405 
1406 
1407     if (imageStream && !imageData.volume.empty())
1408     {
1409         setUpMovieVolume(subgraph, imageStream, imageData);
1410     }
1411 
1412     osg::ImageSequence* imageSequence = dynamic_cast<osg::ImageSequence*>(image.get());
1413     if (imageSequence)
1414     {
1415         if (imageData.imageSequenceInteractionMode==ImageData::USE_MOUSE_X_POSITION)
1416         {
1417             subgraph->setUpdateCallback(new osgPresentation::ImageSequenceUpdateCallback(imageSequence, _propertyManager.get(), "mouse.x_normalized"));
1418         }
1419         else if (imageData.imageSequenceInteractionMode==ImageData::USE_MOUSE_Y_POSITION)
1420         {
1421             subgraph->setUpdateCallback(new osgPresentation::ImageSequenceUpdateCallback(imageSequence, _propertyManager.get(), "mouse.y_normalized"));
1422         }
1423     }
1424 
1425     // attached any rotation
1426     if (positionData.rotation[0]!=0.0)
1427     {
1428         osg::MatrixTransform* animation_transform = new osg::MatrixTransform;
1429         animation_transform->setDataVariance(osg::Object::DYNAMIC);
1430         animation_transform->setUpdateCallback(
1431             new osgUtil::TransformCallback(subgraph->getBound().center(),
1432                                            osg::Vec3(positionData.rotation[1],positionData.rotation[2],positionData.rotation[3]),
1433                                            osg::DegreesToRadians(positionData.rotation[0])));
1434 
1435         animation_transform->addChild(subgraph);
1436 
1437         subgraph = animation_transform;
1438     }
1439 
1440     // attached any animation
1441     osg::AnimationPathCallback* animation = getAnimationPathCallback(positionData);
1442     if (animation)
1443     {
1444         OSG_INFO<<"Have animation path for image"<<std::endl;
1445 
1446         osg::BoundingSphere::vec_type pivot = positionData.absolute_path ?
1447                 osg::BoundingSphere::vec_type(0.0f,0.0f,0.0f) :
1448                 subgraph->getBound().center();
1449 
1450         osg::PositionAttitudeTransform* animation_transform = new osg::PositionAttitudeTransform;
1451         animation_transform->setDataVariance(osg::Object::DYNAMIC);
1452         animation_transform->setPivotPoint(pivot);
1453         animation->setPivotPoint(pivot);
1454 
1455         animation_transform->setUpdateCallback(animation);
1456 
1457         animation_transform->setReferenceFrame(positionData.absolute_path ?
1458                                                     osg::Transform::ABSOLUTE_RF:
1459                                                     osg::Transform::RELATIVE_RF);
1460 
1461         animation_transform->addChild(subgraph);
1462 
1463         subgraph = animation_transform;
1464     }
1465 
1466     if (positionData.hud)
1467     {
1468         HUDTransform* hudTransform = new HUDTransform(_hudSettings.get());
1469         hudTransform->addChild(subgraph);
1470 
1471         subgraph = hudTransform;
1472     }
1473 
1474     addToCurrentLayer(subgraph);
1475 
1476     if (scriptData.hasScripts()) addScriptsToNode(scriptData, subgraph);
1477 }
1478 
addStereoImagePair(const std::string & filenameLeft,const ImageData & imageDataLeft,const std::string & filenameRight,const ImageData & imageDataRight,const PositionData & positionData,const ScriptData & scriptData)1479 void SlideShowConstructor::addStereoImagePair(const std::string& filenameLeft, const ImageData& imageDataLeft, const std::string& filenameRight, const ImageData& imageDataRight,const PositionData& positionData, const ScriptData& scriptData)
1480 {
1481     osg::ref_ptr<osg::Image> imageLeft = readImage(filenameLeft, imageDataLeft);
1482     osg::ref_ptr<osg::Image> imageRight = (filenameRight==filenameLeft) ? imageLeft.get() : readImage(filenameRight, imageDataRight);
1483 
1484     if (!imageLeft && !imageRight) return;
1485 
1486     bool isImageTranslucent = false;
1487 
1488     osg::ImageStream* imageStreamLeft = dynamic_cast<osg::ImageStream*>(imageLeft.get());
1489     if (imageStreamLeft)
1490     {
1491         imageStreamLeft->setLoopingMode(imageDataLeft.loopingMode);
1492         isImageTranslucent = imageStreamLeft->getPixelFormat()==GL_RGBA ||
1493                              imageStreamLeft->getPixelFormat()==GL_BGRA;
1494     }
1495     else
1496     {
1497         isImageTranslucent = imageLeft->isImageTranslucent();
1498     }
1499 
1500     osg::ImageStream* imageStreamRight = dynamic_cast<osg::ImageStream*>(imageRight.get());
1501     if (imageStreamRight)
1502     {
1503         imageStreamRight->setLoopingMode(imageDataRight.loopingMode);
1504         if (!isImageTranslucent)
1505         {
1506             isImageTranslucent = imageStreamRight->getPixelFormat()==GL_RGBA ||
1507                                 imageStreamRight->getPixelFormat()==GL_BGRA;
1508         }
1509     }
1510     else if (!isImageTranslucent)
1511     {
1512         isImageTranslucent = imageRight->isImageTranslucent();
1513     }
1514 
1515     if (imageDataLeft.blendingHint==ImageData::ON || imageDataRight.blendingHint==ImageData::ON)
1516     {
1517         isImageTranslucent = true;
1518     }
1519     else if (imageDataLeft.blendingHint==ImageData::OFF || imageDataRight.blendingHint==ImageData::OFF)
1520     {
1521         isImageTranslucent = false;
1522     }
1523 
1524 
1525     float s = imageLeft->s();
1526     float t = imageLeft->t();
1527 
1528 
1529     float sx = imageDataLeft.region_in_pixel_coords ? 1.0f : s;
1530     float sy = imageDataLeft.region_in_pixel_coords ? 1.0f : t;
1531 
1532     float x1 = imageDataLeft.region[0]*sx;
1533     float y1 = imageDataLeft.region[1]*sy;
1534     float x2 = imageDataLeft.region[2]*sx;
1535     float y2 = imageDataLeft.region[3]*sy;
1536 
1537     float aspectRatio = (y2-y1)/(x2-x1);
1538 
1539     float image_width = _slideWidth*positionData.scale.x();
1540     float image_height = image_width*aspectRatio*positionData.scale.y()/positionData.scale.x();
1541 
1542     float offset = 0.0f;
1543 
1544     bool usedTextureRectangle = false;
1545 
1546     osg::Vec3 pos = computePositionInModelCoords(positionData);
1547     osg::Vec3 image_local_pos = osg::Vec3(-image_width*0.5f+offset,-offset,-image_height*0.5f-offset);
1548     osg::Vec3 image_pos = positionData.autoRotate ? image_local_pos : (pos+image_local_pos);
1549 
1550 
1551     osg::Node* pictureLeft = 0;
1552     {
1553         osg::Geometry* pictureLeftQuad = createTexturedQuadGeometry(image_pos, positionData.rotate, image_width,image_height,imageLeft.get(),usedTextureRectangle);
1554         osg::StateSet* pictureLeftStateSet = pictureLeftQuad->getOrCreateStateSet();
1555 
1556         if (isImageTranslucent)
1557         {
1558             pictureLeftStateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
1559         }
1560 
1561         attachTexMat(pictureLeftStateSet, imageDataLeft, s, t, usedTextureRectangle);
1562 
1563         if (positionData.autoRotate)
1564         {
1565             osg::Billboard* billboard = new osg::Billboard;
1566             billboard->setMode(osg::Billboard::POINT_ROT_EYE);
1567             billboard->setNormal(osg::Vec3(0.0f,-1.0f,0.0f));
1568             billboard->setAxis(osg::Vec3(0.0f,0.0f,1.0f));
1569             billboard->addDrawable(pictureLeftQuad,pos);
1570             pictureLeft = billboard;
1571         }
1572         else
1573         {
1574             osg::Geode* geode = new osg::Geode;
1575             geode->addDrawable(pictureLeftQuad);
1576             pictureLeft = geode;
1577         }
1578 
1579         pictureLeft->setNodeMask(_leftEyeMask);
1580     }
1581 
1582     osg::Node* pictureRight = 0;
1583     {
1584         osg::Geometry* pictureRightQuad = createTexturedQuadGeometry(image_pos, positionData.rotate, image_width,image_height,imageRight.get(),usedTextureRectangle);
1585         osg::StateSet* pictureRightStateSet = pictureRightQuad->getOrCreateStateSet();
1586 
1587         if (isImageTranslucent)
1588         {
1589             pictureRightStateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
1590         }
1591 
1592         attachTexMat(pictureRightStateSet, imageDataRight, s, t, usedTextureRectangle);
1593 
1594         if (positionData.autoRotate)
1595         {
1596             osg::Billboard* billboard = new osg::Billboard;
1597             billboard->setMode(osg::Billboard::POINT_ROT_EYE);
1598             billboard->setNormal(osg::Vec3(0.0f,-1.0f,0.0f));
1599             billboard->setAxis(osg::Vec3(0.0f,0.0f,1.0f));
1600             billboard->addDrawable(pictureRightQuad,pos);
1601             pictureRight = billboard;
1602         }
1603         else
1604         {
1605             osg::Geode* geode = new osg::Geode;
1606             geode->addDrawable(pictureRightQuad);
1607             pictureRight = geode;
1608         }
1609 
1610         pictureRight->setNodeMask(_rightEyeMask);
1611     }
1612 
1613     osg::Group* subgraph = new osg::Group;
1614     subgraph->addChild(pictureLeft);
1615     subgraph->addChild(pictureRight);
1616 
1617     if (imageStreamLeft && !imageDataLeft.volume.empty())
1618     {
1619         setUpMovieVolume(subgraph, imageStreamLeft, imageDataLeft);
1620     }
1621 
1622     if (imageStreamRight && !imageDataRight.volume.empty())
1623     {
1624         setUpMovieVolume(subgraph, imageStreamRight, imageDataRight);
1625     }
1626 
1627     osg::ImageSequence* imageSequence = dynamic_cast<osg::ImageSequence*>(imageLeft.get());
1628     if (imageSequence)
1629     {
1630         if (imageDataLeft.imageSequenceInteractionMode==ImageData::USE_MOUSE_X_POSITION)
1631         {
1632             subgraph->setUpdateCallback(new osgPresentation::ImageSequenceUpdateCallback(imageSequence, _propertyManager.get(), "mouse.x_normalized"));
1633         }
1634         else if (imageDataLeft.imageSequenceInteractionMode==ImageData::USE_MOUSE_Y_POSITION)
1635         {
1636             subgraph->setUpdateCallback(new osgPresentation::ImageSequenceUpdateCallback(imageSequence, _propertyManager.get(), "mouse.y_normalized"));
1637         }
1638     }
1639 
1640     // attach any meterial animation.
1641     if (positionData.requiresMaterialAnimation())
1642         subgraph = attachMaterialAnimation(subgraph,positionData)->asGroup();
1643 
1644     if (isImageTranslucent)
1645     {
1646         SetToTransparentBin sttb;
1647         subgraph->accept(sttb);
1648     }
1649 
1650     // attached any rotation
1651     if (positionData.rotation[0]!=0.0)
1652     {
1653         osg::MatrixTransform* animation_transform = new osg::MatrixTransform;
1654         animation_transform->setDataVariance(osg::Object::DYNAMIC);
1655         animation_transform->setUpdateCallback(
1656             new osgUtil::TransformCallback(subgraph->getBound().center(),
1657                                            osg::Vec3(positionData.rotation[1],positionData.rotation[2],positionData.rotation[3]),
1658                                            osg::DegreesToRadians(positionData.rotation[0])));
1659 
1660         animation_transform->addChild(subgraph);
1661 
1662         subgraph = animation_transform;
1663     }
1664 
1665     // attached any animation
1666     osg::AnimationPathCallback* animation = getAnimationPathCallback(positionData);
1667     if (animation)
1668     {
1669         OSG_INFO<<"Have animation path for image"<<std::endl;
1670 
1671         osg::BoundingSphere::vec_type pivot = positionData.absolute_path ?
1672                 osg::BoundingSphere::vec_type(0.0f,0.0f,0.0f) :
1673                 subgraph->getBound().center();
1674 
1675         osg::PositionAttitudeTransform* animation_transform = new osg::PositionAttitudeTransform;
1676         animation_transform->setDataVariance(osg::Object::DYNAMIC);
1677         animation_transform->setPivotPoint(pivot);
1678         animation->setPivotPoint(pivot);
1679 
1680         animation_transform->setUpdateCallback(animation);
1681         animation_transform->setReferenceFrame(positionData.absolute_path ?
1682                                                     osg::Transform::ABSOLUTE_RF:
1683                                                     osg::Transform::RELATIVE_RF);
1684 
1685         animation_transform->addChild(subgraph);
1686 
1687         subgraph = animation_transform;
1688     }
1689 
1690     if (positionData.hud)
1691     {
1692         HUDTransform* hudTransform = new HUDTransform(_hudSettings.get());
1693         hudTransform->addChild(subgraph);
1694 
1695         subgraph = hudTransform;
1696     }
1697 
1698     addToCurrentLayer(subgraph);
1699 
1700     if (scriptData.hasScripts()) addScriptsToNode(scriptData, subgraph);
1701 }
1702 
addGraph(const std::string & contents,const PositionData & positionData,const ImageData & imageData,const ScriptData & scriptData)1703 void SlideShowConstructor::addGraph(const std::string& contents, const PositionData& positionData, const ImageData& imageData, const ScriptData& scriptData)
1704 {
1705     static int s_count=0;
1706 
1707     if (contents.empty()) return;
1708 
1709     std::string tmpDirectory("/tmp/");
1710 
1711     std::string filename = contents;
1712     std::string ext = osgDB::getFileExtension(contents);
1713     if (ext.empty())
1714     {
1715         std::stringstream dotFileNameStream;
1716         dotFileNameStream << tmpDirectory<<"graph_"<<s_count<<std::string(".dot");
1717         filename = dotFileNameStream.str();
1718 
1719         // write out the string to the temporary file.
1720         std::ofstream fout(filename.c_str());
1721         fout<<contents.c_str();
1722     }
1723 
1724     std::stringstream svgFileNameStream;
1725     svgFileNameStream << tmpDirectory<<osgDB::getStrippedName(filename)<<s_count<<std::string(".svg");
1726     std::string tmpSvgFileName(svgFileNameStream.str());
1727     std::string dotFileName = filename;
1728 
1729     if (osgDB::getFileExtension(filename)=="dot")
1730     {
1731         dotFileName = filename;
1732     }
1733     else
1734     {
1735         osg::ref_ptr<osg::Node> model = osgDB::readRefNodeFile(filename, _options.get());
1736         if (!model) return;
1737 
1738         dotFileName = tmpDirectory+osgDB::getStrippedName(filename)+std::string(".dot");
1739 
1740         osg::ref_ptr<osgDB::Options> opts = _options.valid() ? _options->cloneOptions() : (new osgDB::Options);
1741         if (!imageData.options.empty())
1742         {
1743             opts->setOptionString(imageData.options);
1744         }
1745         opts->setObjectCacheHint(osgDB::Options::CACHE_NONE);
1746 
1747         osgDB::writeNodeFile(*model, dotFileName, opts.get());
1748     }
1749 
1750     std::stringstream command;
1751     command<<"dot -Tsvg "<<dotFileName<<" -o "<<tmpSvgFileName;
1752     int result = system(command.str().c_str());
1753     if (result==0)
1754     {
1755         osg::ref_ptr<osgDB::Options> previousOptions = _options;
1756 
1757         // switch off cache so we make sure that we re-read the generated svg each time.
1758         _options = _options.valid() ? _options->cloneOptions() : (new osgDB::Options);
1759         _options->setObjectCacheHint(osgDB::Options::CACHE_NONE);
1760 
1761         addImage(tmpSvgFileName, positionData, imageData, scriptData);
1762 
1763         _options = previousOptions;
1764 
1765         ++s_count;
1766     }
1767     else OSG_NOTICE<<"Error: SlideShowConstructor::addGraph() system("<<command.str()<<") failed with return "<<result<<std::endl;
1768 }
1769 
1770 
addVNC(const std::string & hostname,const PositionData & positionData,const ImageData & imageData,const std::string & password,const ScriptData & scriptData)1771 void SlideShowConstructor::addVNC(const std::string& hostname, const PositionData& positionData, const ImageData& imageData, const std::string& password, const ScriptData& scriptData)
1772 {
1773     if (!password.empty())
1774     {
1775         OSG_NOTICE<<"Setting password"<<std::endl;
1776         if (!osgDB::Registry::instance()->getAuthenticationMap()) osgDB::Registry::instance()->setAuthenticationMap(new osgDB::AuthenticationMap);
1777         osgDB::Registry::instance()->getAuthenticationMap()->addAuthenticationDetails(hostname, new osgDB::AuthenticationDetails("", password));
1778     }
1779 
1780     addInteractiveImage(hostname+".vnc", positionData, imageData, scriptData);
1781 }
1782 
addBrowser(const std::string & url,const PositionData & positionData,const ImageData & imageData,const ScriptData & scriptData)1783 void SlideShowConstructor::addBrowser(const std::string& url, const PositionData& positionData, const ImageData& imageData, const ScriptData& scriptData)
1784 {
1785     addInteractiveImage(url+".gecko", positionData, imageData, scriptData);
1786 }
1787 
addPDF(const std::string & filename,const PositionData & positionData,const ImageData & imageData,const ScriptData & scriptData)1788 void SlideShowConstructor::addPDF(const std::string& filename, const PositionData& positionData, const ImageData& imageData, const ScriptData& scriptData)
1789 {
1790     addInteractiveImage(filename, positionData, imageData, scriptData);
1791 }
1792 
1793 class SetPageCallback: public LayerCallback
1794 {
1795 public:
SetPageCallback(osgWidget::PdfImage * pdfImage,int pageNum)1796     SetPageCallback(osgWidget::PdfImage* pdfImage, int pageNum):
1797         _pdfImage(pdfImage),
1798         _pageNum(pageNum)
1799     {
1800     }
1801 
operator ()(osg::Node *) const1802     virtual void operator() (osg::Node*) const
1803     {
1804         OSG_INFO<<"PDF Page to be updated "<<_pageNum<<std::endl;
1805 
1806         if (_pdfImage.valid() && _pdfImage->getPageNum()!=_pageNum)
1807         {
1808             _pdfImage->page(_pageNum);
1809         }
1810     }
1811 
1812     osg::observer_ptr<osgWidget::PdfImage> _pdfImage;
1813     int _pageNum;
1814 };
1815 
1816 
addInteractiveImage(const std::string & filename,const PositionData & positionData,const ImageData & imageData,const ScriptData & scriptData)1817 osg::Image* SlideShowConstructor::addInteractiveImage(const std::string& filename, const PositionData& positionData, const ImageData& imageData, const ScriptData& scriptData)
1818 {
1819     osg::ref_ptr<osgDB::Options> options = _options;
1820     if (!imageData.options.empty())
1821     {
1822         options = _options->cloneOptions();
1823         options->setOptionString(imageData.options);
1824     }
1825 
1826     osg::ref_ptr<osg::Image> image = osgDB::readRefImageFile(filename, options.get());
1827 
1828     OSG_INFO<<"addInteractiveImage("<<filename<<") "<<image<<std::endl;
1829 
1830 
1831     if (!image) return 0;
1832 
1833     float s = image->s();
1834     float t = image->t();
1835 
1836     float sx = imageData.region_in_pixel_coords ? 1.0f : s;
1837     float sy = imageData.region_in_pixel_coords ? 1.0f : t;
1838 
1839     float x1 = imageData.region[0]*sx;
1840     float y1 = imageData.region[1]*sy;
1841     float x2 = imageData.region[2]*sx;
1842     float y2 = imageData.region[3]*sy;
1843 
1844     float aspectRatio = (y2-y1)/(x2-x1);
1845 
1846     float image_width = _slideWidth*positionData.scale.x();
1847     float image_height = image_width*aspectRatio*positionData.scale.y()/positionData.scale.x();
1848     float offset = 0.0f;
1849 
1850     osg::Vec3 pos = computePositionInModelCoords(positionData);
1851     osg::Vec3 image_local_pos = osg::Vec3(-image_width*0.5f+offset,-offset,-image_height*0.5f-offset);
1852     osg::Vec3 image_pos = positionData.autoRotate ? image_local_pos : (pos+image_local_pos);
1853 
1854     bool usedTextureRectangle = false;
1855     osg::Geometry* pictureQuad = createTexturedQuadGeometry(image_pos, positionData.rotate, image_width, image_height, image.get(), usedTextureRectangle);
1856 
1857     osg::ref_ptr<osgViewer::InteractiveImageHandler> handler = new osgViewer::InteractiveImageHandler(image.get());
1858     pictureQuad->setEventCallback(handler.get());
1859     pictureQuad->setCullCallback(handler.get());
1860 
1861     osg::StateSet* pictureStateSet = pictureQuad->getOrCreateStateSet();
1862 
1863     attachTexMat(pictureStateSet, imageData, s, t, usedTextureRectangle);
1864 
1865     pictureStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
1866 
1867     osg::Node* subgraph = 0;
1868 
1869     if (positionData.autoRotate)
1870     {
1871         osg::Billboard* picture = new osg::Billboard;
1872         picture->setMode(osg::Billboard::POINT_ROT_EYE);
1873         picture->setNormal(osg::Vec3(0.0f,-1.0f,0.0f));
1874         picture->setAxis(osg::Vec3(0.0f,0.0f,1.0f));
1875         picture->addDrawable(pictureQuad,pos);
1876         subgraph = picture;
1877     }
1878     else
1879     {
1880         osg::Geode* picture = new osg::Geode;
1881         picture->addDrawable(pictureQuad);
1882         subgraph = picture;
1883     }
1884 
1885     // attach any meterial animation.
1886     if (positionData.requiresMaterialAnimation())
1887         subgraph = attachMaterialAnimation(subgraph,positionData);
1888 
1889 
1890     // attached any rotation
1891     if (positionData.rotation[0]!=0.0)
1892     {
1893         osg::MatrixTransform* animation_transform = new osg::MatrixTransform;
1894         animation_transform->setDataVariance(osg::Object::DYNAMIC);
1895         animation_transform->setUpdateCallback(
1896             new osgUtil::TransformCallback(subgraph->getBound().center(),
1897                                            osg::Vec3(positionData.rotation[1],positionData.rotation[2],positionData.rotation[3]),
1898                                            osg::DegreesToRadians(positionData.rotation[0])));
1899 
1900         animation_transform->addChild(subgraph);
1901 
1902         subgraph = animation_transform;
1903     }
1904 
1905 
1906     // attached any animation
1907     osg::AnimationPathCallback* animation = getAnimationPathCallback(positionData);
1908     if (animation)
1909     {
1910         OSG_INFO<<"Have animation path for image"<<std::endl;
1911 
1912         osg::BoundingSphere::vec_type pivot = positionData.absolute_path ?
1913                 osg::BoundingSphere::vec_type(0.0f,0.0f,0.0f) :
1914                 subgraph->getBound().center();
1915 
1916         osg::PositionAttitudeTransform* animation_transform = new osg::PositionAttitudeTransform;
1917         animation_transform->setDataVariance(osg::Object::DYNAMIC);
1918         animation_transform->setPivotPoint(pivot);
1919         animation->setPivotPoint(pivot);
1920 
1921         animation_transform->setUpdateCallback(animation);
1922 
1923         animation_transform->setReferenceFrame(positionData.absolute_path ?
1924                                                     osg::Transform::ABSOLUTE_RF:
1925                                                     osg::Transform::RELATIVE_RF);
1926 
1927         animation_transform->addChild(subgraph);
1928 
1929         subgraph = animation_transform;
1930     }
1931 
1932     if (positionData.hud)
1933     {
1934         HUDTransform* hudTransform = new HUDTransform(_hudSettings.get());
1935         hudTransform->addChild(subgraph);
1936 
1937         subgraph = hudTransform;
1938     }
1939 
1940     addToCurrentLayer(subgraph);
1941 
1942     osgWidget::PdfImage* pdfImage = dynamic_cast<osgWidget::PdfImage*>(image.get());
1943     if (pdfImage && imageData.page>=0)
1944     {
1945         getOrCreateLayerAttributes(_currentLayer.get())->addEnterCallback(new SetPageCallback(pdfImage, imageData.page));
1946 
1947         OSG_INFO<<"Setting pdf page num "<<imageData.page<<std::endl;
1948         pdfImage->setBackgroundColor(imageData.backgroundColor);
1949         pdfImage->page(imageData.page);
1950 
1951         if (imageData.backgroundColor.a()<1.0f)
1952         {
1953             SetToTransparentBin sttb;
1954             subgraph->accept(sttb);
1955         }
1956 
1957 
1958     }
1959 
1960     if (scriptData.hasScripts()) addScriptsToNode(scriptData, subgraph);
1961 
1962     return image.release();
1963 }
1964 
findFileAndRecordPath(const std::string & filename)1965 std::string SlideShowConstructor::findFileAndRecordPath(const std::string& filename)
1966 {
1967     std::string foundFile = osgDB::findDataFile(filename, _options.get());
1968     if (foundFile.empty()) return filename;
1969 
1970     OSG_INFO<<"foundFile "<<foundFile<<std::endl;
1971 
1972     std::string path = osgDB::getFilePath(foundFile);
1973     if (!path.empty() && _filePathData.valid())
1974     {
1975         osgDB::FilePathList::iterator itr = std::find(_filePathData->filePathList.begin(),_filePathData->filePathList.end(),path);
1976         if (itr==_filePathData->filePathList.end())
1977         {
1978             OSG_INFO<<"New path to record "<<path<<std::endl;
1979             _filePathData->filePathList.push_front(path);
1980         }
1981     }
1982 
1983     return foundFile;
1984 
1985 }
1986 
1987 
1988 struct ClipRegionCallback : public osg::NodeCallback
1989 {
1990 public:
ClipRegionCallbackClipRegionCallback1991     ClipRegionCallback(const osg::Matrixd& originalMatrix, const std::string& str):
1992         _matrix(originalMatrix),
1993         _source(str) {}
1994 
operator ()ClipRegionCallback1995     virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
1996     {
1997         osg::MatrixTransform* transform = dynamic_cast<osg::MatrixTransform*>(node);
1998         if (transform)
1999         {
2000             PropertyReader pr(nv->getNodePath(), _source);
2001 
2002             float xMin=0.0;
2003             float yMin=0.0;
2004             float zMin=0.0;
2005             float xMax=1.0;
2006             float yMax=1.0;
2007             float zMax=1.0;
2008 
2009             pr>>xMin>>yMin>>zMin>>xMax>>yMax>>zMax;
2010 
2011             if (pr.ok())
2012             {
2013                 OSG_NOTICE<<"ClipRegionCallback : xMin="<<xMin<<", yMin="<<yMin<<", zMin="<<zMin<<", xMax="<<xMax<<", yMax="<<yMax<<", zMax="<<zMax<<std::endl;
2014             }
2015             else
2016             {
2017                 OSG_NOTICE<<"Problem in reading, ClipRegionCallback : xMin="<<xMin<<", yMin="<<yMin<<", zMin="<<zMin<<", xMax="<<xMax<<", yMax="<<yMax<<", zMax="<<zMax<<std::endl;
2018             }
2019 
2020             osg::Matrixd tm = osg::Matrix::scale(xMax-xMin, yMax-yMin, zMax-zMin) *
2021                               osg::Matrix::translate(xMin,yMin,zMin);
2022 
2023             transform->setMatrix(tm * _matrix);
2024 
2025         }
2026         else
2027         {
2028             OSG_NOTICE<<"ClipRegionCallback not attached to MatrixTransform, unable to update any values."<<std::endl;
2029         }
2030 
2031         // note, callback is responsible for scenegraph traversal so
2032         // they must call traverse(node,nv) to ensure that the
2033         // scene graph subtree (and associated callbacks) are traversed.
2034         traverse(node, nv);
2035     }
2036 
2037 protected:
2038 
2039     osg::Matrixd _matrix;
2040     std::string  _source;
2041 };
2042 
2043 
addModel(const std::string & filename,const PositionData & positionData,const ModelData & modelData,const ScriptData & scriptData)2044 void SlideShowConstructor::addModel(const std::string& filename, const PositionData& positionData, const ModelData& modelData, const ScriptData& scriptData)
2045 {
2046     OSG_INFO<<"SlideShowConstructor::addModel("<<filename<<")"<<std::endl;
2047 
2048     osg::ref_ptr<osgDB::Options> options = _options;
2049     if (!modelData.options.empty())
2050     {
2051         options = _options->cloneOptions();
2052         options->setOptionString(modelData.options);
2053     }
2054 
2055     osg::ref_ptr<osg::Node> subgraph;
2056 
2057     if (filename=="sphere")
2058     {
2059         osg::Geode* geode = new osg::Geode;
2060         geode->addDrawable(new osg::ShapeDrawable(new osg::Sphere));
2061 
2062         subgraph = geode;
2063     }
2064     else if (filename=="box")
2065     {
2066         osg::Geode* geode = new osg::Geode;
2067         geode->addDrawable(new osg::ShapeDrawable(new osg::Box));
2068 
2069         subgraph = geode;
2070     }
2071     else
2072     {
2073         subgraph = osgDB::readRefNodeFile(filename, options.get());
2074         if (subgraph) recordOptionsFilePath(options.get());
2075     }
2076 
2077     if (!modelData.region.empty())
2078     {
2079         osg::ref_ptr<osg::ClipNode> clipnode = new osg::ClipNode;
2080         clipnode->createClipBox(osg::BoundingBox(0.0,0.0,0.0,1.0,1.0,1.0),0);
2081         clipnode->setCullingActive(false);
2082 
2083         osg::ref_ptr<osg::MatrixTransform> transform = new osg::MatrixTransform;
2084         transform->addChild(clipnode.get());
2085 
2086         osg::ref_ptr<osg::Group> group = new osg::Group;
2087         group->addChild(subgraph.get());
2088         group->addChild(transform.get());
2089 
2090         //clipnode->setStateSetModes(*(group->getOrCreateStateSet()), osg::StateAttribute::ON);
2091         group->setStateSet(clipnode->getStateSet());
2092 
2093         osg::ComputeBoundsVisitor cbbv(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN);
2094         subgraph->accept(cbbv);
2095         osg::BoundingBox bb = cbbv.getBoundingBox();
2096         double width = bb.xMax()-bb.xMin();
2097         double length = bb.yMax()-bb.yMin();
2098         double height = bb.zMax()-bb.zMin();
2099 
2100         osg::Matrixd matrix = osg::Matrixd::translate(-0.5,-0.5,-0.5)*osg::Matrixd::scale(width,length,height)*osg::Matrixd::translate(bb.center());
2101         transform->setMatrix(matrix);
2102 
2103         if (containsPropertyReference(modelData.region))
2104         {
2105             transform->addUpdateCallback(new ClipRegionCallback(matrix, modelData.region));
2106         }
2107         else
2108         {
2109             double region[6];
2110             std::istringstream sstream(modelData.region);
2111             sstream>>region[0]>>region[1]>>region[2]>>region[3]>>region[4]>>region[5];
2112 
2113             osg::Matrix tm = osg::Matrix::scale(region[3]-region[0], region[4]-region[1], region[5]-region[2]) *
2114                              osg::Matrix::translate(region[0],region[1],region[2]);
2115 
2116             transform->setMatrix( tm * matrix );
2117         }
2118 
2119         subgraph = group;
2120 
2121         // osgDB::writeNodeFile(*subgraph, "output.osgt");
2122 
2123     }
2124 
2125 
2126     if (subgraph.valid())
2127     {
2128         addModel(subgraph.get(), positionData, modelData, scriptData);
2129     }
2130     else
2131     {
2132         OSG_NOTICE<<"Could not loaded model file : "<<filename<<std::endl;
2133     }
2134 
2135 
2136     OSG_INFO<<"end of SlideShowConstructor::addModel("<<filename<<")"<<std::endl<<std::endl;
2137 
2138 }
2139 
decorateSubgraphForPositionAndAnimation(osg::Node * node,const PositionData & positionData)2140 osg::Node* SlideShowConstructor::decorateSubgraphForPositionAndAnimation(osg::Node* node, const PositionData& positionData)
2141 {
2142     osg::Node* subgraph = node;
2143     osg::Object::DataVariance defaultMatrixDataVariance = osg::Object::DYNAMIC; // STATIC
2144 
2145     OSG_INFO<<"SlideShowConstructor::decorateSubgraphForPositionAndAnimation() "<<std::endl;
2146 
2147     if (positionData.frame==SLIDE)
2148     {
2149         osg::Vec3 pos = convertSlideToModel(positionData.position);
2150 
2151         const osg::BoundingSphere& bs = subgraph->getBound();
2152         float slide_scale = _slideHeight*(1.0f-positionData.position.z())*0.7f/bs.radius();
2153 
2154         osg::MatrixTransform* transform = new osg::MatrixTransform;
2155         transform->setDataVariance(defaultMatrixDataVariance);
2156         transform->setMatrix(osg::Matrix::translate(-bs.center())*
2157                              osg::Matrix::scale(positionData.scale.x()*slide_scale, positionData.scale.y()*slide_scale ,positionData.scale.z()*slide_scale)*
2158                              osg::Matrix::rotate(osg::DegreesToRadians(positionData.rotate[0]),positionData.rotate[1],positionData.rotate[2],positionData.rotate[3])*
2159                              osg::Matrix::translate(pos));
2160 
2161 
2162         transform->setStateSet(createTransformStateSet());
2163         transform->addChild(subgraph);
2164 
2165         subgraph = transform;
2166 
2167     }
2168     else
2169     {
2170         osg::Matrix matrix(osg::Matrix::scale(1.0f/positionData.scale.x(),1.0f/positionData.scale.y(),1.0f/positionData.scale.z())*
2171                            osg::Matrix::rotate(osg::DegreesToRadians(positionData.rotate[0]),positionData.rotate[1],positionData.rotate[2],positionData.rotate[3])*
2172                            osg::Matrix::translate(positionData.position));
2173 
2174         osg::MatrixTransform* transform = new osg::MatrixTransform;
2175         transform->setDataVariance(defaultMatrixDataVariance);
2176         transform->setMatrix(osg::Matrix::inverse(matrix));
2177 
2178         OSG_INFO<<"Position Matrix "<<transform->getMatrix()<<std::endl;
2179 
2180         transform->addChild(subgraph);
2181 
2182         subgraph = transform;
2183     }
2184 
2185     float referenceSizeRatio = 0.707;
2186     float referenceSize = subgraph->getBound().radius() * referenceSizeRatio;
2187 
2188     // attached any rotation
2189     if (positionData.rotation[0]!=0.0)
2190     {
2191         osg::MatrixTransform* animation_transform = new osg::MatrixTransform;
2192         animation_transform->setDataVariance(osg::Object::DYNAMIC);
2193         animation_transform->setUpdateCallback(
2194             new osgUtil::TransformCallback(subgraph->getBound().center(),
2195                                            osg::Vec3(positionData.rotation[1],positionData.rotation[2],positionData.rotation[3]),
2196                                            osg::DegreesToRadians(positionData.rotation[0])));
2197 
2198         animation_transform->addChild(subgraph);
2199 
2200         OSG_INFO<<"Rotation Matrix "<<animation_transform->getMatrix()<<std::endl;
2201 
2202         subgraph = animation_transform;
2203     }
2204 
2205 
2206     // attached any animation
2207     osg::AnimationPathCallback* animation = getAnimationPathCallback(positionData);
2208     if (animation)
2209     {
2210         OSG_INFO<<"Have animation path for model"<<std::endl;
2211 
2212         osg::BoundingSphere::vec_type pivot = positionData.absolute_path ?
2213             osg::BoundingSphere::vec_type(0.0f,0.0f,0.0f) :
2214             subgraph->getBound().center();
2215 
2216         osg::AnimationPath* path = animation->getAnimationPath();
2217         if (positionData.animation_name=="wheel" && (path->getTimeControlPointMap()).size()>=2)
2218         {
2219             OSG_INFO<<"****  Need to handle special wheel animation"<<std::endl;
2220 
2221             osg::AnimationPath::TimeControlPointMap& controlPoints = path->getTimeControlPointMap();
2222 
2223             osg::AnimationPath::TimeControlPointMap::iterator curr_itr = controlPoints.begin();
2224             osg::AnimationPath::TimeControlPointMap::iterator prev_itr=curr_itr;
2225             ++curr_itr;
2226 
2227             osg::AnimationPath::ControlPoint* prev_cp = &(prev_itr->second);
2228             osg::AnimationPath::ControlPoint* curr_cp = &(curr_itr->second);
2229 
2230             float totalLength = 0;
2231             float rotation_y_axis = 0;
2232             osg::Vec3 delta_position = curr_cp->getPosition() - prev_cp->getPosition();
2233             float rotation_z_axis = atan2f(delta_position.y(),delta_position.x());
2234 
2235             osg::Quat quat_y_axis,quat_z_axis,quat_combined;
2236 
2237             quat_y_axis.makeRotate(rotation_y_axis,0.0f,1.0f,0.0f);
2238             quat_z_axis.makeRotate(rotation_z_axis,0.0f,0.0f,1.0f);
2239             quat_combined = quat_y_axis*quat_z_axis;
2240 
2241             // set first rotation.
2242             prev_cp->setRotation(quat_combined);
2243 
2244             for(;
2245                 curr_itr!=controlPoints.end();
2246                 ++curr_itr)
2247             {
2248                 prev_cp = &(prev_itr->second);
2249                 curr_cp = &(curr_itr->second);
2250 
2251                 delta_position = curr_cp->getPosition() - prev_cp->getPosition();
2252 
2253                 totalLength += delta_position.length();
2254 
2255                 // rolling - rotation about the y axis.
2256                 rotation_y_axis = totalLength/referenceSize;
2257 
2258                 // direction - rotation about the z axis.
2259                 rotation_z_axis = atan2f(delta_position.y(),delta_position.x());
2260 
2261                 OSG_INFO<<" rotation_y_axis="<<rotation_y_axis<<" rotation_z_axis="<<rotation_z_axis<<std::endl;
2262 
2263                 quat_y_axis.makeRotate(rotation_y_axis,0.0f,1.0f,0.0f);
2264                 quat_z_axis.makeRotate(rotation_z_axis,0.0f,0.0f,1.0f);
2265                 quat_combined = quat_y_axis*quat_z_axis;
2266 
2267                 curr_cp->setRotation(quat_combined);
2268 
2269                 prev_itr = curr_itr;
2270 
2271             }
2272 
2273         }
2274 
2275 
2276         osg::PositionAttitudeTransform* animation_transform = new osg::PositionAttitudeTransform;
2277         animation_transform->setDataVariance(osg::Object::DYNAMIC);
2278         animation_transform->setPivotPoint(pivot);
2279         animation->setPivotPoint(pivot);
2280         animation_transform->setUpdateCallback(animation);
2281 
2282         animation_transform->setReferenceFrame(positionData.absolute_path ?
2283                                                     osg::Transform::ABSOLUTE_RF:
2284                                                     osg::Transform::RELATIVE_RF);
2285 
2286         animation_transform->addChild(subgraph);
2287 
2288         subgraph = animation_transform;
2289     }
2290 
2291     return subgraph;
2292 }
2293 
2294 
addModel(osg::Node * subgraph,const PositionData & positionData,const ModelData & modelData,const ScriptData & scriptData)2295 void SlideShowConstructor::addModel(osg::Node* subgraph, const PositionData& positionData, const ModelData& modelData, const ScriptData& scriptData)
2296 {
2297     if (!modelData.effect.empty())
2298     {
2299         if (modelData.effect=="SpecularHighlights" || modelData.effect=="glossy")
2300         {
2301             osgFX::SpecularHighlights* specularHighlights = new osgFX::SpecularHighlights;
2302             specularHighlights->setTextureUnit(1);
2303             specularHighlights->addChild(subgraph);
2304             subgraph = specularHighlights;
2305         }
2306     }
2307 
2308 
2309 
2310     // attach any meterial animation.
2311     if (positionData.requiresMaterialAnimation())
2312         subgraph = attachMaterialAnimation(subgraph,positionData);
2313 
2314 
2315     subgraph = decorateSubgraphForPositionAndAnimation(subgraph, positionData);
2316 
2317     findImageStreamsAndAddCallbacks(subgraph);
2318 
2319     addToCurrentLayer(subgraph);
2320 
2321     if (scriptData.hasScripts()) addScriptsToNode(scriptData, subgraph);
2322 }
2323 
2324 class DraggerVolumeTileCallback : public osgManipulator::DraggerCallback
2325 {
2326 public:
2327 
DraggerVolumeTileCallback(osgVolume::VolumeTile * volume,osgVolume::Locator * locator)2328     DraggerVolumeTileCallback(osgVolume::VolumeTile* volume, osgVolume::Locator* locator):
2329         _volume(volume),
2330         _locator(locator) {}
2331 
2332 
2333     virtual bool receive(const osgManipulator::MotionCommand& command);
2334 
2335 
2336     osg::observer_ptr<osgVolume::VolumeTile>    _volume;
2337     osg::ref_ptr<osgVolume::Locator>            _locator;
2338 
2339     osg::Matrix _startMotionMatrix;
2340 
2341     osg::Matrix _localToWorld;
2342     osg::Matrix _worldToLocal;
2343 
2344 };
2345 
receive(const osgManipulator::MotionCommand & command)2346 bool DraggerVolumeTileCallback::receive(const osgManipulator::MotionCommand& command)
2347 {
2348     if (!_locator) return false;
2349 
2350     switch (command.getStage())
2351     {
2352         case osgManipulator::MotionCommand::START:
2353         {
2354             // Save the current matrix
2355             _startMotionMatrix = _locator->getTransform();
2356 
2357             // Get the LocalToWorld and WorldToLocal matrix for this node.
2358             osg::NodePath nodePathToRoot;
2359             osgManipulator::computeNodePathToRoot(*_volume,nodePathToRoot);
2360             _localToWorld = _startMotionMatrix * osg::computeLocalToWorld(nodePathToRoot);
2361             _worldToLocal = osg::Matrix::inverse(_localToWorld);
2362 
2363             return true;
2364         }
2365         case osgManipulator::MotionCommand::MOVE:
2366         {
2367             // Transform the command's motion matrix into local motion matrix.
2368             osg::Matrix localMotionMatrix = _localToWorld * command.getWorldToLocal()
2369                                             * command.getMotionMatrix()
2370                                             * command.getLocalToWorld() * _worldToLocal;
2371 
2372             // Transform by the localMotionMatrix
2373             _locator->setTransform(localMotionMatrix * _startMotionMatrix);
2374 
2375             // OSG_NOTICE<<"New locator matrix "<<_locator->getTransform()<<std::endl;
2376 
2377             return true;
2378         }
2379         case osgManipulator::MotionCommand::FINISH:
2380         {
2381             return true;
2382         }
2383         case osgManipulator::MotionCommand::NONE:
2384         default:
2385             return false;
2386     }
2387 }
2388 
2389 class VolumeTileCallback : public osg::NodeCallback
2390 {
2391     public:
2392 
VolumeTileCallback()2393         VolumeTileCallback()
2394         {
2395         }
2396 
VolumeTileCallback(const VolumeTileCallback & vtc,const osg::CopyOp & copyop)2397         VolumeTileCallback(const VolumeTileCallback& vtc,const osg::CopyOp& copyop):
2398             osg::NodeCallback(vtc,copyop) {}
2399 
2400         META_Object(osgPresentation, VolumeTileCallback);
2401 
reset()2402         void reset() {}
update(osg::Node *)2403         void update(osg::Node* /*node*/) {}
setPause(bool)2404         void setPause(bool /*pause*/) {}
2405 
operator ()(osg::Node * node,osg::NodeVisitor * nv)2406         virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
2407         {
2408             osgVolume::VolumeTile* tile = dynamic_cast<osgVolume::VolumeTile*>(node);
2409             osgVolume::Locator* locator = tile ? tile->getLocator() : 0;
2410             if (tile)
2411             {
2412                 OSG_NOTICE<<"VolumeTileCallback : Have locator matrix "<<locator->getTransform()<<std::endl;
2413             }
2414 
2415             // note, callback is responsible for scenegraph traversal so
2416             // they must call traverse(node,nv) to ensure that the
2417             // scene graph subtree (and associated callbacks) are traversed.
2418             traverse(node,nv);
2419         }
2420 
2421 };
2422 
2423 
2424 struct VolumeRegionCallback : public osg::NodeCallback
2425 {
2426 public:
VolumeRegionCallbackVolumeRegionCallback2427     VolumeRegionCallback(const osg::Matrixd& originalMatrix, const std::string& str):
2428         _matrix(originalMatrix),
2429         _source(str) {}
2430 
operator ()VolumeRegionCallback2431     virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
2432     {
2433         osgVolume::VolumeTile* tile = dynamic_cast<osgVolume::VolumeTile*>(node);
2434         osgVolume::Locator* locator = tile ? tile->getLocator() : 0;
2435         if (locator)
2436         {
2437             PropertyReader pr(nv->getNodePath(), _source);
2438 
2439             float xMin=0.0;
2440             float yMin=0.0;
2441             float zMin=0.0;
2442             float xMax=1.0;
2443             float yMax=1.0;
2444             float zMax=1.0;
2445 
2446             pr>>xMin>>yMin>>zMin>>xMax>>yMax>>zMax;
2447 
2448             if (pr.ok())
2449             {
2450                 OSG_NOTICE<<"VolumeRegionCallback : xMin="<<xMin<<", yMin="<<yMin<<", zMin="<<zMin<<", xMax="<<xMax<<", yMax="<<yMax<<", zMax="<<zMax<<std::endl;
2451             }
2452             else
2453             {
2454                 OSG_NOTICE<<"Problem in reading, VolumeRegionCallback : xMin="<<xMin<<", yMin="<<yMin<<", zMin="<<zMin<<", xMax="<<xMax<<", yMax="<<yMax<<", zMax="<<zMax<<std::endl;
2455             }
2456 
2457             osg::Matrixd tm = osg::Matrix::scale(xMax-xMin, yMax-yMin, zMax-zMin) *
2458                               osg::Matrix::translate(xMin,yMin,zMin);
2459 
2460             locator->setTransform(tm * _matrix);
2461 
2462         }
2463         else
2464         {
2465             OSG_NOTICE<<"VolumeRegionCallback not attached to VolumeTile, unable to update any values."<<std::endl;
2466         }
2467 
2468         // note, callback is responsible for scenegraph traversal so
2469         // they must call traverse(node,nv) to ensure that the
2470         // scene graph subtree (and associated callbacks) are traversed.
2471         traverse(node, nv);
2472     }
2473 
2474 protected:
2475 
2476     osg::Matrixd _matrix;
2477     std::string  _source;
2478 };
2479 
2480 struct ScalarPropertyCallback : public osg::NodeCallback
2481 {
2482 public:
ScalarPropertyCallbackScalarPropertyCallback2483     ScalarPropertyCallback(osgVolume::ScalarProperty* sp, const std::string& str):
2484         _sp(sp),
2485         _source(str) {}
2486 
operator ()ScalarPropertyCallback2487     virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
2488     {
2489         PropertyReader pr(nv->getNodePath(), _source);
2490 
2491         float value=0.0;
2492         pr>>value;
2493 
2494         if (pr.ok())
2495         {
2496             OSG_NOTICE<<"ScalarPropertyCallback : value ["<<_source<<"]="<<value<<std::endl;
2497             _sp->setValue(value);
2498         }
2499         else
2500         {
2501             OSG_NOTICE<<"Problem in reading, ScalarPropertyCallback : value="<<value<<std::endl;
2502         }
2503 
2504         // note, callback is responsible for scenegraph traversal so
2505         // they must call traverse(node,nv) to ensure that the
2506         // scene graph subtree (and associated callbacks) are traversed.
2507         traverse(node, nv);
2508     }
2509 
2510 protected:
2511 
2512     osgVolume::ScalarProperty* _sp;
2513     std::string  _source;
2514 };
2515 
2516 struct CollectVolumeSettingsVisitor : public osgVolume::PropertyVisitor, public osg::NodeVisitor
2517 {
CollectVolumeSettingsVisitorCollectVolumeSettingsVisitor2518     CollectVolumeSettingsVisitor():
2519         osgVolume::PropertyVisitor(false) {}
2520 
applyCollectVolumeSettingsVisitor2521     virtual void apply(osg::Node& node)
2522     {
2523         osgVolume::VolumeTile* tile = dynamic_cast<osgVolume::VolumeTile*>(&node);
2524         if (tile)
2525         {
2526             OSG_NOTICE<<"Found Tile "<<tile<<std::endl;
2527             tile->getLayer()->getProperty()->accept(*this);
2528             return;
2529         }
2530 
2531         osgUI::Widget* widget = dynamic_cast<osgUI::Widget*>(&node);
2532         if (widget)
2533         {
2534             OSG_NOTICE<<"Found Widget "<<widget<<std::endl;
2535             _widgets.push_back(widget);
2536             return;
2537         }
2538 
2539 
2540         node.traverse(*this);
2541     }
2542 
applyCollectVolumeSettingsVisitor2543     virtual void apply(osgVolume::VolumeSettings& vs)
2544     {
2545         _vsList.push_back(&vs);
2546     }
2547 
2548     typedef std::vector< osg::ref_ptr<osgVolume::VolumeSettings> > VolumeSettingsList;
2549     VolumeSettingsList _vsList;
2550 
2551     typedef std::vector< osg::ref_ptr<osgUI::Widget> > WidgetList;
2552     WidgetList _widgets;
2553 };
2554 
2555 struct VolumeSettingsCallback : public osgGA::GUIEventHandler
2556 {
2557 
VolumeSettingsCallbackVolumeSettingsCallback2558     VolumeSettingsCallback():
2559         //_saveKey(19), // Ctril-S
2560         //_editKey(05) // Ctrl-E
2561         _saveKey('W'),
2562         _editKey('E')
2563     {
2564     }
2565 
2566     int _saveKey;
2567     int _editKey;
2568 
handleVolumeSettingsCallback2569     bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa, osg::Object* object, osg::NodeVisitor* nv)
2570     {
2571         if (ea.getHandled()) return false;
2572 
2573         osg::Node* node = dynamic_cast<osg::Node*>(object);
2574         if (!node)
2575         {
2576             OSG_NOTICE<<"Warning: VolumeSettingsCallback assigned to a node other than VolumeTile, cannot operate edit/save."<<std::endl;
2577             return false;
2578         }
2579 
2580 
2581         if (ea.getEventType()==osgGA::GUIEventAdapter::KEYUP)
2582         {
2583 
2584             if (ea.getKey()==_saveKey)
2585             {
2586                 CollectVolumeSettingsVisitor cvsv;
2587                 node->accept(cvsv);
2588 
2589                 for(CollectVolumeSettingsVisitor::VolumeSettingsList::iterator itr = cvsv._vsList.begin();
2590                     itr != cvsv._vsList.end();
2591                     ++itr)
2592                 {
2593                     osgVolume::VolumeSettings* vs = itr->get();
2594                     std::string filename = vs->getName();
2595                     if (!filename.empty())
2596                     {
2597                         OSG_NOTICE<<"Save VolumeSettings "<<vs<<" to filename "<<filename<<std::endl;
2598                         osgDB::writeObjectFile(*vs, filename);
2599                     }
2600                     else
2601                     {
2602                         OSG_NOTICE<<"VolumeSettings "<<vs<<" with blank filename, saving to 'no_filename_vs.osgt'"<<std::endl;
2603                         osgDB::writeObjectFile(*vs, "no_filename_vs.osgt");
2604                     }
2605                 }
2606                 return true;
2607             }
2608             if (ea.getKey()==_editKey)
2609             {
2610                 OSG_NOTICE<<"Need to edit VolumeSettings "<<std::endl;
2611 
2612                 CollectVolumeSettingsVisitor cvsv;
2613                 node->accept(cvsv);
2614 
2615                 for(CollectVolumeSettingsVisitor::WidgetList::iterator itr = cvsv._widgets.begin();
2616                     itr != cvsv._widgets.end();
2617                     ++itr)
2618                 {
2619                     osgUI::Widget* widget = itr->get();
2620                     OSG_NOTICE<<"Toggling visibility of Widget "<<widget<<std::endl;
2621 
2622                     widget->setVisible(!widget->getVisible());
2623                 }
2624                 return true;
2625             }
2626         }
2627         return false;
2628     }
2629 };
2630 
2631 
setUpVolumeScalarProperty(osgVolume::VolumeTile * tile,osgVolume::ScalarProperty * property,const std::string & source)2632 void SlideShowConstructor::setUpVolumeScalarProperty(osgVolume::VolumeTile* tile, osgVolume::ScalarProperty* property, const std::string& source)
2633 {
2634     if (!source.empty())
2635     {
2636         if (containsPropertyReference(source))
2637         {
2638             tile->addUpdateCallback(new ScalarPropertyCallback( property, source));
2639         }
2640         else
2641         {
2642             float value;
2643             std::istringstream sstream(source);
2644             sstream>>value;
2645             property->setValue(value);
2646         }
2647     }
2648 }
2649 
2650 
addVolume(const std::string & filename,const PositionData & in_positionData,const VolumeData & volumeData,const ScriptData & scriptData)2651 void SlideShowConstructor::addVolume(const std::string& filename, const PositionData& in_positionData, const VolumeData& volumeData, const ScriptData& scriptData)
2652 {
2653     // osg::Object::DataVariance defaultMatrixDataVariance = osg::Object::DYNAMIC; // STATIC
2654 
2655     PositionData positionData(in_positionData);
2656 
2657     osg::ref_ptr<osgDB::Options> options = _options;
2658     if (!volumeData.options.empty())
2659     {
2660         options = _options->cloneOptions();
2661         options->setOptionString(volumeData.options);
2662     }
2663 
2664     std::string foundFile = filename;
2665     osg::ref_ptr<osg::Image> image;
2666     osg::ref_ptr<osgVolume::Volume> volume;
2667     osg::ref_ptr<osgVolume::VolumeTile> tile;
2668     osg::ref_ptr<osgVolume::ImageLayer> layer;
2669 
2670     // check for wild cards
2671     if (filename.find('*')!=std::string::npos)
2672     {
2673         osgDB::DirectoryContents filenames = osgDB::expandWildcardsInFilename(filename);
2674         if (filenames.empty()) return;
2675 
2676         // make sure images are in alphabetical order.
2677         std::sort(filenames.begin(), filenames.end(), osgDB::FileNameComparator());
2678 
2679         typedef std::vector< osg::ref_ptr<osg::Image> > Images;
2680         Images images;
2681         for(osgDB::DirectoryContents::iterator itr = filenames.begin();
2682             itr != filenames.end();
2683             ++itr)
2684         {
2685             osg::ref_ptr<osg::Image> loadedImage = osgDB::readRefImageFile(*itr, options.get());
2686             if (loadedImage.valid())
2687             {
2688                 images.push_back(loadedImage.get());
2689             }
2690         }
2691 
2692         image = osg::createImage3DWithAlpha(images);
2693     }
2694     else
2695     {
2696         osgDB::FileType fileType = osgDB::fileType(foundFile);
2697         if (fileType == osgDB::FILE_NOT_FOUND)
2698         {
2699             foundFile = findFileAndRecordPath(foundFile);
2700             fileType = osgDB::fileType(foundFile);
2701         }
2702 
2703         if (fileType == osgDB::DIRECTORY)
2704         {
2705             image = osgDB::readRefImageFile(foundFile+".dicom", options.get());
2706         }
2707         else if (fileType == osgDB::REGULAR_FILE)
2708         {
2709             std::string ext = osgDB::getFileExtension(foundFile);
2710             if (ext=="osg" || ext=="ive" || ext=="osgx" || ext=="osgb" || ext=="osgt")
2711             {
2712                 osg::ref_ptr<osg::Object> obj = osgDB::readRefObjectFile(foundFile);
2713                 image = dynamic_cast<osg::Image*>(obj.get());
2714                 volume = dynamic_cast<osgVolume::Volume*>(obj.get());
2715             }
2716             else
2717             {
2718                 image = osgDB::readRefImageFile( foundFile, options.get() );
2719             }
2720         }
2721         else
2722         {
2723             // not found image, so fallback to plugins/callbacks to find the model.
2724             image = osgDB::readRefImageFile( filename, options.get() );
2725             if (image) recordOptionsFilePath(options.get() );
2726         }
2727     }
2728 
2729     if (!image && !volume) return;
2730 
2731 
2732     if (volumeData.colorSpaceOperation!=osg::NO_COLOR_SPACE_OPERATION)
2733     {
2734         OSG_NOTICE<<"Doing colour space conversion"<<std::endl;
2735         osg::ref_ptr<osg::Image> converted_image = osg::colorSpaceConversion(volumeData.colorSpaceOperation, image.get(), volumeData.colorModulate);
2736         if (converted_image!=image)
2737         {
2738             image->swap(*converted_image);
2739         }
2740     }
2741 
2742     if (positionData.scale.x()<0.0)
2743     {
2744         image->flipHorizontal();
2745         positionData.scale.x() = fabs(positionData.scale.x());
2746 
2747         OSG_INFO<<"addVolume(..) image->flipHorizontal();"<<std::endl;
2748     }
2749 
2750     if (positionData.scale.y()<0.0)
2751     {
2752         image->flipVertical();
2753         positionData.scale.y() = fabs(positionData.scale.y());
2754 
2755         OSG_INFO<<"addVolume(..) image->flipVertical();"<<std::endl;
2756     }
2757 
2758     if (positionData.scale.z()<0.0)
2759     {
2760         image->flipDepth();
2761         positionData.scale.z() = fabs(positionData.scale.z());
2762 
2763         OSG_INFO<<"addVolume(..) image->flipDepth();"<<std::endl;
2764     }
2765 
2766     if (volume.valid())
2767     {
2768         if (!tile)
2769         {
2770             if (volume->getNumChildren()>0)
2771             {
2772                 tile = dynamic_cast<osgVolume::VolumeTile*>(volume->getChild(0));
2773             }
2774         }
2775     }
2776     else
2777     {
2778         volume = new osgVolume::Volume;
2779     }
2780 
2781     if (tile.valid())
2782     {
2783         layer = dynamic_cast<osgVolume::ImageLayer*>(tile->getLayer());
2784         image = layer.valid() ? layer->getImage() : 0;
2785     }
2786     else
2787     {
2788         if (!image) return;
2789 
2790         tile = new osgVolume::VolumeTile;
2791         volume->addChild(tile.get());
2792     }
2793 
2794     osg::ref_ptr<osgVolume::VolumeSettings> vs = volumeData.volumeSettings;
2795 
2796     if (!layer)
2797     {
2798         if (!image) return;
2799 
2800         osg::ref_ptr<osgVolume::ImageDetails> details = dynamic_cast<osgVolume::ImageDetails*>(image->getUserData());
2801         osg::ref_ptr<osg::RefMatrix> matrix = details ? details->getMatrix() : dynamic_cast<osg::RefMatrix*>(image->getUserData());
2802 
2803         osg::ref_ptr<osgVolume::ImageLayer> layer = new osgVolume::ImageLayer(image.get());
2804         if (details)
2805         {
2806             layer->setTexelOffset(details->getTexelOffset());
2807             layer->setTexelScale(details->getTexelScale());
2808         }
2809         layer->rescaleToZeroToOneRange();
2810 
2811         if (matrix.valid())
2812         {
2813             layer->setLocator(new osgVolume::Locator(*matrix));
2814             tile->setLocator(new osgVolume::Locator(*matrix));
2815         }
2816         else
2817         {
2818             layer->setLocator(new osgVolume::Locator());
2819             tile->setLocator(new osgVolume::Locator());
2820         }
2821 
2822         if (!volumeData.region.empty())
2823         {
2824             if (containsPropertyReference(volumeData.region))
2825             {
2826                 tile->addUpdateCallback(new VolumeRegionCallback((matrix.valid() ? *matrix : osg::Matrix::identity()), volumeData.region));
2827             }
2828             else
2829             {
2830                 float region[6];
2831                 std::istringstream sstream(volumeData.region);
2832                 sstream>>region[0]>>region[1]>>region[2]>>region[3]>>region[4]>>region[5];
2833 
2834                 osg::Matrix tm = osg::Matrix::scale(region[3]-region[0], region[4]-region[1], region[5]-region[2]) *
2835                                 osg::Matrix::translate(region[0],region[1],region[2]);
2836 
2837                 if (matrix.valid())
2838                 {
2839                     tile->setLocator(new osgVolume::Locator(tm * (*matrix)));
2840                 }
2841                 else
2842                 {
2843                     tile->setLocator(new osgVolume::Locator(tm));
2844                 }
2845             }
2846         }
2847 
2848         tile->setLayer(layer.get());
2849 
2850         osg::ref_ptr<osgVolume::CompositeProperty> groupPropetry = new osgVolume::CompositeProperty;
2851 
2852         osg::ref_ptr<osgVolume::SwitchProperty> sp = new osgVolume::SwitchProperty;
2853         sp->setActiveProperty(0);
2854         groupPropetry->addProperty(sp.get());
2855 
2856 
2857         osg::ref_ptr<osgVolume::AlphaFuncProperty> ap = vs.valid() ? vs->getCutoffProperty() : new osgVolume::AlphaFuncProperty(0.1f);
2858         setUpVolumeScalarProperty(tile.get(), ap.get(), volumeData.cutoffValue);
2859 
2860         osg::ref_ptr<osgVolume::TransparencyProperty> tp = vs.valid() ? vs->getTransparencyProperty() : new osgVolume::TransparencyProperty(1.0f);
2861         setUpVolumeScalarProperty(tile.get(), tp.get(), volumeData.alphaValue);
2862 
2863         osg::ref_ptr<osgVolume::SampleRatioProperty> sr = vs.valid() ? vs->getSampleRatioProperty() : new osgVolume::SampleRatioProperty(1.0);
2864         setUpVolumeScalarProperty(tile.get(), sr.get(), volumeData.sampleRatioValue);
2865 
2866         osg::ref_ptr<osgVolume::SampleRatioWhenMovingProperty> srm = vs.valid() ? vs->getSampleRatioWhenMovingProperty() : 0;
2867         if (!volumeData.sampleRatioWhenMovingValue.empty())
2868         {
2869             srm = new osgVolume::SampleRatioWhenMovingProperty(1.0);
2870             setUpVolumeScalarProperty(tile.get(), srm.get(), volumeData.sampleRatioWhenMovingValue);
2871         }
2872 
2873 
2874         // part of hull implementation.
2875         osg::ref_ptr<osgVolume::ExteriorTransparencyFactorProperty> etfp;
2876         if (!volumeData.exteriorTransparencyFactorValue.empty())
2877         {
2878             etfp = new osgVolume::ExteriorTransparencyFactorProperty(0.0f);
2879             setUpVolumeScalarProperty(tile.get(), etfp.get(), volumeData.exteriorTransparencyFactorValue);
2880         }
2881 
2882         // deprecated, used by old RayTracedTechnique
2883         osg::ref_ptr<osgVolume::SampleDensityProperty> sd = new osgVolume::SampleDensityProperty(0.005);
2884         setUpVolumeScalarProperty(tile.get(), sd.get(), volumeData.sampleDensityValue);
2885 
2886         osg::ref_ptr<osgVolume::SampleDensityWhenMovingProperty> sdm;
2887         if (!volumeData.sampleDensityWhenMovingValue.empty())
2888         {
2889             sdm = new osgVolume::SampleDensityWhenMovingProperty(0.005);
2890             setUpVolumeScalarProperty(tile.get(), sdm.get(), volumeData.sampleDensityWhenMovingValue);
2891         }
2892 
2893         osg::ref_ptr<osgVolume::TransferFunctionProperty> tfp = volumeData.transferFunction.valid() ? new osgVolume::TransferFunctionProperty(volumeData.transferFunction.get()) : 0;
2894 
2895         if (volumeData.volumeSettings.valid())
2896         {
2897             groupPropetry->addProperty(volumeData.volumeSettings.get());
2898         }
2899         else
2900         {
2901             if (ap.valid()) groupPropetry->addProperty(ap.get());
2902             if (tp.valid()) groupPropetry->addProperty(tp.get());
2903 
2904             if (sr.valid()) groupPropetry->addProperty(sr.get());
2905             if (srm.valid()) groupPropetry->addProperty(srm.get());
2906         }
2907 
2908 
2909         if (sd.valid()) groupPropetry->addProperty(sd.get());
2910         if (sdm.valid()) groupPropetry->addProperty(sdm.get());
2911 
2912         if (tfp.valid()) groupPropetry->addProperty(tfp.get());
2913         if (etfp.valid()) groupPropetry->addProperty(etfp.get());
2914 
2915 #if 1
2916         {
2917             // Standard
2918             osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty;
2919 
2920             sp->addProperty(cp);
2921         }
2922 
2923         {
2924             // Light
2925             sp->addProperty(new osgVolume::LightingProperty);
2926         }
2927 
2928         {
2929             // Isosurface
2930             osgVolume::IsoSurfaceProperty* isp = vs.valid() ? vs->getIsoSurfaceProperty() : new osgVolume::IsoSurfaceProperty(0.1);
2931             setUpVolumeScalarProperty(tile.get(), isp, volumeData.alphaValue);
2932 
2933             sp->addProperty(isp);
2934         }
2935 
2936         {
2937             // MaximumIntensityProjection
2938             sp->addProperty(new osgVolume::MaximumIntensityProjectionProperty);
2939         }
2940 
2941         if (volumeData.volumeSettings.valid())
2942         {
2943             sp->setActiveProperty(volumeData.volumeSettings->getShadingModel());
2944         }
2945         else
2946         {
2947             switch(volumeData.shadingModel)
2948             {
2949                 case(osgVolume::VolumeSettings::Standard):                     sp->setActiveProperty(0); break;
2950                 case(osgVolume::VolumeSettings::Light):                        sp->setActiveProperty(1); break;
2951                 case(osgVolume::VolumeSettings::Isosurface):                   sp->setActiveProperty(2); break;
2952                 case(osgVolume::VolumeSettings::MaximumIntensityProjection):   sp->setActiveProperty(3); break;
2953             }
2954         }
2955 #else
2956         {
2957             // Standard
2958             osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty;
2959             cp->addProperty(ap.get());
2960             cp->addProperty(tp.get());
2961 
2962             sp->addProperty(cp);
2963         }
2964 
2965         {
2966             // Light
2967             osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty;
2968             cp->addProperty(ap.get());
2969             cp->addProperty(tp.get());
2970             cp->addProperty(new osgVolume::LightingProperty);
2971             if (sd.valid()) cp->addProperty(sd.get());
2972             if (sdm.valid()) cp->addProperty(sdm.get());
2973             if (sr.valid()) cp->addProperty(sr.get());
2974             if (srm.valid()) cp->addProperty(srm.get());
2975             if (tfp.valid()) cp->addProperty(tfp.get());
2976             if (etfp.valid()) cp->addProperty(etfp.get());
2977 
2978             sp->addProperty(cp);
2979         }
2980 
2981         {
2982             // Isosurface
2983             osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty;
2984             cp->addProperty(tp.get());
2985 
2986 
2987             osgVolume::IsoSurfaceProperty* isp = new osgVolume::IsoSurfaceProperty(0.1);
2988             setUpVolumeScalarProperty(tile.get(), isp, volumeData.alphaValue);
2989             cp->addProperty(isp);
2990 
2991             if (sd.valid()) cp->addProperty(sd.get());
2992             if (sdm.valid()) cp->addProperty(sdm.get());
2993             if (sr.valid()) cp->addProperty(sr.get());
2994             if (srm.valid()) cp->addProperty(srm.get());
2995             if (tfp.valid()) cp->addProperty(tfp.get());
2996             if (etfp.valid()) cp->addProperty(etfp.get());
2997 
2998             sp->addProperty(cp);
2999         }
3000 
3001         {
3002             // MaximumIntensityProjection
3003             osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty;
3004             cp->addProperty(ap.get());
3005             cp->addProperty(tp.get());
3006             cp->addProperty(new osgVolume::MaximumIntensityProjectionProperty);
3007             if (sd.valid()) cp->addProperty(sd.get());
3008             if (sdm.valid()) cp->addProperty(sdm.get());
3009             if (sr.valid()) cp->addProperty(sr.get());
3010             if (srm.valid()) cp->addProperty(srm.get());
3011             if (tfp.valid()) cp->addProperty(tfp.get());
3012             if (etfp.valid()) cp->addProperty(etfp.get());
3013 
3014             sp->addProperty(cp);
3015         }
3016 
3017         switch(volumeData.shadingModel)
3018         {
3019             case(osgVolume::VolumeSettings::Standard):                     sp->setActiveProperty(0); break;
3020             case(osgVolume::VolumeSettings::Light):                        sp->setActiveProperty(1); break;
3021             case(osgVolume::VolumeSettings::Isosurface):                   sp->setActiveProperty(2); break;
3022             case(osgVolume::VolumeSettings::MaximumIntensityProjection):   sp->setActiveProperty(3); break;
3023         }
3024 #endif
3025 
3026 #if 1
3027         layer->addProperty(groupPropetry.get());
3028 #else
3029         layer->addProperty(sp.get());
3030 #endif
3031         switch(volumeData.technique)
3032         {
3033             case(osgVolume::VolumeSettings::FixedFunction):
3034                 tile->setVolumeTechnique(new osgVolume::FixedFunctionTechnique);
3035                 break;
3036             case(osgVolume::VolumeSettings::RayTraced):
3037                 tile->setVolumeTechnique(new osgVolume::RayTracedTechnique);
3038                 break;
3039             case(osgVolume::VolumeSettings::MultiPass):
3040                 tile->setVolumeTechnique(new osgVolume::MultipassTechnique);
3041                 break;
3042         }
3043 
3044         tile->addEventCallback(new osgVolume::PropertyAdjustmentCallback());
3045     }
3046 
3047     if (dynamic_cast<osgVolume::MultipassTechnique*>(tile->getVolumeTechnique())!=0)
3048     {
3049         if (dynamic_cast<osgVolume::VolumeScene*>(_root.get())==0)
3050         {
3051             osg::ref_ptr<osgVolume::VolumeScene> volumeScene = new osgVolume::VolumeScene;
3052             volumeScene->addChild(_root.get());
3053             _root = volumeScene.get();
3054         }
3055     }
3056 
3057     if (!volumeData.hull.empty())
3058     {
3059         osg::ref_ptr<osg::Node> hull = osgDB::readRefNodeFile(volumeData.hull, _options.get());
3060         if (hull.valid())
3061         {
3062             hull = decorateSubgraphForPositionAndAnimation(hull.get(), volumeData.hullPositionData);
3063             tile->addChild(hull.get());
3064         }
3065     }
3066 
3067 
3068     osg::ref_ptr<osg::Node> model = volume.get();
3069     osg::ref_ptr<osg::Group> group = dynamic_cast<osg::Group*>(model.get());
3070 
3071     if (volumeData.useTabbedDragger || volumeData.useTrackballDragger)
3072     {
3073         if (!group)
3074         {
3075             group = new osg::Group;
3076             group->addChild(volume.get());
3077             model = group.get();
3078         }
3079 
3080         osg::ref_ptr<osgManipulator::Dragger> dragger;
3081         if (volumeData.useTabbedDragger)
3082         {
3083             if (volumeData.useTrackballDragger)
3084                 dragger = new osgManipulator::TabBoxTrackballDragger;
3085             else
3086                 dragger = new osgManipulator::TabBoxDragger;
3087         }
3088         else
3089             dragger = new osgManipulator::TrackballDragger();
3090 
3091         dragger->setupDefaultGeometry();
3092         dragger->setHandleEvents(true);
3093         dragger->setActivationModKeyMask(osgGA::GUIEventAdapter::MODKEY_SHIFT);
3094         dragger->addDraggerCallback(new DraggerVolumeTileCallback(tile.get(), tile->getLocator()));
3095         dragger->setMatrix(osg::Matrix::translate(0.5,0.5,0.5)*tile->getLocator()->getTransform());
3096 
3097         group->addChild(dragger.get());
3098 
3099     }
3100 
3101 
3102 #if 1
3103     osg::ref_ptr<osgUI::Widget> widget = vs.valid() ? osgDB::readRefFile<osgUI::Widget>("ui/VolumeSettings.lua") : 0;
3104     if (widget)
3105     {
3106         OSG_NOTICE<<"Adding widget"<<std::endl;
3107 
3108         widget->setVisible(false);
3109         vs->setName("VolumeSettings");
3110         widget->getOrCreateUserDataContainer()->addUserObject(vs.get());
3111 
3112         osg::Vec3 pos = convertSlideToModel(osg::Vec3(0.0f,0.0f,0.0f));
3113 
3114         const osg::BoundingBox& bb = widget->getExtents();
3115         float slide_scale = 0.5f*_slideWidth/(bb.xMax()-bb.xMin());
3116 
3117         osg::MatrixTransform* transform = new osg::MatrixTransform;
3118         transform->setDataVariance(osg::Object::DYNAMIC);
3119         transform->setMatrix(osg::Matrix::rotate(osg::inDegrees(90.0f),osg::Vec3(1.0f,0.0f,0.0f)) * osg::Matrix::scale(slide_scale,slide_scale,slide_scale)*osg::Matrix::translate(pos));
3120         transform->addChild(widget);
3121 
3122         transform->addEventCallback(new VolumeSettingsCallback());
3123 
3124 #if 0
3125         HUDTransform* hudTransform = new HUDTransform(_hudSettings.get());
3126         hudTransform->addChild(transform);
3127 
3128         addToCurrentLayer(hudTransform);
3129 #else
3130         addToCurrentLayer(transform);
3131 #endif
3132     }
3133 #endif
3134 
3135 
3136     ModelData modelData;
3137     addModel(model.get(), positionData, modelData, scriptData);
3138 }
3139 
attachTexMat(osg::StateSet * stateset,const ImageData & imageData,float s,float t,bool textureRectangle)3140 bool SlideShowConstructor::attachTexMat(osg::StateSet* stateset, const ImageData& imageData, float s, float t, bool textureRectangle)
3141 {
3142     float xScale = textureRectangle ? s : 1.0f;
3143     float yScale = textureRectangle ? t : 1.0f;
3144 
3145     float sx = (textureRectangle ? s : 1.0f) / (imageData.region_in_pixel_coords ? s : 1.0f);
3146     float sy = (textureRectangle ? t : 1.0f) / (imageData.region_in_pixel_coords ? t : 1.0f);
3147 
3148     float x1 = imageData.region[0]*sx;
3149     float y1 = imageData.region[1]*sy;
3150     float x2 = imageData.region[2]*sx;
3151     float y2 = imageData.region[3]*sy;
3152 
3153     if (x1!=0.0f || y1!=0.0f || x2!=xScale || y2 != yScale ||
3154         imageData.texcoord_rotate != 0.0f)
3155     {
3156         osg::TexMat* texmat = new osg::TexMat;
3157         texmat->setMatrix(osg::Matrix::translate(-0.5f*xScale,-0.5f*yScale,0.0f)*
3158                           osg::Matrix::rotate(osg::DegreesToRadians(imageData.texcoord_rotate),0.0f,0.0f,1.0f)*
3159                           osg::Matrix::translate(0.5f*xScale,0.5f*yScale,0.0f)*
3160                           osg::Matrix::scale((x2-x1)/xScale,(y2-y1)/yScale,1.0f)*
3161                           osg::Matrix::translate(x1,
3162                                                  y1,
3163                                                  0.0f));
3164 
3165         stateset->setTextureAttribute(0,texmat);
3166         return true;
3167     }
3168     return false;
3169 }
3170 
attachMaterialAnimation(osg::Node * model,const PositionData & positionData)3171 osg::Node* SlideShowConstructor::attachMaterialAnimation(osg::Node* model, const PositionData& positionData)
3172 {
3173     osg::ref_ptr<AnimationMaterial> animationMaterial = 0;
3174 
3175     if (!positionData.animation_material_filename.empty())
3176     {
3177 #if 0
3178         std::string absolute_animation_file_path = osgDB::findDataFile(positionData.animation_material_filename, _options.get());
3179         if (!absolute_animation_file_path.empty())
3180         {
3181             std::ifstream animation_filestream(absolute_animation_file_path.c_str());
3182             if (!animation_filestream.eof())
3183             {
3184                 animationMaterial = new AnimationMaterial;
3185                 animationMaterial->read(animation_filestream);
3186             }
3187         }
3188 #else
3189         animationMaterial = osgDB::readRefFile<AnimationMaterial>(positionData.animation_material_filename, _options.get());
3190 #endif
3191 
3192     }
3193     else if (!positionData.fade.empty())
3194     {
3195         std::istringstream iss(positionData.fade);
3196 
3197         animationMaterial = new AnimationMaterial;
3198         while (!iss.fail() && !iss.eof())
3199         {
3200             float time=1.0f, alpha=1.0f;
3201             iss >> time >> alpha;
3202             if (!iss.fail())
3203             {
3204                 osg::Material* material = new osg::Material;
3205                 material->setAmbient(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,alpha));
3206                 material->setDiffuse(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,alpha));
3207                 animationMaterial->insert(time,material);
3208             }
3209         }
3210     }
3211 
3212     if (animationMaterial)
3213     {
3214         animationMaterial->setLoopMode(positionData.animation_material_loop_mode);
3215 
3216         AnimationMaterialCallback* animationMaterialCallback = new AnimationMaterialCallback(animationMaterial.get());
3217         animationMaterialCallback->setTimeOffset(positionData.animation_material_time_offset);
3218         animationMaterialCallback->setTimeMultiplier(positionData.animation_material_time_multiplier);
3219 
3220         osg::Group* decorator = new osg::Group;
3221         decorator->addChild(model);
3222 
3223         decorator->setUpdateCallback(animationMaterialCallback);
3224 
3225         if (animationMaterial->requiresBlending())
3226         {
3227             SetToTransparentBin sttb;
3228             decorator->accept(sttb);
3229         }
3230 
3231         return decorator;
3232     }
3233 
3234     return model;
3235 }
3236 
getAnimationPathCallback(const PositionData & positionData)3237 osg::AnimationPathCallback* SlideShowConstructor::getAnimationPathCallback(const PositionData& positionData)
3238 {
3239     if (!positionData.path.empty())
3240     {
3241         // need to create an Options object with cache off to prevent sharing of animation paths
3242         osg::ref_ptr<osgDB::Options> options = _options.valid() ? _options->cloneOptions() : new osgDB::Options;
3243         options->setObjectCacheHint(osgDB::Options::CACHE_NONE);
3244 
3245         osg::ref_ptr<osg::Object> object = osgDB::readRefObjectFile(positionData.path, options.get());
3246         osg::AnimationPath* animation = dynamic_cast<osg::AnimationPath*>(object.get());
3247         if (animation)
3248         {
3249             if (positionData.frame==SlideShowConstructor::SLIDE)
3250             {
3251                 osg::AnimationPath::TimeControlPointMap& controlPoints = animation->getTimeControlPointMap();
3252                 for(osg::AnimationPath::TimeControlPointMap::iterator itr=controlPoints.begin();
3253                     itr!=controlPoints.end();
3254                     ++itr)
3255                 {
3256                     osg::AnimationPath::ControlPoint& cp = itr->second;
3257                     cp.setPosition(convertSlideToModel(cp.getPosition()+positionData.position));
3258                 }
3259             }
3260 
3261             animation->setLoopMode(positionData.path_loop_mode);
3262 
3263             osg::AnimationPathCallback* apc = new osg::AnimationPathCallback(animation);
3264             apc->setTimeOffset(positionData.path_time_offset);
3265             apc->setTimeMultiplier(positionData.path_time_multiplier);
3266             apc->setUseInverseMatrix(positionData.inverse_path);
3267 
3268             OSG_INFO<<"UseInverseMatrix "<<positionData.inverse_path<<std::endl;
3269 
3270             return apc;
3271 
3272         }
3273 
3274     }
3275     return 0;
3276 }
3277 
computePositionInModelCoords(const PositionData & positionData) const3278 osg::Vec3 SlideShowConstructor::computePositionInModelCoords(const PositionData& positionData) const
3279 {
3280     if (positionData.frame==SLIDE)
3281     {
3282         OSG_INFO<<"********* Scaling from slide coords to model coords"<<std::endl;
3283         return convertSlideToModel(positionData.position);
3284     }
3285     else
3286     {
3287         OSG_INFO<<"keeping original model coords"<<std::endl;
3288         return positionData.position;
3289     }
3290 }
3291 
convertSlideToModel(const osg::Vec3 & position) const3292 osg::Vec3 SlideShowConstructor::convertSlideToModel(const osg::Vec3& position) const
3293 {
3294     return osg::Vec3(_slideOrigin+osg::Vec3(_slideWidth*position.x(),0.0f,_slideHeight*position.y()))*(1.0f-position.z());
3295 }
3296 
convertModelToSlide(const osg::Vec3 & position) const3297 osg::Vec3 SlideShowConstructor::convertModelToSlide(const osg::Vec3& position) const
3298 {
3299     return osg::Vec3((position.x()*(_slideOrigin.y()/position.y())-_slideOrigin.x())/_slideWidth,
3300                      (position.z()*(_slideOrigin.y()/position.y())-_slideOrigin.z())/_slideHeight,
3301                      1.0f-position.y()/_slideOrigin.y());
3302 }
3303 
updatePositionFromInModelCoords(const osg::Vec3 & vertex,PositionData & positionData) const3304 void SlideShowConstructor::updatePositionFromInModelCoords(const osg::Vec3& vertex, PositionData& positionData) const
3305 {
3306     if (positionData.frame==SLIDE)
3307     {
3308         positionData.position = convertModelToSlide(vertex);
3309     }
3310     else
3311     {
3312         positionData.position = vertex;
3313     }
3314 }
3315 
recordOptionsFilePath(const osgDB::Options * options)3316 void SlideShowConstructor::recordOptionsFilePath(const osgDB::Options* options)
3317 {
3318     if (options)
3319     {
3320         std::string filename_used = _options->getPluginStringData("filename");
3321         std::string path = osgDB::getFilePath(filename_used);
3322         if (!path.empty() && _filePathData.valid())
3323         {
3324             osgDB::FilePathList::iterator itr = std::find(_filePathData->filePathList.begin(),_filePathData->filePathList.end(),path);
3325             if (itr==_filePathData->filePathList.end())
3326             {
3327                 OSG_INFO<<"SlideShowConstructor::recordOptionsFilePath(..) - new path to record path="<<path<<" filename_used="<<filename_used<<std::endl;
3328                 _filePathData->filePathList.push_front(path);
3329             }
3330         }
3331     }
3332 }
3333 
3334