root/OpenSceneGraph/trunk/examples/osgkeyboardmouse/osgkeyboardmouse.cpp @ 4955

Revision 4955, 10.3 kB (checked in by robert, 9 years ago)

Added ability to write out the selected parts of the scene graph.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1// C++ source file - (C) 2003 Robert Osfield, released under the OSGPL.
2//
3// Simple example of use of Producer::RenderSurface + KeyboardMouseCallback + SceneView
4// example that provides the user with control over view position with basic picking.
5
6#include <Producer/RenderSurface>
7#include <Producer/KeyboardMouse>
8#include <Producer/Trackball>
9
10#include <osg/Timer>
11#include <osg/io_utils>
12
13#include <osgUtil/SceneView>
14#include <osgUtil/IntersectVisitor>
15
16#include <osgDB/ReadFile>
17#include <osgDB/WriteFile>
18
19#include <osgFX/Scribe>
20
21
22class CreateModelToSaveVisitor : public osg::NodeVisitor
23{
24public:
25
26    CreateModelToSaveVisitor():
27        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)       
28    {
29        _group = new osg::Group;
30        _addToModel = false;
31    }
32   
33    virtual void apply(osg::Node& node)
34    {
35        osgFX::Scribe* scribe = dynamic_cast<osgFX::Scribe*>(&node);
36        if (scribe)
37        {
38            for(unsigned int i=0; i<scribe->getNumChildren(); ++i)
39            {
40                _group->addChild(scribe->getChild(i));
41            }
42        }
43        else
44        {
45            traverse(node);
46        }
47    }
48   
49    osg::ref_ptr<osg::Group> _group;
50    bool _addToModel;
51};
52
53class MyKeyboardMouseCallback : public Producer::KeyboardMouseCallback
54{
55public:
56
57    MyKeyboardMouseCallback(osgUtil::SceneView* sceneView) :
58        Producer::KeyboardMouseCallback(),
59        _mx(0.0f),_my(0.0f),_mbutton(0),
60        _done(false),
61        _trackBall(new Producer::Trackball),
62        _sceneView(sceneView)
63    {
64        resetTrackball();
65        _mouseMovingOnPreviousRelease = false;
66    }
67
68    virtual void specialKeyPress( Producer::KeyCharacter key )
69    {
70        if (key==Producer::KeyChar_Escape)
71                    shutdown();
72    }
73
74    virtual void shutdown()
75    {
76        _done = true;
77    }
78
79    virtual void keyPress( Producer::KeyCharacter key)
80    {
81        if (key==' ') resetTrackball();
82        else if (key=='o') saveSelectedModel();
83    }
84
85    virtual void mouseMotion( float mx, float my )
86    {
87        _mx = mx;
88        _my = my;
89    }
90
91    virtual void buttonPress( float mx, float my, unsigned int mbutton )
92    {
93         _mx = mx;
94         _my = my;
95         _mbutton |= (1<<(mbutton-1));
96         
97         _mx_buttonPress = _mx;
98         _my_buttonPress = _my;
99    }
100    virtual void buttonRelease( float mx, float my, unsigned int mbutton )
101    {
102        _mx = mx;
103        _my = my;
104        _mbutton &= ~(1<<(mbutton-1));
105       
106        if (_mx==_mx_buttonPress && _my_buttonPress==_my)
107        {
108            if (!_mouseMovingOnPreviousRelease)
109            {
110                // button press and release without moving so assume this means
111                // the users wants to pick.
112                pick(_mx,_my);
113            }
114            _mouseMovingOnPreviousRelease = false;
115        }
116        else
117        {
118            _mouseMovingOnPreviousRelease = true;
119        }
120    }
121
122    bool done() { return _done; }
123    float mx()  { return _mx; }
124    float my()  { return _my; }
125    unsigned int mbutton()  { return _mbutton; }
126   
127    void resetTrackball()
128    {
129        osg::Node* scene = _sceneView->getSceneData();
130        if (scene)
131        {
132            const osg::BoundingSphere& bs = scene->getBound();
133            if (bs.valid())
134            {
135                _trackBall->reset();
136                _trackBall->setOrientation( Producer::Trackball::Z_UP );
137                _trackBall->setDistance(bs.radius()*2.0f);
138                _trackBall->translate(-bs.center().x(),-bs.center().y(),-bs.center().z());
139            }
140        }
141    }
142   
143    osg::Matrixd getViewMatrix()
144    {
145        _trackBall->input( mx(), my(), mbutton() );
146        return osg::Matrixd(_trackBall->getMatrix().ptr());
147    }
148   
149    void pick(float x, float y)
150    {
151        osg::Node* scene = _sceneView->getSceneData();
152        if (scene)
153        {
154            std::cout<<"Picking "<<x<<"\t"<<y<<std::endl;
155
156            int origX, origY, width, height;
157            _sceneView->getViewport(origX,origY,width,height);
158
159            // convert Producer's non dimensional x,y coords back into pixel coords.
160            int pixel_x = (int)((x+1.0f)*0.5f*(float)width);
161            int pixel_y = (int)((y+1.0f)*0.5f*(float)height);
162           
163           
164            osgUtil::PickVisitor pick(_sceneView->getViewport(),
165                                      _sceneView->getProjectionMatrix(),
166                                      _sceneView->getViewMatrix(),
167                                      pixel_x, pixel_y);
168
169            scene->accept(pick);
170           
171            osgUtil::PickVisitor::LineSegmentHitListMap& segHitList = pick.getSegHitList();
172            if (!segHitList.empty() && !segHitList.begin()->second.empty())
173            {
174                std::cout<<"Got hits"<<std::endl;
175               
176                // get the hits for the first segment
177                osgUtil::PickVisitor::HitList& hits = segHitList.begin()->second;
178               
179                // just take the first hit - nearest the eye point.
180                osgUtil::Hit& hit = hits.front();
181               
182                osg::NodePath& nodePath = hit._nodePath;
183                osg::Node* node = (nodePath.size()>=1)?nodePath[nodePath.size()-1]:0;
184                osg::Group* parent = (nodePath.size()>=2)?dynamic_cast<osg::Group*>(nodePath[nodePath.size()-2]):0;
185
186                if (node) std::cout<<"  Hits "<<node->className()<<" nodePath size"<<nodePath.size()<<std::endl;
187
188                // now we try to decorate the hit node by the osgFX::Scribe to show that its been "picked"
189                if (parent && node)
190                {
191               
192                    std::cout<<"  parent "<<parent->className()<<std::endl;
193                   
194                    osgFX::Scribe* parentAsScribe = dynamic_cast<osgFX::Scribe*>(parent);
195                    if (!parentAsScribe)
196                    {
197                        // node not already picked, so highlight it with an osgFX::Scribe
198                        osgFX::Scribe* scribe = new osgFX::Scribe();
199                        scribe->addChild(node);
200                        parent->replaceChild(node,scribe);
201                    }
202                    else
203                    {
204                        // node already picked so we want to remove scribe to unpick it.
205                        osg::Node::ParentList parentList = parentAsScribe->getParents();
206                        for(osg::Node::ParentList::iterator itr=parentList.begin();
207                            itr!=parentList.end();
208                            ++itr)
209                        {
210                            (*itr)->replaceChild(parentAsScribe,node);
211                        }
212                    }
213                }
214
215            }
216           
217        }       
218       
219    }
220
221    void saveSelectedModel()
222    {
223        CreateModelToSaveVisitor cmtsv;
224        _sceneView->getSceneData()->accept(cmtsv);
225       
226        if (cmtsv._group->getNumChildren()>0)
227        {
228            osgDB::writeNodeFile(*cmtsv._group, "selected_model.osg");
229        }
230    }
231
232private:
233
234    float                               _mx, _my;
235    float                               _mx_buttonPress, _my_buttonPress;
236    unsigned int                        _mbutton;
237    bool                                _mouseMovingOnPreviousRelease;
238   
239    bool                                _done;
240   
241    osg::ref_ptr<Producer::Trackball>   _trackBall;
242    osg::ref_ptr<osgUtil::SceneView>    _sceneView;
243};
244
245int main( int argc, char **argv )
246{
247    if (argc<2)
248    {
249        std::cout << argv[0] <<": requires filename argument." << std::endl;
250        return 1;
251    }
252
253    // load the scene.
254    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFile(argv[1]);
255    if (!loadedModel)
256    {
257        std::cout << argv[0] <<": No data loaded." << std::endl;
258        return 1;
259    }
260   
261    // create the window to draw to.
262    osg::ref_ptr<Producer::RenderSurface> renderSurface = new Producer::RenderSurface;
263    renderSurface->setWindowName("osgkeyboardmouse");
264    renderSurface->setWindowRectangle(100,100,800,600);
265    renderSurface->useBorder(true);
266    renderSurface->realize();
267   
268
269    // create the view of the scene.
270    osg::ref_ptr<osgUtil::SceneView> sceneView = new osgUtil::SceneView;
271    sceneView->setDefaults();
272    sceneView->setSceneData(loadedModel.get());
273
274
275    // set up a KeyboardMouse to manage the events comming in from the RenderSurface
276    osg::ref_ptr<Producer::KeyboardMouse>  kbm = new Producer::KeyboardMouse(renderSurface.get());
277
278    // create a KeyboardMouseCallback to handle the mouse events within this applications
279    osg::ref_ptr<MyKeyboardMouseCallback> kbmcb = new MyKeyboardMouseCallback(sceneView.get());
280
281
282    // record the timer tick at the start of rendering.   
283    osg::Timer_t start_tick = osg::Timer::instance()->tick();
284   
285    unsigned int frameNum = 0;
286
287    // main loop (note, window toolkits which take control over the main loop will require a window redraw callback containing the code below.)
288    while( renderSurface->isRealized() && !kbmcb->done())
289    {
290        // set up the frame stamp for current frame to record the current time and frame number so that animtion code can advance correctly
291        osg::FrameStamp* frameStamp = new osg::FrameStamp;
292        frameStamp->setReferenceTime(osg::Timer::instance()->delta_s(start_tick,osg::Timer::instance()->tick()));
293        frameStamp->setFrameNumber(frameNum++);
294       
295        // pass frame stamp to the SceneView so that the update, cull and draw traversals all use the same FrameStamp
296        sceneView->setFrameStamp(frameStamp);
297
298        // pass any keyboard mouse events onto the local keyboard mouse callback.       
299        kbm->update( *kbmcb );
300       
301        // set the view
302        sceneView->setViewMatrix(kbmcb->getViewMatrix());
303
304        // update the viewport dimensions, incase the window has been resized.
305        sceneView->setViewport(0,0,renderSurface->getWindowWidth(),renderSurface->getWindowHeight());
306
307        // do the update traversal the scene graph - such as updating animations
308        sceneView->update();
309       
310        // do the cull traversal, collect all objects in the view frustum into a sorted set of rendering bins
311        sceneView->cull();
312       
313        // draw the rendering bins.
314        sceneView->draw();
315
316        // Swap Buffers
317        renderSurface->swapBuffers();
318    }
319
320    return 0;
321}
Note: See TracBrowser for help on using the browser.