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