root/OpenSceneGraph/trunk/src/osgPlugins/p3d/ReaderWriterP3D.cpp @ 10396

Revision 10396, 70.4 kB (checked in by robert, 5 years ago)

Refactored preset3D/p3d plugin so that common scene graph extensions and classes now live in a separate osgPresenttation NodeKit?.

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 <osg/Notify>
14#include <osg/io_utils>
15
16#include <osgDB/ReaderWriter>
17#include <osgDB/FileNameUtils>
18#include <osgDB/FileUtils>
19#include <osgDB/Registry>
20
21#include <osgWidget/PdfReader>
22
23#include <osgPresentation/SlideShowConstructor>
24
25#include <stdio.h>
26#include <string.h>
27#include <stdlib.h>
28
29#include <osgDB/XmlParser>
30
31#include <sstream>
32#include <iostream>
33
34
35/**
36 * OpenSceneGraph plugin wrapper/converter.
37 */
38class ReaderWriterP3DXML : public osgDB::ReaderWriter
39{
40public:
41    ReaderWriterP3DXML()
42    {
43        _colorMap["WHITE"]  .set(1.0f,1.0f,1.0f,1.0f);
44        _colorMap["BLACK"]  .set(0.0f,0.0f,0.0f,1.0f);
45        _colorMap["PURPLE"] .set(1.0f,0.0f,1.0f,1.0f);
46        _colorMap["BLUE"]   .set(0.0f,0.0f,1.0f,1.0f);
47        _colorMap["RED"]    .set(1.0f,0.0f,0.0f,1.0f);
48        _colorMap["CYAN"]   .set(0.0f,1.0f,1.0f,1.0f);
49        _colorMap["YELLOW"] .set(1.0f,1.0f,0.0f,1.0f);
50        _colorMap["GREEN"]  .set(0.0f,1.0f,0.0f,1.0f);
51        _colorMap["SKY"]    .set(0.2f, 0.2f, 0.4f, 1.0f);
52
53        _layoutMap["LEFT_TO_RIGHT"] = osgText::Text::LEFT_TO_RIGHT;
54        _layoutMap["RIGHT_TO_LEFT"] = osgText::Text::RIGHT_TO_LEFT;
55        _layoutMap["VERTICAL"] = osgText::Text::VERTICAL;
56
57        _alignmentMap["LEFT_TOP"] = osgText::Text::LEFT_TOP;
58        _alignmentMap["LEFT_CENTER"] = osgText::Text::LEFT_CENTER;
59        _alignmentMap["LEFT_BOTTOM"] = osgText::Text::LEFT_BOTTOM;
60
61        _alignmentMap["CENTER_TOP"] = osgText::Text::CENTER_TOP;
62        _alignmentMap["CENTER_CENTER"] = osgText::Text::CENTER_CENTER;
63        _alignmentMap["CENTER_BOTTOM"] = osgText::Text::CENTER_BOTTOM;
64
65        _alignmentMap["RIGHT_TOP"] = osgText::Text::RIGHT_TOP;
66        _alignmentMap["RIGHT_CENTER"] = osgText::Text::RIGHT_CENTER;
67        _alignmentMap["RIGHT_BOTTOM"] = osgText::Text::RIGHT_BOTTOM;
68       
69        _alignmentMap["LEFT_BASE_LINE"] = osgText::Text::LEFT_BASE_LINE;
70        _alignmentMap["CENTER_BASE_LINE"] = osgText::Text::CENTER_BASE_LINE;
71        _alignmentMap["RIGHT_BASE_LINE"] = osgText::Text::RIGHT_BASE_LINE;
72        _alignmentMap["BASE_LINE"] = osgText::Text::LEFT_BASE_LINE;
73
74        _stringKeyMap["Home"]=' ';
75        _stringKeyMap["Start"]= osgGA::GUIEventAdapter::KEY_Home;
76        _stringKeyMap["Next"]= osgGA::GUIEventAdapter::KEY_Page_Down;
77        _stringKeyMap["Previous"]=osgGA::GUIEventAdapter::KEY_Page_Up;
78        _stringKeyMap["Up"]=osgGA::GUIEventAdapter::KEY_Up;
79        _stringKeyMap["Down"]=osgGA::GUIEventAdapter::KEY_Down;
80        _stringKeyMap["End"]=osgGA::GUIEventAdapter::KEY_End;
81        _stringKeyMap["Page Down"]=osgGA::GUIEventAdapter::KEY_Page_Down;
82        _stringKeyMap["Page Up"]=osgGA::GUIEventAdapter::KEY_Page_Up;
83        _stringKeyMap["F1"]=osgGA::GUIEventAdapter::KEY_F1;
84        _stringKeyMap["F2"]=osgGA::GUIEventAdapter::KEY_F2;
85        _stringKeyMap["F3"]=osgGA::GUIEventAdapter::KEY_F3;
86        _stringKeyMap["F4"]=osgGA::GUIEventAdapter::KEY_F4;
87        _stringKeyMap["F5"]=osgGA::GUIEventAdapter::KEY_F5;
88        _stringKeyMap["F6"]=osgGA::GUIEventAdapter::KEY_F6;
89        _stringKeyMap["F7"]=osgGA::GUIEventAdapter::KEY_F7;
90        _stringKeyMap["F8"]=osgGA::GUIEventAdapter::KEY_F8;
91        _stringKeyMap["F9"]=osgGA::GUIEventAdapter::KEY_F9;
92        _stringKeyMap["F10"]=osgGA::GUIEventAdapter::KEY_F10;
93        _stringKeyMap["F11"]=osgGA::GUIEventAdapter::KEY_F11;
94        _stringKeyMap["F12"]=osgGA::GUIEventAdapter::KEY_F12;
95
96
97        _notifyLevel = osg::INFO;
98    }
99   
100    virtual const char* className() const
101    {
102        return "present3D XML Reader/Writer";
103    }
104
105    virtual bool acceptsExtension(const std::string& extension) const
106    {
107        return osgDB::equalCaseInsensitive(extension,"p3d") ||
108               osgDB::equalCaseInsensitive(extension,"xml") ;
109    }
110
111    virtual ReadResult readNode(const std::string& fileName,
112                                const osgDB::ReaderWriter::Options* options) const;
113
114    virtual ReadResult readNode(std::istream& fin, const Options* options) const;
115
116    ReadResult readNode(osgDB::XmlNode::Input& input, osgDB::ReaderWriter::Options* options) const;
117
118    void parseModel(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const;
119
120    void parseVolume(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const;
121
122    void parseStereoPair(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const;
123
124    void parseLayer(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const;
125 
126    void parseBullets(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur, bool inheritPreviousLayers, bool defineAsBaseLayer) const;
127    void parseText(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur, bool inheritPreviousLayers, bool defineAsBaseLayer) const;
128
129    void parsePage (osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const;
130   
131    void parseSlide (osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur, bool parseTitles=true, bool parseLayers=true) const;
132
133    void parsePdfDocument (osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const;
134
135    osg::Vec4 mapStringToColor(const std::string& str) const
136    {
137        ColorMap::const_iterator itr=_colorMap.find(str);
138        if (itr!=_colorMap.end()) return itr->second;
139        osg::Vec4 color;
140        if (read(str,color)) return color;
141        else return osg::Vec4(0.0f,0.0f,0.0f,1.0f);
142    }
143   
144    inline osg::Vec4 accumulateRotation(const osg::Vec4& lhs, const osg::Vec4& rhs) const
145    {
146        osg::Quat qlhs,qrhs;
147        qlhs.makeRotate(osg::DegreesToRadians(lhs[0]),lhs[1],lhs[2],lhs[3]);
148        qrhs.makeRotate(osg::DegreesToRadians(rhs[0]),rhs[1],rhs[2],rhs[3]);
149        osg::Quat quat = qlhs*qrhs;
150        osg::Vec4d result;
151        quat.getRotate ( result[0], result[1], result[2], result[3]);
152        result[0] = osg::RadiansToDegrees(result[0]);
153        return result;
154    }
155   
156    inline bool read(const char* str, int& value) const;
157    inline bool read(const char* str, float& value) const;
158    inline bool read(const char* str, double& value) const;
159    inline bool read(const char* str, osg::Vec2& value) const;
160    inline bool read(const char* str, osg::Vec3& value) const;
161    inline bool read(const char* str, osg::Vec4& value) const;
162   
163    inline bool read(const std::string& str, int& value) const;
164    inline bool read(const std::string& str, float& value) const;
165    inline bool read(const std::string& str, double& value) const;
166    inline bool read(const std::string& str, osg::Vec2& value) const;
167    inline bool read(const std::string& str, osg::Vec3& value) const;
168    inline bool read(const std::string& str, osg::Vec4& value) const;
169
170    bool getProperty(osgDB::XmlNode*cur, const char* token) const;
171    bool getProperty(osgDB::XmlNode*cur, const char* token, int& value) const;
172    bool getProperty(osgDB::XmlNode*cur, const char* token, float& value) const;
173    bool getProperty(osgDB::XmlNode*cur, const char* token, double& value) const;
174    bool getProperty(osgDB::XmlNode*cur, const char* token, osg::Vec2& value) const;
175    bool getProperty(osgDB::XmlNode*cur, const char* token, osg::Vec3& value) const;
176    bool getProperty(osgDB::XmlNode*cur, const char* token, osg::Vec4& value) const;
177    bool getProperty(osgDB::XmlNode*cur, const char* token, std::string& value) const;
178    bool getProperty(osgDB::XmlNode*cur, const char* token, osgText::Text::Layout& value) const;
179    bool getProperty(osgDB::XmlNode*cur, const char* token, osgText::Text::AlignmentType& value) const;
180   
181    bool getProperties(osgDB::XmlNode*cur, osgPresentation::SlideShowConstructor::PositionData& value) const;
182    bool getProperties(osgDB::XmlNode*cur, osgPresentation::SlideShowConstructor::FontData& value) const;
183    bool getProperties(osgDB::XmlNode*cur, osgPresentation::SlideShowConstructor::ModelData& value) const;
184    bool getProperties(osgDB::XmlNode*cur, osgPresentation::SlideShowConstructor::ImageData& value) const;
185    bool getJumpProperties(osgDB::XmlNode*cur, bool& relativeJump, int& slideNum, int& layerNum) const;
186 
187    bool getKeyPositionInner(osgDB::XmlNode*cur, osgPresentation::KeyPosition& keyPosition) const;
188    bool getKeyPosition(osgDB::XmlNode*cur, osgPresentation::KeyPosition& keyPosition) const;
189
190    typedef std::map<std::string,osg::Vec4> ColorMap;
191    typedef std::map<std::string,osgText::Text::Layout> LayoutMap;
192    typedef std::map<std::string,osgText::Text::AlignmentType> AlignmentMap;
193    typedef std::map<std::string, unsigned int> StringKeyMap;
194
195    std::string expandEnvVarsInFileName(const std::string& filename) const;
196
197
198    ColorMap            _colorMap;
199    LayoutMap           _layoutMap;
200    AlignmentMap        _alignmentMap;
201    StringKeyMap        _stringKeyMap;
202   
203    typedef std::map<std::string, osg::ref_ptr<osgDB::XmlNode> > TemplateMap;
204    mutable TemplateMap _templateMap;
205
206    osg::NotifySeverity _notifyLevel;
207
208};
209
210// now register with Registry to instantiate the above
211// reader/writer.
212REGISTER_OSGPLUGIN(p3d, ReaderWriterP3DXML)
213
214
215std::string ReaderWriterP3DXML::expandEnvVarsInFileName(const std::string& filename) const
216{
217    std::string argument(filename);
218    std::string::size_type start_pos = argument.find("${");
219   
220    while (start_pos != std::string::npos)
221    {       
222        std::string::size_type end_pos = argument.find("}",start_pos);
223        if (start_pos != std::string::npos)
224        {
225            std::string var = argument.substr(start_pos+2, end_pos-start_pos-2);
226            const char* str = getenv(var.c_str());
227            if (str)
228            {
229                argument.erase(start_pos, end_pos-start_pos+1);
230                argument.insert(start_pos, str);
231            }
232            start_pos = argument.find("${",end_pos);
233        }
234        else
235        {
236            start_pos = std::string::npos;
237        }
238       
239    }
240   
241    return argument;
242}
243
244bool ReaderWriterP3DXML::read(const char* str, int& value) const
245{
246    if (!str) return false;
247    std::istringstream iss((const char*)str);
248    iss >> value;
249    return !iss.fail();
250}
251
252bool ReaderWriterP3DXML::read(const char* str, float& value) const
253{
254    if (!str) return false;
255    std::istringstream iss((const char*)str);
256    iss >> value;
257    return !iss.fail();
258}
259
260bool ReaderWriterP3DXML::read(const char* str, double& value) const
261{
262    if (!str) return false;
263    std::istringstream iss((const char*)str);
264    iss >> value;
265    return !iss.fail();
266}
267
268bool ReaderWriterP3DXML::read(const char* str, osg::Vec2& value) const
269{
270    if (!str) return false;
271    std::istringstream iss((const char*)str);
272    iss >> value.x() >> value.y();
273    return !iss.fail();
274}
275
276bool ReaderWriterP3DXML::read(const char* str, osg::Vec3& value) const
277{
278    if (!str) return false;
279    std::istringstream iss((const char*)str);
280    iss >> value.x() >> value.y() >> value.z();
281    return !iss.fail();
282}
283
284bool ReaderWriterP3DXML::read(const char* str, osg::Vec4& value) const
285{
286    if (!str) return false;
287    std::istringstream iss((const char*)str);
288    iss >> value.x() >> value.y() >> value.z() >> value.w();
289    return !iss.fail();
290}
291
292bool ReaderWriterP3DXML::read(const std::string& str, int& value) const
293{
294    std::istringstream iss(str);
295    iss >> value;
296    return !iss.fail();
297}
298
299bool ReaderWriterP3DXML::read(const std::string& str, float& value) const
300{
301    std::istringstream iss(str);
302    iss >> value;
303    return !iss.fail();
304}
305
306bool ReaderWriterP3DXML::read(const std::string& str, double& value) const
307{
308    std::istringstream iss(str);
309    iss >> value;
310    return !iss.fail();
311}
312
313bool ReaderWriterP3DXML::read(const std::string& str, osg::Vec2& value) const
314{
315    std::istringstream iss(str);
316    iss >> value.x() >> value.y();
317    return !iss.fail();
318}
319
320bool ReaderWriterP3DXML::read(const std::string& str, osg::Vec3& value) const
321{
322    std::istringstream iss(str);
323    iss >> value.x() >> value.y() >> value.z();
324    return !iss.fail();
325}
326
327bool ReaderWriterP3DXML::read(const std::string& str, osg::Vec4& value) const
328{
329    std::istringstream iss(str);
330    iss >> value.x() >> value.y() >> value.z() >> value.w();
331    return !iss.fail();
332}
333
334bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode* cur, const char* token) const
335{
336    return cur->properties.count(token)!=0;
337}
338
339bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode*cur, const char* token, int& value) const
340{
341    osgDB::XmlNode::Properties::iterator itr = cur->properties.find(token);
342    if (itr==cur->properties.end()) return false;
343    return read(itr->second,value);
344}
345
346bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode*cur, const char* token, float& value) const
347{
348    osgDB::XmlNode::Properties::iterator itr = cur->properties.find(token);
349    if (itr==cur->properties.end()) return false;
350    return read(itr->second,value);
351}
352
353bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode*cur, const char* token, double& value) const
354{
355    osgDB::XmlNode::Properties::iterator itr = cur->properties.find(token);
356    if (itr==cur->properties.end()) return false;
357    return read(itr->second,value);
358}
359
360bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode*cur, const char* token, osg::Vec2& value) const
361{
362    osgDB::XmlNode::Properties::iterator itr = cur->properties.find(token);
363    if (itr==cur->properties.end()) return false;
364    return read(itr->second,value);
365}
366
367bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode*cur, const char* token, osg::Vec3& value) const
368{
369    osgDB::XmlNode::Properties::iterator itr = cur->properties.find(token);
370    if (itr==cur->properties.end()) return false;
371    return read(itr->second,value);
372}
373
374bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode*cur, const char* token, osg::Vec4& value) const
375{
376    osgDB::XmlNode::Properties::iterator itr = cur->properties.find(token);
377    if (itr==cur->properties.end()) return false;
378    return read(itr->second,value);
379}
380
381bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode*cur, const char* token, std::string& value) const
382{
383    osgDB::XmlNode::Properties::iterator itr = cur->properties.find(token);
384    if (itr==cur->properties.end()) return false;
385    value = itr->second;
386    return true;
387}
388
389bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode*cur, const char* token, osgText::Text::Layout& value) const
390{
391    osgDB::XmlNode::Properties::iterator pitr = cur->properties.find(token);
392    if (pitr==cur->properties.end()) return false;
393
394    const std::string& str = pitr->second;
395    LayoutMap::const_iterator itr = _layoutMap.find(str);
396    if (itr!=_layoutMap.end())
397    {
398        value = itr->second;
399    }
400    return true;
401}
402
403bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode*cur, const char* token, osgText::Text::AlignmentType& value) const
404{
405    osgDB::XmlNode::Properties::iterator pitr = cur->properties.find(token);
406    if (pitr==cur->properties.end()) return false;
407
408    const std::string& str = pitr->second;
409    AlignmentMap::const_iterator itr = _alignmentMap.find(str);
410    if (itr!=_alignmentMap.end())
411    {
412        value = itr->second;
413    }
414    return true;
415}
416
417bool ReaderWriterP3DXML::getProperties(osgDB::XmlNode*cur, osgPresentation::SlideShowConstructor::PositionData& value) const
418{
419    bool propertiesRead=false;   
420
421    osg::Vec3 position(0.0f,1.0f,0.0f);
422    osg::Vec4 rotate(0.0f,0.0f,0.0f,1.0f);
423    float scale = 1.0f;
424
425    osg::Vec4 rotation(0.0f,0.0f,0.0f,1.0f);
426
427    // temporary
428    std::string str;
429
430    if (getProperty(cur, "coordinate_frame", str))
431    {
432        propertiesRead = true;
433
434        if (str=="model") value.frame = osgPresentation::SlideShowConstructor::MODEL;
435        else if (str=="slide") value.frame = osgPresentation::SlideShowConstructor::SLIDE;
436        else osg::notify(_notifyLevel)<<"Parser error - coordinate_frame=\""<<str<<"\" unrecongonized value"<<std::endl;
437       
438        osg::notify(_notifyLevel)<<"read coordinate_frame "<< ((value.frame==osgPresentation::SlideShowConstructor::MODEL) ? "osgPresentation::SlideShowConstructor::MODEL" : "osgPresentation::SlideShowConstructor::SLIDE")<<std::endl;
439    }
440
441    if (value.frame==osgPresentation::SlideShowConstructor::SLIDE)
442    {
443       
444        if (getProperty(cur, "position", str))
445        {
446            value.position.set(0.5,0.5,0.0);
447
448            propertiesRead = true;
449
450            osg::Vec2 vec2;
451            osg::Vec3 vec3;
452       
453            bool fail = false;
454            if (str=="center") value.position.set(0.5f,.5f,0.0f);
455            else if (str=="eye") value.position.set(0.0f,0.0f,1.0f);
456            else if (read(str,vec3)) value.position = vec3;
457            else if (read(str,vec2)) value.position.set(vec3.x(),vec3.y(),0.0f);
458            else fail = true;
459
460            if (fail) osg::notify(_notifyLevel)<<"Parser error - position=\""<<str<<"\" unrecongonized value"<<std::endl;
461            else osg::notify(_notifyLevel)<<"Read position="<<value.position<<std::endl;
462        }
463    }
464    else // value.frame==osgPresentation::SlideShowConstructor::MODEL
465    {
466
467        if (getProperty(cur, "position", str))
468        {
469            value.position.set(0.0,0.0,0.0);
470
471            propertiesRead = true;
472           
473            bool fail = false;
474            if (str=="center") value.position.set(0.0f,1.0f,0.0f);
475            else if (str=="eye") value.position.set(0.0f,0.0f,0.0f);
476            else if (!read(str,value.position)) fail = true;
477
478            if (fail) osg::notify(_notifyLevel)<<"Parser error - position=\""<<str<<"\" unrecongonized value"<<std::endl;
479            else osg::notify(_notifyLevel)<<"Read position="<<value.position<<std::endl;
480        }
481    }
482
483   
484    if (getProperty(cur, "scale", scale))
485    {
486        value.scale.set(scale,scale,scale);
487        propertiesRead = true;
488        osg::notify(_notifyLevel)<<"scale read "<<scale<<std::endl;
489    }
490
491    if (getProperty(cur, "scale_x", scale) || getProperty(cur, "width", scale))
492    {
493        value.scale.x() = scale;
494        propertiesRead = true;
495        osg::notify(_notifyLevel)<<"scale read_x "<<scale<<std::endl;
496    }
497
498    if (getProperty(cur, "scale_y", scale) || getProperty(cur, "height", scale))
499    {
500        value.scale.y() = scale;
501        propertiesRead = true;
502        osg::notify(_notifyLevel)<<"scale read_y "<<scale<<std::endl;
503    }
504
505    if (getProperty(cur, "scale_z", scale))
506    {
507        value.scale.z() = scale;
508        propertiesRead = true;
509        osg::notify(_notifyLevel)<<"scale read_z "<<scale<<std::endl;
510    }
511
512    if (getProperty(cur, "rotate", rotate))
513    {
514        value.rotate = rotate;
515        propertiesRead = true;
516        osg::notify(_notifyLevel)<<"rotate read "<<rotate<<std::endl;
517    }
518
519    if (getProperty(cur, "rotate1", rotate))
520    {
521        // note may need to reverse once Quat * order is sorted out.
522        value.rotate = accumulateRotation(rotate,value.rotate);
523        propertiesRead = true;
524        osg::notify(_notifyLevel)<<"rotate1 read "<<rotate<<std::endl;
525    }
526
527    if (getProperty(cur, "rotate2", rotate))
528    {
529        // note may need to reverse once Quat * order is sorted out.
530        value.rotate = accumulateRotation(rotate,value.rotate);
531        propertiesRead = true;
532        osg::notify(_notifyLevel)<<"rotate1 read "<<rotate<<std::endl;
533    }
534
535    if (getProperty(cur, "rotate3", rotate))
536    {
537        // note may need to reverse once Quat * order is sorted out.
538        value.rotate = accumulateRotation(rotate,value.rotate);
539        propertiesRead = true;
540        osg::notify(_notifyLevel)<<"rotate1 read "<<rotate<<std::endl;
541    }
542
543    if (getProperty(cur, "rotation", rotation))
544    {
545        value.rotation = rotation;
546        osg::notify(_notifyLevel)<<"rotation read "<<rotation<<std::endl;
547        propertiesRead = true;
548    }
549
550    if (getProperty(cur, "rotation1", rotation))
551    {
552        value.rotation = accumulateRotation(rotation,value.rotation);
553        osg::notify(_notifyLevel)<<"rotation1 read "<<rotation<<std::endl;
554        propertiesRead = true;
555    }
556
557    if (getProperty(cur, "rotation2", rotation))
558    {
559        value.rotation = accumulateRotation(rotation,value.rotation);
560        osg::notify(_notifyLevel)<<"rotation2 read "<<rotation<<std::endl;
561        propertiesRead = true;
562    }
563
564    if (getProperty(cur, "rotation3", rotation))
565    {
566        value.rotation = accumulateRotation(rotation,value.rotation);
567        osg::notify(_notifyLevel)<<"rotation3 read "<<rotation<<std::endl;
568        propertiesRead = true;
569    }
570
571    if (getProperty(cur, "path", str))
572    {
573   
574        value.absolute_path = false;
575        value.inverse_path = false;
576        value.path = expandEnvVarsInFileName(str);
577
578        osg::notify(_notifyLevel)<<"path read "<<str<<std::endl;
579        propertiesRead = true;
580    }
581
582    if (getProperty(cur, "camera_path", str))
583    {
584        value.absolute_path = true;
585        value.inverse_path = true;
586        value.path = expandEnvVarsInFileName(str);
587
588        osg::notify(_notifyLevel)<<"camera path read "<<str<<std::endl;
589        propertiesRead = true;
590    }
591
592    if (getProperty(cur, "path_time_offset", value.path_time_offset))
593    {
594        osg::notify(_notifyLevel)<<"read path_time_offset"<<value.path_time_offset<<std::endl;
595        propertiesRead = true;
596    }
597
598    if (getProperty(cur, "path_time_multiplier", value.path_time_multiplier))
599    {
600        osg::notify(_notifyLevel)<<"read path_time_multiplier"<<value.path_time_multiplier<<std::endl;
601        propertiesRead = true;
602    }
603
604    if (getProperty(cur, "animation_material_time_offset", value.animation_material_time_offset))
605    {
606        osg::notify(_notifyLevel)<<"read animation_material_time_offset"<<value.animation_material_time_offset<<std::endl;
607        propertiesRead = true;
608    }
609
610    if (getProperty(cur, "animation_material_time_multiplier", value.animation_material_time_multiplier))
611    {
612        osg::notify(_notifyLevel)<<"read animation_material_time_multiplier"<<value.animation_material_time_multiplier<<std::endl;
613        propertiesRead = true;
614    }
615
616    if (getProperty(cur, "animation_material", str))
617    {
618        value.animation_material_filename = str;
619
620        osg::notify(_notifyLevel)<<"animation_material read "<<str<<std::endl;
621        propertiesRead = true;
622    }
623
624    if (getProperty(cur, "animation_name", str))
625    {
626        value.animation_name = str;
627
628        osg::notify(_notifyLevel)<<"animation_name "<<str<<std::endl;
629        propertiesRead = true;
630    }
631
632    if (getProperty(cur, "fade", value.fade))
633    {
634        osg::notify(_notifyLevel)<<"fade "<<value.fade<<std::endl;
635        propertiesRead = true;
636    }
637
638    if (getProperty(cur, "path_loop_mode", str))
639    {
640        osg::notify(_notifyLevel)<<"path_loop_mode "<<str<<std::endl;
641        if (str=="LOOP") value.path_loop_mode=osg::AnimationPath::LOOP;
642        else if (str=="SWING") value.path_loop_mode=osg::AnimationPath::SWING;
643        else if (str=="NO_LOOPING") value.path_loop_mode=osg::AnimationPath::NO_LOOPING;
644        propertiesRead = true;
645    }
646
647    if (getProperty(cur, "animation_material_loop_mode", str))
648    {
649        osg::notify(_notifyLevel)<<"animation_material_loop_mode "<<str<<std::endl;
650        if (str=="LOOP") value.animation_material_loop_mode=osgPresentation::AnimationMaterial::LOOP;
651        else if (str=="SWING") value.animation_material_loop_mode=osgPresentation::AnimationMaterial::SWING;
652        else if (str=="NO_LOOPING") value.animation_material_loop_mode=osgPresentation::AnimationMaterial::NO_LOOPING;
653        propertiesRead = true;
654    }
655
656    return propertiesRead;
657}
658
659bool ReaderWriterP3DXML::getProperties(osgDB::XmlNode*cur, osgPresentation::SlideShowConstructor::FontData& value) const
660{
661    bool propertiesRead=false;   
662   
663    osg::notify(_notifyLevel)<<"in getProperties(FontData)"<<std::endl;
664
665    if (getProperty(cur, "font", value.font))
666    {
667        propertiesRead = true;
668        osg::notify(_notifyLevel)<<"read font \""<<value.font<<"\""<<std::endl;
669    }
670
671    if (getProperty(cur, "character_size", value.characterSize))
672    {
673        propertiesRead = true;
674        osg::notify(_notifyLevel)<<"read height \""<<value.characterSize<<"\""<<std::endl;
675    }
676
677    if (getProperty(cur, "layout", value.layout))
678    {
679        propertiesRead = true;
680       
681        osg::notify(_notifyLevel)<<"read layout \""<<value.layout<<"\""<<std::endl;
682    }
683
684    if (getProperty(cur, "alignment", value.alignment))
685    {
686        propertiesRead = true;
687       
688        osg::notify(_notifyLevel)<<"read alignment \""<<value.alignment<<"\""<<std::endl;
689    }
690
691    return propertiesRead;
692}
693
694bool ReaderWriterP3DXML::getProperties(osgDB::XmlNode*cur, osgPresentation::SlideShowConstructor::ModelData& value) const
695{
696    bool propertiesRead=false;   
697   
698    osg::notify(_notifyLevel)<<"in getProperties(ModelData)"<<std::endl;
699
700    if (getProperty(cur, "effect", value.effect))
701    {
702        propertiesRead = true;
703        osg::notify(_notifyLevel)<<"read effect \""<<value.effect<<"\""<<std::endl;
704    }
705
706    return propertiesRead;
707}
708
709bool ReaderWriterP3DXML::getProperties(osgDB::XmlNode*cur, osgPresentation::SlideShowConstructor::ImageData& value) const
710{
711    bool propertiesRead=false;   
712   
713    osg::notify(_notifyLevel)<<"in getProperties(ImageData)"<<std::endl;
714
715    if (getProperty(cur, "page", value.page))
716    {
717        propertiesRead = true;
718        osg::notify(_notifyLevel)<<"read page \""<<value.page<<"\""<<std::endl;
719    }
720
721    osg::Vec4 bgColour;
722    if (getProperty(cur, "background", value.backgroundColor))
723    {
724        propertiesRead = true;
725        osg::notify(_notifyLevel)<<"read background colour \""<<value.backgroundColor<<"\""<<std::endl;
726    }
727
728    if (getProperty(cur, "width", value.width))
729    {
730        propertiesRead = true;
731        osg::notify(_notifyLevel)<<"read width \""<<value.width<<"\""<<std::endl;
732    }
733
734    if (getProperty(cur, "height", value.height))
735    {
736        propertiesRead = true;
737        osg::notify(_notifyLevel)<<"read height \""<<value.height<<"\""<<std::endl;
738    }
739
740    if (getProperty(cur, "region", value.region))
741    {
742        propertiesRead = true;
743        value.region_in_pixel_coords = false;
744        osg::notify(_notifyLevel)<<"read region \""<<value.region<<"\""<<std::endl;
745    }
746
747    if (getProperty(cur, "pixel_region", value.region))
748    {
749        propertiesRead = true;
750        value.region_in_pixel_coords = true;
751        osg::notify(_notifyLevel)<<"read pixel_region \""<<value.region<<"\""<<std::endl;
752    }
753
754    std::string str;
755    if (getProperty(cur, "looping", str))
756    {
757        propertiesRead = true;
758        if (str=="ON") value.loopingMode = osg::ImageStream::LOOPING;
759        else value.loopingMode = osg::ImageStream::NO_LOOPING;
760        osg::notify(_notifyLevel)<<"looping \""<<str<<"\""<<std::endl;
761    }
762
763/*
764    if (getProperty(cur, "texcoord_offset", value.texcoord_offset))
765    {
766        propertiesRead = true;
767        osg::notify(_notifyLevel)<<"read offset \""<<value.texcoord_offset<<"\""<<std::endl;
768    }
769
770    if (getProperty(cur, "texcoord_scale", value.texcoord_scale))
771    {
772        propertiesRead = true;
773        osg::notify(_notifyLevel)<<"read texcoord_scale \""<<value.texcoord_scale<<"\""<<std::endl;
774    }
775   
776    if (getProperty(cur, "texcoord_rotate", value.texcoord_rotate))
777    {
778        propertiesRead = true;
779        osg::notify(_notifyLevel)<<"read texcoord_rotate \""<<value.texcoord_rotate<<"\""<<std::endl;
780    }
781*/
782    return propertiesRead;
783}
784
785bool ReaderWriterP3DXML::getJumpProperties(osgDB::XmlNode*cur, bool& relativeJump, int& slideNum, int& layerNum) const
786{
787    bool propertyRead = false;
788
789    if (getProperty(cur, "slide", slideNum))
790    {
791        osg::notify(osg::NOTICE)<<"slide "<<slideNum<<std::endl;
792        propertyRead = true;
793    }
794
795    if (getProperty(cur, "layer", layerNum))
796    {
797        osg::notify(osg::NOTICE)<<"layer "<<layerNum<<std::endl;
798        propertyRead = true;
799    }
800
801    std::string jumpType;
802    if (getProperty(cur, "jump", jumpType))
803    {
804        osg::notify(osg::NOTICE)<<"jump "<<jumpType<<std::endl;
805        propertyRead = true;
806        relativeJump = (jumpType=="relative") || (jumpType=="Relative") || (jumpType=="RELATIVE") ;
807    }
808
809    return propertyRead;
810}
811
812void ReaderWriterP3DXML::parseModel(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const
813{
814
815    osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getModelPositionData();
816   bool positionRead = getProperties(cur,positionData);
817
818    osgPresentation::SlideShowConstructor::ModelData modelData;// = constructor.getModelData();
819    getProperties(cur,modelData);
820
821    std::string filename = cur->contents;
822
823    if (!filename.empty())
824    {
825        constructor.addModel(filename,
826                             positionRead ? positionData : constructor.getModelPositionData(),
827                             modelData);
828    }
829}
830
831void ReaderWriterP3DXML::parseVolume(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const
832{
833
834    osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getModelPositionData();
835    bool positionRead = getProperties(cur,positionData);
836
837    std::string filename = cur->contents;
838
839    if (!filename.empty())
840    {
841        constructor.addVolume(filename,
842                             positionRead ? positionData : constructor.getModelPositionData());
843    }
844}
845
846void ReaderWriterP3DXML::parseStereoPair(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const
847{
848    std::string filenameLeft;
849    std::string filenameRight;
850
851    osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getImagePositionData();
852    bool positionRead = getProperties(cur,positionData);
853
854    osgPresentation::SlideShowConstructor::ImageData imageDataLeft;// = constructor.getImageData();
855    osgPresentation::SlideShowConstructor::ImageData imageDataRight;// = constructor.getImageData();
856
857    for(osgDB::XmlNode::Children::iterator itr = cur->children.begin();
858        itr != cur->children.end();
859        ++itr)
860    {
861        osgDB::XmlNode* child = itr->get();
862
863        if (child->name == "image_left")
864        {
865            getProperties(child,imageDataLeft);
866            filenameLeft = child->name;
867        }
868        if (cur->name == "image_right")
869        {
870            getProperties(child,imageDataRight);
871            filenameRight = child->name;
872            getProperties(cur,imageDataRight);
873        }
874    }
875
876    if (!filenameLeft.empty() && !filenameRight.empty())
877        constructor.addStereoImagePair(filenameLeft,imageDataLeft,
878                                       filenameRight, imageDataRight,
879                                       positionRead ? positionData : constructor.getImagePositionData());
880
881}
882
883bool ReaderWriterP3DXML::getKeyPosition(osgDB::XmlNode*cur, osgPresentation::KeyPosition& keyPosition) const
884{
885    if (cur->name == "key")
886    {
887        return getKeyPositionInner(cur, keyPosition);
888    }
889    if (cur->name == "escape" ||
890        cur->name == "esc" ||
891        cur->name == "exit")
892    {
893        keyPosition.set(osgGA::GUIEventAdapter::KEY_Escape, 0.0f, 0.0f);
894        return true;
895    }
896    return false;
897}
898
899bool ReaderWriterP3DXML::getKeyPositionInner(osgDB::XmlNode*cur, osgPresentation::KeyPosition& keyPosition) const
900{
901    // x in range -1 to 1, from left to right
902    float x = FLT_MAX;
903    getProperty(cur, "x", x);
904
905    // y in range -1 to 1, from bottom to top
906    float y = FLT_MAX;
907    getProperty(cur, "y", y);
908
909    float h = FLT_MAX;
910    if (getProperty(cur, "h", h))
911    {
912        // h in range 0.0 to 1, from left to right
913        x = h*2.0f-1.0f;
914    }
915
916    float v = FLT_MAX;
917    if (getProperty(cur, "v", v))
918    {
919        // v in range 0.0 to 1, from bottom to top
920        y = v*2.0f-1.0f;
921    }
922
923
924    std::string key = cur->contents;
925    unsigned int keyValue = 0;
926
927    StringKeyMap::const_iterator itr=_stringKeyMap.find(key);
928    if (itr != _stringKeyMap.end())
929    {
930        keyValue = itr->second;
931    }
932    else if (key.length()==1)
933    {
934        keyValue = key[0];
935    }
936    else
937    {
938        osg::notify(osg::NOTICE)<<"Warning: unreconginized key sequence '"<<key<<"'"<<std::endl;
939    }
940
941    keyPosition.set(keyValue,x,y);
942    return true;
943}
944
945
946
947
948void ReaderWriterP3DXML::parseLayer(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode* root) const
949{
950    // create a keyPosition just in case we need it.
951    osgPresentation::KeyPosition keyPosition;
952
953    osg::notify(osg::INFO)<<std::endl<<"parseLayer"<<std::endl;
954
955    float totalIndent = 0.0f;
956
957    for(osgDB::XmlNode::Children::iterator itr = root->children.begin();
958        itr != root->children.end();
959        ++itr)
960    {
961        osgDB::XmlNode* cur = itr->get();
962        if (cur->name == "run")
963        {
964            osg::notify(osg::INFO)<<"run ["<<cur->contents<<"]"<<std::endl;
965            constructor.addLayerRunString(cur->contents);
966        }
967        else if (cur->name == "jump")
968        {
969            osg::notify(osg::NOTICE)<<"Parsed Jump "<<std::endl;
970
971            bool relativeJump = true;
972            int slideNum = 0;
973            int layerNum = 0;
974            if (getJumpProperties(cur, relativeJump, slideNum, layerNum))
975            {
976                osg::notify(osg::NOTICE)<<"Layer Jump "<<relativeJump<<","<< slideNum<<", "<<layerNum<<std::endl;
977           
978                constructor.setLayerJump(relativeJump, slideNum, layerNum);
979            }
980        }
981        else if (cur->name == "click_to_run")
982        {
983            bool relativeJump = true;
984            int slideNum = 0;
985            int layerNum = 0;
986            getJumpProperties(cur, relativeJump, slideNum, layerNum);
987
988            osg::notify(osg::INFO)<<"click_to_run ["<<cur->contents<<"]"<<std::endl;
989            constructor.layerClickToDoOperation(cur->contents,osgPresentation::RUN, relativeJump, slideNum, layerNum);
990        }
991        else if (cur->name == "click_to_load")
992        {
993            bool relativeJump = true;
994            int slideNum = 0;
995            int layerNum = 0;
996            getJumpProperties(cur, relativeJump, slideNum, layerNum);
997
998            osg::notify(osg::INFO)<<"click_to_load ["<<cur->contents<<"]"<<std::endl;
999            constructor.layerClickToDoOperation(cur->contents,osgPresentation::LOAD, relativeJump, slideNum, layerNum);
1000        }
1001
1002        else if (cur->name == "click_to_event")
1003        {
1004            bool relativeJump = true;
1005            int slideNum = 0;
1006            int layerNum = 0;
1007            getJumpProperties(cur, relativeJump, slideNum, layerNum);
1008
1009            if (getKeyPositionInner( cur, keyPosition))
1010            {
1011                osg::notify(osg::INFO)<<"click_to_event ["<<keyPosition._key<<"]"<<std::endl;
1012                constructor.layerClickEventOperation(keyPosition, relativeJump, slideNum, layerNum);
1013            }
1014        }
1015
1016        else if (cur->name == "click_to_jump")
1017        {
1018            bool relativeJump = true;
1019            int slideNum = 0;
1020            int layerNum = 0;
1021            getJumpProperties(cur, relativeJump, slideNum, layerNum);
1022
1023            constructor.layerClickEventOperation(osgPresentation::JUMP, relativeJump, slideNum, layerNum);
1024        }
1025
1026        else if (cur->name == "newline")
1027        {
1028            constructor.translateTextCursor(osg::Vec3(0.0f,-0.05f,0.0f));
1029        }
1030        else if (cur->name == "indent")
1031        {
1032            float localIndent = 0.05f;
1033            constructor.translateTextCursor(osg::Vec3(localIndent,0.0f,0.0f));
1034            totalIndent += localIndent;
1035        }
1036        else if (cur->name == "unindent")
1037        {
1038            float localIndent = -0.05f;
1039            constructor.translateTextCursor(osg::Vec3(localIndent,0.0f,0.0f));
1040            totalIndent += localIndent;
1041        }
1042        else if (cur->name == "bullet")
1043        {
1044            osg::notify(osg::INFO)<<"bullet ["<<cur->contents<<"]"<<std::endl;
1045            osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getTextPositionData();
1046            bool positionRead = getProperties(cur,positionData);
1047
1048            osgPresentation::SlideShowConstructor::FontData fontData = constructor.getTextFontData();
1049            bool fontRead = getProperties(cur,fontData);
1050
1051            constructor.addBullet(cur->contents,
1052                                    positionRead ? positionData : constructor.getTextPositionData(),
1053                                    fontRead ? fontData : constructor.getTextFontData());
1054        }
1055        else if (cur->name == "paragraph")
1056        {
1057            osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getTextPositionData();
1058            bool positionRead = getProperties(cur,positionData);
1059
1060            osgPresentation::SlideShowConstructor::FontData fontData = constructor.getTextFontData();
1061            bool fontRead = getProperties(cur,fontData);
1062
1063            constructor.addParagraph(cur->contents,
1064                                        positionRead ? positionData : constructor.getTextPositionData(),
1065                                        fontRead ? fontData : constructor.getTextFontData());
1066        }
1067        else if (cur->name == "image")
1068        {
1069            osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getImagePositionData();
1070            bool positionRead = getProperties(cur,positionData);
1071
1072            osgPresentation::SlideShowConstructor::ImageData imageData;// = constructor.getImageData();
1073            getProperties(cur,imageData);
1074
1075            constructor.addImage(cur->contents,
1076                                    positionRead ? positionData : constructor.getImagePositionData(),
1077                                    imageData);
1078        }
1079        else if (cur->name == "vnc")
1080        {
1081            osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getImagePositionData();
1082            bool positionRead = getProperties(cur,positionData);
1083
1084            osgPresentation::SlideShowConstructor::ImageData imageData;// = constructor.getImageData();
1085            getProperties(cur,imageData);
1086
1087            constructor.addVNC(cur->contents,
1088                                    positionRead ? positionData : constructor.getImagePositionData(),
1089                                    imageData);
1090        }
1091        else if (cur->name == "browser")
1092        {
1093            osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getImagePositionData();
1094            bool positionRead = getProperties(cur,positionData);
1095
1096            osgPresentation::SlideShowConstructor::ImageData imageData;// = constructor.getImageData();
1097            getProperties(cur,imageData);
1098
1099            constructor.addBrowser(cur->contents,
1100                                    positionRead ? positionData : constructor.getImagePositionData(),
1101                                    imageData);
1102        }
1103        else if (cur->name == "pdf")
1104        {
1105            osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getImagePositionData();
1106            bool positionRead = getProperties(cur,positionData);
1107
1108            osgPresentation::SlideShowConstructor::ImageData imageData;// = constructor.getImageData();
1109            getProperties(cur,imageData);
1110
1111            constructor.addPDF(cur->contents,
1112                                    positionRead ? positionData : constructor.getImagePositionData(),
1113                                    imageData);
1114        }
1115        else if (cur->name == "stereo_pair")
1116        {
1117            parseStereoPair(constructor, cur);
1118        }
1119        else if (cur->name == "model")
1120        {
1121            parseModel(constructor, cur);
1122        }
1123        else if (cur->name == "volume")
1124        {
1125            parseVolume(constructor, cur);
1126        }
1127        else if (cur->name == "duration")
1128        {
1129            constructor.setLayerDuration(atof(cur->contents.c_str()));
1130        }
1131        else if (getKeyPosition(cur, keyPosition))
1132        {
1133            constructor.addLayerKey(keyPosition);
1134        }
1135    }
1136
1137    if (totalIndent != 0.0f)
1138    {
1139        constructor.translateTextCursor(osg::Vec3(-totalIndent,0.0f,0.0f));
1140    }
1141
1142}
1143
1144void ReaderWriterP3DXML::parseBullets(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur, bool inheritPreviousLayers, bool defineAsBaseLayer) const
1145{
1146    constructor.addLayer(inheritPreviousLayers, defineAsBaseLayer);
1147
1148    osg::notify(osg::INFO)<<"bullets ["<<cur->contents<<"]"<<std::endl;
1149    osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getTextPositionData();
1150    bool positionRead = getProperties(cur,positionData);
1151
1152    osgPresentation::SlideShowConstructor::FontData fontData = constructor.getTextFontData();
1153    bool fontRead = getProperties(cur,fontData);
1154
1155    constructor.addBullet(cur->contents,
1156                            positionRead ? positionData : constructor.getTextPositionData(),
1157                            fontRead ? fontData : constructor.getTextFontData());
1158}
1159
1160
1161void ReaderWriterP3DXML::parseText(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur, bool inheritPreviousLayers, bool defineAsBaseLayer) const
1162{
1163    constructor.addLayer(inheritPreviousLayers, defineAsBaseLayer);
1164
1165    osg::notify(osg::INFO)<<"text ["<<cur->contents<<"]"<<std::endl;
1166    osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getTextPositionData();
1167    bool positionRead = getProperties(cur,positionData);
1168
1169    osgPresentation::SlideShowConstructor::FontData fontData = constructor.getTextFontData();
1170    bool fontRead = getProperties(cur,fontData);
1171
1172    constructor.addParagraph(cur->contents,
1173                            positionRead ? positionData : constructor.getTextPositionData(),
1174                            fontRead ? fontData : constructor.getTextFontData());
1175}
1176
1177void ReaderWriterP3DXML::parsePage(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const
1178{
1179    constructor.addSlide();
1180
1181    std::string title;
1182    getProperty(cur, "title", title);
1183
1184    std::string inherit;
1185    getProperty(cur, "inherit", inherit);
1186
1187    if (!inherit.empty() && _templateMap.count(inherit)!=0)
1188    {
1189        parseSlide(constructor, _templateMap[inherit].get(), true, false);
1190    }
1191
1192    if (!title.empty())
1193    {
1194        constructor.setSlideTitle(title,
1195                                    constructor.getTitlePositionData(),
1196                                    constructor.getTitleFontData());
1197    }
1198
1199    if (!inherit.empty() && _templateMap.count(inherit)!=0)
1200    {
1201        parseSlide(constructor, _templateMap[inherit].get(), false, true);
1202    }
1203
1204    constructor.addLayer(true,false);
1205
1206    osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getTextPositionData();
1207    bool positionRead = getProperties(cur,positionData);
1208
1209    osgPresentation::SlideShowConstructor::FontData fontData = constructor.getTextFontData();
1210    bool fontRead = getProperties(cur,fontData);
1211
1212    constructor.addParagraph(cur->contents,
1213                            positionRead ? positionData : constructor.getTextPositionData(),
1214                            fontRead ? fontData : constructor.getTextFontData());
1215}
1216
1217void ReaderWriterP3DXML::parsePdfDocument(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const
1218{
1219    std::string title;
1220    getProperty(cur, "title", title);
1221
1222    std::string inherit;
1223    getProperty(cur, "inherit", inherit);
1224
1225    constructor.addSlide();
1226
1227    if (!inherit.empty() && _templateMap.count(inherit)!=0)
1228    {
1229        parseSlide(constructor, _templateMap[inherit].get(), true, false);
1230    }
1231
1232    if (!title.empty())
1233    {
1234        constructor.setSlideTitle(title,
1235                                    constructor.getTitlePositionData(),
1236                                    constructor.getTitleFontData());
1237    }
1238
1239    if (!inherit.empty() && _templateMap.count(inherit)!=0)
1240    {
1241        parseSlide(constructor, _templateMap[inherit].get(), false, true);
1242    }
1243
1244    constructor.addLayer(true,false);
1245
1246    osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getImagePositionData();
1247    getProperties(cur,positionData);
1248
1249    osgPresentation::SlideShowConstructor::ImageData imageData;// = constructor.getImageData();
1250    imageData.page = 0;
1251    getProperties(cur,imageData);
1252
1253    osg::Image* image = constructor.addInteractiveImage(cur->contents, positionData, imageData);
1254    osgWidget::PdfImage* pdfImage = dynamic_cast<osgWidget::PdfImage*>(image);
1255    if (pdfImage)
1256    {
1257        int numPages = pdfImage->getNumOfPages();
1258        osg::notify(osg::NOTICE)<<"NumOfPages = "<<numPages<<std::endl;
1259
1260        if (numPages>1)
1261        {
1262            for(int pageNum=1; pageNum<numPages; ++pageNum)
1263            {
1264                imageData.page = pageNum;
1265
1266                constructor.addSlide();
1267
1268                if (!inherit.empty() && _templateMap.count(inherit)!=0)
1269                {
1270                    parseSlide(constructor, _templateMap[inherit].get(), true, false);
1271                }
1272
1273                if (!title.empty())
1274                {
1275                    constructor.setSlideTitle(title,
1276                                                constructor.getTitlePositionData(),
1277                                                constructor.getTitleFontData());
1278                }
1279
1280                if (!inherit.empty() && _templateMap.count(inherit)!=0)
1281                {
1282                    parseSlide(constructor, _templateMap[inherit].get(), false, true);
1283                }
1284
1285                constructor.addLayer(true,false);
1286
1287                constructor.addPDF(cur->contents, positionData, imageData);
1288
1289            }
1290        }
1291    }
1292}
1293
1294void ReaderWriterP3DXML::parseSlide (osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode* root, bool parseTitles, bool parseLayers) const
1295{
1296
1297    osg::Vec4 previous_bgcolor = constructor.getBackgroundColor();
1298    osg::Vec4 previous_textcolor = constructor.getTextColor();
1299
1300    // create a keyPosition just in case we need it.
1301    osgPresentation::KeyPosition keyPosition;
1302
1303    for(osgDB::XmlNode::Children::iterator itr = root->children.begin();
1304        itr != root->children.end();
1305        ++itr)
1306    {
1307        osgDB::XmlNode* cur = itr->get();
1308
1309        if (parseTitles)
1310        {
1311            if (cur->name == "title")
1312            {
1313                osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getTitlePositionData();
1314                bool positionRead = getProperties(cur,positionData);
1315
1316                osgPresentation::SlideShowConstructor::FontData fontData = constructor.getTitleFontData();
1317                bool fontRead = getProperties(cur,fontData);
1318
1319                constructor.setSlideTitle(cur->contents,
1320                                          positionRead ? positionData : constructor.getTitlePositionData(),
1321                                          fontRead ? fontData : constructor.getTitleFontData());
1322            }
1323            else if (cur->name == "background")
1324            {
1325                constructor.setSlideBackground(cur->contents);
1326            }
1327            else if (cur->name == "bgcolor")
1328            {
1329                constructor.setBackgroundColor(mapStringToColor(cur->contents),true);
1330            }
1331            else if (cur->name == "textcolor")
1332            {
1333                constructor.setTextColor(mapStringToColor(cur->contents));
1334            }
1335        }
1336        if (parseLayers)
1337        {
1338            if (cur->name == "base")
1339            {
1340                constructor.addLayer(true, true);
1341                parseLayer (constructor, cur);
1342            }
1343            else if (cur->name == "layer")
1344            {
1345                constructor.addLayer(true, false);
1346                parseLayer (constructor, cur);
1347            }
1348            else if (cur->name == "clean_layer")
1349            {
1350                constructor.addLayer(false, false);
1351                parseLayer (constructor, cur);
1352            }
1353            else if (cur->name == "modify_layer")
1354            {
1355                int layerNum;
1356                if (getProperty(cur, "layer", layerNum))
1357                {           
1358                    constructor.selectLayer(layerNum);
1359                }
1360                else
1361                {
1362                    constructor.addLayer(true, false);
1363                }
1364
1365                parseLayer (constructor, cur);
1366            }
1367            else if (cur->name == "bullets")
1368            {
1369                parseBullets (constructor, cur,true, false);
1370            }
1371            else if (cur->name == "duration")
1372            {
1373                constructor.setSlideDuration(atof(cur->contents.c_str()));
1374            }
1375            else if (getKeyPosition(cur, keyPosition))
1376            {
1377                constructor.addSlideKey(keyPosition);
1378            }
1379        }
1380    }
1381
1382    constructor.setBackgroundColor(previous_bgcolor,false);
1383    constructor.setTextColor(previous_textcolor);
1384
1385    return;
1386}
1387
1388#include <iostream>
1389
1390
1391struct MyFindFileCallback : public osgDB::FindFileCallback
1392{
1393    virtual std::string findDataFile(const std::string& filename, const osgDB::Options* options, osgDB::CaseSensitivity caseSensitivity)
1394    {
1395        osg::notify(osg::NOTICE)<<std::endl<<std::endl<<"find file "<<filename<<std::endl;
1396
1397        const osgDB::FilePathList& paths = options ? options->getDatabasePathList() : osgDB::getDataFilePathList();
1398
1399        for(osgDB::FilePathList::const_iterator itr = paths.begin();
1400            itr != paths.end();
1401            ++itr)
1402        {
1403            const std::string& path = *itr;
1404            std::string newpath = osgDB::concatPaths(path, filename);
1405            if (osgDB::containsServerAddress(path))
1406            {
1407                osgDB::ReaderWriter* rw = osgDB::Registry::instance()->getReaderWriterForExtension("curl");
1408                osg::notify(osg::NOTICE)<<"  file on server "<<*itr<<", try path "<<newpath<<std::endl;
1409                osg::notify(osg::NOTICE)<<"  we have curl rw= "<<rw<<std::endl;
1410                if (rw && rw->fileExists(newpath, options))
1411                {
1412                    osg::notify(osg::NOTICE)<<"  FOUND on server "<<newpath<<std::endl;
1413                    return newpath;
1414                }
1415            }
1416            else
1417            {
1418                if(osgDB::fileExists(newpath))
1419                {
1420                    osg::notify(osg::NOTICE)<<" FOUND "<<newpath<<std::endl;
1421                    return newpath;
1422                }
1423            }
1424        }
1425
1426        return osgDB::Registry::instance()->findDataFileImplementation(filename, options, caseSensitivity);
1427    }
1428};
1429
1430class MyReadFileCallback : public virtual osgDB::ReadFileCallback
1431{
1432    public:
1433
1434        osgDB::FilePathList _paths;
1435
1436        typedef std::map< std::string, osg::ref_ptr<osg::Object> >  ObjectCache;
1437
1438        enum ObjectType
1439        {
1440            OBJECT,
1441            IMAGE,
1442            HEIGHT_FIELD,
1443            NODE,
1444            SHADER
1445        };
1446
1447        osgDB::ReaderWriter::ReadResult readLocal(ObjectType type, const std::string& filename, const osgDB::Options* options)
1448        {
1449            osg::notify(osg::INFO)<<"Trying local file "<<filename<<std::endl;
1450
1451            switch(type)
1452            {
1453                case(OBJECT): return osgDB::Registry::instance()->readObjectImplementation(filename,options);
1454                case(IMAGE): return osgDB::Registry::instance()->readImageImplementation(filename,options);
1455                case(HEIGHT_FIELD): return osgDB::Registry::instance()->readHeightFieldImplementation(filename,options);
1456                case(NODE): return osgDB::Registry::instance()->readNodeImplementation(filename,options);
1457                case(SHADER): return osgDB::Registry::instance()->readShaderImplementation(filename,options);
1458            }
1459            return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
1460        }
1461
1462       
1463        osgDB::ReaderWriter::ReadResult readFileCache(ObjectType type, const std::string& filename, const osgDB::Options* options)
1464        {
1465
1466            osgDB::FileCache* fileCache = options ? options->getFileCache() : 0;
1467            if (!fileCache) fileCache = osgDB::Registry::instance()->getFileCache();
1468            if (!fileCache) return osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND;
1469
1470            osg::notify(osg::INFO)<<"Trying fileCache "<<filename<<std::endl;
1471
1472            osgDB::ReaderWriter::ReadResult result;
1473            if (fileCache && fileCache->isFileAppropriateForFileCache(filename))
1474            {
1475                if (fileCache->existsInCache(filename))
1476                {
1477                    switch(type)
1478                    {
1479                        case(OBJECT):
1480                            result = fileCache->readObject(filename, 0);
1481                            break;
1482                        case(IMAGE):
1483                            result = fileCache->readImage(filename, 0);
1484                            break;
1485                        case(HEIGHT_FIELD):
1486                            result = fileCache->readHeightField(filename, 0);
1487                            break;
1488                        case(NODE):
1489                            result = fileCache->readNode(filename,0);
1490                            break;
1491                        case(SHADER):
1492                            result = fileCache->readShader(filename, 0);
1493                            break;
1494                    }
1495
1496                    if (result.success())
1497                    {
1498                        osg::notify(osg::INFO)<<"   File read from FileCache."<<std::endl;
1499                        return result;
1500                    }
1501
1502                    osg::notify(osg::NOTICE)<<"   File in FileCache, but not successfully read"<<std::endl;
1503                }
1504                else
1505                {
1506                    osg::notify(osg::INFO)<<"   File does not exist in FileCache: "<<fileCache->createCacheFileName(filename)<<std::endl;
1507                }
1508            }
1509
1510            return osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND;
1511
1512        }
1513
1514        osgDB::ReaderWriter::ReadResult readServer(ObjectType type, const std::string& filename, const osgDB::Options* options)
1515        {
1516            osg::notify(osg::INFO)<<"Trying server file "<<filename<<std::endl;
1517
1518            osgDB::ReaderWriter::ReadResult result;
1519            osgDB::ReaderWriter* rw = osgDB::Registry::instance()->getReaderWriterForExtension("curl");
1520            if (!rw) return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
1521
1522            switch(type)
1523            {
1524                case(OBJECT):
1525                    result = rw->readObject(filename,options);
1526                    break;
1527                case(IMAGE):
1528                    result = rw->readImage(filename,options);
1529                    break;
1530                case(HEIGHT_FIELD):
1531                    result = rw->readHeightField(filename,options);
1532                    break;
1533                case(NODE):
1534                    result = rw->readNode(filename,options);
1535                    break;
1536                case(SHADER):
1537                    result = rw->readShader(filename,options);
1538                    break;
1539            }
1540
1541            if (result.success())
1542            {
1543                osgDB::FileCache* fileCache = options ? options->getFileCache() : 0;
1544                if (!fileCache) fileCache = osgDB::Registry::instance()->getFileCache();
1545
1546                if (fileCache && fileCache->isFileAppropriateForFileCache(filename))
1547                {
1548                    switch(type)
1549                    {
1550                        case(OBJECT):
1551                            fileCache->writeObject(*result.getObject(),filename,options);
1552                            break;
1553                        case(IMAGE):
1554                            result.getImage()->setFileName(filename);
1555                            fileCache->writeImage(*result.getImage(),filename,options);
1556                            break;
1557                        case(HEIGHT_FIELD):
1558                            fileCache->writeHeightField(*result.getHeightField(),filename,options);
1559                            break;
1560                        case(NODE):
1561                            fileCache->writeNode(*result.getNode(),filename,options);
1562                            break;
1563                        case(SHADER):
1564                            fileCache->writeShader(*result.getShader(),filename,options);
1565                            break;
1566                    }
1567                }
1568
1569                return result;
1570            }
1571            return osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND;
1572        }
1573
1574
1575        osgDB::ReaderWriter::ReadResult read(const osgDB::FilePathList& filePathList, ObjectType type, const std::string& filename, const osgDB::Options* options, bool checkLocalFiles)
1576        {
1577            // go look in http paths
1578            for(osgDB::FilePathList::const_iterator itr = filePathList.begin();
1579                itr != filePathList.end();
1580                ++itr)
1581            {
1582                const std::string& path = *itr;
1583                std::string newpath = path.empty() ? filename : osgDB::concatPaths(path, filename);
1584                osgDB::ReaderWriter::ReadResult result;
1585                if (osgDB::containsServerAddress(newpath))
1586                {
1587                    if (checkLocalFiles) result = readFileCache(type, newpath, options);
1588                    else result = readServer(type, newpath, options);
1589                }
1590                else if (checkLocalFiles && osgDB::fileExists(newpath))
1591                {
1592                    result = readLocal(type, newpath, options);
1593                }
1594
1595                if (result.success())
1596                {
1597                    osg::notify(osg::INFO)<<"   inserting object into file cache "<<filename<<", "<<result.getObject()<<std::endl;
1598                    _objectCache[filename] = result.getObject();
1599
1600                    options->setPluginStringData("filename",newpath);
1601                    return result;
1602                }
1603            }
1604            return osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND;
1605        }
1606
1607        osgDB::ReaderWriter::ReadResult read(ObjectType type, const std::string& filename, const osgDB::Options* options)
1608        {
1609            osgDB::FileCache* fileCache = options ? options->getFileCache() : 0;
1610            if (!fileCache) fileCache = osgDB::Registry::instance()->getFileCache();
1611            if (fileCache && !fileCache->isFileAppropriateForFileCache(filename)) fileCache = 0;
1612
1613            osg::notify(osg::INFO)<<"reading file "<<filename<<std::endl;
1614            ObjectCache::iterator itr = _objectCache.find(filename);
1615            if (itr != _objectCache.end())
1616            {
1617                // object is in cache, just retrieve it.
1618                if (itr->second.valid())
1619                {
1620                    osg::notify(osg::INFO)<<"File retrieved from cache, filename="<<filename<<std::endl;
1621                    return itr->second.get();
1622                }
1623                else
1624                {
1625                    osg::notify(osg::INFO)<<"File failed to load previously, won't attempt a second time "<<filename<<std::endl;
1626                    return osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND;
1627                }
1628            }
1629
1630            {
1631                bool checkLocalFiles = true;
1632                osgDB::ReaderWriter::ReadResult result = read(_paths, type, filename, options, checkLocalFiles);
1633                if (result.success()) return result;
1634
1635                if (options && !(options->getDatabasePathList().empty()))
1636                {
1637                    result = read(options->getDatabasePathList(), type, filename, options, checkLocalFiles);
1638                    if (result.success()) return result;
1639                }
1640
1641                result = read(osgDB::Registry::instance()->getDataFilePathList(), type, filename, options, checkLocalFiles);
1642                if (result.success()) return result;
1643            }
1644
1645            {
1646                bool checkLocalFiles = false;
1647                osgDB::ReaderWriter::ReadResult result = read(_paths, type, filename, options, checkLocalFiles);
1648                if (result.success()) return result;
1649
1650                if (options && !(options->getDatabasePathList().empty()))
1651                {
1652                    result = read(options->getDatabasePathList(), type, filename, options, checkLocalFiles);
1653                    if (result.success()) return result;
1654                }
1655
1656                result = read(osgDB::Registry::instance()->getDataFilePathList(), type, filename, options, checkLocalFiles);
1657                if (result.success()) return result;
1658            }
1659
1660            _objectCache[filename] = 0;
1661
1662            return osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND;
1663        }
1664
1665        virtual osgDB::ReaderWriter::ReadResult readObject(const std::string& filename, const osgDB::Options* options)
1666        {
1667            return read(OBJECT, filename, options);
1668        }
1669
1670        virtual osgDB::ReaderWriter::ReadResult readImage(const std::string& filename, const osgDB::Options* options)
1671        {
1672            return read(IMAGE, filename, options);
1673        }
1674
1675        virtual osgDB::ReaderWriter::ReadResult readHeightField(const std::string& filename, const osgDB::Options* options)
1676        {
1677            return read(HEIGHT_FIELD, filename, options);
1678        }
1679
1680        virtual osgDB::ReaderWriter::ReadResult readNode(const std::string& filename, const osgDB::Options* options)
1681        {
1682            return read(NODE, filename, options);
1683        }
1684
1685        virtual osgDB::ReaderWriter::ReadResult readShader(const std::string& filename, const osgDB::Options* options)
1686        {
1687            return read(SHADER, filename, options);
1688        }
1689
1690    protected:
1691        virtual ~MyReadFileCallback() {}
1692
1693        ObjectCache _objectCache;
1694};
1695
1696osgDB::ReaderWriter::ReadResult ReaderWriterP3DXML::readNode(const std::string& file,
1697                                                           const osgDB::ReaderWriter::Options* options) const
1698{
1699    std::string ext = osgDB::getLowerCaseFileExtension(file);
1700    if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
1701
1702    std::string fileName = osgDB::findDataFile( file );
1703    if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
1704
1705    // code for setting up the database path so that internally referenced file are searched for on relative paths.
1706    osg::ref_ptr<osgDB::ReaderWriter::Options> local_opt = options ? static_cast<osgDB::ReaderWriter::Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
1707    local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName));
1708    //local_opt->setFindFileCallback(new MyFindFileCallback);
1709    local_opt->setReadFileCallback(new MyReadFileCallback);
1710
1711    osgDB::XmlNode::Input input;
1712    input.open(fileName);
1713    input.readAllDataIntoBuffer();
1714
1715    return readNode(input, local_opt.get());
1716}
1717
1718osgDB::ReaderWriter::ReadResult ReaderWriterP3DXML::readNode(std::istream& fin, const Options* options) const
1719{
1720    osgDB::XmlNode::Input input;
1721    input.attach(fin);
1722    input.readAllDataIntoBuffer();
1723
1724    osg::ref_ptr<osgDB::ReaderWriter::Options> local_opt = options ? static_cast<osgDB::ReaderWriter::Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
1725    //local_opt->setFindFileCallback(new MyFindFileCallback);
1726    local_opt->setReadFileCallback(new MyReadFileCallback);
1727
1728    return readNode(input, local_opt.get());
1729}
1730
1731osgDB::ReaderWriter::ReadResult ReaderWriterP3DXML::readNode(osgDB::XmlNode::Input& input, osgDB::ReaderWriter::Options* options) const
1732{
1733    bool readOnlyHoldingPage = options ? options->getOptionString()=="holding_slide" : false;
1734
1735    // create a keyPosition just in case we need it.
1736    osgPresentation::KeyPosition keyPosition;
1737
1738    osg::ref_ptr<osgDB::XmlNode> doc = new osgDB::XmlNode;
1739    osgDB::XmlNode* root = 0;
1740
1741
1742    doc->read(input);
1743
1744    osg::notify(osg::INFO)<<"P3D xml file read, now building presentation scene graph."<<std::endl;
1745
1746    // doc->write(std::cout);
1747
1748    if (doc == NULL )
1749    {
1750            fprintf(stderr,"Document not parsed successfully. \n");
1751            return ReadResult::FILE_NOT_HANDLED;
1752    }
1753
1754    for(osgDB::XmlNode::Children::iterator itr = doc->children.begin();
1755        itr != doc->children.end() && !root;
1756        ++itr)
1757    {
1758        if ((*itr)->name=="presentation") root = itr->get();
1759    }
1760
1761    if (root == NULL)
1762    {
1763            fprintf(stderr,"empty document\n");
1764            return ReadResult::FILE_NOT_HANDLED;
1765    }
1766
1767    if (root->name!="presentation")
1768    {
1769            fprintf(stderr,"document of the wrong type, root node != presentation");
1770            return ReadResult::FILE_NOT_HANDLED;
1771    }
1772
1773    osgPresentation::SlideShowConstructor constructor(options);
1774
1775    osgDB::FilePathList previousPaths = osgDB::getDataFilePathList();
1776
1777    bool readSlide = false;
1778
1779
1780    for(osgDB::XmlNode::Children::iterator itr = root->children.begin();
1781        itr != root->children.end();
1782        ++itr)
1783    {
1784        osgDB::XmlNode* cur = itr->get();
1785
1786        if (cur->name=="env")
1787        {
1788            char* str = strdup(cur->contents.c_str());
1789            osg::notify(osg::INFO)<<"putenv("<<str<<")"<<std::endl;
1790            putenv(str);
1791        }
1792    }
1793
1794    std::string pathToPresentation;
1795    MyReadFileCallback* readFileCallback = options ? dynamic_cast<MyReadFileCallback*>(options->getReadFileCallback()) : 0;
1796
1797    if (options && !(options->getDatabasePathList().empty()))
1798    {
1799        pathToPresentation = options->getDatabasePathList().front();
1800
1801       if (readFileCallback) readFileCallback->_paths.push_front(pathToPresentation);
1802    }
1803
1804
1805    for(osgDB::XmlNode::Children::iterator itr = root->children.begin();
1806        itr != root->children.end();
1807        ++itr)
1808    {
1809        osgDB::XmlNode* cur = itr->get();
1810
1811        if (cur->name == "path")
1812        {
1813            std::string newpath = expandEnvVarsInFileName(cur->contents);
1814
1815            // now check if an absolue or http path
1816            std::string::size_type colonPos = newpath.find_first_of(':');
1817            std::string::size_type backslashPos = newpath.find_first_of('/');
1818            std::string::size_type forwardslashPos = newpath.find_first_of('\\');
1819            bool relativePath = colonPos == std::string::npos &&
1820                                backslashPos != 0 &&
1821                                forwardslashPos != 0;
1822
1823            if (relativePath && !pathToPresentation.empty())
1824            {
1825                newpath = osgDB::concatPaths(pathToPresentation, newpath);
1826                osg::notify(osg::NOTICE)<<"relative path = "<<cur->contents<<", newpath="<<newpath<<std::endl;
1827            }
1828            else
1829            {
1830                osg::notify(osg::NOTICE)<<"absolute path = "<<cur->contents<<", newpath="<<newpath<<std::endl;
1831            }
1832
1833            if (readFileCallback) readFileCallback->_paths.push_back(newpath);
1834            else options->getDatabasePathList().push_back(newpath);
1835        }
1836    }
1837
1838
1839    for(osgDB::XmlNode::Children::iterator itr = root->children.begin();
1840        itr != root->children.end();
1841        ++itr)
1842    {
1843        osgDB::XmlNode* cur = itr->get();
1844
1845        if (cur->name == "name")
1846        {
1847            constructor.setPresentationName(cur->contents);
1848        }
1849        else if (cur->name == "loop")
1850        {
1851            constructor.setLoopPresentation(true);
1852        }
1853        else if (cur->name == "auto")
1854        {
1855            constructor.setAutoSteppingActive(true);
1856        }
1857        else if (cur->name == "title-settings")
1858        {
1859            bool fontRead = getProperties(cur,constructor.getTitleFontDataDefault());
1860            if (fontRead)
1861            {
1862                osg::notify(osg::INFO)<<"Title font details read"<<std::endl;
1863            }
1864        }
1865        else if (cur->name == "text-settings")
1866        {
1867            bool fontRead = getProperties(cur,constructor.getTextFontDataDefault());
1868            if (fontRead)
1869            {
1870                osg::notify(osg::INFO)<<"Text font details read"<<std::endl;
1871            }
1872        }
1873        /*else if (cur->name == "ratio")
1874        {
1875            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
1876            if (key) constructor.setPresentationAspectRatio(cur->contents);
1877            xmlFree(key);
1878        }*/
1879        else if (cur->name == "path")
1880        {
1881            osg::notify(osg::INFO)<<"Appending search path "<<cur->contents<<std::endl;
1882            osgDB::getDataFilePathList().push_front(expandEnvVarsInFileName(cur->contents));
1883        }
1884        else if (cur->name == "bgcolor")
1885        {
1886            constructor.setBackgroundColor(mapStringToColor(cur->contents),false);
1887        }
1888        else if (cur->name == "textcolor")
1889        {
1890            constructor.setTextColor(mapStringToColor(cur->contents));
1891        }
1892        else if (cur->name == "duration")
1893        {
1894            constructor.setPresentationDuration(atof(cur->contents.c_str()));
1895        }
1896        else if (getKeyPosition(cur, keyPosition))
1897        {
1898            constructor.addPresentationKey(keyPosition);
1899        }
1900        else if (readOnlyHoldingPage && cur->name == "holding_slide")
1901        {
1902            readSlide = true;
1903            constructor.addSlide();
1904            parseSlide (constructor, cur);
1905        }
1906        else if (!readOnlyHoldingPage && cur->name == "slide")
1907        {
1908            readSlide = true;
1909            constructor.addSlide();
1910
1911            std::string inherit;
1912            if (getProperty(cur, "inherit", inherit) && !inherit.empty() && _templateMap.count(inherit)!=0)
1913            {
1914                parseSlide(constructor, _templateMap[inherit].get(), true, false);
1915                parseSlide (constructor, cur, true, false);
1916                parseSlide(constructor, _templateMap[inherit].get(), false, true);
1917                parseSlide (constructor, cur, false, true);
1918            }
1919            else
1920            {
1921                parseSlide (constructor, cur);
1922            }
1923        }
1924        else if (!readOnlyHoldingPage && cur->name == "modify_slide")
1925        {
1926            readSlide = true;
1927            int slideNum;
1928            if (getProperty(cur, "slide", slideNum))
1929            {           
1930                constructor.selectSlide(slideNum);
1931                parseSlide (constructor, cur);
1932            }
1933            else
1934            {
1935                constructor.addSlide();
1936            }
1937        }
1938        else if (!readOnlyHoldingPage && cur->name == "page")
1939        {
1940            readSlide = true;
1941            parsePage (constructor, cur);
1942        }
1943        else if (!readOnlyHoldingPage && cur->name == "pdf_document")
1944        {
1945            readSlide = true;
1946            parsePdfDocument(constructor, cur);
1947        }
1948        else if (!readOnlyHoldingPage && cur->name == "template_slide")
1949        {
1950            readSlide = true;
1951            std::string name;
1952            if (getProperty(cur, "name", name))
1953            {           
1954                _templateMap[name] = cur;
1955                std::cout<<"Defining template slide "<<name<<std::endl;
1956            }
1957        }
1958    }
1959
1960
1961    osgDB::getDataFilePathList() = previousPaths;
1962   
1963
1964    osg::ref_ptr<osg::Node> presentation_node = constructor.takePresentation();
1965
1966
1967    if (!options || options->getPluginStringData("P3D_EVENTHANDLER")!="none")
1968    {
1969        osgPresentation::SlideEventHandler* seh = new osgPresentation::SlideEventHandler;
1970        seh->set(presentation_node.get());
1971        presentation_node->setEventCallback(seh);
1972    }
1973    return presentation_node.release();
1974}
Note: See TracBrowser for help on using the browser.