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 <osgPresentation/PickEventHandler>
14 #include <osgPresentation/SlideEventHandler>
15 
16 #include <osgViewer/Viewer>
17 #include <osg/Notify>
18 #include <osgDB/FileUtils>
19 #include <osg/io_utils>
20 
21 #include <stdlib.h>
22 
23 using namespace osgPresentation;
24 
25 PickEventHandler::PickEventHandler(osgPresentation::Operation operation, const JumpData& jumpData):
26     _operation(operation),
27     _jumpData(jumpData),
28     _drawablesOnPush()
29 {
30     OSG_INFO<<"PickEventHandler::PickEventHandler(operation="<<operation<<", jumpData.relativeJump="<<jumpData.relativeJump<<", jumpData.="<<jumpData.slideNum<<", jumpData.layerNum="<<jumpData.layerNum<<std::endl;
31 }
32 
33 PickEventHandler::PickEventHandler(const std::string& str, osgPresentation::Operation operation, const JumpData& jumpData):
34     _command(str),
35     _operation(operation),
36     _jumpData(jumpData),
37     _drawablesOnPush()
38 {
39     OSG_INFO<<"PickEventHandler::PickEventHandler(str="<<str<<", operation="<<operation<<", jumpData.relativeJump="<<jumpData.relativeJump<<", jumpData.="<<jumpData.slideNum<<", jumpData.layerNum="<<jumpData.layerNum<<std::endl;
40 }
41 
42 PickEventHandler::PickEventHandler(const osgPresentation::KeyPosition& keyPos, const JumpData& jumpData):
43     _keyPos(keyPos),
44     _operation(osgPresentation::EVENT),
45     _jumpData(jumpData),
46     _drawablesOnPush()
47 {
48     OSG_INFO<<"PickEventHandler::PickEventHandler(keyPos="<<keyPos._key<<", jumpData.relativeJump="<<jumpData.relativeJump<<", jumpData.="<<jumpData.slideNum<<", jumpData.layerNum="<<jumpData.layerNum<<std::endl;
49 }
50 
51 
52 bool PickEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa, osg::Object*, osg::NodeVisitor* nv)
53 {
54     if (ea.getHandled()) return false;
55 
56     switch(ea.getEventType())
57     {
58         case(osgGA::GUIEventAdapter::MOVE):
59         case(osgGA::GUIEventAdapter::PUSH):
60         case(osgGA::GUIEventAdapter::DRAG):
61         case(osgGA::GUIEventAdapter::RELEASE):
62         {
63             if(ea.getEventType() == osgGA::GUIEventAdapter::PUSH)
64             {
65                 _drawablesOnPush.clear();
66             }
67             osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
68             osgUtil::LineSegmentIntersector::Intersections intersections;
69             if (viewer->computeIntersections(ea, nv->getNodePath(), intersections))
70             {
71                 for(osgUtil::LineSegmentIntersector::Intersections::iterator hitr=intersections.begin();
72                     hitr!=intersections.end();
73                     ++hitr)
74                 {
75                     if (_operation == FORWARD_MOUSE_EVENT)
76                     {
77                         osg::ref_ptr<osgGA::GUIEventAdapter> cloned_ea = osg::clone(&ea);
78 
79                         // clear touch-data as this prevents sending the event as mouse-event
80                         cloned_ea->setTouchData(NULL);
81 
82                         // reproject mouse-coord
83                         const osg::BoundingBox bb(hitr->drawable->getBoundingBox());
84                         const osg::Vec3& p(hitr->localIntersectionPoint);
85 
86                         float transformed_x = (p.x() - bb.xMin()) / (bb.xMax() - bb.xMin());
87                         float transformed_y = (p.z() - bb.zMin()) / (bb.zMax() - bb.zMin());
88 
89                         cloned_ea->setX(ea.getXmin() + transformed_x * (ea.getXmax() - ea.getXmin()));
90                         cloned_ea->setY(ea.getYmin() + transformed_y * (ea.getYmax() - ea.getYmin()));
91                         cloned_ea->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS);
92 
93 
94 
95                         // std::cout << transformed_x << "/" << transformed_x << " -> " << cloned_ea->getX() << "/" <<cloned_ea->getY() << std::endl;
96 
97                         SlideEventHandler::instance()->forwardEventToDevices(cloned_ea.get());
98                     }
99                     else if ((_operation == FORWARD_TOUCH_EVENT) && ea.isMultiTouchEvent())
100                     {
101                         osg::ref_ptr<osgGA::GUIEventAdapter> cloned_ea = osg::clone(&ea);
102                         cloned_ea->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS);
103 
104                         osgGA::GUIEventAdapter::TouchData* touch_data = cloned_ea->getTouchData();
105 
106 
107 
108                         // reproject touch-points
109                         const osg::BoundingBox bb(hitr->drawable->getBoundingBox());
110 
111                         osg::Camera* camera = viewer->getCamera();
112                         osg::Matrix matrix = osg::computeLocalToWorld(hitr->nodePath, false) * camera->getViewMatrix() * camera->getProjectionMatrix();
113                         matrix.postMult(camera->getViewport()->computeWindowMatrix());
114 
115                         osg::Matrixd inverse;
116                         inverse.invert(matrix);
117 
118                         // transform touch-points into local coord-system
119                         unsigned int j(0);
120                         for(osgGA::GUIEventAdapter::TouchData::iterator i = touch_data->begin(); i != touch_data->end(); ++i, ++j)
121                         {
122                             osg::Vec3 local = osg::Vec3(i->x, i->y, 0) * inverse;
123 
124                             // std::cout << local << " hit: " << hitr->localIntersectionPoint << std::endl;
125 
126                             local.x() = (local.x() - bb.xMin()) / (bb.xMax() - bb.xMin());
127                             local.z() = (local.z() - bb.zMin()) / (bb.zMax() - bb.zMin());
128 
129                             local.x() = (ea.getXmin() + local.x() * (ea.getXmax() - ea.getXmin()));
130                             local.z() = (ea.getYmin() + local.z() * (ea.getYmax() - ea.getYmin()));
131 
132                             // std::cout << ea.getX() << "/" << ea.getY() << " -- " << i->x << " " << i->y << " -> " << local.x() <<"/" << local.z() << std::endl;
133 
134                             i->x = local.x();
135                             i->y = 1 + local.z(); // no idea why I have to add 1 to get y in the range [0..1]
136                         }
137 
138 
139                         // std::cout << transformed_x << "/" << transformed_x << " -> " << cloned_ea->getX() << "/" <<cloned_ea->getY() << std::endl;
140 
141 
142                         SlideEventHandler::instance()->forwardEventToDevices(cloned_ea.get());
143                     }
144                     else
145                     {
146                         if (ea.getEventType()==osgGA::GUIEventAdapter::PUSH)
147                         {
148                             _drawablesOnPush.insert( hitr->drawable.get() );
149                         }
150                         else if (ea.getEventType()==osgGA::GUIEventAdapter::MOVE)
151                         {
152                             OSG_INFO<<"Tooltip..."<<std::endl;
153                         }
154                         else if (ea.getEventType()==osgGA::GUIEventAdapter::RELEASE)
155                         {
156                             if (_drawablesOnPush.find(hitr->drawable.get()) != _drawablesOnPush.end())
157                                 doOperation();
158                             return true;
159                         }
160                     }
161                 }
162             }
163             break;
164         }
165         case(osgGA::GUIEventAdapter::KEYDOWN):
166         {
167             //OSG_NOTICE<<"PickEventHandler KEYDOWN "<<(char)ea.getKey()<<std::endl;
168             //if (object) OSG_NOTICE<<"    "<<object->className()<<std::endl;
169             break;
170         }
171         default:
172             break;
173     }
174     return false;
175 }
176 
177 void PickEventHandler::getUsage(osg::ApplicationUsage& /*usage*/) const
178 {
179 }
180 
181 void PickEventHandler::doOperation()
182 {
183     switch(_operation)
184     {
185         case(osgPresentation::RUN):
186         {
187             OSG_NOTICE<<"Run "<<_command<<std::endl;
188 
189 #if 0
190             osgDB::FilePathList& paths = osgDB::getDataFilePathList();
191             if (!paths.empty())
192             {
193             #ifdef _WIN32
194                 std::string delimintor(";");
195             #else
196                 std::string delimintor(":");
197             #endif
198                 std::string filepath("OSG_FILE_PATH=");
199 
200                 bool needDeliminator = false;
201                 for(osgDB::FilePathList::iterator itr = paths.begin();
202                     itr != paths.end();
203                     ++itr)
204                 {
205                     if (needDeliminator) filepath += delimintor;
206                     filepath += *itr;
207                     needDeliminator = true;
208                 }
209                 putenv( (char*) filepath.c_str());
210 
211                 std::string binpath("PATH=");
212                 char* path = getenv("PATH");
213                 if (path) binpath += path;
214 
215                 needDeliminator = true;
216                 for(osgDB::FilePathList::iterator itr = paths.begin();
217                     itr != paths.end();
218                     ++itr)
219                 {
220                     if (needDeliminator) binpath += delimintor;
221                     binpath += *itr;
222                     needDeliminator = true;
223                 }
224                 putenv( (char*) binpath.c_str());
225 
226             }
227 #endif
228 
229             bool commandRunsInBackground = (_command.find("&")!=std::string::npos);
230 
231             int result = system(_command.c_str());
232 
233             OSG_INFO<<"system("<<_command<<") result "<<result<<std::endl;
234 
235             if (commandRunsInBackground)
236             {
237                 // Sleep briefly while command runs in background to give it a chance to open
238                 // a window and obscure this present3D's window avoiding this present3D from
239                 // rendering anything new before the new window opens.
240                 OpenThreads::Thread::microSleep(500000); // half second sleep.
241             }
242 
243             break;
244         }
245         case(osgPresentation::LOAD):
246         {
247             OSG_NOTICE<<"Load "<<_command<<std::endl;
248             break;
249         }
250         case(osgPresentation::EVENT):
251         {
252             OSG_NOTICE<<"Event "<<_keyPos._key<<" "<<_keyPos._x<<" "<<_keyPos._y<<std::endl;
253             if (SlideEventHandler::instance()) SlideEventHandler::instance()->dispatchEvent(_keyPos);
254             break;
255         }
256         case(osgPresentation::JUMP):
257         {
258             OSG_INFO<<"Requires jump "<<std::endl;
259             break;
260         }
261         case(osgPresentation::FORWARD_MOUSE_EVENT):
262         case(osgPresentation::FORWARD_TOUCH_EVENT):
263             break;
264     }
265 
266     if (_jumpData.requiresJump())
267     {
268         _jumpData.jump(SlideEventHandler::instance());
269     }
270     else
271     {
272         OSG_INFO<<"No jump required."<<std::endl;
273     }
274 }
275 
276