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

Revision 10117, 62.5 kB (checked in by robert, 6 years ago)

Reorganised placement of classes associated with scene graph.

Warning clean up.

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