1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2  *
3  * This library is open source and may be redistributed and/or modified under
4  * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5  * (at your option) any later version.  The full license is in LICENSE file
6  * included with this distribution, and on the openscenegraph.org website.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * OpenSceneGraph Public License for more details.
12 */
13 
14 #include <osgPresentation/Timeout>
15 #include <osgUtil/CullVisitor>
16 #include <osgGA/EventVisitor>
17 
18 using namespace osgPresentation;
19 
20 
21 class OperationVisitor : public osg::NodeVisitor
22 {
23 public:
24 
25     enum Operation
26     {
27         ENTER,
28         LEAVE,
29         RESET
30     };
31 
OperationVisitor(Operation op)32     OperationVisitor(Operation op) : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), _operation(op), _sleepTime(0.0) {}
33 
apply(osg::Node & node)34     void apply(osg::Node& node)
35     {
36         if (node.getStateSet()) process(node.getStateSet());
37         traverse(node);
38     }
39 
apply(osg::Geode & geode)40     void apply(osg::Geode& geode)
41     {
42         apply(static_cast<osg::Node&>(geode));
43 
44         for(unsigned int i=0;i<geode.getNumDrawables();++i)
45         {
46             osg::Drawable* drawable = geode.getDrawable(i);
47             if (drawable->getStateSet()) process(drawable->getStateSet());
48         }
49     }
50 
process(osg::StateSet * ss)51     virtual void process(osg::StateSet* ss)
52     {
53         for(unsigned int i=0;i<ss->getTextureAttributeList().size();++i)
54         {
55             osg::Texture* texture = dynamic_cast<osg::Texture*>(ss->getTextureAttribute(i,osg::StateAttribute::TEXTURE));
56             osg::Image* image = texture ? texture->getImage(0) : 0;
57             osg::ImageStream* imageStream = dynamic_cast<osg::ImageStream*>(image);
58             if (imageStream) process(imageStream);
59         }
60     }
61 
process(osg::ImageStream * video)62     void process(osg::ImageStream* video)
63     {
64         if (_operation==ENTER)
65         {
66             video->rewind();
67             video->play();
68 
69             _sleepTime = 0.2;
70         }
71         else if (_operation==LEAVE)
72         {
73             video->pause();
74         }
75         else if (_operation==RESET)
76         {
77             video->rewind();
78 
79             _sleepTime = 0.2;
80         }
81     }
82 
sleepTime() const83     double sleepTime() const { return _sleepTime; }
84 
85     Operation   _operation;
86     double      _sleepTime;
87 };
88 
89 
HUDSettings(double slideDistance,float eyeOffset,unsigned int leftMask,unsigned int rightMask)90 HUDSettings::HUDSettings(double slideDistance, float eyeOffset, unsigned int leftMask, unsigned int rightMask):
91     _slideDistance(slideDistance),
92     _eyeOffset(eyeOffset),
93     _leftMask(leftMask),
94     _rightMask(rightMask)
95 {
96 }
97 
~HUDSettings()98 HUDSettings::~HUDSettings()
99 {
100 }
101 
getModelViewMatrix(osg::Matrix & matrix,osg::NodeVisitor * nv) const102 bool HUDSettings::getModelViewMatrix(osg::Matrix& matrix, osg::NodeVisitor* nv) const
103 {
104     matrix.makeLookAt(osg::Vec3d(0.0,0.0,0.0),osg::Vec3d(0.0,_slideDistance,0.0),osg::Vec3d(0.0,0.0,1.0));
105 
106     if (nv)
107     {
108         if (nv->getTraversalMask()==_leftMask)
109         {
110             matrix.postMultTranslate(osg::Vec3(_eyeOffset,0.0,0.0));
111         }
112         else if (nv->getTraversalMask()==_rightMask)
113         {
114             matrix.postMultTranslate(osg::Vec3(-_eyeOffset,0.0,0.0));
115         }
116     }
117 
118     return true;
119 }
120 
getInverseModelViewMatrix(osg::Matrix & matrix,osg::NodeVisitor * nv) const121 bool HUDSettings::getInverseModelViewMatrix(osg::Matrix& matrix, osg::NodeVisitor* nv) const
122 {
123     osg::Matrix modelView;
124     getModelViewMatrix(modelView,nv);
125     matrix.invert(modelView);
126     return true;
127 }
128 
129 
130 
131 
Timeout(HUDSettings * hudSettings)132 Timeout::Timeout(HUDSettings* hudSettings):
133     _previousFrameNumber(-1),
134     _timeOfLastEvent(0.0),
135     _displayTimeout(false),
136     _idleDurationBeforeTimeoutDisplay(DBL_MAX),
137     _idleDurationBeforeTimeoutAction(DBL_MAX),
138     _keyStartsTimoutDisplay(0),
139     _keyDismissTimoutDisplay(0),
140     _keyRunTimeoutAction(0)
141 {
142     _hudSettings = hudSettings;
143     setCullingActive(false);
144     setNumChildrenRequiringEventTraversal(1);
145 }
146 
147 /** Copy constructor using CopyOp to manage deep vs shallow copy.*/
Timeout(const Timeout & timeout,const osg::CopyOp & copyop)148 Timeout::Timeout(const Timeout& timeout,const osg::CopyOp& copyop):
149     osg::Transform(timeout, copyop),
150     _hudSettings(timeout._hudSettings)
151 {
152     setDataVariance(osg::Object::DYNAMIC);
153     setReferenceFrame(osg::Transform::ABSOLUTE_RF);
154 }
155 
~Timeout()156 Timeout::~Timeout()
157 {
158 }
159 
computeLocalToWorldMatrix(osg::Matrix & matrix,osg::NodeVisitor * nv) const160 bool Timeout::computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const
161 {
162     if (_hudSettings.valid()) return _hudSettings->getModelViewMatrix(matrix,nv);
163     else return false;
164 }
165 
computeWorldToLocalMatrix(osg::Matrix & matrix,osg::NodeVisitor * nv) const166 bool Timeout::computeWorldToLocalMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const
167 {
168     if (_hudSettings.valid()) return _hudSettings->getInverseModelViewMatrix(matrix,nv);
169     else return false;
170 }
171 
broadcastEvent(osgViewer::Viewer * viewer,const osgPresentation::KeyPosition & keyPos)172 void Timeout::broadcastEvent(osgViewer::Viewer* viewer, const osgPresentation::KeyPosition& keyPos)
173 {
174     osg::ref_ptr<osgGA::GUIEventAdapter> event = new osgGA::GUIEventAdapter;
175 
176     if (keyPos._key!=0) event->setEventType(osgGA::GUIEventAdapter::KEYDOWN);
177     else event->setEventType(osgGA::GUIEventAdapter::MOVE);
178 
179     if (keyPos._key!=0) event->setKey(keyPos._key);
180     if (keyPos._x!=FLT_MAX) event->setX(keyPos._x);
181     if (keyPos._y!=FLT_MAX) event->setY(keyPos._y);
182 
183     event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS);
184 
185     // dispatch cloned event to devices
186     osgViewer::View::Devices& devices = viewer->getDevices();
187     for(osgViewer::View::Devices::iterator i = devices.begin(); i != devices.end(); ++i)
188     {
189         if((*i)->getCapabilities() & osgGA::Device::SEND_EVENTS)
190         {
191             (*i)->sendEvent(*event);
192         }
193     }
194 }
traverse(osg::NodeVisitor & nv)195 void Timeout::traverse(osg::NodeVisitor& nv)
196 {
197     if (nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR)
198     {
199         osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);
200         if (_displayTimeout && cv)
201         {
202             osgUtil::RenderStage* previous_stage = cv->getCurrentRenderBin()->getStage();
203 
204             osg::ref_ptr<osgUtil::RenderStage> rs = new osgUtil::RenderStage;
205 
206             osg::ColorMask* colorMask = previous_stage->getColorMask();
207             rs->setColorMask(colorMask);
208 
209             // set up the viewport.
210             osg::Viewport* viewport = previous_stage->getViewport();
211             rs->setViewport( viewport );
212 
213             rs->setClearMask(GL_DEPTH_BUFFER_BIT);
214 
215             // record the render bin, to be restored after creation
216             // of the render to text
217             osgUtil::RenderBin* previousRenderBin = cv->getCurrentRenderBin();
218 
219             // set the current renderbin to be the newly created stage.
220             cv->setCurrentRenderBin(rs.get());
221 
222             // traverse the subgraph
223             {
224                 Transform::traverse(nv);
225             }
226 
227             // restore the previous renderbin.
228             cv->setCurrentRenderBin(previousRenderBin);
229 
230             // and the render to texture stage to the current stages
231             // dependency list.
232             cv->getCurrentRenderBin()->getStage()->addPostRenderStage(rs.get(),0);
233         }
234     }
235     else if (nv.getVisitorType()==osg::NodeVisitor::EVENT_VISITOR)
236     {
237         int deltaFrameNumber = (nv.getFrameStamp()->getFrameNumber()-_previousFrameNumber);
238         _previousFrameNumber = nv.getFrameStamp()->getFrameNumber();
239 
240         bool needToRecordEventTime = false;
241         bool needToAction = false;
242 
243         if (deltaFrameNumber>1)
244         {
245             needToRecordEventTime = true;
246         }
247 
248         bool previous_displayTimeout = _displayTimeout;
249         bool needToDismiss = false;
250 
251         osgGA::EventVisitor* ev = dynamic_cast<osgGA::EventVisitor*>(&nv);
252         osgViewer::Viewer* viewer = ev ? dynamic_cast<osgViewer::Viewer*>(ev->getActionAdapter()) : 0;
253         if (ev)
254         {
255             osgGA::EventQueue::Events& events = ev->getEvents();
256             for(osgGA::EventQueue::Events::iterator itr = events.begin();
257                 itr != events.end();
258                 ++itr)
259             {
260                 osgGA::GUIEventAdapter* event = (*itr)->asGUIEventAdapter();
261                 if (!event) continue;
262 
263                 bool keyEvent = event->getEventType()==osgGA::GUIEventAdapter::KEYDOWN ||  event->getEventType()==osgGA::GUIEventAdapter::KEYUP;
264 
265                 if (keyEvent && event->getKey()==_keyStartsTimoutDisplay)
266                 {
267                     OSG_NOTICE<<"_keyStartsTimoutDisplay pressed"<<std::endl;
268                     _displayTimeout = true;
269                 }
270                 else if (keyEvent && event->getKey()==_keyDismissTimoutDisplay)
271                 {
272                     OSG_NOTICE<<"_keyDismissTimoutDisplay pressed"<<std::endl;
273                     needToRecordEventTime = true;
274                     needToDismiss = _displayTimeout;
275                     _displayTimeout = false;
276                 }
277                 else if (keyEvent && event->getKey()==_keyRunTimeoutAction)
278                 {
279                     OSG_NOTICE<<"_keyRunTimeoutAction pressed"<<std::endl;
280                     _displayTimeout = false;
281                     needToRecordEventTime = true;
282                     needToAction = true;
283                 }
284                 else if (event->getEventType()!=osgGA::GUIEventAdapter::FRAME)
285                 {
286                     needToRecordEventTime = true;
287                     needToDismiss = _displayTimeout;
288                     _displayTimeout = false;
289                 }
290             }
291         }
292 
293 
294         if (needToRecordEventTime)
295         {
296             _timeOfLastEvent = nv.getFrameStamp()->getReferenceTime();
297         }
298 
299         double timeSinceLastEvent = nv.getFrameStamp() ? nv.getFrameStamp()->getReferenceTime()-_timeOfLastEvent : 0.0;
300 
301         if (timeSinceLastEvent>_idleDurationBeforeTimeoutDisplay)
302         {
303             _displayTimeout = true;
304         }
305 
306         if (timeSinceLastEvent>_idleDurationBeforeTimeoutAction)
307         {
308             _displayTimeout = false;
309             needToAction = true;
310             needToDismiss = false;
311         }
312 
313         if (!previous_displayTimeout && _displayTimeout)
314         {
315             if (viewer && (_displayBroadcastKeyPos._key!=0 || _displayBroadcastKeyPos._x!=FLT_MAX || _displayBroadcastKeyPos._y!=FLT_MAX))
316             {
317                 OSG_NOTICE<<"Doing display broadcast key event"<<_displayBroadcastKeyPos._key<<std::endl;
318                 broadcastEvent(viewer, _displayBroadcastKeyPos);
319             }
320 
321             OperationVisitor leave(OperationVisitor::ENTER);
322             accept(leave);
323 
324             if (leave.sleepTime()!=0.0)
325             {
326                 OSG_NOTICE<<"Pausing for "<<leave.sleepTime()<<std::endl;
327                 OpenThreads::Thread::microSleep(static_cast<unsigned int>(1000000.0*leave.sleepTime()));
328                 OSG_NOTICE<<"Finished Pause "<<std::endl;
329             }
330 
331         }
332 
333 
334         if (needToDismiss)
335         {
336             if (viewer && (_dismissBroadcastKeyPos._key!=0 || _dismissBroadcastKeyPos._x!=FLT_MAX || _dismissBroadcastKeyPos._y!=FLT_MAX))
337             {
338                 OSG_NOTICE<<"Doing dismiss broadcast key event"<<_dismissBroadcastKeyPos._key<<std::endl;
339                 broadcastEvent(viewer, _dismissBroadcastKeyPos);
340             }
341 
342             OperationVisitor leave(OperationVisitor::LEAVE);
343             accept(leave);
344         }
345 
346         Transform::traverse(nv);
347 
348 
349         if (needToAction)
350         {
351             OSG_NOTICE<<"Do timeout action"<<std::endl;
352             _previousFrameNumber = -1;
353             _timeOfLastEvent = nv.getFrameStamp()->getReferenceTime();
354 
355 
356             if (_actionJumpData.requiresJump())
357             {
358                 OSG_NOTICE<<"Doing timeout jump"<<std::endl;
359                 _actionJumpData.jump(SlideEventHandler::instance());
360             }
361 
362             if (_actionKeyPos._key!=0 || _actionKeyPos._x!=FLT_MAX || _actionKeyPos._y!=FLT_MAX)
363             {
364                 OSG_NOTICE<<"Doing timeout key event"<<_actionKeyPos._key<<std::endl;
365                 if (SlideEventHandler::instance()) SlideEventHandler::instance()->dispatchEvent(_actionKeyPos);
366             }
367 
368             if (viewer && (_actionBroadcastKeyPos._key!=0 || _actionBroadcastKeyPos._x!=FLT_MAX || _actionBroadcastKeyPos._y!=FLT_MAX))
369             {
370                 OSG_NOTICE<<"Doing timeout broadcast key event"<<_actionBroadcastKeyPos._key<<std::endl;
371                 broadcastEvent(viewer, _actionBroadcastKeyPos);
372             }
373 
374         }
375 
376     }
377     else if (nv.getVisitorType()==osg::NodeVisitor::UPDATE_VISITOR)
378     {
379         if (_displayTimeout) Transform::traverse(nv);
380     }
381     else
382     {
383         if (strcmp(nv.className(),"FindOperatorsVisitor")==0)
384         {
385             OSG_NOTICE<<"Timout::traverse() "<<nv.className()<<", ignoring traversal"<<std::endl;
386         }
387         else
388         {
389             Transform::traverse(nv);
390         }
391     }
392 
393 
394 
395 }
396