Added support for sampleRatio and sampleRatioWhenMoving <volume> properties
[openscenegraph:osg.git] / src / osgPlugins / p3d / ReaderWriterP3D.cpp
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 #include <osg/PagedLOD>
16
17 #include <osgDB/ReaderWriter>
18 #include <osgDB/FileNameUtils>
19 #include <osgDB/FileUtils>
20 #include <osgDB/Registry>
21
22 #include <osgWidget/PdfReader>
23
24 #include <osgPresentation/deprecated/SlideShowConstructor>
25
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29
30 #include <osgDB/XmlParser>
31
32 #include <sstream>
33 #include <iostream>
34
35
36 /**
37  * OpenSceneGraph plugin wrapper/converter.
38  */
39 class ReaderWriterP3DXML : public osgDB::ReaderWriter
40 {
41 public:
42     ReaderWriterP3DXML()
43     {
44         supportsOption("suppressEnvTags", "if set to (true|1) all env-tags in the p3d-file will be suppressed");
45
46         _colorMap["WHITE"]  .set(1.0f,1.0f,1.0f,1.0f);
47         _colorMap["BLACK"]  .set(0.0f,0.0f,0.0f,1.0f);
48         _colorMap["PURPLE"] .set(1.0f,0.0f,1.0f,1.0f);
49         _colorMap["BLUE"]   .set(0.0f,0.0f,1.0f,1.0f);
50         _colorMap["RED"]    .set(1.0f,0.0f,0.0f,1.0f);
51         _colorMap["CYAN"]   .set(0.0f,1.0f,1.0f,1.0f);
52         _colorMap["YELLOW"] .set(1.0f,1.0f,0.0f,1.0f);
53         _colorMap["GREEN"]  .set(0.0f,1.0f,0.0f,1.0f);
54         _colorMap["SKY"]    .set(0.2f, 0.2f, 0.4f, 1.0f);
55
56         _layoutMap["LEFT_TO_RIGHT"] = osgText::Text::LEFT_TO_RIGHT;
57         _layoutMap["RIGHT_TO_LEFT"] = osgText::Text::RIGHT_TO_LEFT;
58         _layoutMap["VERTICAL"] = osgText::Text::VERTICAL;
59
60         _alignmentMap["LEFT_TOP"] = osgText::Text::LEFT_TOP;
61         _alignmentMap["LEFT_CENTER"] = osgText::Text::LEFT_CENTER;
62         _alignmentMap["LEFT_BOTTOM"] = osgText::Text::LEFT_BOTTOM;
63
64         _alignmentMap["CENTER_TOP"] = osgText::Text::CENTER_TOP;
65         _alignmentMap["CENTER_CENTER"] = osgText::Text::CENTER_CENTER;
66         _alignmentMap["CENTER_BOTTOM"] = osgText::Text::CENTER_BOTTOM;
67
68         _alignmentMap["RIGHT_TOP"] = osgText::Text::RIGHT_TOP;
69         _alignmentMap["RIGHT_CENTER"] = osgText::Text::RIGHT_CENTER;
70         _alignmentMap["RIGHT_BOTTOM"] = osgText::Text::RIGHT_BOTTOM;
71
72         _alignmentMap["LEFT_BASE_LINE"] = osgText::Text::LEFT_BASE_LINE;
73         _alignmentMap["CENTER_BASE_LINE"] = osgText::Text::CENTER_BASE_LINE;
74         _alignmentMap["RIGHT_BASE_LINE"] = osgText::Text::RIGHT_BASE_LINE;
75         _alignmentMap["BASE_LINE"] = osgText::Text::LEFT_BASE_LINE;
76
77         _characterSizeModeMap["OBJECT_COORDS"] = osgText::Text::OBJECT_COORDS;
78         _characterSizeModeMap["SCREEN_COORDS"] = osgText::Text::SCREEN_COORDS;
79         _characterSizeModeMap["OBJECT_COORDS_WITH_MAXIMUM_SCREEN_SIZE_CAPPED_BY_FONT_HEIGHT"] = osgText::Text::OBJECT_COORDS_WITH_MAXIMUM_SCREEN_SIZE_CAPPED_BY_FONT_HEIGHT;
80
81         _stringKeyMap["Home"]=' ';
82         _stringKeyMap["Start"]= osgGA::GUIEventAdapter::KEY_Home;
83         _stringKeyMap["Next"]= osgGA::GUIEventAdapter::KEY_Page_Down;
84         _stringKeyMap["Previous"]=osgGA::GUIEventAdapter::KEY_Page_Up;
85         _stringKeyMap["Up"]=osgGA::GUIEventAdapter::KEY_Up;
86         _stringKeyMap["Down"]=osgGA::GUIEventAdapter::KEY_Down;
87         _stringKeyMap["End"]=osgGA::GUIEventAdapter::KEY_End;
88         _stringKeyMap["Page Down"]=osgGA::GUIEventAdapter::KEY_Page_Down;
89         _stringKeyMap["Page Up"]=osgGA::GUIEventAdapter::KEY_Page_Up;
90         _stringKeyMap["F1"]=osgGA::GUIEventAdapter::KEY_F1;
91         _stringKeyMap["F2"]=osgGA::GUIEventAdapter::KEY_F2;
92         _stringKeyMap["F3"]=osgGA::GUIEventAdapter::KEY_F3;
93         _stringKeyMap["F4"]=osgGA::GUIEventAdapter::KEY_F4;
94         _stringKeyMap["F5"]=osgGA::GUIEventAdapter::KEY_F5;
95         _stringKeyMap["F6"]=osgGA::GUIEventAdapter::KEY_F6;
96         _stringKeyMap["F7"]=osgGA::GUIEventAdapter::KEY_F7;
97         _stringKeyMap["F8"]=osgGA::GUIEventAdapter::KEY_F8;
98         _stringKeyMap["F9"]=osgGA::GUIEventAdapter::KEY_F9;
99         _stringKeyMap["F10"]=osgGA::GUIEventAdapter::KEY_F10;
100         _stringKeyMap["F11"]=osgGA::GUIEventAdapter::KEY_F11;
101         _stringKeyMap["F12"]=osgGA::GUIEventAdapter::KEY_F12;
102
103
104         _notifyLevel = osg::INFO;
105     }
106
107     virtual const char* className() const
108     {
109         return "present3D XML Reader/Writer";
110     }
111
112     virtual bool acceptsExtension(const std::string& extension) const
113     {
114         return osgDB::equalCaseInsensitive(extension,"p3d") ||
115                osgDB::equalCaseInsensitive(extension,"xml") ;
116     }
117
118
119     virtual ReadResult readNode(const std::string& fileName,
120                                 const osgDB::ReaderWriter::Options* options) const;
121
122     virtual ReadResult readNode(std::istream& fin, const Options* options) const;
123
124     ReadResult readNode(osgDB::XmlNode::Input& input, osgDB::ReaderWriter::Options* options) const;
125
126     osg::Node* parseXmlGraph(osgDB::XmlNode* root, bool readOnlyHoldingPage, osgDB::Options* options) const;
127
128     bool parseProperties(osgDB::XmlNode* root, osg::UserDataContainer& udc) const;
129     bool parsePropertyAnimation(osgDB::XmlNode* root, osgPresentation::PropertyAnimation& pa) const;
130
131     void parseModel(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const;
132
133     osg::TransferFunction1D* readTransferFunctionFile(const std::string& filename, float scale) const;
134     void parseVolume(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const;
135
136
137     void parseStereoPair(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const;
138
139     void parseTimeout(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const;
140
141     void parseSwitch(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const;
142
143     bool parseLayerChild(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode* cur, float& totalIndent) const;
144
145     void parseLayer(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const;
146
147     void parseBullets(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur, bool inheritPreviousLayers, bool defineAsBaseLayer) const;
148     void parseText(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur, bool inheritPreviousLayers, bool defineAsBaseLayer) const;
149
150     void parsePage (osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const;
151
152     void parseSlide (osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur, bool parseTitles=true, bool parseLayers=true) const;
153
154     void parsePdfDocument (osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const;
155
156     osg::Vec4 mapStringToColor(const std::string& str) const
157     {
158         ColorMap::const_iterator itr=_colorMap.find(str);
159         if (itr!=_colorMap.end()) return itr->second;
160         osg::Vec4 color;
161         if (read(str,color)) return color;
162         else return osg::Vec4(0.0f,0.0f,0.0f,1.0f);
163     }
164
165     inline osg::Vec4 accumulateRotation(const osg::Vec4& lhs, const osg::Vec4& rhs) const
166     {
167         osg::Quat qlhs,qrhs;
168         qlhs.makeRotate(osg::DegreesToRadians(lhs[0]),lhs[1],lhs[2],lhs[3]);
169         qrhs.makeRotate(osg::DegreesToRadians(rhs[0]),rhs[1],rhs[2],rhs[3]);
170         osg::Quat quat = qlhs*qrhs;
171         osg::Vec4d result;
172         quat.getRotate ( result[0], result[1], result[2], result[3]);
173         result[0] = osg::RadiansToDegrees(result[0]);
174         return result;
175     }
176
177     inline bool read(const char* str, int& value) const;
178     inline bool read(const char* str, float& value) const;
179     inline bool read(const char* str, double& value) const;
180     inline bool read(const char* str, int numberValues, float* values) const;
181     inline bool read(const char* str, osg::Vec2& value) const;
182     inline bool read(const char* str, osg::Vec3& value) const;
183     inline bool read(const char* str, osg::Vec4& value) const;
184
185     inline bool read(const std::string& str, bool& value) const;
186     inline bool read(const std::string& str, int& value) const;
187     inline bool read(const std::string& str, float& value) const;
188     inline bool read(const std::string& str, double& value) const;
189     inline bool read(const std::string& str, int numberValues, float* values) const;
190     inline bool read(const std::string& str, osg::Vec2& value) const;
191     inline bool read(const std::string& str, osg::Vec3& value) const;
192     inline bool read(const std::string& str, osg::Vec4& value) const;
193
194     bool getProperty(osgDB::XmlNode*cur, const char* token) const;
195     bool getKeyProperty(osgDB::XmlNode*cur, const char* token, int& value) const;
196     bool getProperty(osgDB::XmlNode*cur, const char* token, bool& value) const;
197     bool getProperty(osgDB::XmlNode*cur, const char* token, int& value) const;
198     bool getProperty(osgDB::XmlNode*cur, const char* token, float& value) const;
199     bool getProperty(osgDB::XmlNode*cur, const char* token, double& value) const;
200     bool getProperty(osgDB::XmlNode*cur, const char* token, int numberValues, float* values) const;
201     bool getProperty(osgDB::XmlNode*cur, const char* token, osg::Vec2& value) const;
202     bool getProperty(osgDB::XmlNode*cur, const char* token, osg::Vec3& value) const;
203     bool getProperty(osgDB::XmlNode*cur, const char* token, osg::Vec4& value) const;
204     bool getProperty(osgDB::XmlNode*cur, const char* token, std::string& value) const;
205     bool getTrimmedProperty(osgDB::XmlNode*cur, const char* token, std::string& value) const;
206     bool getProperty(osgDB::XmlNode*cur, const char* token, osgText::Text::Layout& value) const;
207     bool getProperty(osgDB::XmlNode*cur, const char* token, osgText::Text::AlignmentType& value) const;
208     bool getProperty(osgDB::XmlNode*cur, const char* token, osgText::Text::CharacterSizeMode& value) const;
209
210     bool getProperties(osgDB::XmlNode*cur, osgPresentation::SlideShowConstructor::PositionData& value) const;
211     bool getProperties(osgDB::XmlNode*cur, osgPresentation::SlideShowConstructor::FontData& value) const;
212     bool getProperties(osgDB::XmlNode*cur, osgPresentation::SlideShowConstructor::ModelData& value) const;
213     bool getProperties(osgDB::XmlNode*cur, osgPresentation::SlideShowConstructor::ImageData& value) const;
214     bool getProperties(osgDB::XmlNode*cur, osgPresentation::SlideShowConstructor::ScriptData& value) const;
215
216     bool getJumpProperties(osgDB::XmlNode*cur, osgPresentation::JumpData& jumpData) const;
217
218     bool getKeyPositionInner(osgDB::XmlNode*cur, osgPresentation::KeyPosition& keyPosition) const;
219     bool getKeyPosition(osgDB::XmlNode*cur, osgPresentation::KeyPosition& keyPosition) const;
220
221     typedef std::map<std::string,osg::Vec4> ColorMap;
222     typedef std::map<std::string,osgText::Text::Layout> LayoutMap;
223     typedef std::map<std::string,osgText::Text::AlignmentType> AlignmentMap;
224     typedef std::map<std::string,osgText::Text::CharacterSizeMode> CharacterSizeModeMap;
225     typedef std::map<std::string, unsigned int> StringKeyMap;
226
227     std::string expandEnvVarsInFileName(const std::string& filename) const;
228
229
230     ColorMap                _colorMap;
231     LayoutMap               _layoutMap;
232     AlignmentMap            _alignmentMap;
233     CharacterSizeModeMap    _characterSizeModeMap;
234     StringKeyMap            _stringKeyMap;
235
236     typedef std::map<std::string, osg::ref_ptr<osgDB::XmlNode> > TemplateMap;
237     mutable TemplateMap _templateMap;
238
239     osg::NotifySeverity _notifyLevel;
240
241 };
242
243 // now register with Registry to instantiate the above
244 // reader/writer.
245 REGISTER_OSGPLUGIN(p3d, ReaderWriterP3DXML)
246
247 std::string ReaderWriterP3DXML::expandEnvVarsInFileName(const std::string& filename) const
248 {
249     std::string argument(filename);
250     std::string::size_type start_pos = argument.find("${");
251
252     while (start_pos != std::string::npos)
253     {
254         std::string::size_type end_pos = argument.find("}",start_pos);
255         if (start_pos != std::string::npos)
256         {
257             std::string var = argument.substr(start_pos+2, end_pos-start_pos-2);
258             const char* str = getenv(var.c_str());
259             if (str)
260             {
261                 argument.erase(start_pos, end_pos-start_pos+1);
262                 argument.insert(start_pos, str);
263             }
264             start_pos = argument.find("${",end_pos);
265         }
266         else
267         {
268             start_pos = std::string::npos;
269         }
270     }
271
272     return argument;
273 }
274
275 bool ReaderWriterP3DXML::read(const char* str, int& value) const
276 {
277     if (!str) return false;
278     std::istringstream iss((const char*)str);
279     iss >> value;
280     return !iss.fail();
281 }
282
283 bool ReaderWriterP3DXML::read(const char* str, float& value) const
284 {
285     if (!str) return false;
286     std::istringstream iss((const char*)str);
287     iss >> value;
288     return !iss.fail();
289 }
290
291 bool ReaderWriterP3DXML::read(const char* str, double& value) const
292 {
293     if (!str) return false;
294     std::istringstream iss((const char*)str);
295     iss >> value;
296     return !iss.fail();
297 }
298
299 bool ReaderWriterP3DXML::read(const char* str, int numberValues, float* values) const
300 {
301     if (!str) return false;
302     std::istringstream iss((const char*)str);
303     for(int i=0; i<numberValues && !iss.fail(); i++)
304     {
305         iss >> *values;
306         ++values;
307     }
308     return !iss.fail();
309 }
310
311 bool ReaderWriterP3DXML::read(const char* str, osg::Vec2& value) const
312 {
313     if (!str) return false;
314     std::istringstream iss((const char*)str);
315     iss >> value.x() >> value.y();
316     return !iss.fail();
317 }
318
319 bool ReaderWriterP3DXML::read(const char* str, osg::Vec3& value) const
320 {
321     if (!str) return false;
322     std::istringstream iss((const char*)str);
323     iss >> value.x() >> value.y() >> value.z();
324     return !iss.fail();
325 }
326
327 bool ReaderWriterP3DXML::read(const char* str, osg::Vec4& value) const
328 {
329     if (!str) return false;
330     std::istringstream iss((const char*)str);
331     iss >> value.x() >> value.y() >> value.z() >> value.w();
332     return !iss.fail();
333 }
334
335 bool ReaderWriterP3DXML::read(const std::string& str, bool& value) const
336 {
337         if ((str == "1") || (str == "0")) {
338         value = (str == "1");
339         return true;
340     }
341     std::string s(osgDB::convertToLowerCase(str));
342     value = (s == "true");
343     return true;
344 }
345
346 bool ReaderWriterP3DXML::read(const std::string& str, int& value) const
347 {
348     std::istringstream iss(str);
349     iss >> value;
350     return !iss.fail();
351 }
352
353 bool ReaderWriterP3DXML::read(const std::string& str, float& value) const
354 {
355     std::istringstream iss(str);
356     iss >> value;
357     return !iss.fail();
358 }
359
360 bool ReaderWriterP3DXML::read(const std::string& str, double& value) const
361 {
362     std::istringstream iss(str);
363     iss >> value;
364     return !iss.fail();
365 }
366
367
368 bool ReaderWriterP3DXML::read(const std::string& str, int numberValues, float* values) const
369 {
370     std::istringstream iss(str);
371     for(int i=0; i<numberValues && !iss.fail(); i++)
372     {
373         iss >> *values;
374         ++values;
375     }
376     return !iss.fail();
377 }
378
379 bool ReaderWriterP3DXML::read(const std::string& str, osg::Vec2& value) const
380 {
381     std::istringstream iss(str);
382     iss >> value.x() >> value.y();
383     return !iss.fail();
384 }
385
386 bool ReaderWriterP3DXML::read(const std::string& str, osg::Vec3& value) const
387 {
388     std::istringstream iss(str);
389     iss >> value.x() >> value.y() >> value.z();
390     return !iss.fail();
391 }
392
393 bool ReaderWriterP3DXML::read(const std::string& str, osg::Vec4& value) const
394 {
395     std::istringstream iss(str);
396     iss >> value.x() >> value.y() >> value.z() >> value.w();
397     return !iss.fail();
398 }
399
400 bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode* cur, const char* token) const
401 {
402     return cur->properties.count(token)!=0;
403 }
404
405 bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode*cur, const char* token, bool& value) const
406 {
407     osgDB::XmlNode::Properties::iterator itr = cur->properties.find(token);
408     if (itr==cur->properties.end()) return false;
409     return read(itr->second,value);
410 }
411
412 bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode*cur, const char* token, int& value) const
413 {
414     osgDB::XmlNode::Properties::iterator itr = cur->properties.find(token);
415     if (itr==cur->properties.end()) return false;
416     return read(itr->second,value);
417 }
418
419 bool ReaderWriterP3DXML::getKeyProperty(osgDB::XmlNode*cur, const char* token, int& value) const
420 {
421     osgDB::XmlNode::Properties::iterator itr = cur->properties.find(token);
422     if (itr==cur->properties.end()) return false;
423
424     OSG_NOTICE<<"getKeyProperty()="<<itr->second<<std::endl;
425
426     if (itr->second.empty())
427     {
428         OSG_NOTICE<<"   empty()"<<std::endl;
429         return false;
430     }
431
432     if (itr->second.find("0x",0,2)!=std::string::npos)
433     {
434         std::istringstream iss(itr->second);
435         iss>>std::hex>>value;
436         OSG_NOTICE<<"ReaderWriterP3DXML::getKeyProperty() hex result = "<<value<<std::endl;
437         return true;
438     }
439     else if (itr->second.size()>1 && (itr->second[0]>='0' && itr->second[0]<='9'))
440     {
441         std::istringstream iss(itr->second);
442         iss>>value;
443         OSG_NOTICE<<"ReaderWriterP3DXML::getKeyProperty() numeric result = "<<value<<std::endl;
444         return true;
445     }
446     else
447     {
448         value = itr->second[0];
449         OSG_NOTICE<<"ReaderWriterP3DXML::getKeyProperty() alphanumeric result = "<<value<<std::endl;
450         return true;
451     }
452 }
453
454 bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode*cur, const char* token, float& value) const
455 {
456     osgDB::XmlNode::Properties::iterator itr = cur->properties.find(token);
457     if (itr==cur->properties.end()) return false;
458     return read(itr->second,value);
459 }
460
461 bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode*cur, const char* token, double& value) const
462 {
463     osgDB::XmlNode::Properties::iterator itr = cur->properties.find(token);
464     if (itr==cur->properties.end()) return false;
465     return read(itr->second,value);
466 }
467
468 bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode*cur, const char* token, int numberValues, float* values) const
469 {
470     osgDB::XmlNode::Properties::iterator itr = cur->properties.find(token);
471     if (itr==cur->properties.end()) return false;
472     return read(itr->second, numberValues, values);
473 }
474
475 bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode*cur, const char* token, osg::Vec2& value) const
476 {
477     osgDB::XmlNode::Properties::iterator itr = cur->properties.find(token);
478     if (itr==cur->properties.end()) return false;
479     return read(itr->second,value);
480 }
481
482 bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode*cur, const char* token, osg::Vec3& value) const
483 {
484     osgDB::XmlNode::Properties::iterator itr = cur->properties.find(token);
485     if (itr==cur->properties.end()) return false;
486     return read(itr->second,value);
487 }
488
489 bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode*cur, const char* token, osg::Vec4& value) const
490 {
491     osgDB::XmlNode::Properties::iterator itr = cur->properties.find(token);
492     if (itr==cur->properties.end()) return false;
493     return read(itr->second,value);
494 }
495
496 bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode*cur, const char* token, std::string& value) const
497 {
498     osgDB::XmlNode::Properties::iterator itr = cur->properties.find(token);
499     if (itr==cur->properties.end()) return false;
500     value = itr->second;
501     return true;
502 }
503
504 bool ReaderWriterP3DXML::getTrimmedProperty(osgDB::XmlNode*cur, const char* token, std::string& value) const
505 {
506     osgDB::XmlNode::Properties::iterator itr = cur->properties.find(token);
507     if (itr==cur->properties.end()) return false;
508     value = osgDB::trimEnclosingSpaces(itr->second);
509     return true;
510 }
511
512 bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode*cur, const char* token, osgText::Text::Layout& value) const
513 {
514     osgDB::XmlNode::Properties::iterator pitr = cur->properties.find(token);
515     if (pitr==cur->properties.end()) return false;
516
517     const std::string& str = pitr->second;
518     LayoutMap::const_iterator itr = _layoutMap.find(str);
519     if (itr!=_layoutMap.end())
520     {
521         value = itr->second;
522     }
523     return true;
524 }
525
526 bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode*cur, const char* token, osgText::Text::AlignmentType& value) const
527 {
528     osgDB::XmlNode::Properties::iterator pitr = cur->properties.find(token);
529     if (pitr==cur->properties.end()) return false;
530
531     const std::string& str = pitr->second;
532     AlignmentMap::const_iterator itr = _alignmentMap.find(str);
533     if (itr!=_alignmentMap.end())
534     {
535         value = itr->second;
536     }
537     return true;
538 }
539
540 bool ReaderWriterP3DXML::getProperty(osgDB::XmlNode*cur, const char* token, osgText::Text::CharacterSizeMode& value) const
541 {
542     osgDB::XmlNode::Properties::iterator pitr = cur->properties.find(token);
543     if (pitr==cur->properties.end()) return false;
544
545     const std::string& str = pitr->second;
546     CharacterSizeModeMap::const_iterator itr = _characterSizeModeMap.find(str);
547     if (itr!=_characterSizeModeMap.end())
548     {
549         value = itr->second;
550     }
551     return true;
552 }
553
554 bool ReaderWriterP3DXML::getProperties(osgDB::XmlNode*cur, osgPresentation::SlideShowConstructor::PositionData& value) const
555 {
556     bool propertiesRead=false;
557
558     osg::Vec3 position(0.0f,1.0f,0.0f);
559     osg::Vec4 rotate(0.0f,0.0f,0.0f,1.0f);
560     float scale = 1.0f;
561
562     osg::Vec4 rotation(0.0f,0.0f,0.0f,1.0f);
563
564     // temporary
565     std::string str;
566
567     if (getProperty(cur, "coordinate_frame", str))
568     {
569         propertiesRead = true;
570
571         if (str=="model") value.frame = osgPresentation::SlideShowConstructor::MODEL;
572         else if (str=="slide") value.frame = osgPresentation::SlideShowConstructor::SLIDE;
573         else OSG_NOTIFY(_notifyLevel)<<"Parser error - coordinate_frame=\""<<str<<"\" unrecongonized value"<<std::endl;
574
575         OSG_NOTIFY(_notifyLevel)<<"read coordinate_frame "<< ((value.frame==osgPresentation::SlideShowConstructor::MODEL) ? "osgPresentation::SlideShowConstructor::MODEL" : "osgPresentation::SlideShowConstructor::SLIDE")<<std::endl;
576     }
577
578     if (value.frame==osgPresentation::SlideShowConstructor::SLIDE)
579     {
580
581         if (getProperty(cur, "position", str))
582         {
583             value.position.set(0.5,0.5,0.0);
584
585             propertiesRead = true;
586
587             osg::Vec2 vec2;
588             osg::Vec3 vec3;
589
590             bool fail = false;
591             if (str=="center") value.position.set(0.5f,.5f,0.0f);
592             else if (str=="eye") value.position.set(0.0f,0.0f,1.0f);
593             else if (read(str,vec3)) value.position = vec3;
594             else if (read(str,vec2)) value.position.set(vec3.x(),vec3.y(),0.0f);
595             else fail = true;
596
597             if (fail) { OSG_NOTIFY(_notifyLevel)<<"Parser error - position=\""<<str<<"\" unrecongonized value"<<std::endl; }
598             else { OSG_NOTIFY(_notifyLevel)<<"Read position="<<value.position<<std::endl; }
599         }
600     }
601     else // value.frame==osgPresentation::SlideShowConstructor::MODEL
602     {
603
604         if (getProperty(cur, "position", str))
605         {
606             value.position.set(0.0,0.0,0.0);
607
608             propertiesRead = true;
609
610             bool fail = false;
611             if (str=="center") value.position.set(0.0f,1.0f,0.0f);
612             else if (str=="eye") value.position.set(0.0f,0.0f,0.0f);
613             else if (!read(str,value.position)) fail = true;
614
615             if (fail) { OSG_NOTIFY(_notifyLevel)<<"Parser error - position=\""<<str<<"\" unrecongonized value"<<std::endl; }
616             else { OSG_NOTIFY(_notifyLevel)<<"Read position="<<value.position<<std::endl; }
617         }
618     }
619
620
621     if (getProperty(cur, "scale", scale))
622     {
623         value.scale.set(scale,scale,scale);
624         propertiesRead = true;
625         OSG_NOTIFY(_notifyLevel)<<"scale read "<<scale<<std::endl;
626     }
627
628     if (getProperty(cur, "scale_x", scale) || getProperty(cur, "width", scale))
629     {
630         value.scale.x() = scale;
631         propertiesRead = true;
632         OSG_NOTIFY(_notifyLevel)<<"scale read_x "<<scale<<std::endl;
633     }
634
635     if (getProperty(cur, "scale_y", scale) || getProperty(cur, "height", scale))
636     {
637         value.scale.y() = scale;
638         propertiesRead = true;
639         OSG_NOTIFY(_notifyLevel)<<"scale read_y "<<scale<<std::endl;
640     }
641
642     if (getProperty(cur, "scale_z", scale))
643     {
644         value.scale.z() = scale;
645         propertiesRead = true;
646         OSG_NOTIFY(_notifyLevel)<<"scale read_z "<<scale<<std::endl;
647     }
648
649     if (getProperty(cur, "rotate", rotate))
650     {
651         value.rotate = rotate;
652         propertiesRead = true;
653         OSG_NOTIFY(_notifyLevel)<<"rotate read "<<rotate<<std::endl;
654     }
655
656     if (getProperty(cur, "rotate1", rotate))
657     {
658         // note may need to reverse once Quat * order is sorted out.
659         value.rotate = accumulateRotation(rotate,value.rotate);
660         propertiesRead = true;
661         OSG_NOTIFY(_notifyLevel)<<"rotate1 read "<<rotate<<std::endl;
662     }
663
664     if (getProperty(cur, "rotate2", rotate))
665     {
666         // note may need to reverse once Quat * order is sorted out.
667         value.rotate = accumulateRotation(rotate,value.rotate);
668         propertiesRead = true;
669         OSG_NOTIFY(_notifyLevel)<<"rotate1 read "<<rotate<<std::endl;
670     }
671
672     if (getProperty(cur, "rotate3", rotate))
673     {
674         // note may need to reverse once Quat * order is sorted out.
675         value.rotate = accumulateRotation(rotate,value.rotate);
676         propertiesRead = true;
677         OSG_NOTIFY(_notifyLevel)<<"rotate1 read "<<rotate<<std::endl;
678     }
679
680     if (getProperty(cur, "rotation", rotation))
681     {
682         value.rotation = rotation;
683         OSG_NOTIFY(_notifyLevel)<<"rotation read "<<rotation<<std::endl;
684         propertiesRead = true;
685     }
686
687     if (getProperty(cur, "rotation1", rotation))
688     {
689         value.rotation = accumulateRotation(rotation,value.rotation);
690         OSG_NOTIFY(_notifyLevel)<<"rotation1 read "<<rotation<<std::endl;
691         propertiesRead = true;
692     }
693
694     if (getProperty(cur, "rotation2", rotation))
695     {
696         value.rotation = accumulateRotation(rotation,value.rotation);
697         OSG_NOTIFY(_notifyLevel)<<"rotation2 read "<<rotation<<std::endl;
698         propertiesRead = true;
699     }
700
701     if (getProperty(cur, "rotation3", rotation))
702     {
703         value.rotation = accumulateRotation(rotation,value.rotation);
704         OSG_NOTIFY(_notifyLevel)<<"rotation3 read "<<rotation<<std::endl;
705         propertiesRead = true;
706     }
707
708     if (getTrimmedProperty(cur, "path", str))
709     {
710
711         value.absolute_path = false;
712         value.inverse_path = false;
713         value.path = expandEnvVarsInFileName(str);
714
715         OSG_NOTIFY(_notifyLevel)<<"path read "<<str<<std::endl;
716         propertiesRead = true;
717     }
718
719     if (getTrimmedProperty(cur, "camera_path", str))
720     {
721         value.absolute_path = true;
722         value.inverse_path = true;
723         value.path = expandEnvVarsInFileName(str);
724
725         OSG_NOTIFY(_notifyLevel)<<"camera path read "<<str<<std::endl;
726         propertiesRead = true;
727     }
728
729     if (getProperty(cur, "path_time_offset", value.path_time_offset))
730     {
731         OSG_NOTIFY(_notifyLevel)<<"read path_time_offset"<<value.path_time_offset<<std::endl;
732         propertiesRead = true;
733     }
734
735     if (getProperty(cur, "path_time_multiplier", value.path_time_multiplier))
736     {
737         OSG_NOTIFY(_notifyLevel)<<"read path_time_multiplier"<<value.path_time_multiplier<<std::endl;
738         propertiesRead = true;
739     }
740
741     if (getProperty(cur, "animation_material_time_offset", value.animation_material_time_offset))
742     {
743         OSG_NOTIFY(_notifyLevel)<<"read animation_material_time_offset"<<value.animation_material_time_offset<<std::endl;
744         propertiesRead = true;
745     }
746
747     if (getProperty(cur, "animation_material_time_multiplier", value.animation_material_time_multiplier))
748     {
749         OSG_NOTIFY(_notifyLevel)<<"read animation_material_time_multiplier"<<value.animation_material_time_multiplier<<std::endl;
750         propertiesRead = true;
751     }
752
753     if (getTrimmedProperty(cur, "animation_material", str))
754     {
755         value.animation_material_filename = str;
756
757         OSG_NOTIFY(_notifyLevel)<<"animation_material read "<<str<<std::endl;
758         propertiesRead = true;
759     }
760
761     if (getTrimmedProperty(cur, "animation_name", str))
762     {
763         value.animation_name = str;
764
765         OSG_NOTIFY(_notifyLevel)<<"animation_name "<<str<<std::endl;
766         propertiesRead = true;
767     }
768
769     if (getProperty(cur, "fade", value.fade))
770     {
771         OSG_NOTIFY(_notifyLevel)<<"fade "<<value.fade<<std::endl;
772         propertiesRead = true;
773     }
774
775     if (getProperty(cur, "path_loop_mode", str))
776     {
777         OSG_NOTIFY(_notifyLevel)<<"path_loop_mode "<<str<<std::endl;
778         if (str=="LOOP") value.path_loop_mode=osg::AnimationPath::LOOP;
779         else if (str=="SWING") value.path_loop_mode=osg::AnimationPath::SWING;
780         else if (str=="NO_LOOPING") value.path_loop_mode=osg::AnimationPath::NO_LOOPING;
781         propertiesRead = true;
782     }
783
784     if (getProperty(cur, "animation_material_loop_mode", str))
785     {
786         OSG_NOTIFY(_notifyLevel)<<"animation_material_loop_mode "<<str<<std::endl;
787         if (str=="LOOP") value.animation_material_loop_mode=osgPresentation::AnimationMaterial::LOOP;
788         else if (str=="SWING") value.animation_material_loop_mode=osgPresentation::AnimationMaterial::SWING;
789         else if (str=="NO_LOOPING") value.animation_material_loop_mode=osgPresentation::AnimationMaterial::NO_LOOPING;
790         propertiesRead = true;
791     }
792
793     if (getProperty(cur, "billboard", str))
794     {
795         value.autoRotate = (str != "off" && str != "Off" && str != "OFF");
796         OSG_NOTIFY(_notifyLevel)<<"billboard, str="<<str<<", autoRotate="<<value.autoRotate<<std::endl;
797         propertiesRead = true;
798     }
799
800     if (getProperty(cur, "scale_to_screen",str))
801     {
802         value.autoScale = (str != "off" && str != "Off" && str != "OFF");
803         OSG_NOTIFY(_notifyLevel)<<"scale-to-screen, str="<<str<<", autoRotate="<<value.autoScale<<std::endl;
804         propertiesRead = true;
805     }
806
807     if (getProperty(cur, "hud", str))
808     {
809         value.hud = (str != "off" && str != "Off" && str != "OFF");
810         OSG_NOTIFY(_notifyLevel)<<"hud, str="<<str<<", hud="<<value.hud<<std::endl;
811         propertiesRead = true;
812     }
813
814
815     return propertiesRead;
816 }
817
818 bool ReaderWriterP3DXML::getProperties(osgDB::XmlNode*cur, osgPresentation::SlideShowConstructor::FontData& value) const
819 {
820     bool propertiesRead=false;
821
822     OSG_NOTIFY(_notifyLevel)<<"in getProperties(FontData)"<<std::endl;
823
824     if (getProperty(cur, "font", value.font))
825     {
826         propertiesRead = true;
827         OSG_NOTIFY(_notifyLevel)<<"read font \""<<value.font<<"\""<<std::endl;
828     }
829
830     if (getProperty(cur, "character_size", value.characterSize))
831     {
832         propertiesRead = true;
833         OSG_NOTIFY(_notifyLevel)<<"read height \""<<value.characterSize<<"\""<<std::endl;
834     }
835
836     if (getProperty(cur, "character_size_mode", value.characterSizeMode))
837     {
838         propertiesRead = true;
839
840         OSG_NOTIFY(_notifyLevel)<<"read character_size_mode \""<<value.characterSizeMode<<"\""<<std::endl;
841     }
842
843     if (getProperty(cur, "layout", value.layout))
844     {
845         propertiesRead = true;
846
847         OSG_NOTIFY(_notifyLevel)<<"read layout \""<<value.layout<<"\""<<std::endl;
848     }
849
850     if (getProperty(cur, "alignment", value.alignment))
851     {
852         propertiesRead = true;
853
854         OSG_NOTIFY(_notifyLevel)<<"read alignment \""<<value.alignment<<"\""<<std::endl;
855     }
856
857     std::string colorString;
858     if (getProperty(cur, "color", colorString) || getProperty(cur, "colour", colorString) )
859     {
860         propertiesRead = true;
861
862         value.color = mapStringToColor(colorString);
863
864         OSG_NOTIFY(_notifyLevel)<<"read color \""<<value.color<<"\""<<std::endl;
865     }
866
867     return propertiesRead;
868 }
869
870 bool ReaderWriterP3DXML::getProperties(osgDB::XmlNode*cur, osgPresentation::SlideShowConstructor::ModelData& value) const
871 {
872     bool propertiesRead=false;
873
874     OSG_NOTIFY(_notifyLevel)<<"in getProperties(ModelData)"<<std::endl;
875
876     if (getProperty(cur, "region", value.region))
877     {
878         propertiesRead = true;
879         OSG_NOTIFY(_notifyLevel)<<"read region \""<<value.region<<"\""<<std::endl;
880     }
881
882     if (getProperty(cur, "effect", value.effect))
883     {
884         propertiesRead = true;
885         OSG_NOTIFY(_notifyLevel)<<"read effect \""<<value.effect<<"\""<<std::endl;
886     }
887
888     if (getProperty(cur, "options", value.options))
889     {
890         propertiesRead = true;
891         OSG_NOTIFY(_notifyLevel)<<"read options \""<<value.options<<"\""<<std::endl;
892     }
893
894     return propertiesRead;
895 }
896
897 bool ReaderWriterP3DXML::getProperties(osgDB::XmlNode*cur, osgPresentation::SlideShowConstructor::ImageData& value) const
898 {
899     bool propertiesRead=false;
900
901     OSG_NOTIFY(_notifyLevel)<<"in getProperties(ImageData)"<<std::endl;
902
903     if (getProperty(cur, "page", value.page))
904     {
905         propertiesRead = true;
906         OSG_NOTIFY(_notifyLevel)<<"read page \""<<value.page<<"\""<<std::endl;
907     }
908
909     if (getProperty(cur, "options", value.options))
910     {
911         propertiesRead = true;
912         OSG_NOTIFY(_notifyLevel)<<"read options \""<<value.options<<"\""<<std::endl;
913     }
914
915     osg::Vec4 bgColour;
916     if (getProperty(cur, "background", value.backgroundColor))
917     {
918         propertiesRead = true;
919         OSG_NOTIFY(_notifyLevel)<<"read background colour \""<<value.backgroundColor<<"\""<<std::endl;
920     }
921
922     if (getProperty(cur, "width", value.width))
923     {
924         propertiesRead = true;
925         OSG_NOTIFY(_notifyLevel)<<"read width \""<<value.width<<"\""<<std::endl;
926     }
927
928     if (getProperty(cur, "height", value.height))
929     {
930         propertiesRead = true;
931         OSG_NOTIFY(_notifyLevel)<<"read height \""<<value.height<<"\""<<std::endl;
932     }
933
934     if (getProperty(cur, "region", value.region))
935     {
936         propertiesRead = true;
937         value.region_in_pixel_coords = false;
938         OSG_NOTIFY(_notifyLevel)<<"read region \""<<value.region<<"\""<<std::endl;
939     }
940
941     if (getProperty(cur, "pixel_region", value.region))
942     {
943         propertiesRead = true;
944         value.region_in_pixel_coords = true;
945         OSG_NOTIFY(_notifyLevel)<<"read pixel_region \""<<value.region<<"\""<<std::endl;
946     }
947
948     std::string str;
949     if (getProperty(cur, "looping", str))
950     {
951         propertiesRead = true;
952         if (str=="ON") value.loopingMode = osg::ImageStream::LOOPING;
953         else value.loopingMode = osg::ImageStream::NO_LOOPING;
954         OSG_NOTIFY(_notifyLevel)<<"looping \""<<str<<"\""<<std::endl;
955     }
956
957     if (getProperty(cur, "fps", value.fps))
958     {
959         propertiesRead = true;
960         OSG_NOTIFY(_notifyLevel)<<"read fps \""<<value.fps<<"\""<<std::endl;
961     }
962
963     if (getProperty(cur, "duration", value.duration))
964     {
965         propertiesRead = true;
966         OSG_NOTIFY(_notifyLevel)<<"read duration \""<<value.duration<<"\""<<std::endl;
967     }
968
969     if (getProperty(cur, "paging_mode", str))
970     {
971         propertiesRead = true;
972         if (str=="PRE_LOAD_ALL_IMAGES") value.imageSequencePagingMode = osg::ImageSequence::PRE_LOAD_ALL_IMAGES;
973         else if (str=="PAGE_AND_RETAIN_IMAGES") value.imageSequencePagingMode = osg::ImageSequence::PAGE_AND_RETAIN_IMAGES;
974         else if (str=="PAGE_AND_DISCARD_USED_IMAGES") value.imageSequencePagingMode = osg::ImageSequence::PAGE_AND_DISCARD_USED_IMAGES;
975         else if (str=="LOAD_AND_RETAIN_IN_UPDATE_TRAVERSAL") value.imageSequencePagingMode = osg::ImageSequence::LOAD_AND_RETAIN_IN_UPDATE_TRAVERSAL;
976         else if (str=="LOAD_AND_DISCARD_IN_UPDATE_TRAVERSAL") value.imageSequencePagingMode = osg::ImageSequence::LOAD_AND_DISCARD_IN_UPDATE_TRAVERSAL;
977
978         OSG_NOTIFY(_notifyLevel)<<"read imageSequencePagingMode \""<<value.imageSequencePagingMode<<"\""<<std::endl;
979     }
980
981     if (getProperty(cur, "interaction_mode", str))
982     {
983         propertiesRead = true;
984
985         if (str=="PLAY_AUTOMATICALLY_LIKE_MOVIE") value.imageSequenceInteractionMode = osgPresentation::SlideShowConstructor::ImageData::PLAY_AUTOMATICALLY_LIKE_MOVIE;
986         else if (str=="USE_MOUSE_X_POSITION") value.imageSequenceInteractionMode = osgPresentation::SlideShowConstructor::ImageData::USE_MOUSE_X_POSITION;
987         else if (str=="USE_MOUSE_Y_POSITION") value.imageSequenceInteractionMode = osgPresentation::SlideShowConstructor::ImageData::USE_MOUSE_Y_POSITION;
988
989         OSG_NOTIFY(_notifyLevel)<<"read imageSequencePagingMode \""<<value.imageSequenceInteractionMode<<"\""<<std::endl;
990     }
991
992     if (getProperty(cur, "blending", str))
993     {
994         propertiesRead = true;
995
996         if (str=="ON" || str=="On" || str=="on" || str=="enable" ) value.blendingHint = osgPresentation::SlideShowConstructor::ImageData::ON;
997         else if (str=="OFF" || str=="Off" || str=="off" || str=="disable" ) value.blendingHint = osgPresentation::SlideShowConstructor::ImageData::OFF;
998
999         OSG_NOTIFY(_notifyLevel)<<"read blendingHint \""<<value.blendingHint<<"\""<<std::endl;
1000     }
1001
1002     if (getProperty(cur, "delay", value.delayTime))
1003     {
1004         propertiesRead = true;
1005         OSG_NOTIFY(_notifyLevel)<<"read delay \""<<value.delayTime<<"\""<<std::endl;
1006     }
1007
1008     if (getProperty(cur, "start", value.startTime))
1009     {
1010         propertiesRead = true;
1011         OSG_NOTIFY(_notifyLevel)<<"read start \""<<value.startTime<<"\""<<std::endl;
1012     }
1013
1014     if (getProperty(cur, "stop", value.stopTime))
1015     {
1016         propertiesRead = true;
1017         OSG_NOTIFY(_notifyLevel)<<"read stop \""<<value.stopTime<<"\""<<std::endl;
1018     }
1019
1020     if (getProperty(cur, "volume", value.volume))
1021     {
1022         propertiesRead = true;
1023         OSG_NOTIFY(_notifyLevel)<<"read volume \""<<value.volume<<"\""<<std::endl;
1024     }
1025
1026     /*
1027     if (getProperty(cur, "texcoord_offset", value.texcoord_offset))
1028     {
1029         propertiesRead = true;
1030         OSG_NOTIFY(_notifyLevel)<<"read offset \""<<value.texcoord_offset<<"\""<<std::endl;
1031     }
1032
1033     if (getProperty(cur, "texcoord_scale", value.texcoord_scale))
1034     {
1035         propertiesRead = true;
1036         OSG_NOTIFY(_notifyLevel)<<"read texcoord_scale \""<<value.texcoord_scale<<"\""<<std::endl;
1037     }
1038
1039     if (getProperty(cur, "texcoord_rotate", value.texcoord_rotate))
1040     {
1041         propertiesRead = true;
1042         OSG_NOTIFY(_notifyLevel)<<"read texcoord_rotate \""<<value.texcoord_rotate<<"\""<<std::endl;
1043     }
1044 */
1045     return propertiesRead;
1046 }
1047
1048 bool ReaderWriterP3DXML::getProperties(osgDB::XmlNode*cur, osgPresentation::SlideShowConstructor::ScriptData& value) const
1049 {
1050     bool propertiesRead=false;
1051
1052     std::string name;
1053     if (getProperty(cur, "update_script", name))
1054     {
1055         value.scripts.push_back(osgPresentation::SlideShowConstructor::ScriptPair(osgPresentation::SlideShowConstructor::UPDATE_SCRIPT, name));
1056         propertiesRead = true;
1057     }
1058
1059     if (getProperty(cur, "event_script", name))
1060     {
1061         value.scripts.push_back(osgPresentation::SlideShowConstructor::ScriptPair(osgPresentation::SlideShowConstructor::EVENT_SCRIPT, name));
1062         propertiesRead = true;
1063     }
1064
1065     return propertiesRead;
1066 }
1067
1068 bool ReaderWriterP3DXML::parseProperties(osgDB::XmlNode* root, osg::UserDataContainer& udc) const
1069 {
1070     bool readProperties = false;
1071     OSG_NOTICE<<"Doing parseProperties()"<<std::endl;
1072     for(osgDB::XmlNode::Children::iterator itr = root->children.begin();
1073         itr != root->children.end();
1074         ++itr)
1075     {
1076         osgDB::XmlNode* cur = itr->get();
1077
1078         if (cur->name == "property")
1079         {
1080             std::string name;
1081             std::string type;
1082
1083             getProperty(cur, "name", name);
1084             getProperty(cur, "type", type);
1085
1086             if (type=="float")
1087             {
1088                 float value;
1089                 std::stringstream str(cur->contents);
1090                 str>>value;
1091
1092                 udc.setUserValue(name, value);
1093                 readProperties = true;
1094
1095                 OSG_NOTICE<<"Adding property float "<<value<<std::endl;
1096             }
1097             else if (type=="int")
1098             {
1099                 int value;
1100                 std::stringstream str(cur->contents);
1101                 str>>value;
1102
1103                 udc.setUserValue(name, value);
1104                 readProperties = true;
1105
1106                 OSG_NOTICE<<"Adding property int "<<value<<std::endl;
1107             }
1108             else
1109             {
1110                 udc.setUserValue(name, cur->contents);
1111                 readProperties = true;
1112                 OSG_NOTICE<<"Adding property string "<<cur->contents<<std::endl;
1113             }
1114         }
1115         else
1116         {
1117             OSG_NOTICE<<"Unhandled tag["<<cur->name<<"] expecting <property>"<<std::endl;
1118         }
1119     }
1120     return readProperties;
1121 }
1122
1123 bool ReaderWriterP3DXML::parsePropertyAnimation(osgDB::XmlNode* root, osgPresentation::PropertyAnimation& pa) const
1124 {
1125     bool readKeyframes = false;
1126     OSG_NOTICE<<"Doing parsePropertyAnimation()"<<std::endl;
1127     for(osgDB::XmlNode::Children::iterator itr = root->children.begin();
1128         itr != root->children.end();
1129         ++itr)
1130     {
1131         osgDB::XmlNode* cur = itr->get();
1132
1133         if (cur->name == "key_frame")
1134         {
1135
1136             double time;
1137             if (getProperty(cur, "time", time))
1138             {
1139                 osg::ref_ptr<osg::UserDataContainer> udc = new osg::DefaultUserDataContainer;
1140                 if (parseProperties(cur, *udc))
1141                 {
1142                     OSG_NOTICE<<"Adding keyframe"<<std::endl;
1143                     pa.addKeyFrame(time, udc.get());
1144                     readKeyframes = true;
1145                 }
1146             }
1147             else
1148             {
1149                 OSG_NOTICE<<"No time assigned to key_frame, ignoring <key_frame>"<<std::endl;
1150             }
1151         }
1152         else
1153         {
1154             OSG_NOTICE<<"Unhandled tag["<<cur->name<<"] expecting <key_frame>"<<std::endl;
1155         }
1156     }
1157
1158     return readKeyframes;
1159 }
1160
1161
1162 bool ReaderWriterP3DXML::getJumpProperties(osgDB::XmlNode* cur, osgPresentation::JumpData& jumpData) const
1163 {
1164     bool propertyRead = false;
1165
1166     if (getProperty(cur, "slide_name", jumpData.slideName))
1167     {
1168         OSG_INFO<<"slide_name "<<jumpData.slideName<<std::endl;
1169         propertyRead = true;
1170     }
1171
1172     if (getProperty(cur, "slide", jumpData.slideNum))
1173     {
1174         OSG_INFO<<"slide "<<jumpData.slideNum<<std::endl;
1175         propertyRead = true;
1176     }
1177
1178     if (getProperty(cur, "layer", jumpData.layerNum))
1179     {
1180         OSG_INFO<<"layer "<<jumpData.layerNum<<std::endl;
1181         propertyRead = true;
1182     }
1183
1184     if (getProperty(cur, "layer_name", jumpData.layerName))
1185     {
1186         OSG_INFO<<"layer_name "<<jumpData.layerName<<std::endl;
1187         propertyRead = true;
1188     }
1189
1190     std::string jumpType;
1191     if (getProperty(cur, "jump", jumpType))
1192     {
1193         OSG_INFO<<"jump "<<jumpType<<std::endl;
1194         propertyRead = true;
1195         jumpData.relativeJump = (jumpType=="relative") || (jumpType=="Relative") || (jumpType=="RELATIVE") ;
1196     }
1197
1198     return propertyRead;
1199 }
1200
1201 void ReaderWriterP3DXML::parseModel(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const
1202 {
1203
1204     osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getModelPositionData();
1205    bool positionRead = getProperties(cur, positionData);
1206
1207     osgPresentation::SlideShowConstructor::ModelData modelData;// = constructor.getModelData();
1208     getProperties(cur, modelData);
1209
1210     osgPresentation::SlideShowConstructor::ScriptData scriptData;
1211     getProperties(cur, scriptData);
1212
1213     std::string filename = cur->getTrimmedContents();
1214
1215     if (!filename.empty())
1216     {
1217         constructor.addModel(filename,
1218                              positionRead ? positionData : constructor.getModelPositionData(),
1219                              modelData,
1220                              scriptData
1221                             );
1222     }
1223 }
1224
1225
1226
1227 osg::TransferFunction1D* ReaderWriterP3DXML::readTransferFunctionFile(const std::string& filename, float scale) const
1228 {
1229     std::string foundFile = osgDB::findDataFile(filename);
1230     if (foundFile.empty())
1231     {
1232         OSG_NOTICE<<"Error: could not find transfer function file : "<<filename<<std::endl;
1233         return 0;
1234     }
1235
1236     OSG_NOTICE<<"Reading transfer function "<<filename<<std::endl;
1237
1238     osg::TransferFunction1D::ColorMap colorMap;
1239     osgDB::ifstream fin(foundFile.c_str());
1240     while(fin)
1241     {
1242         char readline[4096];
1243         *readline = 0;
1244         fin.getline(readline, sizeof(readline));
1245
1246         if (*readline!=0)
1247         {
1248             std::stringstream str(readline);
1249
1250             float value, red, green, blue, alpha;
1251             str >> value >> red >> green >> blue >> alpha;
1252
1253             *readline = 0;
1254             str.getline(readline, sizeof(readline));
1255
1256             char* comment = readline;
1257             while(*comment==' ' || *comment=='\t' ) ++comment;
1258
1259             if (*comment!=0)
1260             {
1261                 OSG_NOTICE<<"value = "<<value<<" ("<<red<<", "<<green<<", "<<blue<<", "<<alpha<<") comment = ["<<comment<<"]"<<std::endl;
1262             }
1263             else
1264             {
1265                 OSG_NOTICE<<"value = "<<value<<" ("<<red<<", "<<green<<", "<<blue<<", "<<alpha<<")"<<std::endl;
1266             }
1267             colorMap[value] = osg::Vec4(red*scale,green*scale,blue*scale,alpha*scale);
1268         }
1269     }
1270
1271     if (colorMap.empty())
1272     {
1273         OSG_NOTICE<<"Error: No values read from transfer function file: "<<filename<<std::endl;
1274         return 0;
1275     }
1276
1277     osg::TransferFunction1D* tf = new osg::TransferFunction1D;
1278     tf->assign(colorMap);
1279
1280     return tf;
1281 }
1282
1283
1284 void ReaderWriterP3DXML::parseVolume(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode* cur) const
1285 {
1286
1287     osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getModelPositionData();
1288     bool positionRead = getProperties(cur,positionData);
1289
1290     osgPresentation::SlideShowConstructor::VolumeData volumeData;
1291
1292     // check the rendering technique/shading model to use
1293     std::string technique;
1294     if (getProperty(cur, "technique", technique))
1295     {
1296         if      (technique=="standard") volumeData.shadingModel =  osgPresentation::SlideShowConstructor::VolumeData::Standard;
1297         else if (technique=="mip") volumeData.shadingModel =  osgPresentation::SlideShowConstructor::VolumeData::MaximumIntensityProjection;
1298         else if (technique=="isosurface" || technique=="iso" ) volumeData.shadingModel =  osgPresentation::SlideShowConstructor::VolumeData::Isosurface;
1299         else if (technique=="light") volumeData.shadingModel =  osgPresentation::SlideShowConstructor::VolumeData::Light;
1300     }
1301
1302     std::string renderer;
1303     if (getProperty(cur, "renderer", renderer))
1304     {
1305         if      (renderer=="FixedFunction") volumeData.technique =  osgPresentation::SlideShowConstructor::VolumeData::FixedFunction;
1306         else if (renderer=="RayTraced") volumeData.technique =  osgPresentation::SlideShowConstructor::VolumeData::RayTraced;
1307         else if (renderer=="MultiPass") volumeData.technique =  osgPresentation::SlideShowConstructor::VolumeData::MultiPass;
1308     }
1309
1310     std::string hull;
1311     if (getProperty(cur, "hull", hull))
1312     {
1313         volumeData.hull = hull;
1314     }
1315
1316     if (getProperty(cur, "alpha", volumeData.alphaValue)) {}
1317     if (getProperty(cur, "cutoff", volumeData.cutoffValue)) {}
1318     if (getProperty(cur, "region", volumeData.region)) {}
1319     if (getProperty(cur, "sampleDensity", volumeData.sampleDensityValue)) {}
1320     if (getProperty(cur, "sampleDensityWhenMoving", volumeData.sampleDensityWhenMovingValue)) {}
1321     if (getProperty(cur, "sampleRatio", volumeData.sampleRatioValue)) {}
1322     if (getProperty(cur, "sampleRatioWhenMoving", volumeData.sampleRatioWhenMovingValue)) {}
1323
1324
1325     if (getProperty(cur, "colourModulate", volumeData.colorModulate)) {}
1326     if (getProperty(cur, "colorModulate", volumeData.colorModulate)) {}
1327
1328     std::string operation;
1329     if (getProperty(cur, "colorSpaceOperation", operation) || getProperty(cur, "colourSpaceOperation", operation))
1330     {
1331         if (operation=="NO_COLOR_SPACE_OPERATION") volumeData.colorSpaceOperation = osg::NO_COLOR_SPACE_OPERATION;
1332         else if (operation=="MODULATE_ALPHA_BY_LUMINANCE") volumeData.colorSpaceOperation = osg::MODULATE_ALPHA_BY_LUMINANCE;
1333         else if (operation=="MODULATE_ALPHA_BY_COLOR") volumeData.colorSpaceOperation = osg::MODULATE_ALPHA_BY_COLOR;
1334         else if (operation=="REPLACE_ALPHA_WITH_LUMINANCE") volumeData.colorSpaceOperation = osg::REPLACE_ALPHA_WITH_LUMINANCE;
1335         else if (operation=="REPLACE_RGB_WITH_LUMINANCE") volumeData.colorSpaceOperation = osg::REPLACE_RGB_WITH_LUMINANCE;
1336     }
1337
1338
1339
1340     // check for any transfer function required
1341     std::string transferFunctionFile;
1342     if (getTrimmedProperty(cur, "tf", transferFunctionFile))
1343     {
1344         volumeData.transferFunction = readTransferFunctionFile(transferFunctionFile, 1.0);
1345     }
1346
1347     if (getTrimmedProperty(cur, "tf-255", transferFunctionFile))
1348     {
1349         volumeData.transferFunction = readTransferFunctionFile(transferFunctionFile, 1.0/255.0);
1350     }
1351
1352     if (getProperty(cur, "options", volumeData.options)) {}
1353
1354     // check for draggers required
1355     std::string dragger;
1356     if (getProperty(cur, "dragger", dragger))
1357     {
1358         if (dragger=="trackball")
1359         {
1360             volumeData.useTabbedDragger = false;
1361             volumeData.useTrackballDragger = true;
1362         }
1363         if (dragger=="trackball-box")
1364         {
1365             volumeData.useTabbedDragger = true;
1366             volumeData.useTrackballDragger = true;
1367         }
1368         else
1369         {
1370             volumeData.useTabbedDragger = true;
1371             volumeData.useTrackballDragger = false;
1372         }
1373     }
1374
1375     osgPresentation::SlideShowConstructor::ScriptData scriptData;
1376     getProperties(cur, scriptData);
1377
1378     std::string filename = cur->getTrimmedContents();
1379     if (!filename.empty())
1380     {
1381         constructor.addVolume(filename,
1382                              positionRead ? positionData : constructor.getModelPositionData(),
1383                              volumeData,
1384                              scriptData
1385                              );
1386     }
1387 }
1388
1389 void ReaderWriterP3DXML::parseStereoPair(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const
1390 {
1391
1392     OSG_INFO<<"ReaderWriterP3DXML::parseStereoPair()"<<std::endl;
1393
1394
1395     std::string filenameLeft;
1396     std::string filenameRight;
1397
1398     osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getImagePositionData();
1399     bool positionRead = getProperties(cur,positionData);
1400
1401     osgPresentation::SlideShowConstructor::ImageData imageDataLeft;// = constructor.getImageData();
1402     osgPresentation::SlideShowConstructor::ImageData imageDataRight;// = constructor.getImageData();
1403
1404     getProperties(cur,imageDataLeft);
1405     getProperties(cur,imageDataRight);
1406
1407     for(osgDB::XmlNode::Children::iterator itr = cur->children.begin();
1408         itr != cur->children.end();
1409         ++itr)
1410     {
1411         osgDB::XmlNode* child = itr->get();
1412
1413         if (child->name == "image_left")
1414         {
1415             getProperties(child,imageDataLeft);
1416             filenameLeft = child->getTrimmedContents();
1417         }
1418         else if (child->name == "imagesequence_left")
1419         {
1420             imageDataLeft.imageSequence = true;
1421             getProperties(child,imageDataLeft);
1422             filenameLeft = child->getTrimmedContents();
1423         }
1424         else if (child->name == "image_right")
1425         {
1426             getProperties(child,imageDataRight);
1427             filenameRight = child->getTrimmedContents();
1428
1429             getProperties(cur,imageDataRight);
1430         }
1431         else if (child->name == "imagesequence_right")
1432         {
1433             imageDataRight.imageSequence = true;
1434             getProperties(child,imageDataRight);
1435             filenameRight = child->getTrimmedContents();
1436         }
1437     }
1438
1439     osgPresentation::SlideShowConstructor::ScriptData scriptData;
1440     getProperties(cur, scriptData);
1441
1442     OSG_INFO<<"    filenameLeft="<<filenameLeft<<std::endl;
1443     OSG_INFO<<"    filenameRight="<<filenameRight<<std::endl;
1444
1445     if (!filenameLeft.empty() && !filenameRight.empty())
1446         constructor.addStereoImagePair(filenameLeft,imageDataLeft,
1447                                        filenameRight, imageDataRight,
1448                                        positionRead ? positionData : constructor.getImagePositionData(),
1449                                        scriptData);
1450
1451 }
1452
1453 bool ReaderWriterP3DXML::getKeyPosition(osgDB::XmlNode*cur, osgPresentation::KeyPosition& keyPosition) const
1454 {
1455     if (cur->name == "key")
1456     {
1457         return getKeyPositionInner(cur, keyPosition);
1458     }
1459     if (cur->name == "escape" ||
1460         cur->name == "esc" ||
1461         cur->name == "exit")
1462     {
1463         keyPosition.set(osgGA::GUIEventAdapter::KEY_Escape, 0.0f, 0.0f, false);
1464         return true;
1465     }
1466     return false;
1467 }
1468
1469 bool ReaderWriterP3DXML::getKeyPositionInner(osgDB::XmlNode*cur, osgPresentation::KeyPosition& keyPosition) const
1470 {
1471     // x in range -1 to 1, from left to right
1472     float x = FLT_MAX;
1473     getProperty(cur, "x", x);
1474
1475     // y in range -1 to 1, from bottom to top
1476     float y = FLT_MAX;
1477     getProperty(cur, "y", y);
1478
1479     float h = FLT_MAX;
1480     if (getProperty(cur, "h", h))
1481     {
1482         // h in range 0.0 to 1, from left to right
1483         x = h*2.0f-1.0f;
1484     }
1485
1486     float v = FLT_MAX;
1487     if (getProperty(cur, "v", v))
1488     {
1489         // v in range 0.0 to 1, from bottom to top
1490         y = v*2.0f-1.0f;
1491     }
1492
1493     bool forward_to_devices = false;
1494     getProperty(cur, "forward_to_devices", forward_to_devices);
1495
1496     std::string key = cur->getTrimmedContents();
1497     unsigned int keyValue = 0;
1498
1499     if (key.empty())
1500     {
1501         OSG_NOTICE<<"Warning: empty <key></key> is invalid, ignoring tag."<<std::endl;
1502         return false;
1503     }
1504
1505     StringKeyMap::const_iterator itr=_stringKeyMap.find(key);
1506     if (itr != _stringKeyMap.end())
1507     {
1508         keyValue = itr->second;
1509     }
1510     else if (key.find("0x",0,2)!=std::string::npos)
1511     {
1512         std::istringstream iss(key);
1513         iss>>std::hex>>keyValue;
1514         OSG_INFO<<"ReaderWriterP3DXML::getKeyPositionInner() hex result = "<<keyValue<<std::endl;
1515     }
1516     else if (key.size()>1 && (key[0]>='0' && key[0]<='9'))
1517     {
1518         std::istringstream iss(key);
1519         iss>>keyValue;
1520         OSG_INFO<<"ReaderWriterP3DXML::getKeyPositionInner() numeric result = "<<keyValue<<std::endl;
1521     }
1522     else if (key.length()==1)
1523     {
1524         OSG_INFO<<"ReaderWriterP3DXML::getKeyPositionInner() alphanumeric result = "<<keyValue<<std::endl;
1525         keyValue = key[0];
1526     }
1527     else
1528     {
1529         OSG_NOTICE<<"Warning: invalid key used in <key>"<<key<<"</key>, ignoring tag. key=["<<key<<"]"<<std::endl;
1530         return false;
1531     }
1532
1533     keyPosition.set(keyValue,x,y, forward_to_devices);
1534     return true;
1535 }
1536
1537
1538 void ReaderWriterP3DXML::parseTimeout(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode* root) const
1539 {
1540     osg::ref_ptr<osgPresentation::Timeout> timeout = new osgPresentation::Timeout(constructor.getHUDSettings());
1541
1542     // to allow the timeout to be nested with a Layer but still behave like a Layer itself we push the timeout as a Layer, saving the original Layer
1543     constructor.pushCurrentLayer(timeout.get());
1544
1545     OSG_NOTICE<<"parseTimeout"<<std::endl;
1546
1547     float totalIndent = 0.0f;
1548
1549     for(osgDB::XmlNode::Children::iterator itr = root->children.begin();
1550         itr != root->children.end();
1551         ++itr)
1552     {
1553         osgDB::XmlNode* cur = itr->get();
1554         if (parseLayerChild(constructor, cur, totalIndent))
1555         {
1556             // no need to do anything
1557         }
1558         else if (cur->name == "timeout_jump")
1559         {
1560             osgPresentation::JumpData jumpData;
1561             if (getJumpProperties(cur, jumpData))
1562             {
1563                 OSG_NOTICE<<"Timeout Jump "<<jumpData.relativeJump<<","<< jumpData.slideNum<<", "<<jumpData.layerNum<<std::endl;
1564                 timeout->setActionJumpData(jumpData);
1565             }
1566         }
1567         else if (cur->name == "timeout_event")
1568         {
1569             osgPresentation::KeyPosition keyPosition;
1570             if (getKeyPositionInner( cur, keyPosition))
1571             {
1572                 OSG_NOTICE<<"timeout event ["<<keyPosition._key<<"]"<<std::endl;
1573                 timeout->setActionKeyPosition(keyPosition);
1574             }
1575         }
1576         else if (cur->name == "display_broadcast_event")
1577         {
1578             osgPresentation::KeyPosition keyPosition;
1579             if (getKeyPositionInner( cur, keyPosition))
1580             {
1581                 OSG_NOTICE<<"display broadcast event ["<<keyPosition._key<<"]"<<std::endl;
1582                 timeout->setDisplayBroadcastKeyPosition(keyPosition);
1583             }
1584         }
1585         else if (cur->name == "dismiss_broadcast_event")
1586         {
1587             osgPresentation::KeyPosition keyPosition;
1588             if (getKeyPositionInner( cur, keyPosition))
1589             {
1590                 OSG_NOTICE<<"dismiss broadcast event ["<<keyPosition._key<<"]"<<std::endl;
1591                 timeout->setDismissBroadcastKeyPosition(keyPosition);
1592             }
1593         }
1594         else if (cur->name == "timeout_broadcast_event")
1595         {
1596             osgPresentation::KeyPosition keyPosition;
1597             if (getKeyPositionInner( cur, keyPosition))
1598             {
1599                 OSG_NOTICE<<"timeout broadcast event ["<<keyPosition._key<<"]"<<std::endl;
1600                 timeout->setActionBroadcastKeyPosition(keyPosition);
1601             }
1602         }
1603         else if (cur->name == "idle_duration_before_timeout_display")
1604         {
1605             std::istringstream iss(cur->getTrimmedContents());
1606             double duration;
1607             iss>>duration;
1608             if (!iss.fail())
1609             {
1610                 OSG_NOTICE<<"timeout->setIdleDurationBeforeTimeoutDisplay("<<duration<<")"<<std::endl;
1611                 timeout->setIdleDurationBeforeTimeoutDisplay(duration);
1612             }
1613         }
1614         else if (cur->name == "idle_duration_before_timeout_action")
1615         {
1616             std::istringstream iss(cur->getTrimmedContents());
1617             double duration;
1618             iss>>duration;
1619             if (!iss.fail())
1620             {
1621                 OSG_NOTICE<<"timeout->setIdleDurationBeforeTimeoutAction("<<duration<<")"<<std::endl;
1622                 timeout->setIdleDurationBeforeTimeoutAction(duration);
1623             }
1624         }
1625         else if (cur->name == "key_starts_timeout_display")
1626         {
1627             osgPresentation::KeyPosition keyPosition;
1628             if (getKeyPositionInner( cur, keyPosition) && keyPosition._key!=0)
1629             {
1630                 OSG_NOTICE<<"timeout->setKeyStartsTimoutDisplay("<<keyPosition._key<<")"<<std::endl;
1631                 timeout->setKeyStartsTimoutDisplay(keyPosition._key);
1632             }
1633         }
1634         else if (cur->name == "key_dismiss_timeout_display")
1635         {
1636             osgPresentation::KeyPosition keyPosition;
1637             if (getKeyPositionInner( cur, keyPosition) && keyPosition._key!=0)
1638             {
1639                 OSG_NOTICE<<"timeout->setKeyDismissTimoutDisplay("<<keyPosition._key<<")"<<std::endl;
1640                 timeout->setKeyDismissTimoutDisplay(keyPosition._key);
1641             }
1642         }
1643         else if (cur->name == "key_run_action")
1644         {
1645             osgPresentation::KeyPosition keyPosition;
1646             if (getKeyPositionInner( cur, keyPosition) && keyPosition._key!=0)
1647             {
1648                 OSG_NOTICE<<"timeout->setKeyRunTimoutAction("<<keyPosition._key<<")"<<std::endl;
1649                 timeout->setKeyRunTimoutAction(keyPosition._key);
1650             }
1651         }
1652
1653     }
1654
1655     constructor.popCurrentLayer(); // return the parent level
1656 }
1657
1658
1659 bool ReaderWriterP3DXML::parseLayerChild(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode* cur, float& totalIndent) const
1660 {
1661     if (cur->name == "newline")
1662     {
1663         constructor.translateTextCursor(osg::Vec3(0.0f,-0.05f,0.0f));
1664         return true;
1665     }
1666     else if (cur->name == "indent")
1667     {
1668         float localIndent = 0.05f;
1669         constructor.translateTextCursor(osg::Vec3(localIndent,0.0f,0.0f));
1670         totalIndent += localIndent;
1671         return true;
1672     }
1673     else if (cur->name == "unindent")
1674     {
1675         float localIndent = -0.05f;
1676         constructor.translateTextCursor(osg::Vec3(localIndent,0.0f,0.0f));
1677         totalIndent += localIndent;
1678         return true;
1679     }
1680     else if (cur->name == "bullet")
1681     {
1682         OSG_INFO<<"bullet ["<<cur->contents<<"]"<<std::endl;
1683         osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getTextPositionData();
1684         bool positionRead = getProperties(cur,positionData);
1685
1686         osgPresentation::SlideShowConstructor::FontData fontData = constructor.getTextFontData();
1687         bool fontRead = getProperties(cur,fontData);
1688
1689         osgPresentation::SlideShowConstructor::ScriptData scriptData;
1690         getProperties(cur, scriptData);
1691
1692         constructor.addBullet(cur->contents,
1693                                 positionRead ? positionData : constructor.getTextPositionData(),
1694                                 fontRead ? fontData : constructor.getTextFontData(),
1695                                 scriptData
1696                              );
1697         return true;
1698     }
1699     else if (cur->name == "paragraph")
1700     {
1701         osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getTextPositionData();
1702         bool positionRead = getProperties(cur,positionData);
1703
1704         osgPresentation::SlideShowConstructor::FontData fontData = constructor.getTextFontData();
1705         bool fontRead = getProperties(cur,fontData);
1706
1707         osgPresentation::SlideShowConstructor::ScriptData scriptData;
1708         getProperties(cur, scriptData);
1709
1710         constructor.addParagraph(cur->contents,
1711                                     positionRead ? positionData : constructor.getTextPositionData(),
1712                                     fontRead ? fontData : constructor.getTextFontData(),
1713                                     scriptData
1714                                 );
1715         return true;
1716     }
1717     else if (cur->name == "image")
1718     {
1719         osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getImagePositionData();
1720         bool positionRead = getProperties(cur,positionData);
1721
1722         osgPresentation::SlideShowConstructor::ImageData imageData;// = constructor.getImageData();
1723         getProperties(cur,imageData);
1724
1725         osgPresentation::SlideShowConstructor::ScriptData scriptData;
1726         getProperties(cur, scriptData);
1727
1728         constructor.addImage(cur->getTrimmedContents(),
1729                                 positionRead ? positionData : constructor.getImagePositionData(),
1730                                 imageData,
1731                                 scriptData
1732                             );
1733         return true;
1734     }
1735     else if (cur->name == "imagesequence")
1736     {
1737         osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getImagePositionData();
1738         bool positionRead = getProperties(cur,positionData);
1739
1740         osgPresentation::SlideShowConstructor::ImageData imageData;// = constructor.getImageData();
1741         imageData.imageSequence = true;
1742         getProperties(cur,imageData);
1743
1744         osgPresentation::SlideShowConstructor::ScriptData scriptData;
1745         getProperties(cur, scriptData);
1746
1747         constructor.addImage(cur->getTrimmedContents(),
1748                                 positionRead ? positionData : constructor.getImagePositionData(),
1749                                 imageData,
1750                                 scriptData
1751                             );
1752         return true;
1753     }
1754     else if (cur->name == "graph")
1755     {
1756         osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getImagePositionData();
1757         bool positionRead = getProperties(cur,positionData);
1758
1759         osgPresentation::SlideShowConstructor::ImageData imageData;// = constructor.getImageData();
1760         getProperties(cur,imageData);
1761
1762         std::string options;
1763         getProperty(cur, "options", options);
1764
1765         osgPresentation::SlideShowConstructor::ScriptData scriptData;
1766         getProperties(cur, scriptData);
1767
1768         constructor.addGraph(cur->getTrimmedContents(),
1769                                 positionRead ? positionData : constructor.getImagePositionData(),
1770                                 imageData,
1771                                 scriptData
1772                             );
1773         return true;
1774     }
1775     else if (cur->name == "vnc")
1776     {
1777         osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getImagePositionData();
1778         bool positionRead = getProperties(cur,positionData);
1779
1780         osgPresentation::SlideShowConstructor::ImageData imageData;// = constructor.getImageData();
1781         getProperties(cur,imageData);
1782
1783         std::string password;
1784         getProperty(cur, "password", password);
1785
1786         osgPresentation::SlideShowConstructor::ScriptData scriptData;
1787         getProperties(cur, scriptData);
1788
1789         constructor.addVNC(cur->getTrimmedContents(),
1790                                 positionRead ? positionData : constructor.getImagePositionData(),
1791                                 imageData,
1792                                 password,
1793                                 scriptData
1794                             );
1795         return true;
1796     }
1797     else if (cur->name == "browser")
1798     {
1799         osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getImagePositionData();
1800         bool positionRead = getProperties(cur,positionData);
1801
1802         osgPresentation::SlideShowConstructor::ImageData imageData;// = constructor.getImageData();
1803         getProperties(cur,imageData);
1804
1805         osgPresentation::SlideShowConstructor::ScriptData scriptData;
1806         getProperties(cur, scriptData);
1807
1808         constructor.addBrowser(cur->getTrimmedContents(),
1809                                 positionRead ? positionData : constructor.getImagePositionData(),
1810                                 imageData,
1811                                 scriptData);
1812         return true;
1813     }
1814     else if (cur->name == "pdf")
1815     {
1816         osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getImagePositionData();
1817         bool positionRead = getProperties(cur,positionData);
1818
1819         osgPresentation::SlideShowConstructor::ImageData imageData;// = constructor.getImageData();
1820         getProperties(cur,imageData);
1821
1822         osgPresentation::SlideShowConstructor::ScriptData scriptData;
1823         getProperties(cur, scriptData);
1824
1825         constructor.addPDF(cur->getTrimmedContents(),
1826                                 positionRead ? positionData : constructor.getImagePositionData(),
1827                                 imageData,
1828                                 scriptData
1829                           );
1830         return true;
1831     }
1832     else if (cur->name == "stereo_pair")
1833     {
1834         parseStereoPair(constructor, cur);
1835         return true;
1836     }
1837     else if (cur->name == "model")
1838     {
1839         parseModel(constructor, cur);
1840         return true;
1841     }
1842     else if (cur->name == "volume")
1843     {
1844         parseVolume(constructor, cur);
1845         return true;
1846     }
1847     else if (cur->name == "duration")
1848     {
1849         constructor.setLayerDuration(osg::asciiToDouble(cur->contents.c_str()));
1850         return true;
1851     }
1852     else if (cur->name == "property_animation")
1853     {
1854         osg::ref_ptr<osgPresentation::PropertyAnimation> pa = new osgPresentation::PropertyAnimation;
1855         if (parsePropertyAnimation(cur,*pa))
1856         {
1857             constructor.addPropertyAnimation(osgPresentation::SlideShowConstructor::CURRENT_LAYER, pa.get());
1858         }
1859         return true;
1860     }
1861     else if (cur->name == "properties")
1862     {
1863         if (!constructor.getCurrentLayer()) constructor.addLayer();
1864         if (constructor.getCurrentLayer())
1865         {
1866             osg::ref_ptr<osg::UserDataContainer> udc = constructor.getCurrentLayer()->getOrCreateUserDataContainer();
1867             if (parseProperties(cur, *udc))
1868             {
1869                 OSG_NOTICE<<"Assigned properties to Layer"<<std::endl;
1870             }
1871         }
1872         return true;
1873     }
1874
1875     return false;
1876 }
1877
1878
1879 void ReaderWriterP3DXML::parseSwitch(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const
1880 {
1881    osg::ref_ptr<osg::Switch> switchNode = new osg::Switch;;
1882
1883     // to allow the timeout to be nested with a Layer but still behave like a Layer itself we push the timeout as a Layer, saving the original Layer
1884     constructor.pushCurrentLayer(switchNode.get());
1885
1886     OSG_NOTICE<<"parseSwitch"<<std::endl;
1887
1888     parseLayer(constructor, cur);
1889
1890     switchNode->setSingleChildOn(0);
1891
1892     constructor.popCurrentLayer(); // return the parent level
1893 }
1894
1895 void ReaderWriterP3DXML::parseLayer(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode* root) const
1896 {
1897     OSG_INFO<<std::endl<<"parseLayer"<<std::endl;
1898
1899     float totalIndent = 0.0f;
1900
1901     osgPresentation::SlideShowConstructor::ScriptData scriptData;
1902     if (getProperties(root, scriptData))
1903     {
1904         for(osgPresentation::SlideShowConstructor::ScriptData::Scripts::iterator itr = scriptData.scripts.begin();
1905             itr != scriptData.scripts.end();
1906             ++itr)
1907         {
1908             constructor.addScriptCallback(osgPresentation::SlideShowConstructor::CURRENT_LAYER, itr->first, itr->second);
1909         }
1910     }
1911
1912     for(osgDB::XmlNode::Children::iterator itr = root->children.begin();
1913         itr != root->children.end();
1914         ++itr)
1915     {
1916         osgDB::XmlNode* cur = itr->get();
1917         if (parseLayerChild(constructor, cur, totalIndent))
1918         {
1919             // no need to do anything
1920         }
1921         else if (cur->name == "switch")
1922         {
1923             parseSwitch(constructor, cur);
1924         }
1925         else if (cur->name == "timeout")
1926         {
1927             parseTimeout(constructor, cur);
1928         }
1929         else if (cur->name == "run")
1930         {
1931             OSG_INFO<<"run ["<<cur->contents<<"]"<<std::endl;
1932             constructor.addLayerRunString(cur->contents);
1933         }
1934         else if (cur->name == "jump")
1935         {
1936             OSG_INFO<<"Parsed Jump "<<std::endl;
1937
1938             osgPresentation::JumpData jumpData;
1939             if (getJumpProperties(cur, jumpData))
1940             {
1941                 OSG_INFO<<"Layer Jump "<<jumpData.relativeJump<<","<< jumpData.slideNum<<", "<<jumpData.layerNum<<std::endl;
1942
1943                 constructor.setLayerJump(jumpData);
1944             }
1945         }
1946         else if (cur->name == "click_to_run")
1947         {
1948             osgPresentation::JumpData jumpData;
1949             getJumpProperties(cur, jumpData);
1950
1951             OSG_INFO<<"click_to_run ["<<cur->contents<<"]"<<std::endl;
1952             constructor.layerClickToDoOperation(cur->contents,osgPresentation::RUN, jumpData);
1953         }
1954         else if (cur->name == "forward_mouse_event_to_device")
1955         {
1956             osgPresentation::JumpData jumpData;
1957
1958             OSG_ALWAYS<<"forward_mouse_event_to_device ["<<cur->contents<<"]"<<std::endl;
1959             constructor.layerClickToDoOperation(cur->contents,osgPresentation::FORWARD_EVENT, jumpData);
1960         }
1961         else if (cur->name == "click_to_load")
1962         {
1963             osgPresentation::JumpData jumpData;
1964             getJumpProperties(cur, jumpData);
1965
1966             OSG_INFO<<"click_to_load ["<<cur->contents<<"]"<<std::endl;
1967             constructor.layerClickToDoOperation(cur->contents,osgPresentation::LOAD, jumpData);
1968         }
1969
1970         else if (cur->name == "click_to_event")
1971         {
1972             osgPresentation::JumpData jumpData;
1973             getJumpProperties(cur, jumpData);
1974
1975             osgPresentation::KeyPosition keyPosition;
1976             if (getKeyPositionInner( cur, keyPosition))
1977             {
1978                 OSG_INFO<<"click_to_event ["<<keyPosition._key<<"]"<<std::endl;
1979                 constructor.layerClickEventOperation(keyPosition, jumpData);
1980             }
1981         }
1982
1983         else if (cur->name == "click_to_jump")
1984         {
1985             osgPresentation::JumpData jumpData;
1986             getJumpProperties(cur, jumpData);
1987
1988             constructor.layerClickEventOperation(osgPresentation::JUMP, jumpData);
1989         }
1990
1991         else if (cur->name == "key_to_run")
1992         {
1993             int key;
1994             if (getKeyProperty(cur, "key", key))
1995             {
1996                 osgPresentation::JumpData jumpData;
1997                 getJumpProperties(cur, jumpData);
1998
1999                 OSG_NOTICE<<"key_to_run ["<<cur->contents<<"], key="<<key<<std::endl;
2000                 constructor.keyToDoOperation(osgPresentation::SlideShowConstructor::CURRENT_LAYER, key, cur->contents,osgPresentation::RUN, jumpData);
2001             }
2002         }
2003         else if (cur->name == "key_to_load")
2004         {
2005             int key;
2006             if (getKeyProperty(cur, "key", key))
2007             {
2008                 osgPresentation::JumpData jumpData;
2009                 getJumpProperties(cur, jumpData);
2010
2011                 OSG_NOTICE<<"key_to_load ["<<cur->contents<<"]"<<std::endl;
2012                 constructor.keyToDoOperation(osgPresentation::SlideShowConstructor::CURRENT_LAYER, key, cur->contents,osgPresentation::LOAD, jumpData);
2013             }
2014         }
2015
2016         else if (cur->name == "key_to_event")
2017         {
2018             int key;
2019             if (getKeyProperty(cur, "key", key))
2020             {
2021                 osgPresentation::JumpData jumpData;
2022                 getJumpProperties(cur, jumpData);
2023
2024                 osgPresentation::KeyPosition keyPosition;
2025                 if (getKeyPositionInner( cur, keyPosition))
2026                 {
2027                     OSG_NOTICE<<"key_to_event ["<<keyPosition._key<<"]"<<std::endl;
2028                     constructor.keyEventOperation(osgPresentation::SlideShowConstructor::CURRENT_LAYER, key, keyPosition, jumpData);
2029                 }
2030             }
2031         }
2032
2033         else if (cur->name == "key_to_jump")
2034         {
2035             int key;
2036             if (getKeyProperty(cur, "key", key))
2037             {
2038                 osgPresentation::JumpData jumpData;
2039                 getJumpProperties(cur, jumpData);
2040
2041                 OSG_NOTICE<<"key_to_jump"<<std::endl;
2042
2043                 constructor.keyEventOperation(osgPresentation::SlideShowConstructor::CURRENT_LAYER, key, osgPresentation::JUMP, jumpData);
2044             }
2045             else
2046             {
2047                 OSG_NOTICE<<"key_to_jump failed."<<std::endl;
2048             }
2049         }
2050         else
2051         {
2052             osgPresentation::KeyPosition keyPosition;
2053             if (getKeyPosition(cur, keyPosition))
2054             {
2055                 constructor.addLayerKey(keyPosition);
2056             }
2057         }
2058     }
2059
2060     if (totalIndent != 0.0f)
2061     {
2062         constructor.translateTextCursor(osg::Vec3(-totalIndent,0.0f,0.0f));
2063     }
2064
2065     std::string name;
2066     if (getProperty(root, "layer_name", name))
2067     {
2068         if (constructor.getCurrentLayer())
2069         {
2070             constructor.getCurrentLayer()->setUserValue("name",name);
2071             OSG_NOTICE<<"Setting current layers name "<<name<<std::endl;
2072         }
2073         else
2074         {
2075             OSG_NOTICE<<"getCurrentSlide() returns NULL, unable to set name "<<std::endl;
2076         }
2077     }
2078 }
2079
2080 void ReaderWriterP3DXML::parseBullets(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur, bool inheritPreviousLayers, bool defineAsBaseLayer) const
2081 {
2082     constructor.addLayer(inheritPreviousLayers, defineAsBaseLayer);
2083
2084     OSG_INFO<<"bullets ["<<cur->contents<<"]"<<std::endl;
2085     osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getTextPositionData();
2086     bool positionRead = getProperties(cur,positionData);
2087
2088     osgPresentation::SlideShowConstructor::FontData fontData = constructor.getTextFontData();
2089     bool fontRead = getProperties(cur,fontData);
2090
2091     osgPresentation::SlideShowConstructor::ScriptData scriptData;
2092     getProperties(cur,scriptData);
2093
2094     constructor.addBullet(cur->contents,
2095                             positionRead ? positionData : constructor.getTextPositionData(),
2096                             fontRead ? fontData : constructor.getTextFontData(),
2097                             scriptData
2098                          );
2099 }
2100
2101
2102 void ReaderWriterP3DXML::parseText(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur, bool inheritPreviousLayers, bool defineAsBaseLayer) const
2103 {
2104     constructor.addLayer(inheritPreviousLayers, defineAsBaseLayer);
2105
2106     OSG_INFO<<"text ["<<cur->contents<<"]"<<std::endl;
2107     osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getTextPositionData();
2108     bool positionRead = getProperties(cur,positionData);
2109
2110     osgPresentation::SlideShowConstructor::FontData fontData = constructor.getTextFontData();
2111     bool fontRead = getProperties(cur,fontData);
2112
2113     osgPresentation::SlideShowConstructor::ScriptData scriptData;
2114     getProperties(cur,scriptData);
2115
2116     constructor.addParagraph(cur->contents,
2117                             positionRead ? positionData : constructor.getTextPositionData(),
2118                             fontRead ? fontData : constructor.getTextFontData(),
2119                             scriptData
2120                             );
2121 }
2122
2123 void ReaderWriterP3DXML::parsePage(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const
2124 {
2125     constructor.addSlide();
2126
2127     std::string title;
2128     getProperty(cur, "title", title);
2129
2130     std::string inherit;
2131     getProperty(cur, "inherit", inherit);
2132
2133     if (!inherit.empty() && _templateMap.count(inherit)!=0)
2134     {
2135         parseSlide(constructor, _templateMap[inherit].get(), true, false);
2136     }
2137
2138     if (!title.empty())
2139     {
2140         constructor.setSlideTitle(title,
2141                                     constructor.getTitlePositionData(),
2142                                     constructor.getTitleFontData());
2143     }
2144
2145     if (!inherit.empty() && _templateMap.count(inherit)!=0)
2146     {
2147         parseSlide(constructor, _templateMap[inherit].get(), false, true);
2148     }
2149
2150     constructor.addLayer(true,false);
2151
2152     osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getTextPositionData();
2153     bool positionRead = getProperties(cur,positionData);
2154
2155     osgPresentation::SlideShowConstructor::FontData fontData = constructor.getTextFontData();
2156     bool fontRead = getProperties(cur,fontData);
2157
2158     osgPresentation::SlideShowConstructor::ScriptData scriptData;
2159     getProperties(cur, scriptData);
2160
2161     constructor.addParagraph(cur->contents,
2162                             positionRead ? positionData : constructor.getTextPositionData(),
2163                             fontRead ? fontData : constructor.getTextFontData(),
2164                             scriptData
2165                             );
2166 }
2167
2168 void ReaderWriterP3DXML::parsePdfDocument(osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode*cur) const
2169 {
2170     std::string title;
2171     getProperty(cur, "title", title);
2172
2173     std::string inherit;
2174     getProperty(cur, "inherit", inherit);
2175
2176     constructor.addSlide();
2177
2178     if (!inherit.empty() && _templateMap.count(inherit)!=0)
2179     {
2180         parseSlide(constructor, _templateMap[inherit].get(), true, false);
2181     }
2182
2183     if (!title.empty())
2184     {
2185         constructor.setSlideTitle(title,
2186                                     constructor.getTitlePositionData(),
2187                                     constructor.getTitleFontData());
2188     }
2189
2190     if (!inherit.empty() && _templateMap.count(inherit)!=0)
2191     {
2192         parseSlide(constructor, _templateMap[inherit].get(), false, true);
2193     }
2194
2195     constructor.addLayer(true,false);
2196
2197     osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getImagePositionData();
2198     getProperties(cur,positionData);
2199
2200     osgPresentation::SlideShowConstructor::ImageData imageData;// = constructor.getImageData();
2201     imageData.page = 0;
2202     getProperties(cur,imageData);
2203
2204     osgPresentation::SlideShowConstructor::ScriptData scriptData;
2205     getProperties(cur, scriptData);
2206
2207     osg::Image* image = constructor.addInteractiveImage(cur->contents, positionData, imageData, scriptData);
2208     osgWidget::PdfImage* pdfImage = dynamic_cast<osgWidget::PdfImage*>(image);
2209     if (pdfImage)
2210     {
2211         int numPages = pdfImage->getNumOfPages();
2212         OSG_INFO<<"NumOfPages = "<<numPages<<std::endl;
2213
2214         if (numPages>1)
2215         {
2216             for(int pageNum=1; pageNum<numPages; ++pageNum)
2217             {
2218                 imageData.page = pageNum;
2219
2220                 constructor.addSlide();
2221
2222                 if (!inherit.empty() && _templateMap.count(inherit)!=0)
2223                 {
2224                     parseSlide(constructor, _templateMap[inherit].get(), true, false);
2225                 }
2226
2227                 if (!title.empty())
2228                 {
2229                     constructor.setSlideTitle(title,
2230                                                 constructor.getTitlePositionData(),
2231                                                 constructor.getTitleFontData());
2232                 }
2233
2234                 if (!inherit.empty() && _templateMap.count(inherit)!=0)
2235                 {
2236                     parseSlide(constructor, _templateMap[inherit].get(), false, true);
2237                 }
2238
2239                 constructor.addLayer(true,false);
2240
2241                 constructor.addPDF(cur->getTrimmedContents(), positionData, imageData, scriptData);
2242
2243             }
2244         }
2245     }
2246 }
2247
2248 void ReaderWriterP3DXML::parseSlide (osgPresentation::SlideShowConstructor& constructor, osgDB::XmlNode* root, bool parseTitles, bool parseLayers) const
2249 {
2250
2251     osg::Vec4 previous_bgcolor = constructor.getBackgroundColor();
2252     osg::Vec4 previous_textcolor = constructor.getTextColor();
2253
2254     // create a keyPosition just in case we need it.
2255     osgPresentation::KeyPosition keyPosition;
2256
2257     osgPresentation::SlideShowConstructor::ScriptData scriptData;
2258     if (getProperties(root, scriptData))
2259     {
2260         for(osgPresentation::SlideShowConstructor::ScriptData::Scripts::iterator itr = scriptData.scripts.begin();
2261             itr != scriptData.scripts.end();
2262             ++itr)
2263         {
2264             constructor.addScriptCallback(osgPresentation::SlideShowConstructor::CURRENT_SLIDE, itr->first, itr->second);
2265         }
2266     }
2267
2268     for(osgDB::XmlNode::Children::iterator itr = root->children.begin();
2269         itr != root->children.end();
2270         ++itr)
2271     {
2272         osgDB::XmlNode* cur = itr->get();
2273
2274         if (parseTitles)
2275         {
2276             if (cur->name == "title")
2277             {
2278                 osgPresentation::SlideShowConstructor::PositionData positionData = constructor.getTitlePositionData();
2279                 bool positionRead = getProperties(cur,positionData);
2280
2281                 osgPresentation::SlideShowConstructor::FontData fontData = constructor.getTitleFontData();
2282                 bool fontRead = getProperties(cur,fontData);
2283
2284                 constructor.setSlideTitle(cur->contents,
2285                                           positionRead ? positionData : constructor.getTitlePositionData(),
2286                                           fontRead ? fontData : constructor.getTitleFontData());
2287             }
2288             else if (cur->name == "background")
2289             {
2290                 constructor.setSlideBackground(cur->contents);
2291
2292                 std::string str;
2293                 if (getProperty(cur, "hud", str))
2294                 {
2295                     bool hud = (str != "off" && str != "Off" && str != "OFF");
2296                     OSG_NOTIFY(_notifyLevel)<<"background hud, str="<<str<<", hud="<<hud<<std::endl;
2297                     constructor.setSlideBackgrondHUD(hud);
2298                 }
2299             }
2300             else if (cur->name == "bgcolor")
2301             {
2302                 constructor.setBackgroundColor(mapStringToColor(cur->contents),true);
2303             }
2304             else if (cur->name == "textcolor")
2305             {
2306                 constructor.setTextColor(mapStringToColor(cur->contents));
2307             }
2308         }
2309         if (parseLayers)
2310         {
2311             if (cur->name == "base")
2312             {
2313                 constructor.addLayer(true, true);
2314                 std::string inherit;
2315                 if (getProperty(cur, "inherit", inherit) && !inherit.empty() && _templateMap.count(inherit)!=0)
2316                 {
2317                     parseLayer(constructor, _templateMap[inherit].get());
2318                 }
2319                 parseLayer (constructor, cur);
2320
2321             }
2322             else if (cur->name == "layer")
2323             {
2324                 constructor.addLayer(true, false);
2325                 std::string inherit;
2326                 if (getProperty(cur, "inherit", inherit) && !inherit.empty() && _templateMap.count(inherit)!=0)
2327                 {
2328                     parseLayer(constructor, _templateMap[inherit].get());
2329                 }
2330
2331                 parseLayer (constructor, cur);
2332             }
2333             else if (cur->name == "clean_layer")
2334             {
2335                 constructor.addLayer(false, false);
2336                 std::string inherit;
2337                 if (getProperty(cur, "inherit", inherit) && !inherit.empty() && _templateMap.count(inherit)!=0)
2338                 {
2339                     parseLayer(constructor, _templateMap[inherit].get());
2340                 }
2341                 parseLayer (constructor, cur);
2342             }
2343             else if (cur->name == "modify_layer")
2344             {
2345                 int layerNum;
2346                 if (getProperty(cur, "layer", layerNum))
2347                 {
2348                     constructor.selectLayer(layerNum);
2349                 }
2350                 else
2351                 {
2352                     constructor.addLayer(true, false);
2353                 }
2354
2355                 parseLayer (constructor, cur);
2356             }
2357             else if (cur->name == "bullets")
2358             {
2359                 parseBullets (constructor, cur,true, false);
2360             }
2361             else if (cur->name == "duration")
2362             {
2363                 constructor.setSlideDuration(osg::asciiToDouble(cur->contents.c_str()));
2364             }
2365             else if (cur->name == "property_animation")
2366             {
2367                 osg::ref_ptr<osgPresentation::PropertyAnimation> pa = new osgPresentation::PropertyAnimation;
2368                 if (parsePropertyAnimation(cur,*pa))
2369                 {
2370                     constructor.addPropertyAnimation(osgPresentation::SlideShowConstructor::CURRENT_SLIDE, pa.get());
2371                 }
2372             }
2373             else if (cur->name == "properties")
2374             {
2375                 if (!constructor.getCurrentSlide()) constructor.addSlide();
2376                 if (constructor.getCurrentSlide())
2377                 {
2378                     osg::ref_ptr<osg::UserDataContainer> udc = constructor.getCurrentSlide()->getOrCreateUserDataContainer();
2379                     if (parseProperties(cur, *udc))
2380                     {
2381                         OSG_NOTICE<<"Assigned properties to Slide"<<std::endl;
2382                     }
2383                 }
2384             }
2385             else if (getKeyPosition(cur, keyPosition))
2386             {
2387                 constructor.addSlideKey(keyPosition);
2388             }
2389         }
2390     }
2391
2392     std::string name;
2393     if (getProperty(root, "slide_name", name))
2394     {
2395         if (constructor.getCurrentSlide())
2396         {
2397             constructor.getCurrentSlide()->setUserValue("name",name);
2398             OSG_NOTICE<<"Setting current slide name "<<name<<std::endl;
2399         }
2400         else
2401         {
2402             OSG_NOTICE<<"getCurrentSlide() returns NULL, unable to set name "<<std::endl;
2403         }
2404     }
2405
2406     constructor.setBackgroundColor(previous_bgcolor,false);
2407     constructor.setTextColor(previous_textcolor);
2408
2409     return;
2410 }
2411
2412 #include <iostream>
2413
2414
2415 struct MyFindFileCallback : public osgDB::FindFileCallback
2416 {
2417     virtual std::string findDataFile(const std::string& filename, const osgDB::Options* options, osgDB::CaseSensitivity caseSensitivity)
2418     {
2419         OSG_INFO<<std::endl<<std::endl<<"find file "<<filename<<std::endl;
2420
2421         const osgDB::FilePathList& paths = options ? options->getDatabasePathList() : osgDB::getDataFilePathList();
2422
2423         for(osgDB::FilePathList::const_iterator itr = paths.begin();
2424             itr != paths.end();
2425             ++itr)
2426         {
2427             const std::string& path = *itr;
2428             std::string newpath = osgDB::concatPaths(path, filename);
2429             if (osgDB::containsServerAddress(path))
2430             {
2431                 osgDB::ReaderWriter* rw = osgDB::Registry::instance()->getReaderWriterForExtension("curl");
2432                 OSG_INFO<<"  file on server "<<*itr<<", try path "<<newpath<<std::endl;
2433                 OSG_INFO<<"  we have curl rw= "<<rw<<std::endl;
2434                 if (rw && rw->fileExists(newpath, options))
2435                 {
2436                     OSG_INFO<<"  FOUND on server "<<newpath<<std::endl;
2437                     return newpath;
2438                 }
2439             }
2440             else
2441             {
2442                 if(osgDB::fileExists(newpath))
2443                 {
2444                     OSG_INFO<<" FOUND "<<newpath<<std::endl;
2445                     return newpath;
2446                 }
2447             }
2448         }
2449
2450         return osgDB::Registry::instance()->findDataFileImplementation(filename, options, caseSensitivity);
2451     }
2452 };
2453
2454 class MyReadFileCallback : public virtual osgDB::ReadFileCallback
2455 {
2456     public:
2457
2458         osgDB::FilePathList _paths;
2459
2460         typedef std::map< std::string, osg::ref_ptr<osg::Object> >  ObjectCache;
2461
2462         enum ObjectType
2463         {
2464             OBJECT,
2465             IMAGE,
2466             HEIGHT_FIELD,
2467             NODE,
2468             SHADER
2469         };
2470
2471         osgDB::ReaderWriter::ReadResult readLocal(ObjectType type, const std::string& filename, const osgDB::Options* options)
2472         {
2473             OSG_INFO<<"Trying local file "<<filename<<std::endl;
2474
2475             switch(type)
2476             {
2477                 case(OBJECT): return osgDB::Registry::instance()->readObjectImplementation(filename,options);
2478                 case(IMAGE): return osgDB::Registry::instance()->readImageImplementation(filename,options);
2479                 case(HEIGHT_FIELD): return osgDB::Registry::instance()->readHeightFieldImplementation(filename,options);
2480                 case(NODE): return osgDB::Registry::instance()->readNodeImplementation(filename,options);
2481                 case(SHADER): return osgDB::Registry::instance()->readShaderImplementation(filename,options);
2482             }
2483             return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
2484         }
2485
2486
2487         osgDB::ReaderWriter::ReadResult readFileCache(ObjectType type, const std::string& filename, const osgDB::Options* options)
2488         {
2489
2490             osgDB::FileCache* fileCache = options ? options->getFileCache() : 0;
2491             if (!fileCache) fileCache = osgDB::Registry::instance()->getFileCache();
2492             if (!fileCache) return osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND;
2493
2494             OSG_INFO<<"Trying fileCache "<<filename<<std::endl;
2495
2496             osgDB::ReaderWriter::ReadResult result;
2497             if (fileCache && fileCache->isFileAppropriateForFileCache(filename))
2498             {
2499                 if (fileCache->existsInCache(filename))
2500                 {
2501                     switch(type)
2502                     {
2503                         case(OBJECT):
2504                             result = fileCache->readObject(filename, 0);
2505                             break;
2506                         case(IMAGE):
2507                             result = fileCache->readImage(filename, 0);
2508                             break;
2509                         case(HEIGHT_FIELD):
2510                             result = fileCache->readHeightField(filename, 0);
2511                             break;
2512                         case(NODE):
2513                             result = fileCache->readNode(filename,0);
2514                             break;
2515                         case(SHADER):
2516                             result = fileCache->readShader(filename, 0);
2517                             break;
2518                     }
2519
2520                     if (result.success())
2521                     {
2522                         OSG_INFO<<"   File read from FileCache."<<std::endl;
2523                         return result;
2524                     }
2525
2526                     OSG_INFO<<"   File in FileCache, but not successfully read"<<std::endl;
2527                 }
2528                 else
2529                 {
2530                     OSG_INFO<<"   File does not exist in FileCache: "<<fileCache->createCacheFileName(filename)<<std::endl;
2531                 }
2532             }
2533
2534             return osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND;
2535
2536         }
2537
2538         osgDB::ReaderWriter::ReadResult readServer(ObjectType type, const std::string& filename, const osgDB::Options* options)
2539         {
2540             OSG_INFO<<"Trying server file "<<filename<<std::endl;
2541
2542             osgDB::ReaderWriter::ReadResult result;
2543
2544             // get a specific readerwriter capable of handling the protocol and extension, will return a registered fallback readerwriter for extension '*'
2545             osgDB::ReaderWriter* rw = osgDB::Registry::instance()->getReaderWriterForProtocolAndExtension(
2546                 osgDB::getServerProtocol(filename),
2547                 osgDB::getFileExtension(filename));
2548
2549             if (!rw) return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
2550
2551             switch(type)
2552             {
2553                 case(OBJECT):
2554                     result = rw->readObject(filename,options);
2555                     break;
2556                 case(IMAGE):
2557                     result = rw->readImage(filename,options);
2558                     break;
2559                 case(HEIGHT_FIELD):
2560                     result = rw->readHeightField(filename,options);
2561                     break;
2562                 case(NODE):
2563                     result = rw->readNode(filename,options);
2564                     break;
2565                 case(SHADER):
2566                     result = rw->readShader(filename,options);
2567                     break;
2568             }
2569
2570             if (result.success())
2571             {
2572                 osgDB::FileCache* fileCache = options ? options->getFileCache() : 0;
2573                 if (!fileCache) fileCache = osgDB::Registry::instance()->getFileCache();
2574
2575                 if (fileCache && fileCache->isFileAppropriateForFileCache(filename))
2576                 {
2577                     switch(type)
2578                     {
2579                         case(OBJECT):
2580                             fileCache->writeObject(*result.getObject(),filename,options);
2581                             break;
2582                         case(IMAGE):
2583                             result.getImage()->setFileName(filename);
2584                             fileCache->writeImage(*result.getImage(),filename,options);
2585                             break;
2586                         case(HEIGHT_FIELD):
2587                             fileCache->writeHeightField(*result.getHeightField(),filename,options);
2588                             break;
2589                         case(NODE):
2590                             fileCache->writeNode(*result.getNode(),filename,options);
2591                             break;
2592                         case(SHADER):
2593                             fileCache->writeShader(*result.getShader(),filename,options);
2594                             break;
2595                     }
2596                 }
2597
2598                 return result;
2599             }
2600             return osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND;
2601         }
2602
2603
2604         osgDB::ReaderWriter::ReadResult read(const osgDB::FilePathList& filePathList, ObjectType type, const std::string& filename, const osgDB::Options* options, bool checkLocalFiles)
2605         {
2606             // go look in http paths
2607             for(osgDB::FilePathList::const_iterator itr = filePathList.begin();
2608                 itr != filePathList.end();
2609                 ++itr)
2610             {
2611                 const std::string& path = *itr;
2612                 std::string newpath = osgDB::containsServerAddress(filename) ? filename : path.empty() ? filename : osgDB::concatPaths(path, filename);
2613                 osgDB::ReaderWriter::ReadResult result;
2614                 if (osgDB::containsServerAddress(newpath))
2615                 {
2616                     if (checkLocalFiles) result = readFileCache(type, newpath, options);
2617                     else result = readServer(type, newpath, options);
2618                 }
2619                 else if (checkLocalFiles && osgDB::fileExists(newpath))
2620                 {
2621                     result = readLocal(type, newpath, options);
2622                 }
2623
2624                 if (result.success())
2625                 {
2626                     OSG_INFO<<"   inserting object into file cache "<<filename<<", "<<result.getObject()<<std::endl;
2627                     _objectCache[filename] = result.getObject();
2628
2629                     options->setPluginStringData("filename",newpath);
2630                     return result;
2631                 }
2632             }
2633             return osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND;
2634         }
2635
2636         osgDB::ReaderWriter::ReadResult read(ObjectType type, const std::string& filename, const osgDB::Options* options)
2637         {
2638             osgDB::FileCache* fileCache = options ? options->getFileCache() : 0;
2639             if (!fileCache) fileCache = osgDB::Registry::instance()->getFileCache();
2640             if (fileCache && !fileCache->isFileAppropriateForFileCache(filename)) fileCache = 0;
2641
2642             OSG_INFO<<"MyReadFileCallback::reading file "<<filename<<std::endl;
2643             ObjectCache::iterator itr = _objectCache.find(filename);
2644             if (itr != _objectCache.end())
2645             {
2646                 // object is in cache, just retrieve it.
2647                 if (itr->second.valid())
2648                 {
2649                     OSG_INFO<<"File retrieved from cache, filename="<<filename<<std::endl;
2650                     return itr->second.get();
2651                 }
2652                 else
2653                 {
2654                     OSG_INFO<<"File failed to load previously, won't attempt a second time "<<filename<<std::endl;
2655                     return osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND;
2656                 }
2657             }
2658
2659             OSG_INFO<<"   MyReadFileCallback::reading file A"<<filename<<std::endl;
2660
2661             {
2662                 bool checkLocalFiles = true;
2663                 osgDB::ReaderWriter::ReadResult result = read(_paths, type, filename, options, checkLocalFiles);
2664                 if (result.success()) return result;
2665
2666                 if (options && !(options->getDatabasePathList().empty()))
2667                 {
2668                     result = read(options->getDatabasePathList(), type, filename, options, checkLocalFiles);
2669                     if (result.success()) return result;
2670                 }
2671
2672                 result = read(osgDB::Registry::instance()->getDataFilePathList(), type, filename, options, checkLocalFiles);
2673                 if (result.success()) return result;
2674             }
2675
2676             OSG_INFO<<"   MyReadFileCallback::reading file B"<<filename<<std::endl;
2677
2678             {
2679                 bool checkLocalFiles = false;
2680                 osgDB::ReaderWriter::ReadResult result = read(_paths, type, filename, options, checkLocalFiles);
2681                 if (result.success()) return result;
2682
2683                 if (options && !(options->getDatabasePathList().empty()))
2684                 {
2685                     result = read(options->getDatabasePathList(), type, filename, options, checkLocalFiles);
2686                     if (result.success()) return result;
2687                 }
2688
2689                 result = read(osgDB::Registry::instance()->getDataFilePathList(), type, filename, options, checkLocalFiles);
2690                 if (result.success()) return result;
2691             }
2692
2693             OSG_INFO<<"   MyReadFileCallback::reading file C"<<filename<<std::endl;
2694
2695             _objectCache[filename] = 0;
2696
2697             return osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND;
2698         }
2699
2700         virtual osgDB::ReaderWriter::ReadResult readObject(const std::string& filename, const osgDB::Options* options)
2701         {
2702             return read(OBJECT, filename, options);
2703         }
2704
2705         virtual osgDB::ReaderWriter::ReadResult readImage(const std::string& filename, const osgDB::Options* options)
2706         {