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