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/Cursor>
15 
16 #include <osgUtil/CullVisitor>
17 #include <osgGA/EventVisitor>
18 #include <osgDB/ReadFile>
19 #include <osgDB/FileUtils>
20 #include <osgViewer/View>
21 #include <osg/Texture2D>
22 #include <osg/io_utils>
23 
24 using namespace osgPresentation;
25 
Cursor()26 Cursor::Cursor():
27     _size(0.05f),
28     _cursorDirty(true)
29 {
30     setDataVariance(osg::Object::DYNAMIC);
31     setCullingActive(false);
32     setNumChildrenRequiringEventTraversal(1);
33     setNumChildrenRequiringUpdateTraversal(1);
34 }
35 
Cursor(const std::string & filename,float size)36 Cursor::Cursor(const std::string& filename, float size):
37     _cursorDirty(true)
38 {
39     setDataVariance(osg::Object::DYNAMIC);
40     setCullingActive(false);
41     setNumChildrenRequiringEventTraversal(1);
42     setNumChildrenRequiringUpdateTraversal(1);
43 
44     setFilename(filename);
45     setSize(size);
46 }
47 
Cursor(const Cursor & rhs,const osg::CopyOp & copyop)48 Cursor::Cursor(const Cursor& rhs,const osg::CopyOp& copyop):
49     osg::Group(rhs, copyop),
50     _filename(rhs._filename),
51     _size(rhs._size),
52     _cursorDirty(true)
53 {
54     setDataVariance(osg::Object::DYNAMIC);
55     setCullingActive(false);
56 }
57 
~Cursor()58 Cursor::~Cursor()
59 {
60 }
61 
initializeCursor()62 void Cursor::initializeCursor()
63 {
64     if (!_cursorDirty) return;
65     if (_filename.empty()) return;
66 
67     removeChildren(0, getNumChildren()-1);
68 
69     OSG_INFO<<"Curosr::initializeCursor()"<<std::endl;
70     _cursorDirty = false;
71 
72     _transform = new osg::AutoTransform;
73 
74     _transform->setAutoRotateMode(osg::AutoTransform::ROTATE_TO_CAMERA);
75     _transform->setAutoScaleToScreen(true);
76 
77     osg::ref_ptr<osg::Geode> geode = new osg::Geode;
78 
79 
80     osg::ref_ptr<osg::Image> image = osgDB::readRefImageFile(osgDB::findDataFile(_filename));
81     osg::ref_ptr<osg::Texture2D> texture = (image.valid()) ? new osg::Texture2D(image.get()) : 0;
82 
83     // full cursor
84     {
85         osg::ref_ptr<osg::Geometry> geom = osg::createTexturedQuadGeometry(osg::Vec3(-_size*0.5f,-_size*0.5f,0.0f),osg::Vec3(_size,0.0f,0.0f),osg::Vec3(0.0f,_size,0.0f));
86         geode->addDrawable(geom.get());
87 
88         osg::StateSet* stateset = geom->getOrCreateStateSet();
89         stateset->setMode(GL_BLEND,osg::StateAttribute::ON|osg::StateAttribute::PROTECTED);
90         stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
91         stateset->setRenderBinDetails(1001, "DepthSortedBin");
92 
93         if (texture.valid()) stateset->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON|osg::StateAttribute::PROTECTED);
94     }
95 
96     {
97         osg::ref_ptr<osg::Geometry> geom = osg::createTexturedQuadGeometry(osg::Vec3(-_size*0.5f,-_size*0.5f,0.0f),osg::Vec3(_size,0.0f,0.0f),osg::Vec3(0.0f,_size,0.0f));
98         geode->addDrawable(geom.get());
99 
100         osg::Vec4Array* colors = new osg::Vec4Array;
101         colors->push_back(osg::Vec4(1.0f,1.0f,1.0f,0.25f));
102         geom->setColorArray(colors, osg::Array::BIND_OVERALL);
103 
104         osg::StateSet* stateset = geom->getOrCreateStateSet();
105         stateset->setMode(GL_BLEND,osg::StateAttribute::ON|osg::StateAttribute::PROTECTED);
106         stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
107         stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);
108         stateset->setRenderBinDetails(1000, "DepthSortedBin");
109 
110         if (texture.valid()) stateset->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON|osg::StateAttribute::PROTECTED);
111     }
112 
113 
114 
115     _transform->addChild(geode.get());
116 
117     addChild(_transform.get());
118 }
119 
updatePosition()120 void Cursor::updatePosition()
121 {
122     if (!_camera)
123     {
124         OSG_INFO<<"Cursor::updatePosition() : Update position failed, no camera assigned"<<std::endl;
125         return;
126     }
127 
128     double distance = 1.0f;
129 
130     osgViewer::View* view = dynamic_cast<osgViewer::View*>(_camera->getView());
131     if (view)
132     {
133         osg::DisplaySettings* ds = (view->getDisplaySettings()!=0) ? view->getDisplaySettings() : osg::DisplaySettings::instance().get();
134 
135         double sd = ds->getScreenDistance();
136         double fusionDistance = sd;
137         switch(view->getFusionDistanceMode())
138         {
139             case(osgUtil::SceneView::USE_FUSION_DISTANCE_VALUE):
140                 fusionDistance = view->getFusionDistanceValue();
141                 break;
142             case(osgUtil::SceneView::PROPORTIONAL_TO_SCREEN_DISTANCE):
143                 fusionDistance *= view->getFusionDistanceValue();
144                 break;
145         }
146 
147         distance = fusionDistance;
148     }
149 
150     osg::Matrix VP =  _camera->getViewMatrix() * _camera->getProjectionMatrix();
151 
152     osg::Matrix inverse_VP;
153     inverse_VP.invert(VP);
154 
155     osg::Vec3d eye(0.0,0.0,0.0);
156     osg::Vec3d farpoint(_cursorXY.x(), _cursorXY.y(), 1.0);
157 
158     osg::Vec3d eye_world = eye * osg::Matrix::inverse(_camera->getViewMatrix());
159     osg::Vec3d farpoint_world = farpoint * inverse_VP;
160 
161     osg::Vec3d normal = farpoint_world-eye_world;
162     normal.normalize();
163 
164     osg::Vec3d cursorPosition = eye_world + normal * distance;
165     _transform->setPosition(cursorPosition);
166 }
167 
168 
traverse(osg::NodeVisitor & nv)169 void Cursor::traverse(osg::NodeVisitor& nv)
170 {
171     if (nv.getVisitorType()==osg::NodeVisitor::UPDATE_VISITOR)
172     {
173         if (_cursorDirty) initializeCursor();
174 
175         // updatePosition();
176 
177         // traverse the subgraph
178         Group::traverse(nv);
179     }
180     else if (nv.getVisitorType()==osg::NodeVisitor::EVENT_VISITOR)
181     {
182         osgGA::EventVisitor* ev = dynamic_cast<osgGA::EventVisitor*>(&nv);
183         if (!ev) return;
184 
185         osgGA::EventQueue::Events& events = ev->getEvents();
186         for(osgGA::EventQueue::Events::iterator itr = events.begin();
187             itr != events.end();
188             ++itr)
189         {
190             osgGA::GUIEventAdapter* event = (*itr)->asGUIEventAdapter();
191             if (!event) continue;
192 
193             switch(event->getEventType())
194             {
195                 case(osgGA::GUIEventAdapter::PUSH):
196                 case(osgGA::GUIEventAdapter::RELEASE):
197                 case(osgGA::GUIEventAdapter::MOVE):
198                 case(osgGA::GUIEventAdapter::DRAG):
199                 {
200                     if (event->getNumPointerData()>=1)
201                     {
202                         const osgGA::PointerData* pd = event->getPointerData(event->getNumPointerData()-1);
203                         osg::Camera* camera = dynamic_cast<osg::Camera*>(pd->object.get());
204 
205                         _cursorXY.set(pd->getXnormalized(), pd->getYnormalized());
206                         _camera = camera;
207                     }
208                     else
209                     {
210                         osgViewer::View* view = dynamic_cast<osgViewer::View*>(ev->getActionAdapter());
211                         osg::Camera* camera = (view!=0) ? view->getCamera() : 0;
212 
213                         _cursorXY.set(event->getXnormalized(), event->getYnormalized());
214                         _camera = camera;
215                     }
216                     break;
217                 }
218                 case(osgGA::GUIEventAdapter::KEYDOWN):
219                 {
220                     if (event->getKey()=='c')
221                     {
222                         for(unsigned int i=0; i< getNumChildren(); ++i)
223                         {
224                             osg::Node* node = getChild(i);
225                             node->setNodeMask(node->getNodeMask()!=0 ? 0 : 0xffffff);
226                         }
227                     }
228                     break;
229                 }
230                 default:
231                     break;
232 
233             }
234         }
235         Group::traverse(nv);
236     }
237     else  if (nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR)
238     {
239 #if 0
240         if (!_camera)
241         {
242             osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);
243             if (cv)
244             {
245                 _camera = cv->getCurrentCamera();
246             }
247         }
248 #endif
249         if (_camera.valid())
250         {
251             updatePosition();
252             Group::traverse(nv);
253         }
254     }
255 }
256