root/OpenSceneGraph/trunk/applications/present3D/SlideShowConstructor.cpp @ 10207

Revision 10207, 58.6 kB (checked in by robert, 5 years ago)

Integrated support for relative paths, and http hosted presentations

Line 
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 "SlideShowConstructor.h"
14
15#include <osg/Geometry>
16#include <osg/PolygonOffset>
17#include <osg/Geode>
18#include <osg/Texture2D>
19#include <osg/TextureRectangle>
20#include <osg/MatrixTransform>
21#include <osg/PositionAttitudeTransform>
22#include <osg/TexMat>
23#include <osg/ShapeDrawable>
24#include <osg/Notify>
25#include <osg/io_utils>
26
27#include <osgUtil/TransformCallback>
28
29#include <osgDB/ReadFile>
30#include <osgDB/WriteFile>
31#include <osgDB/FileUtils>
32#include <osgDB/Input>
33#include <osgDB/FileNameUtils>
34
35#include <osgWidget/PdfReader>
36
37#include <osgViewer/ViewerEventHandlers>
38
39#include <osgText/Text>
40
41#include <osgFX/SpecularHighlights>
42
43#include <osgVolume/Volume>
44#include <osgVolume/RayTracedTechnique>
45#include <osgVolume/FixedFunctionTechnique>
46
47#include <sstream>
48#include <algorithm>
49
50#include "AnimationMaterial.h"
51#include "PickEventHandler.h"
52
53using namespace osgPresentation;
54
55class SetToTransparentBin : public osg::NodeVisitor
56{
57public:
58
59    SetToTransparentBin():
60        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
61       
62    virtual void appply(osg::Node& node)
63    {
64        if (node.getStateSet())
65        {
66            node.getStateSet()->setMode(GL_BLEND,osg::StateAttribute::ON);
67            node.getStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
68        }
69    }
70   
71    virtual void apply(osg::Geode& geode)
72    {
73        if (geode.getStateSet())
74        {
75            geode.getStateSet()->setMode(GL_BLEND,osg::StateAttribute::ON);
76            geode.getStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
77        }
78        for(unsigned int i=0;i<geode.getNumDrawables();++i)
79        {
80            if (geode.getDrawable(i)->getStateSet())
81            {
82                geode.getDrawable(i)->getStateSet()->setMode(GL_BLEND,osg::StateAttribute::ON);
83                geode.getDrawable(i)->getStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
84            }
85        }
86    }       
87};
88
89SlideShowConstructor::SlideShowConstructor(const osgDB::ReaderWriter::Options* options):
90    _options(options)
91{
92    _slideDistance = osg::DisplaySettings::instance()->getScreenDistance();
93    _slideHeight = osg::DisplaySettings::instance()->getScreenHeight();
94    _slideWidth = osg::DisplaySettings::instance()->getScreenWidth();
95
96    _backgroundColor.set(0.0f,0.0f,0.0f,1.0f);
97
98    _presentationDuration = -1.0;
99
100    // set up title defaults
101    _titleFontDataDefault.font = "fonts/arial.ttf";
102    _titleFontDataDefault.color.set(1.0f,1.0f,1.0f,1.0f);
103    _titleFontDataDefault.layout = osgText::Text::LEFT_TO_RIGHT;
104    _titleFontDataDefault.alignment = osgText::Text::CENTER_BASE_LINE;
105    _titleFontDataDefault.axisAlignment = osgText::Text::XZ_PLANE;
106    _titleFontDataDefault.characterSize = 0.06f;
107    _titleFontDataDefault.maximumWidth = 0.9f;
108
109    _titlePositionDataDefault.position.set(0.5f,0.92f,0.0f);
110
111    // set up text defaults
112    _textFontDataDefault.font = "fonts/arial.ttf";
113    _textFontDataDefault.color.set(1.0f,1.0f,1.0f,1.0f);
114    _textFontDataDefault.layout = osgText::Text::LEFT_TO_RIGHT;
115    _textFontDataDefault.alignment = osgText::Text::LEFT_BASE_LINE;
116    _textFontDataDefault.axisAlignment = osgText::Text::XZ_PLANE;
117    _textFontDataDefault.characterSize = 0.04f;
118    _textFontDataDefault.maximumWidth = 0.8f;
119
120    _textPositionDataDefault.position.set(0.1f,0.85f,0.0f);
121
122    _loopPresentation = false;
123    _autoSteppingActive = false;
124}
125
126void SlideShowConstructor::setPresentationAspectRatio(float aspectRatio)
127{
128    _slideWidth = _slideHeight*aspectRatio;
129}
130
131void SlideShowConstructor::setPresentationAspectRatio(const std::string& str)
132{
133    if (str=="Reality Theatre") setPresentationAspectRatio(3.0f);
134    else if (str=="Desktop") setPresentationAspectRatio(1280.0f/1024.0f);
135    else
136    {
137        float ratio = (float)atof(str.c_str());
138        if (ratio!=0.0) setPresentationAspectRatio(1280.0f/1024.0f);
139        else
140        {
141            osg::notify(osg::WARN)<<"Error: presentation aspect ratio incorrect type"<<std::endl;
142            osg::notify(osg::WARN)<<"       valid types are \"Reality Theatre\", \"Desktop\" or a numerical value."<<std::endl;
143        }
144    }
145}
146
147void SlideShowConstructor::createPresentation()
148{
149    _slideOrigin.set(-_slideWidth*0.5f,_slideDistance,-_slideHeight*0.5f);
150
151#if 0
152    _titleFontDataDefault.characterSize = 0.06f;
153    _titleFontDataDefault.maximumWidth = 0.9f;
154
155    _textFontDataDefault.characterSize = 0.04f;
156    _textFontDataDefault.maximumWidth = 0.8f;
157#endif
158   
159    osg::notify(osg::INFO)<<"_titlePositionDataDefault.position="<<_titlePositionDataDefault.position<<std::endl;
160
161    _textPositionDataDefault.position.set(0.1f,_titlePositionDataDefault.position.y()-_titleFontDataDefault.characterSize,0.0f);
162    _imagePositionDataDefault.position.set(0.5f,0.5f,0.0f);
163    _modelPositionDataDefault.position.set(0.5f,0.5f,0.0f);
164
165    _root = new osg::Group;
166   
167    _presentationSwitch = new osg::Switch;
168    _presentationSwitch->setName(std::string("Presentation_")+_presentationName);
169   
170    _root->addChild(_presentationSwitch.get());
171   
172    osg::Vec3 slideCenter = _slideOrigin + osg::Vec3(_slideWidth*0.5f,0.0f,_slideHeight*0.5f);
173       
174    HomePosition* hp = new HomePosition;
175    hp->eye.set(0.0f,0.0f,0.0f);
176    hp->center = slideCenter;
177    hp->up.set(0.0f,0.0f,1.0f);
178   
179    osg::notify(osg::INFO)<<" slideCenter "<<slideCenter<<std::endl;
180   
181    if (_presentationDuration>=0.0)
182    {
183        setDuration(_presentationSwitch.get(),_presentationDuration);
184    }
185     
186    _root->setUserData(hp);
187   
188    if (_loopPresentation) _root->addDescription("loop");
189    if (_autoSteppingActive) _root->addDescription("auto");
190}
191
192LayerAttributes* SlideShowConstructor::getOrCreateLayerAttributes(osg::Node* node)
193{
194    LayerAttributes* la = dynamic_cast<LayerAttributes*>(node->getUserData());
195    if (!la)
196    {
197        if (node->getUserData())
198        {
199            osg::notify(osg::NOTICE)<<"UserData already assigned, overriding to set LayerAttributes."<<std::endl;
200        }
201
202        la = new LayerAttributes;
203        node->setUserData(la);
204    }
205   
206    return la;
207}
208
209void SlideShowConstructor::setBackgroundColor(const osg::Vec4& color, bool updateClearNode)
210{
211    _backgroundColor = color;
212    if (updateClearNode && _slideClearNode.valid()) _slideClearNode->setClearColor(_backgroundColor);
213}
214
215void SlideShowConstructor::setTextColor(const osg::Vec4& color)
216{
217    _titleFontDataDefault.color = color;
218    _textFontDataDefault.color = color;
219
220    _titleFontData.color = _titleFontDataDefault.color;
221    _textFontData.color = _textFontDataDefault.color;
222
223}
224
225void SlideShowConstructor::setPresentationName(const std::string& name)
226{
227    _presentationName = name;
228    if (_presentationSwitch.valid()) _presentationSwitch->setName(std::string("Presentation_")+_presentationName);
229}
230
231void SlideShowConstructor::setPresentationDuration(double duration)
232{
233    _presentationDuration = duration;
234    if (_presentationDuration>=0.0 && _presentationSwitch.valid())
235    {
236        setDuration(_presentationSwitch.get(),_presentationDuration);
237    }
238}
239
240void SlideShowConstructor::addSlide()
241{
242    if (!_presentationSwitch) createPresentation();
243
244    // reset fonts
245    _titleFontData = _titleFontDataDefault;
246    _textFontData = _textFontDataDefault;
247
248    // reset cursors
249    _titlePositionData = _titlePositionDataDefault;
250    _textPositionData = _textPositionDataDefault;
251    _imagePositionData =  _imagePositionDataDefault;
252    _modelPositionData =  _modelPositionDataDefault;   
253   
254    _slide = new osg::Switch;
255    _slide->setName(std::string("Slide_")+_slideTitle);
256   
257    _slideClearNode = new osg::ClearNode;
258    _slideClearNode->setClearColor(_backgroundColor);
259    _slideClearNode->addChild(_slide.get());
260   
261    _presentationSwitch->addChild(_slideClearNode.get());
262
263    _previousLayer = 0;
264    _currentLayer = 0;
265   
266   
267    _filePathData = new FilePathData(osgDB::getDataFilePathList());
268   
269    _slideClearNode->setUserData(_filePathData.get());
270}
271
272void SlideShowConstructor::selectSlide(int slideNum)
273{
274    if (slideNum<0)
275    {       
276        addSlide();
277    }
278    else if (slideNum>=static_cast<int>(_presentationSwitch->getNumChildren()))
279    {
280        addSlide();
281    }
282    else
283    {
284        _slideClearNode = dynamic_cast<osg::ClearNode*>(_presentationSwitch->getChild(slideNum));
285        if (!_slideClearNode || _slideClearNode->getNumChildren()==0 || _slideClearNode->getChild(0)->asSwitch()==0)
286        {
287            addSlide();
288        }
289        else
290        {
291            _slide = _slideClearNode->getChild(0)->asSwitch();
292            _previousLayer = _slide->getChild(_slide->getNumChildren()-1)->asGroup();
293            _currentLayer = 0;
294        }
295    }
296}
297
298void SlideShowConstructor::setSlideDuration(double duration)
299{
300    if (!_slide) addSlide();
301
302    if (_slide.valid())
303    {
304        setDuration(_slide.get(),duration);
305    }
306}
307
308void SlideShowConstructor::addLayer(bool inheritPreviousLayers, bool defineAsBaseLayer)
309{
310    if (!_slide) addSlide();
311
312    _currentLayer = new osg::Group;
313
314    // osg::notify(osg::NOTICE)<<"addLayer"<<std::endl;
315   
316    if (!_previousLayer || !inheritPreviousLayers)
317    {
318        _textPositionData = _textPositionDataDefault;
319        _imagePositionData =  _imagePositionDataDefault;
320        _modelPositionData =  _modelPositionDataDefault;   
321
322        // osg::notify(osg::NOTICE)<<"   new layer background = "<<_slideBackgroundImageFileName<<std::endl;
323
324        osg::ref_ptr<osg::Image> image = !_slideBackgroundImageFileName.empty() ?
325            osgDB::readImageFile(_slideBackgroundImageFileName, _options.get()) :
326            0;
327
328        // create the background and title..
329        if (image.valid())
330        {
331            osg::Geode* background = new osg::Geode;
332
333            osg::StateSet* backgroundStateSet = background->getOrCreateStateSet();
334            backgroundStateSet->setAttributeAndModes(
335                        new osg::PolygonOffset(1.0f,2.0f),
336                        osg::StateAttribute::ON);
337
338   
339            bool useTextureRectangle = true;
340            float s = useTextureRectangle ? image->s() : 1.0;
341            float t = useTextureRectangle ? image->t() : 1.0;
342            osg::Geometry* backgroundQuad = osg::createTexturedQuadGeometry(_slideOrigin,
343                                                            osg::Vec3(_slideWidth,0.0f,0.0f),
344                                                            osg::Vec3(0.0f,0.0f,_slideHeight),
345                                                            s, t);
346            // osg::notify(osg::NOTICE)<<"Image loaded "<<image.get()<<"  "<<_slideBackgroundImageFileName<<std::endl;
347
348            if (useTextureRectangle)
349            {
350                osg::TextureRectangle* texture = new osg::TextureRectangle(image.get());
351                backgroundStateSet->setTextureAttributeAndModes(0,
352                            texture,
353                            osg::StateAttribute::ON);
354            }
355            else
356            {
357                osg::Texture2D* texture = new osg::Texture2D(image.get());
358                texture->setResizeNonPowerOfTwoHint(false);
359                backgroundStateSet->setTextureAttributeAndModes(0,
360                            texture,
361                            osg::StateAttribute::ON);
362            }
363
364            background->addDrawable(backgroundQuad);
365
366            _currentLayer->addChild(background);
367        }
368       
369        if (!_slideTitle.empty())
370        {
371            osg::Geode* geode = new osg::Geode;
372
373            osg::Vec3 localPosition = computePositionInModelCoords(_titlePositionData);
374
375            osgText::Text* text = new osgText::Text;
376            text->setFont(_titleFontData.font);
377            text->setColor(_titleFontData.color);
378            text->setCharacterSize(_titleFontData.characterSize*_slideHeight);
379            text->setFontResolution(110,120);
380            text->setMaximumWidth(_titleFontData.maximumWidth*_slideWidth);
381            text->setLayout(_titleFontData.layout);
382            text->setAlignment(_titleFontData.alignment);
383            text->setAxisAlignment(_titleFontData.axisAlignment);
384            //text->setPosition(_titlePositionData.position);
385            text->setPosition(localPosition);
386
387            text->setText(_slideTitle);
388
389            geode->addDrawable(text);
390
391            _currentLayer->addChild(geode);
392        }
393       
394    }
395    else
396    {
397        // copy previous layer's children across into new layer.
398        for(unsigned int i=0;i<_previousLayer->getNumChildren();++i)
399        {
400            _currentLayer->addChild(_previousLayer->getChild(i));
401        }
402    }
403
404    if (!defineAsBaseLayer)
405    {
406        _slide->addChild(_currentLayer.get());
407    }
408   
409    _previousLayer = _currentLayer;
410}
411
412void SlideShowConstructor::selectLayer(int layerNum)
413{
414    if (!_slide)
415    {
416        addSlide();
417        addLayer();
418    }
419    else if (layerNum>=0 && layerNum<static_cast<int>(_slide->getNumChildren()) && _slide->getChild(layerNum)->asGroup())
420    {
421        _currentLayer = _slide->getChild(layerNum)->asGroup();
422        _previousLayer = _currentLayer;
423    }
424    else
425    {
426        addLayer();
427    }
428   
429}
430
431
432void SlideShowConstructor::setLayerDuration(double duration)
433{
434    if (!_currentLayer) addLayer();
435
436    if (_currentLayer.valid())
437    {
438        setDuration(_currentLayer.get(),duration);
439    }
440}
441
442void SlideShowConstructor::layerClickToDoOperation(Operation operation, bool relativeJump, int slideNum, int layerNum)
443{
444    if (!_currentLayer) addLayer();
445   
446    if (_currentLayer.valid())
447    {
448        if (_previousLayer==_currentLayer)
449        {
450            if (_currentLayer->getNumChildren()>0)
451            {
452                osg::notify(osg::INFO)<<"creating new group within layer"<<std::endl;
453                osg::Group* group = new osg::Group;
454                _currentLayer->addChild(group);
455                _currentLayer = group;
456            }
457        }
458        else
459        {
460            osg::notify(osg::INFO)<<"creating secondary group within layer"<<std::endl;
461            osg::Group* group = new osg::Group;
462            _previousLayer->addChild(group);
463            _currentLayer = group;
464        }               
465        _currentLayer->setEventCallback(new PickEventHandler(operation, relativeJump, slideNum, layerNum));
466    }
467   
468}
469
470
471void SlideShowConstructor::layerClickToDoOperation(const std::string& command, Operation operation, bool relativeJump, int slideNum, int layerNum)
472{
473    if (!_currentLayer) addLayer();
474   
475    if (_currentLayer.valid())
476    {
477        if (_previousLayer==_currentLayer)
478        {
479            if (_currentLayer->getNumChildren()>0)
480            {
481                osg::notify(osg::INFO)<<"creating new group within layer"<<std::endl;
482                osg::Group* group = new osg::Group;
483                _currentLayer->addChild(group);
484                _currentLayer = group;
485            }
486        }
487        else
488        {
489            osg::notify(osg::INFO)<<"creating secondary group within layer"<<std::endl;
490            osg::Group* group = new osg::Group;
491            _previousLayer->addChild(group);
492            _currentLayer = group;
493        }               
494        _currentLayer->setEventCallback(new PickEventHandler(command, operation, relativeJump, slideNum, layerNum));
495    }
496   
497}
498
499
500void SlideShowConstructor::layerClickEventOperation(const KeyPosition& keyPos, bool relativeJump, int slideNum, int layerNum)
501{
502    if (!_currentLayer) addLayer();
503   
504    if (_currentLayer.valid())
505    {
506        if (_previousLayer==_currentLayer)
507        {
508            if (_currentLayer->getNumChildren()>0)
509            {
510                osg::notify(osg::INFO)<<"creating new group within layer"<<std::endl;
511                osg::Group* group = new osg::Group;
512                _currentLayer->addChild(group);
513                _currentLayer = group;
514            }
515        }
516        else
517        {
518            osg::notify(osg::INFO)<<"creating secondary group within layer"<<std::endl;
519            osg::Group* group = new osg::Group;
520            _previousLayer->addChild(group);
521            _currentLayer = group;
522        }               
523        _currentLayer->setEventCallback(new PickEventHandler(keyPos, relativeJump, slideNum, layerNum));
524    }
525   
526}
527
528void SlideShowConstructor::addBullet(const std::string& bullet, PositionData& positionData, FontData& fontData)
529{
530    if (!_currentLayer) addLayer();
531
532    osg::Geode* geode = new osg::Geode;
533
534    osgText::Text* text = new osgText::Text;
535
536    osg::Vec3 localPosition = computePositionInModelCoords(positionData);
537
538    text->setFont(fontData.font);
539    text->setColor(fontData.color);
540    text->setCharacterSize(fontData.characterSize*_slideHeight);
541    text->setFontResolution(110,120);
542    text->setMaximumWidth(fontData.maximumWidth*_slideWidth);
543    text->setLayout(fontData.layout);
544    text->setAlignment(fontData.alignment);
545    text->setAxisAlignment(fontData.axisAlignment);
546    text->setPosition(localPosition);
547   
548    text->setText(bullet);
549
550    osg::BoundingBox bb = text->getBound();
551   
552    // note, this increment is only "correct" when text is on the plane of the slide..
553    // will need to make this more general later.
554    localPosition.z() = bb.zMin()-fontData.characterSize*_slideHeight*1.5;
555   
556    geode->addDrawable(text);
557   
558    osg::Node* subgraph = geode;
559   
560    if (positionData.requiresMaterialAnimation())
561        subgraph = attachMaterialAnimation(subgraph,positionData);
562
563    if (positionData.rotation[0]!=0.0)
564    {
565        osg::MatrixTransform* animation_transform = new osg::MatrixTransform;
566        animation_transform->setDataVariance(osg::Object::DYNAMIC);
567        animation_transform->setUpdateCallback(
568            new osgUtil::TransformCallback(geode->getBound().center(),
569                                           osg::Vec3(positionData.rotation[1],positionData.rotation[2],positionData.rotation[3]),
570                                           osg::DegreesToRadians(positionData.rotation[0])));
571        animation_transform->addChild(subgraph);
572
573        subgraph = animation_transform;
574    }
575
576    _currentLayer->addChild(subgraph);
577
578    updatePositionFromInModelCoords(localPosition, positionData);
579}
580
581void SlideShowConstructor::addParagraph(const std::string& paragraph, PositionData& positionData, FontData& fontData)
582{
583    if (!_currentLayer) addLayer();
584
585    osg::Geode* geode = new osg::Geode;
586
587    osg::Vec3 localPosition = computePositionInModelCoords(positionData);
588
589    osgText::Text* text = new osgText::Text;
590
591    text->setFont(fontData.font);
592    text->setColor(fontData.color);
593    text->setCharacterSize(fontData.characterSize*_slideHeight);
594    text->setFontResolution(110,120);
595    text->setMaximumWidth(fontData.maximumWidth*_slideWidth);
596    text->setLayout(fontData.layout);
597    text->setAlignment(fontData.alignment);
598    text->setAxisAlignment(fontData.axisAlignment);
599    text->setPosition(localPosition);
600   
601    text->setText(paragraph);
602
603    osg::BoundingBox bb = text->getBound();
604   
605    // note, this increment is only "correct" when text is on the plane of the slide..
606    // will need to make this more general later.
607    localPosition.z() = bb.zMin()-fontData.characterSize*_slideHeight*1.5;
608
609    geode->addDrawable(text);
610   
611    osg::Node* subgraph = geode;
612
613    if (positionData.requiresMaterialAnimation())
614        subgraph = attachMaterialAnimation(subgraph,positionData);
615
616    if (positionData.rotation[0]!=0.0)
617    {
618        osg::MatrixTransform* animation_transform = new osg::MatrixTransform;
619        animation_transform->setDataVariance(osg::Object::DYNAMIC);
620        animation_transform->setUpdateCallback(
621            new osgUtil::TransformCallback(geode->getBound().center(),
622                                           osg::Vec3(positionData.rotation[1],positionData.rotation[2],positionData.rotation[3]),
623                                           osg::DegreesToRadians(positionData.rotation[0])));
624        animation_transform->addChild(subgraph);
625
626        subgraph = animation_transform;
627    }
628
629    _currentLayer->addChild(subgraph);
630
631    updatePositionFromInModelCoords(localPosition, positionData);
632}
633
634class FindImageStreamsVisitor : public osg::NodeVisitor
635{
636public:
637    FindImageStreamsVisitor():
638        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
639
640    virtual void apply(osg::Node& node)
641    {
642        if (node.getStateSet())
643        {
644                process(node.getStateSet());
645        }
646        traverse(node);
647    }
648
649    virtual void apply(osg::Geode& node)
650    {
651        if (node.getStateSet())
652        {
653                process(node.getStateSet());
654        }
655
656        for(unsigned int i=0;i<node.getNumDrawables();++i)
657        {
658            osg::Drawable* drawable = node.getDrawable(i);
659            if (drawable && drawable->getStateSet())
660            {
661                process(drawable->getStateSet());
662            }
663        }
664    }
665
666    void process(osg::StateSet* ss)
667    {
668        for(unsigned int i=0;i<ss->getTextureAttributeList().size();++i)
669        {
670            osg::Texture* texture = dynamic_cast<osg::Texture*>(ss->getTextureAttribute(i,osg::StateAttribute::TEXTURE));
671            osg::Image* image = texture ? texture->getImage(0) : 0;
672            osg::ImageStream* imageStream = image ? dynamic_cast<osg::ImageStream*>(image) : 0;
673            if (imageStream)
674            {
675                texture->setDataVariance(osg::Object::DYNAMIC);
676                texture->setUnRefImageDataAfterApply(false);
677                texture->setResizeNonPowerOfTwoHint(false);
678                texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR);
679                texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR);
680                texture->setClientStorageHint(true);
681            }
682        }
683    }
684
685};
686
687void SlideShowConstructor::findImageStreamsAndAddCallbacks(osg::Node* node)
688{
689    FindImageStreamsVisitor fisv;
690    node->accept(fisv);
691}
692
693
694osg::Geometry* SlideShowConstructor::createTexturedQuadGeometry(const osg::Vec3& pos, const osg::Vec4& rotation, float width, float height, osg::Image* image, bool& usedTextureRectangle)
695{
696    osg::Geometry* pictureQuad = 0;
697    osg::Texture* texture = 0;
698    osg::StateSet* stateset = 0;
699
700    osg::Vec3 positionVec = pos;
701    osg::Vec3 widthVec(width,0.0f,0.0f);
702    osg::Vec3 heightVec(0.0f,0.0f,height);
703
704    osg::Matrixd rotationMatrix = osg::Matrixd::rotate(osg::DegreesToRadians(rotation[0]),rotation[1],rotation[2],rotation[3]);
705    widthVec = widthVec*rotationMatrix;
706    heightVec = heightVec*rotationMatrix;
707
708    osg::ImageStream* imageStream = dynamic_cast<osg::ImageStream*>(image);
709 
710    bool flipYAxis = image->getOrigin()==osg::Image::TOP_LEFT;
711
712#ifdef __sgi
713    bool useTextureRectangle = false;
714#else
715    bool useTextureRectangle = true;
716#endif
717
718    // pass back info on wether texture 2D is used.
719    usedTextureRectangle = useTextureRectangle;
720
721    if (useTextureRectangle)
722    {
723        pictureQuad = osg::createTexturedQuadGeometry(positionVec,
724                                           widthVec,
725                                           heightVec,
726                                           0.0f, flipYAxis ? image->t() : 0.0f,
727                                           image->s(), flipYAxis ? 0.0f : image->t());
728
729        stateset = pictureQuad->getOrCreateStateSet();                               
730
731        texture = new osg::TextureRectangle(image);
732        stateset->setTextureAttributeAndModes(0,
733                    texture,
734                    osg::StateAttribute::ON);
735                   
736       
737                   
738    }
739    else
740    {
741        pictureQuad = osg::createTexturedQuadGeometry(positionVec,
742                                           widthVec,
743                                           heightVec,
744                                           0.0f, flipYAxis ? 1.0f : 0.0f,
745                                           1.0f, flipYAxis ? 0.0f : 1.0f);
746                                       
747        stateset = pictureQuad->getOrCreateStateSet();                               
748
749        texture = new osg::Texture2D(image);
750       
751        stateset->setTextureAttributeAndModes(0,
752                    texture,
753                    osg::StateAttribute::ON);
754
755    }
756
757    if (!pictureQuad) return 0;
758
759    if (imageStream)
760    {
761        imageStream->pause();
762   
763        osg::notify(osg::INFO)<<"Reading video "<<imageStream->getFileName()<<std::endl;
764       
765        // make sure that OSX uses the client storage extension to accelerate peformance where possible.
766        texture->setClientStorageHint(true);
767    }
768
769
770    return pictureQuad;
771}
772
773
774void SlideShowConstructor::addImage(const std::string& filename, const PositionData& positionData, const ImageData& imageData)
775{
776    if (!_currentLayer) addLayer();
777
778    osg::Image* image = osgDB::readImageFile(filename, _options.get());
779    if (image) recordOptionsFilePath(_options.get());
780
781    if (!image) return;
782
783    bool isImageTranslucent = false;
784
785    osg::ImageStream* imageStream = dynamic_cast<osg::ImageStream*>(image);
786    if (imageStream)
787    {
788        imageStream->setLoopingMode(imageData.loopingMode);
789
790        isImageTranslucent = imageStream->getPixelFormat()==GL_RGBA ||
791                             imageStream->getPixelFormat()==GL_BGRA;
792
793    }
794    else
795    {
796        isImageTranslucent = image->isImageTranslucent();
797    }
798
799    float s = image->s();
800    float t = image->t();
801
802    // temporary hack
803    float height = 0.0f;
804
805    float sx = imageData.region_in_pixel_coords ? 1.0f : s;
806    float sy = imageData.region_in_pixel_coords ? 1.0f : t;
807
808    float x1 = imageData.region[0]*sx;
809    float y1 = imageData.region[1]*sy;
810    float x2 = imageData.region[2]*sx;
811    float y2 = imageData.region[3]*sy;
812
813    float aspectRatio = (y2-y1)/(x2-x1);
814
815    float image_width = _slideWidth*positionData.scale.x();
816    float image_height = image_width*aspectRatio*positionData.scale.y()/positionData.scale.x();
817    float offset = height*image_height*0.1f;
818
819    osg::Vec3 pos = computePositionInModelCoords(positionData) + osg::Vec3(-image_width*0.5f+offset,-offset,-image_height*0.5f-offset);
820
821    osg::Geode* picture = new osg::Geode;
822    osg::Node* subgraph = picture;
823
824
825    bool usedTextureRectangle = false;
826    osg::Geometry* pictureQuad = createTexturedQuadGeometry(pos, positionData.rotate, image_width, image_height, image, usedTextureRectangle);
827    osg::StateSet* pictureStateSet = pictureQuad->getOrCreateStateSet();
828
829    attachTexMat(pictureStateSet, imageData, s, t, usedTextureRectangle);
830
831    picture->addDrawable(pictureQuad);
832
833    // attach any meterial animation.
834    if (positionData.requiresMaterialAnimation())
835        subgraph = attachMaterialAnimation(subgraph,positionData);
836
837
838    if (isImageTranslucent)
839    {
840        SetToTransparentBin sttb;
841        subgraph->accept(sttb);
842        pictureStateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
843    }
844
845    // attached any rotation
846    if (positionData.rotation[0]!=0.0)
847    {
848        osg::MatrixTransform* animation_transform = new osg::MatrixTransform;
849        animation_transform->setDataVariance(osg::Object::DYNAMIC);
850        animation_transform->setUpdateCallback(
851            new osgUtil::TransformCallback(picture->getBound().center(),
852                                           osg::Vec3(positionData.rotation[1],positionData.rotation[2],positionData.rotation[3]),
853                                           osg::DegreesToRadians(positionData.rotation[0])));
854
855        animation_transform->addChild(subgraph);
856
857        subgraph = animation_transform;
858    }
859
860
861    // attached any animation
862    osg::AnimationPathCallback* animation = getAnimationPathCallback(positionData);
863    if (animation)
864    {
865        osg::notify(osg::INFO)<<"Have animation path for image"<<std::endl;
866
867        osg::Vec3 pivot = positionData.absolute_path ? osg::Vec3(0.0f,0.0f,0.0f) : subgraph->getBound().center();
868
869        osg::PositionAttitudeTransform* animation_transform = new osg::PositionAttitudeTransform;
870        animation_transform->setDataVariance(osg::Object::DYNAMIC);
871        animation_transform->setPivotPoint(pivot);
872        animation->setPivotPoint(pivot);
873
874        animation_transform->setUpdateCallback(animation);
875
876        animation_transform->setReferenceFrame(positionData.absolute_path ?
877                                                    osg::Transform::ABSOLUTE_RF:
878                                                    osg::Transform::RELATIVE_RF);
879
880        animation_transform->addChild(subgraph);
881
882        subgraph = animation_transform;
883    }
884
885    _currentLayer->addChild(subgraph);
886}
887
888void SlideShowConstructor::addStereoImagePair(const std::string& filenameLeft, const ImageData& imageDataLeft, const std::string& filenameRight, const ImageData& imageDataRight,const PositionData& positionData)
889{
890    if (!_currentLayer) addLayer();
891
892
893    osg::ref_ptr<osg::Image> imageLeft = osgDB::readImageFile(filenameLeft, _options.get());
894    if (imageLeft.valid()) recordOptionsFilePath(_options.get());
895
896    osg::ref_ptr<osg::Image> imageRight = (filenameRight==filenameLeft) ? imageLeft.get() : osgDB::readImageFile(filenameRight, _options.get());
897    if (imageRight.valid()) recordOptionsFilePath(_options.get());
898
899    if (!imageLeft && !imageRight) return;
900
901    bool isImageTranslucent = false;
902
903    osg::ImageStream* imageStreamLeft = dynamic_cast<osg::ImageStream*>(imageLeft.get());
904    if (imageStreamLeft)
905    {
906        imageStreamLeft->setLoopingMode(imageDataLeft.loopingMode);
907        isImageTranslucent = imageStreamLeft->getPixelFormat()==GL_RGBA ||
908                             imageStreamLeft->getPixelFormat()==GL_BGRA;
909    }
910    else
911    {
912        isImageTranslucent = imageLeft->isImageTranslucent();
913    }
914
915    osg::ImageStream* imageStreamRight = dynamic_cast<osg::ImageStream*>(imageRight.get());
916    if (imageStreamRight)
917    {
918        imageStreamRight->setLoopingMode(imageDataRight.loopingMode);
919        if (!isImageTranslucent)
920        {
921            isImageTranslucent = imageStreamRight->getPixelFormat()==GL_RGBA ||
922                                imageStreamRight->getPixelFormat()==GL_BGRA;
923        }
924    }
925    else if (!isImageTranslucent)
926    {
927        isImageTranslucent = imageRight->isImageTranslucent();
928    }
929
930
931    float s = imageLeft->s();
932    float t = imageLeft->t();
933   
934    // temporary hack
935    float height = 0.0f;
936
937    float sx = imageDataLeft.region_in_pixel_coords ? 1.0f : s;
938    float sy = imageDataLeft.region_in_pixel_coords ? 1.0f : t;
939
940    float x1 = imageDataLeft.region[0]*sx;
941    float y1 = imageDataLeft.region[1]*sy;
942    float x2 = imageDataLeft.region[2]*sx;
943    float y2 = imageDataLeft.region[3]*sy;
944   
945    float aspectRatio = (y2-y1)/(x2-x1);
946
947    float image_width = _slideWidth*positionData.scale.x();
948    float image_height = image_width*aspectRatio*positionData.scale.y()/positionData.scale.x();
949
950    float offset = height*image_height*0.1f;
951   
952    bool usedTextureRectangle = false;
953
954    osg::Vec3 pos = computePositionInModelCoords(positionData) +
955                    osg::Vec3(-image_width*0.5f+offset,-offset,-image_height*0.5f-offset);
956
957    osg::Geode* pictureLeft = new osg::Geode;
958    {
959        pictureLeft->setNodeMask(0x01);
960
961        osg::Geometry* pictureLeftQuad = createTexturedQuadGeometry(pos, positionData.rotate, image_width,image_height,imageLeft.get(),usedTextureRectangle);
962        osg::StateSet* pictureLeftStateSet = pictureLeftQuad->getOrCreateStateSet();
963
964        if (isImageTranslucent)
965        {
966            pictureLeftStateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
967        }
968
969        attachTexMat(pictureLeftStateSet, imageDataLeft, s, t, usedTextureRectangle);
970
971        pictureLeft->addDrawable(pictureLeftQuad);
972
973    }
974
975    osg::Geode* pictureRight = new osg::Geode;
976    {
977        pictureRight->setNodeMask(0x02);
978
979        osg::Geometry* pictureRightQuad = createTexturedQuadGeometry(pos, positionData.rotate, image_width,image_height,imageRight.get(),usedTextureRectangle);
980        osg::StateSet* pictureRightStateSet = pictureRightQuad->getOrCreateStateSet();
981
982        if (isImageTranslucent)
983        {
984            pictureRightStateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
985        }
986
987        attachTexMat(pictureRightStateSet, imageDataRight, s, t, usedTextureRectangle);
988
989        pictureRight->addDrawable(pictureRightQuad);
990    }
991
992    osg::Group* subgraph = new osg::Group;
993    subgraph->addChild(pictureLeft);
994    subgraph->addChild(pictureRight);
995
996    // attach any meterial animation.
997    if (positionData.requiresMaterialAnimation())
998        subgraph = attachMaterialAnimation(subgraph,positionData)->asGroup();
999
1000    if (isImageTranslucent)
1001    {
1002        SetToTransparentBin sttb;
1003        subgraph->accept(sttb);
1004    }
1005
1006    // attached any rotation
1007    if (positionData.rotation[0]!=0.0)
1008    {
1009        osg::MatrixTransform* animation_transform = new osg::MatrixTransform;
1010        animation_transform->setDataVariance(osg::Object::DYNAMIC);
1011        animation_transform->setUpdateCallback(
1012            new osgUtil::TransformCallback(subgraph->getBound().center(),
1013                                           osg::Vec3(positionData.rotation[1],positionData.rotation[2],positionData.rotation[3]),
1014                                           osg::DegreesToRadians(positionData.rotation[0])));
1015                                           
1016        animation_transform->addChild(subgraph);
1017       
1018        subgraph = animation_transform;
1019    }
1020
1021
1022    // attached any animation
1023    osg::AnimationPathCallback* animation = getAnimationPathCallback(positionData);
1024    if (animation)
1025    {
1026        osg::notify(osg::INFO)<<"Have animation path for image"<<std::endl;
1027       
1028        osg::Vec3 pivot = positionData.absolute_path ? osg::Vec3(0.0f,0.0f,0.0f) : subgraph->getBound().center();
1029       
1030        osg::PositionAttitudeTransform* animation_transform = new osg::PositionAttitudeTransform;
1031        animation_transform->setDataVariance(osg::Object::DYNAMIC);
1032        animation_transform->setPivotPoint(pivot);
1033        animation->setPivotPoint(pivot);
1034
1035        animation_transform->setUpdateCallback(animation);
1036        animation_transform->setReferenceFrame(positionData.absolute_path ?
1037                                                    osg::Transform::ABSOLUTE_RF:
1038                                                    osg::Transform::RELATIVE_RF);
1039
1040        animation_transform->addChild(subgraph);
1041
1042        subgraph = animation_transform;
1043    }
1044
1045    _currentLayer->addChild(subgraph);
1046}
1047
1048void SlideShowConstructor::addVNC(const std::string& hostname, const PositionData& positionData, const ImageData& imageData)
1049{
1050    addInteractiveImage(hostname+".vnc", positionData, imageData);
1051}
1052
1053void SlideShowConstructor::addBrowser(const std::string& url, const PositionData& positionData, const ImageData& imageData)
1054{
1055    addInteractiveImage(url+".gecko", positionData, imageData);
1056}
1057
1058void SlideShowConstructor::addPDF(const std::string& filename, const PositionData& positionData, const ImageData& imageData)
1059{
1060    addInteractiveImage(filename, positionData, imageData);
1061}
1062
1063class SetPageCallback: public LayerCallback
1064{
1065public:
1066    SetPageCallback(osgWidget::PdfImage* pdfImage, int pageNum):
1067        _pdfImage(pdfImage),
1068        _pageNum(pageNum)
1069    {
1070    }
1071
1072    virtual void operator() (osg::Node*) const
1073    {
1074        osg::notify(osg::INFO)<<"PDF Page to be updated "<<_pageNum<<std::endl;
1075   
1076        if (_pdfImage.valid() && _pdfImage->getPageNum()!=_pageNum)
1077        {
1078            _pdfImage->page(_pageNum);
1079        }
1080    }
1081   
1082    osg::observer_ptr<osgWidget::PdfImage> _pdfImage;
1083    int _pageNum;
1084};
1085
1086
1087osg::Image* SlideShowConstructor::addInteractiveImage(const std::string& filename, const PositionData& positionData, const ImageData& imageData)
1088{
1089    if (!_currentLayer) addLayer();
1090
1091    osg::Image* image = osgDB::readImageFile(filename, _options.get());
1092   
1093    osg::notify(osg::INFO)<<"addInteractiveImage("<<filename<<") "<<image<<std::endl;
1094   
1095   
1096    if (!image) return 0;
1097   
1098    float s = image->s();
1099    float t = image->t();
1100   
1101    // temporary hack
1102    float height = 0.0f;
1103   
1104    float sx = imageData.region_in_pixel_coords ? 1.0f : s;
1105    float sy = imageData.region_in_pixel_coords ? 1.0f : t;
1106
1107    float x1 = imageData.region[0]*sx;
1108    float y1 = imageData.region[1]*sy;
1109    float x2 = imageData.region[2]*sx;
1110    float y2 = imageData.region[3]*sy;
1111   
1112    float aspectRatio = (y2-y1)/(x2-x1);
1113
1114    float image_width = _slideWidth*positionData.scale.x();
1115    float image_height = image_width*aspectRatio*positionData.scale.y()/positionData.scale.x();
1116    float offset = height*image_height*0.1f;
1117   
1118    osg::Vec3 pos = computePositionInModelCoords(positionData) + osg::Vec3(-image_width*0.5f+offset,-offset,-image_height*0.5f-offset);
1119
1120    osg::Geode* picture = new osg::Geode;
1121    osg::Node* subgraph = picture;
1122
1123
1124    bool usedTextureRectangle = false;
1125    osg::Geometry* pictureQuad = createTexturedQuadGeometry(pos, positionData.rotate, image_width, image_height, image, usedTextureRectangle);
1126
1127    osg::ref_ptr<osgViewer::InteractiveImageHandler> handler = new osgViewer::InteractiveImageHandler(image);
1128    pictureQuad->setEventCallback(handler.get());
1129    pictureQuad->setCullCallback(handler.get());
1130
1131    osg::StateSet* pictureStateSet = pictureQuad->getOrCreateStateSet();
1132
1133    attachTexMat(pictureStateSet, imageData, s, t, usedTextureRectangle);
1134
1135    pictureStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
1136
1137    picture->addDrawable(pictureQuad);
1138
1139    // attach any meterial animation.
1140    if (positionData.requiresMaterialAnimation())
1141        subgraph = attachMaterialAnimation(subgraph,positionData);
1142
1143
1144    // attached any rotation
1145    if (positionData.rotation[0]!=0.0)
1146    {
1147        osg::MatrixTransform* animation_transform = new osg::MatrixTransform;
1148        animation_transform->setDataVariance(osg::Object::DYNAMIC);
1149        animation_transform->setUpdateCallback(
1150            new osgUtil::TransformCallback(picture->getBound().center(),
1151                                           osg::Vec3(positionData.rotation[1],positionData.rotation[2],positionData.rotation[3]),
1152                                           osg::DegreesToRadians(positionData.rotation[0])));
1153                                           
1154        animation_transform->addChild(subgraph);
1155       
1156        subgraph = animation_transform;
1157    }
1158
1159
1160    // attached any animation
1161    osg::AnimationPathCallback* animation = getAnimationPathCallback(positionData);
1162    if (animation)
1163    {
1164        osg::notify(osg::INFO)<<"Have animation path for image"<<std::endl;
1165       
1166        osg::Vec3 pivot = positionData.absolute_path ? osg::Vec3(0.0f,0.0f,0.0f) : subgraph->getBound().center();
1167       
1168        osg::PositionAttitudeTransform* animation_transform = new osg::PositionAttitudeTransform;
1169        animation_transform->setDataVariance(osg::Object::DYNAMIC);
1170        animation_transform->setPivotPoint(pivot);
1171        animation->setPivotPoint(pivot);
1172
1173        animation_transform->setUpdateCallback(animation);
1174
1175        animation_transform->setReferenceFrame(positionData.absolute_path ?
1176                                                    osg::Transform::ABSOLUTE_RF:
1177                                                    osg::Transform::RELATIVE_RF);
1178
1179        animation_transform->addChild(subgraph);
1180
1181        subgraph = animation_transform;
1182    }
1183
1184    _currentLayer->addChild(subgraph);
1185   
1186    osgWidget::PdfImage* pdfImage = dynamic_cast<osgWidget::PdfImage*>(image);
1187    if (pdfImage && imageData.page>=0)
1188    {
1189        getOrCreateLayerAttributes(_currentLayer.get())->addEnterCallback(new SetPageCallback(pdfImage, imageData.page));
1190
1191        osg::notify(osg::INFO)<<"Setting pdf page num "<<imageData.page<<std::endl;
1192        pdfImage->setBackgroundColor(imageData.backgroundColor);
1193        pdfImage->page(imageData.page);
1194
1195        if (imageData.backgroundColor.a()<1.0f)
1196        {
1197            SetToTransparentBin sttb;
1198            subgraph->accept(sttb);
1199        }
1200
1201
1202    }
1203
1204
1205    return image;
1206}
1207
1208std::string SlideShowConstructor::findFileAndRecordPath(const std::string& filename)
1209{
1210    std::string foundFile = osgDB::findDataFile(filename, _options.get());
1211    if (foundFile.empty()) return foundFile;
1212
1213    osg::notify(osg::INFO)<<"foundFile "<<foundFile<<std::endl;
1214
1215    std::string path = osgDB::getFilePath(foundFile);
1216    if (!path.empty() && _filePathData.valid())
1217    {
1218        osgDB::FilePathList::iterator itr = std::find(_filePathData->filePathList.begin(),_filePathData->filePathList.end(),path);
1219        if (itr==_filePathData->filePathList.end())
1220        {
1221            osg::notify(osg::INFO)<<"New path to record "<<path<<std::endl;
1222            _filePathData->filePathList.push_front(path);
1223        }
1224    }
1225   
1226    return foundFile;
1227
1228}
1229
1230void SlideShowConstructor::addModel(const std::string& filename, const PositionData& positionData, const ModelData& modelData)
1231{
1232    osg::notify(osg::INFO)<<"SlideShowConstructor::addModel("<<filename<<")"<<std::endl;
1233
1234    osg::Node* subgraph = 0;
1235
1236    if (filename=="sphere")
1237    {
1238        osg::Geode* geode = new osg::Geode;
1239        geode->addDrawable(new osg::ShapeDrawable(new osg::Sphere));
1240       
1241        subgraph = geode;
1242    }
1243    else if (filename=="box")
1244    {
1245        osg::Geode* geode = new osg::Geode;
1246        geode->addDrawable(new osg::ShapeDrawable(new osg::Box));
1247       
1248        subgraph = geode;
1249    }
1250    else
1251    {
1252        subgraph = osgDB::readNodeFile(filename, _options.get());
1253        if (subgraph) recordOptionsFilePath(_options.get());
1254    }
1255   
1256    if (subgraph)
1257    {
1258        addModel(subgraph, positionData, modelData);
1259    }
1260
1261    osg::notify(osg::INFO)<<"end of SlideShowConstructor::addModel("<<filename<<")"<<std::endl<<std::endl;
1262
1263}
1264
1265void SlideShowConstructor::addModel(osg::Node* subgraph, const PositionData& positionData, const ModelData& modelData)
1266{
1267    osg::Object::DataVariance defaultMatrixDataVariance = osg::Object::DYNAMIC; // STATIC
1268
1269    if (!modelData.effect.empty())
1270    {
1271        if (modelData.effect=="SpecularHighlights" || modelData.effect=="glossy")
1272        {
1273            osgFX::SpecularHighlights* specularHighlights = new osgFX::SpecularHighlights;
1274            specularHighlights->setTextureUnit(1);
1275            specularHighlights->addChild(subgraph);
1276            subgraph = specularHighlights;
1277        }
1278    }
1279   
1280    if (positionData.frame==SLIDE)
1281    {
1282        osg::Vec3 pos = convertSlideToModel(positionData.position);
1283     
1284        const osg::BoundingSphere& bs = subgraph->getBound();
1285        float model_scale = positionData.scale.x()*_slideHeight*(1.0f-positionData.position.z())*0.7f/bs.radius();
1286
1287        osg::MatrixTransform* transform = new osg::MatrixTransform;
1288        transform->setDataVariance(defaultMatrixDataVariance);
1289        transform->setMatrix(osg::Matrix::translate(-bs.center())*
1290                             osg::Matrix::scale(model_scale,model_scale,model_scale)*
1291                             osg::Matrix::rotate(osg::DegreesToRadians(positionData.rotate[0]),positionData.rotate[1],positionData.rotate[2],positionData.rotate[3])*
1292                             osg::Matrix::translate(pos));
1293
1294
1295        transform->setStateSet(createTransformStateSet());
1296        transform->addChild(subgraph);
1297
1298        subgraph = transform;
1299
1300    }
1301    else
1302    {
1303        osg::Matrix matrix(osg::Matrix::scale(1.0f/positionData.scale.x(),1.0f/positionData.scale.x(),1.0f/positionData.scale.x())*
1304                           osg::Matrix::rotate(osg::DegreesToRadians(positionData.rotate[0]),positionData.rotate[1],positionData.rotate[2],positionData.rotate[3])*
1305                           osg::Matrix::translate(positionData.position));
1306
1307        osg::MatrixTransform* transform = new osg::MatrixTransform;
1308        transform->setDataVariance(defaultMatrixDataVariance);
1309        transform->setMatrix(osg::Matrix::inverse(matrix));
1310       
1311        osg::notify(osg::INFO)<<"Position Matrix "<<transform->getMatrix()<<std::endl;
1312
1313        transform->addChild(subgraph);
1314
1315        subgraph = transform;
1316    }
1317   
1318    float referenceSizeRatio = 0.707;
1319    float referenceSize = subgraph->getBound().radius() * referenceSizeRatio;
1320
1321
1322    // attach any meterial animation.
1323    if (positionData.requiresMaterialAnimation())
1324        subgraph = attachMaterialAnimation(subgraph,positionData);
1325
1326    // attached any rotation
1327    if (positionData.rotation[0]!=0.0)
1328    {
1329        osg::MatrixTransform* animation_transform = new osg::MatrixTransform;
1330        animation_transform->setDataVariance(osg::Object::DYNAMIC);
1331        animation_transform->setUpdateCallback(
1332            new osgUtil::TransformCallback(subgraph->getBound().center(),
1333                                           osg::Vec3(positionData.rotation[1],positionData.rotation[2],positionData.rotation[3]),
1334                                           osg::DegreesToRadians(positionData.rotation[0])));
1335
1336        animation_transform->addChild(subgraph);
1337
1338        osg::notify(osg::INFO)<<"Rotation Matrix "<<animation_transform->getMatrix()<<std::endl;
1339
1340        subgraph = animation_transform;
1341    }
1342
1343
1344    // attached any animation
1345    osg::AnimationPathCallback* animation = getAnimationPathCallback(positionData);
1346    if (animation)
1347    {
1348        osg::notify(osg::INFO)<<"Have animation path for model"<<std::endl;
1349
1350        osg::Vec3 pivot = positionData.absolute_path ? osg::Vec3(0.0f,0.0f,0.0f) : subgraph->getBound().center();
1351
1352        osg::AnimationPath* path = animation->getAnimationPath();
1353        if (positionData.animation_name=="wheel" && (path->getTimeControlPointMap()).size()>=2)
1354        {
1355            osg::notify(osg::INFO)<<"****  Need to handle special wheel animation"<<std::endl;
1356
1357            osg::AnimationPath::TimeControlPointMap& controlPoints = path->getTimeControlPointMap();
1358           
1359            osg::AnimationPath::TimeControlPointMap::iterator curr_itr = controlPoints.begin();
1360            osg::AnimationPath::TimeControlPointMap::iterator prev_itr=curr_itr;
1361            ++curr_itr;
1362           
1363            osg::AnimationPath::ControlPoint* prev_cp = &(prev_itr->second);
1364            osg::AnimationPath::ControlPoint* curr_cp = &(curr_itr->second);
1365
1366            float totalLength = 0;
1367            float rotation_y_axis = 0;
1368            osg::Vec3 delta_position = curr_cp->getPosition() - prev_cp->getPosition();
1369            float rotation_z_axis = atan2f(delta_position.y(),delta_position.x());
1370
1371            osg::Quat quat_y_axis,quat_z_axis,quat_combined;
1372           
1373            quat_y_axis.makeRotate(rotation_y_axis,0.0f,1.0f,0.0f);
1374            quat_z_axis.makeRotate(rotation_z_axis,0.0f,0.0f,1.0f);
1375            quat_combined = quat_y_axis*quat_z_axis;
1376
1377            // set first rotation.
1378            prev_cp->setRotation(quat_combined);
1379
1380            for(;
1381                curr_itr!=controlPoints.end();
1382                ++curr_itr)
1383            {
1384                prev_cp = &(prev_itr->second);
1385                curr_cp = &(curr_itr->second);
1386               
1387                delta_position = curr_cp->getPosition() - prev_cp->getPosition();
1388               
1389                totalLength += delta_position.length();
1390               
1391                // rolling - rotation about the y axis.
1392                rotation_y_axis = totalLength/referenceSize;
1393               
1394                // direction - rotation about the z axis.
1395                rotation_z_axis = atan2f(delta_position.y(),delta_position.x());
1396
1397                osg::notify(osg::INFO)<<" rotation_y_axis="<<rotation_y_axis<<" rotation_z_axis="<<rotation_z_axis<<std::endl;
1398               
1399                quat_y_axis.makeRotate(rotation_y_axis,0.0f,1.0f,0.0f);
1400                quat_z_axis.makeRotate(rotation_z_axis,0.0f,0.0f,1.0f);
1401                quat_combined = quat_y_axis*quat_z_axis;
1402               
1403                curr_cp->setRotation(quat_combined);             
1404               
1405                prev_itr = curr_itr;
1406
1407            }
1408
1409        }
1410
1411
1412        osg::PositionAttitudeTransform* animation_transform = new osg::PositionAttitudeTransform;
1413        animation_transform->setDataVariance(osg::Object::DYNAMIC);
1414        animation_transform->setPivotPoint(pivot);
1415        animation->setPivotPoint(pivot);
1416        animation_transform->setUpdateCallback(animation);
1417
1418        animation_transform->setReferenceFrame(positionData.absolute_path ?
1419                                                    osg::Transform::ABSOLUTE_RF:
1420                                                    osg::Transform::RELATIVE_RF);
1421
1422        animation_transform->addChild(subgraph);
1423
1424        subgraph = animation_transform;
1425    }
1426
1427    findImageStreamsAndAddCallbacks(subgraph);
1428
1429    _currentLayer->addChild(subgraph);
1430}
1431
1432
1433void SlideShowConstructor::addVolume(const std::string& filename, const PositionData& positionData)
1434{
1435    // osg::Object::DataVariance defaultMatrixDataVariance = osg::Object::DYNAMIC; // STATIC
1436
1437    std::string foundFile = filename;
1438
1439    osgDB::FileType fileType = osgDB::fileType(foundFile);
1440    if (fileType == osgDB::FILE_NOT_FOUND)
1441    {
1442        foundFile = findFileAndRecordPath(foundFile);
1443        fileType = osgDB::fileType(foundFile);
1444    }
1445   
1446    osg::ref_ptr<osg::Image> image;
1447    if (fileType == osgDB::DIRECTORY)
1448    {
1449       image = osgDB::readImageFile(foundFile+".dicom", _options.get());
1450    }
1451    else if (fileType == osgDB::REGULAR_FILE)
1452    {
1453        image = osgDB::readImageFile( foundFile, _options.get() );
1454    }
1455    else
1456    {
1457        // not found image, so fallback to plguins/callbacks to find the model.
1458        image = osgDB::readImageFile( filename, _options.get() );
1459        if (image) recordOptionsFilePath(_options.get() );
1460    }
1461
1462    if (!image) return;
1463
1464
1465    osg::ref_ptr<osgVolume::Volume> volume = new osgVolume::Volume;
1466    osg::ref_ptr<osgVolume::VolumeTile> tile = new osgVolume::VolumeTile;
1467    volume->addChild(tile.get());
1468
1469    osg::ref_ptr<osgVolume::ImageLayer> layer = new osgVolume::ImageLayer(image.get());
1470    layer->rescaleToZeroToOneRange();
1471
1472    osg::RefMatrix* matrix = dynamic_cast<osg::RefMatrix*>(image->getUserData());       
1473    if (matrix)
1474    {
1475        osgVolume::Locator* locator = new osgVolume::Locator(*matrix);
1476        layer->setLocator(locator);
1477        tile->setLocator(locator);
1478    }
1479
1480    tile->setLayer(layer.get());
1481
1482    float alphaFunc = 0.1;
1483
1484    osgVolume::SwitchProperty* sp = new osgVolume::SwitchProperty;
1485    sp->setActiveProperty(0);
1486
1487    osgVolume::AlphaFuncProperty* ap = new osgVolume::AlphaFuncProperty(alphaFunc);
1488    osgVolume::SampleDensityProperty* sd = new osgVolume::SampleDensityProperty(0.005);
1489    osgVolume::TransparencyProperty* tp = new osgVolume::TransparencyProperty(1.0);
1490
1491    {
1492        // Standard
1493        osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty;
1494        cp->addProperty(ap);
1495        cp->addProperty(sd);
1496        cp->addProperty(tp);
1497
1498        sp->addProperty(cp);
1499    }
1500
1501    {
1502        // Light
1503        osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty;
1504        cp->addProperty(ap);
1505        cp->addProperty(sd);
1506        cp->addProperty(tp);
1507        cp->addProperty(new osgVolume::LightingProperty);
1508
1509        sp->addProperty(cp);
1510    }
1511
1512    {
1513        // Isosurface
1514        osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty;
1515        cp->addProperty(sd);
1516        cp->addProperty(tp);
1517        cp->addProperty(new osgVolume::IsoSurfaceProperty(alphaFunc));
1518
1519        sp->addProperty(cp);
1520    }
1521
1522    {
1523        // MaximumIntensityProjection
1524        osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty;
1525        cp->addProperty(ap);
1526        cp->addProperty(sd);
1527        cp->addProperty(tp);
1528        cp->addProperty(new osgVolume::MaximumIntensityProjectionProperty);
1529
1530        sp->addProperty(cp);
1531    }
1532
1533    layer->addProperty(sp);
1534    tile->setVolumeTechnique(new osgVolume::RayTracedTechnique);
1535    tile->setEventCallback(new osgVolume::PropertyAdjustmentCallback());
1536
1537    ModelData modelData;
1538    addModel(volume.get(), positionData, modelData);
1539}
1540
1541bool SlideShowConstructor::attachTexMat(osg::StateSet* stateset, const ImageData& imageData, float s, float t, bool textureRectangle)
1542{
1543    float xScale = textureRectangle ? s : 1.0f;
1544    float yScale = textureRectangle ? t : 1.0f;
1545
1546    float sx = (textureRectangle ? s : 1.0f) / (imageData.region_in_pixel_coords ? s : 1.0f);
1547    float sy = (textureRectangle ? t : 1.0f) / (imageData.region_in_pixel_coords ? t : 1.0f);
1548
1549    float x1 = imageData.region[0]*sx;
1550    float y1 = imageData.region[1]*sy;
1551    float x2 = imageData.region[2]*sx;
1552    float y2 = imageData.region[3]*sy;
1553
1554    if (x1!=0.0f || y1!=0.0f || x2!=xScale || y2 != yScale ||
1555        imageData.texcoord_rotate != 0.0f)
1556    {
1557        osg::TexMat* texmat = new osg::TexMat;
1558        texmat->setMatrix(osg::Matrix::translate(-0.5f*xScale,-0.5f*yScale,0.0f)*
1559                          osg::Matrix::rotate(osg::DegreesToRadians(imageData.texcoord_rotate),0.0f,0.0f,1.0f)*
1560                          osg::Matrix::translate(0.5f*xScale,0.5f*yScale,0.0f)*
1561                          osg::Matrix::scale((x2-x1)/xScale,(y2-y1)/yScale,1.0f)*
1562                          osg::Matrix::translate(x1,
1563                                                 y1,
1564                                                 0.0f));
1565                         
1566        stateset->setTextureAttribute(0,texmat);
1567        return true;
1568    }
1569    return false;
1570}
1571
1572osg::Node* SlideShowConstructor::attachMaterialAnimation(osg::Node* model, const PositionData& positionData)
1573{
1574    ss3d::AnimationMaterial* animationMaterial = 0;
1575
1576    if (!positionData.animation_material_filename.empty())
1577    {
1578#if 0
1579        std::string absolute_animation_file_path = osgDB::findDataFile(positionData.animation_material_filename, _options.get());
1580        if (!absolute_animation_file_path.empty())
1581        {       
1582            std::ifstream animation_filestream(absolute_animation_file_path.c_str());
1583            if (!animation_filestream.eof())
1584            {
1585                animationMaterial = new ss3d::AnimationMaterial;
1586                animationMaterial->read(animation_filestream);
1587            }
1588        }
1589#else
1590        osg::ref_ptr<osg::Object> object = osgDB::readObjectFile(positionData.animation_material_filename, _options.get());
1591        animationMaterial = dynamic_cast<ss3d::AnimationMaterial*>(object.get());
1592#endif
1593
1594    }
1595    else if (!positionData.fade.empty())
1596    {
1597        std::istringstream iss(positionData.fade);
1598       
1599        animationMaterial = new ss3d::AnimationMaterial;
1600        while (!iss.fail() && !iss.eof())
1601        {
1602            float time=1.0f, alpha=1.0f;
1603            iss >> time >> alpha;
1604            if (!iss.fail())
1605            {
1606                osg::Material* material = new osg::Material;
1607                material->setAmbient(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,alpha));
1608                material->setDiffuse(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,alpha));
1609                animationMaterial->insert(time,material);
1610            }
1611        }
1612    }
1613   
1614    if (animationMaterial)
1615    {
1616        animationMaterial->setLoopMode(positionData.animation_material_loop_mode);
1617
1618        ss3d::AnimationMaterialCallback* animationMaterialCallback = new ss3d::AnimationMaterialCallback(animationMaterial);
1619        animationMaterialCallback->setTimeOffset(positionData.animation_material_time_offset);
1620        animationMaterialCallback->setTimeMultiplier(positionData.animation_material_time_multiplier);
1621
1622        osg::Group* decorator = new osg::Group;
1623        decorator->addChild(model);
1624
1625        decorator->setUpdateCallback(animationMaterialCallback);
1626
1627        if (animationMaterial->requiresBlending())
1628        {
1629            SetToTransparentBin sttb;
1630            decorator->accept(sttb);
1631        }
1632
1633        return decorator;
1634    }
1635
1636    return model;
1637}
1638
1639osg::AnimationPathCallback* SlideShowConstructor::getAnimationPathCallback(const PositionData& positionData)
1640{
1641    if (!positionData.path.empty())
1642    {
1643        osg::ref_ptr<osg::Object> object = osgDB::readObjectFile(positionData.path, _options.get());
1644        osg::AnimationPath* animation = dynamic_cast<osg::AnimationPath*>(object.get());
1645        if (animation)
1646        {
1647            if (positionData.frame==SlideShowConstructor::SLIDE)
1648            {
1649                osg::AnimationPath::TimeControlPointMap& controlPoints = animation->getTimeControlPointMap();
1650                for(osg::AnimationPath::TimeControlPointMap::iterator itr=controlPoints.begin();
1651                    itr!=controlPoints.end();
1652                    ++itr)
1653                {
1654                    osg::AnimationPath::ControlPoint& cp = itr->second;
1655                    cp.setPosition(convertSlideToModel(cp.getPosition()+positionData.position));
1656                }
1657            }
1658
1659            animation->setLoopMode(positionData.path_loop_mode);
1660
1661            osg::AnimationPathCallback* apc = new osg::AnimationPathCallback(animation);
1662            apc->setTimeOffset(positionData.path_time_offset);
1663            apc->setTimeMultiplier(positionData.path_time_multiplier);
1664            apc->setUseInverseMatrix(positionData.inverse_path);
1665
1666            osg::notify(osg::INFO)<<"UseInverseMatrix "<<positionData.inverse_path<<std::endl;
1667
1668            return apc;
1669
1670        }
1671
1672    }
1673    return 0;
1674}
1675
1676osg::Vec3 SlideShowConstructor::computePositionInModelCoords(const PositionData& positionData) const
1677{
1678    if (positionData.frame==SLIDE)
1679    {
1680        osg::notify(osg::INFO)<<"********* Scaling from slide coords to model coords"<<std::endl;
1681        return convertSlideToModel(positionData.position);
1682    }
1683    else
1684    {
1685        osg::notify(osg::INFO)<<"keeping original model coords"<<std::endl;
1686        return positionData.position;
1687    }
1688}
1689
1690osg::Vec3 SlideShowConstructor::convertSlideToModel(const osg::Vec3& position) const
1691{
1692    return osg::Vec3(_slideOrigin+osg::Vec3(_slideWidth*position.x(),0.0f,_slideHeight*position.y()))*(1.0f-position.z());
1693}
1694
1695osg::Vec3 SlideShowConstructor::convertModelToSlide(const osg::Vec3& position) const
1696{
1697    return osg::Vec3((position.x()*(_slideOrigin.y()/position.y())-_slideOrigin.x())/_slideWidth,
1698                     (position.z()*(_slideOrigin.y()/position.y())-_slideOrigin.z())/_slideHeight,
1699                     1.0f-position.y()/_slideOrigin.y());
1700}
1701
1702void SlideShowConstructor::updatePositionFromInModelCoords(const osg::Vec3& vertex, PositionData& positionData) const
1703{
1704    if (positionData.frame==SLIDE)
1705    {
1706        positionData.position = convertModelToSlide(vertex);
1707    }
1708    else
1709    {
1710        positionData.position = vertex;
1711    }
1712}
1713
1714void SlideShowConstructor::recordOptionsFilePath(const osgDB::Options* options)
1715{
1716    if (options)
1717    {
1718        std::string filename_used = _options->getPluginStringData("filename");
1719        std::string path = osgDB::getFilePath(filename_used);
1720        if (!path.empty() && _filePathData.valid())
1721        {
1722            osgDB::FilePathList::iterator itr = std::find(_filePathData->filePathList.begin(),_filePathData->filePathList.end(),path);
1723            if (itr==_filePathData->filePathList.end())
1724            {
1725                osg::notify(osg::INFO)<<"SlideShowConstructor::recordOptionsFilePath(..) - new path to record path="<<path<<" filename_used="<<filename_used<<std::endl;
1726                _filePathData->filePathList.push_front(path);
1727            }
1728        }
1729    }
1730}
Note: See TracBrowser for help on using the browser.