root/OpenSceneGraph/trunk/src/osgViewer/ViewerEventHandlers.cpp @ 9340

Revision 9340, 26.4 kB (checked in by robert, 5 years ago)

From Ulrich Hertlein, Typo fixes + "optional parameter to RecordCameraPathHandler? to control the frame rate for record/playback. Default is 25.0, the environment variable takes preference if set."

Line 
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 <stdlib.h>
15#include <float.h>
16#include <limits.h>
17
18#include <iomanip>
19#include <sstream>
20
21#include <osgDB/FileNameUtils>
22
23#include <osg/Geometry>
24#include <osg/TexMat>
25#include <osg/TextureRectangle>
26#include <osg/io_utils>
27
28#include <osgViewer/Viewer>
29#include <osgViewer/ViewerEventHandlers>
30
31namespace osgViewer
32{
33
34/*
35** WindowSizeHandler
36*/
37
38WindowSizeHandler::WindowSizeHandler() :
39    _keyEventToggleFullscreen('f'),
40    _toggleFullscreen(true),
41    _keyEventWindowedResolutionUp('>'),
42    _keyEventWindowedResolutionDown('<'),
43    _changeWindowedResolution(true),
44    _currentResolutionIndex(-1)
45{
46    _resolutionList.push_back(osg::Vec2(640, 480));
47    _resolutionList.push_back(osg::Vec2(800, 600));
48    _resolutionList.push_back(osg::Vec2(1024, 768));
49    _resolutionList.push_back(osg::Vec2(1152, 864));
50    _resolutionList.push_back(osg::Vec2(1280, 720));
51    _resolutionList.push_back(osg::Vec2(1280, 768));
52    _resolutionList.push_back(osg::Vec2(1280, 1024));
53    _resolutionList.push_back(osg::Vec2(1440, 900));
54    _resolutionList.push_back(osg::Vec2(1400, 1050));
55    _resolutionList.push_back(osg::Vec2(1600, 900));
56    _resolutionList.push_back(osg::Vec2(1600, 1024));
57    _resolutionList.push_back(osg::Vec2(1600, 1200));
58    _resolutionList.push_back(osg::Vec2(1680, 1050));
59    _resolutionList.push_back(osg::Vec2(1920, 1080));
60    _resolutionList.push_back(osg::Vec2(1920, 1200));
61    _resolutionList.push_back(osg::Vec2(2048, 1536));
62    _resolutionList.push_back(osg::Vec2(2560, 2048));
63    _resolutionList.push_back(osg::Vec2(3200, 2400));
64    _resolutionList.push_back(osg::Vec2(3840, 2400));
65}
66
67void WindowSizeHandler::getUsage(osg::ApplicationUsage &usage) const
68{
69    usage.addKeyboardMouseBinding(reinterpret_cast<const char*>(&_keyEventToggleFullscreen), "Toggle full screen.");
70    usage.addKeyboardMouseBinding(reinterpret_cast<const char*>(&_keyEventWindowedResolutionUp), "Increase the screen resolution (in windowed mode).");
71    usage.addKeyboardMouseBinding(reinterpret_cast<const char*>(&_keyEventWindowedResolutionDown), "Decrease the screen resolution (in windowed mode).");
72}
73
74bool WindowSizeHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa)
75{
76    osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
77    if (!view) return false;
78   
79    osgViewer::ViewerBase* viewer = view->getViewerBase();
80
81    if (viewer == NULL)
82    {
83        return false;
84    }
85
86    if (ea.getHandled()) return false;
87
88    switch(ea.getEventType())
89    {
90        case(osgGA::GUIEventAdapter::KEYUP):
91        {
92            if (_toggleFullscreen == true && ea.getKey() == _keyEventToggleFullscreen)
93            {
94                osgViewer::Viewer::Windows    windows;
95
96                viewer->getWindows(windows);
97                for(osgViewer::Viewer::Windows::iterator itr = windows.begin();
98                    itr != windows.end();
99                    ++itr)
100                {
101                    toggleFullscreen(*itr);
102                }
103                return true;
104            }
105            else if (_changeWindowedResolution == true && ea.getKey() == _keyEventWindowedResolutionUp)
106            {
107                // Increase resolution
108                osgViewer::Viewer::Windows    windows;
109
110                viewer->getWindows(windows);
111                for(osgViewer::Viewer::Windows::iterator itr = windows.begin();
112                    itr != windows.end();
113                    ++itr)
114                {
115                    changeWindowedResolution(*itr, true);
116                }
117                return true;
118            }
119            else if (_changeWindowedResolution == true && ea.getKey() == _keyEventWindowedResolutionDown)
120            {
121                // Decrease resolution
122                osgViewer::Viewer::Windows    windows;
123
124                viewer->getWindows(windows);
125                for(osgViewer::Viewer::Windows::iterator itr = windows.begin();
126                    itr != windows.end();
127                    ++itr)
128                {
129                    changeWindowedResolution(*itr, false);
130                }
131                return true;
132            }
133            break;
134        }
135    default:
136        break;
137    }
138    return false;
139}
140
141void WindowSizeHandler::toggleFullscreen(osgViewer::GraphicsWindow *window)
142{
143    osg::GraphicsContext::WindowingSystemInterface    *wsi = osg::GraphicsContext::getWindowingSystemInterface();
144
145    if (wsi == NULL)
146    {
147        osg::notify(osg::NOTICE) << "Error, no WindowSystemInterface available, cannot toggle window fullscreen." << std::endl;
148        return;
149    }
150
151    unsigned int    screenWidth;
152    unsigned int    screenHeight;
153
154    wsi->getScreenResolution(*(window->getTraits()), screenWidth, screenHeight);
155
156    int x;
157    int y;
158    int width;
159    int height;
160
161    window->getWindowRectangle(x, y, width, height);
162
163    bool    isFullScreen = x == 0 && y == 0 && width == (int)screenWidth && height == (int)screenHeight;
164
165    if (isFullScreen)
166    {
167        osg::Vec2    resolution;
168
169        if (_currentResolutionIndex == -1)
170        {
171            _currentResolutionIndex = getNearestResolution(screenWidth, screenHeight, screenWidth / 2, screenHeight / 2);
172        }
173        resolution = _resolutionList[_currentResolutionIndex];
174        window->setWindowDecoration(true);
175        window->setWindowRectangle((screenWidth - (int)resolution.x()) / 2, (screenHeight - (int)resolution.y()) / 2, (int)resolution.x(), (int)resolution.y());
176        osg::notify(osg::INFO) << "Screen resolution = " << (int)resolution.x() << "x" << (int)resolution.y() << std::endl; 
177    }
178    else
179    {
180        window->setWindowDecoration(false);
181        window->setWindowRectangle(0, 0, screenWidth, screenHeight);
182    }
183
184    window->grabFocusIfPointerInWindow();
185}
186
187void WindowSizeHandler::changeWindowedResolution(osgViewer::GraphicsWindow *window, bool increase)
188{
189    osg::GraphicsContext::WindowingSystemInterface    *wsi = osg::GraphicsContext::getWindowingSystemInterface();
190
191    if (wsi == NULL)
192    {
193        osg::notify(osg::NOTICE) << "Error, no WindowSystemInterface available, cannot toggle window fullscreen." << std::endl;
194        return;
195    }
196
197    unsigned int    screenWidth;
198    unsigned int    screenHeight;
199
200    wsi->getScreenResolution(*(window->getTraits()), screenWidth, screenHeight);
201
202    int x;
203    int y;
204    int width;
205    int height;
206
207    window->getWindowRectangle(x, y, width, height);
208
209    bool    isFullScreen = x == 0 && y == 0 && width == (int)screenWidth && height == (int)screenHeight;
210
211    if (window->getWindowDecoration() == true || isFullScreen == false)
212    {
213        osg::Vec2    resolution;
214
215        if (_currentResolutionIndex == -1)
216        {
217            _currentResolutionIndex = getNearestResolution(screenWidth, screenHeight, width, height);
218        }
219
220        if (increase == true)
221        {
222            // Find the next resolution
223            for (int i = _currentResolutionIndex + 1; i < (int)_resolutionList.size(); ++i)
224            {
225                if ((unsigned int)_resolutionList[i].x() <= screenWidth && (unsigned int)_resolutionList[i].y() <= screenHeight)
226                {
227                    _currentResolutionIndex = i;
228                    break;
229                }
230            }
231        }
232        else
233        {
234            // Find the previous resolution
235            for (int i = _currentResolutionIndex - 1; i >= 0; --i)
236            {
237                if ((unsigned int)_resolutionList[i].x() <= screenWidth && (unsigned int)_resolutionList[i].y() <= screenHeight)
238                {
239                    _currentResolutionIndex = i;
240                    break;
241                }
242            }
243        }
244
245        resolution = _resolutionList[_currentResolutionIndex];
246        window->setWindowDecoration(true);
247        window->setWindowRectangle((screenWidth - (int)resolution.x()) / 2, (screenHeight - (int)resolution.y()) / 2, (int)resolution.x(), (int)resolution.y());
248        osg::notify(osg::INFO) << "Screen resolution = " << (int)resolution.x() << "x" << (int)resolution.y() << std::endl; 
249
250        window->grabFocusIfPointerInWindow();
251    }
252}
253
254unsigned int WindowSizeHandler::getNearestResolution(int screenWidth, int screenHeight, int width, int height) const
255{
256    unsigned int    position = 0;
257    unsigned int    result = 0;
258    int                delta = INT_MAX;
259
260    for (std::vector<osg::Vec2>::const_iterator it = _resolutionList.begin();
261        it != _resolutionList.end();
262        ++it, ++position)
263    {
264        if ((int)it->x() <= screenWidth && (int)it->y() <= screenHeight)
265        {
266            int tmp = static_cast<int>(osg::absolute((width * height) - (it->x() * it->y())));
267
268            if (tmp < delta)
269            {
270                delta = tmp;
271                result = position;
272            }
273        }
274    }
275    return (result);
276}
277
278/*
279** ThreadingHandler
280*/
281
282ThreadingHandler::ThreadingHandler() :
283    _keyEventChangeThreadingModel('m'),
284    _changeThreadingModel(true),
285    _keyEventChangeEndBarrierPosition('e'),
286    _changeEndBarrierPosition(true)
287{
288    _tickOrLastKeyPress = osg::Timer::instance()->tick();
289}
290
291void ThreadingHandler::getUsage(osg::ApplicationUsage &usage) const
292{
293    usage.addKeyboardMouseBinding(reinterpret_cast<const char*>(&_keyEventChangeThreadingModel), "Toggle threading model.");
294    usage.addKeyboardMouseBinding(reinterpret_cast<const char*>(&_keyEventChangeEndBarrierPosition), "Toggle the placement of the end of frame barrier.");
295}
296
297bool ThreadingHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa)
298{
299    osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
300    if (!view) return false;
301   
302    osgViewer::ViewerBase* viewerBase = view->getViewerBase();
303    osgViewer::Viewer* viewer = dynamic_cast<Viewer*>(viewerBase);
304
305    if (viewerBase == NULL)
306    {
307        return false;
308    }
309
310    if (ea.getHandled()) return false;
311
312    switch(ea.getEventType())
313    {
314        case(osgGA::GUIEventAdapter::KEYUP):
315        {
316            double    delta = osg::Timer::instance()->delta_s(_tickOrLastKeyPress, osg::Timer::instance()->tick());
317
318            if (_changeThreadingModel == true && ea.getKey() == _keyEventChangeThreadingModel && delta > 1.0)
319            {
320                _tickOrLastKeyPress = osg::Timer::instance()->tick();
321
322                switch(viewerBase->getThreadingModel())
323                {
324                case(osgViewer::ViewerBase::SingleThreaded):
325                    viewerBase->setThreadingModel(osgViewer::ViewerBase::CullDrawThreadPerContext);
326                    osg::notify(osg::NOTICE)<<"Threading model 'CullDrawThreadPerContext' selected."<<std::endl;
327                    break;
328                case(osgViewer::ViewerBase::CullDrawThreadPerContext):
329                    viewerBase->setThreadingModel(osgViewer::ViewerBase::DrawThreadPerContext);
330                    osg::notify(osg::NOTICE)<<"Threading model 'DrawThreadPerContext' selected."<<std::endl;
331                    break;
332                case(osgViewer::ViewerBase::DrawThreadPerContext):
333                    viewerBase->setThreadingModel(osgViewer::ViewerBase::CullThreadPerCameraDrawThreadPerContext);
334                    osg::notify(osg::NOTICE)<<"Threading model 'CullThreadPerCameraDrawThreadPerContext' selected."<<std::endl;
335                    break;
336                case(osgViewer::ViewerBase::CullThreadPerCameraDrawThreadPerContext):
337                    viewerBase->setThreadingModel(osgViewer::ViewerBase::SingleThreaded);
338                    osg::notify(osg::NOTICE)<<"Threading model 'SingleThreaded' selected."<<std::endl;
339                    break;
340#if 1                   
341                case(osgViewer::ViewerBase::AutomaticSelection):
342                    viewerBase->setThreadingModel(osgViewer::ViewerBase::SingleThreaded);
343                    osg::notify(osg::NOTICE)<<"Threading model 'SingleThreaded' selected."<<std::endl;
344#else                   
345                case(osgViewer::ViewerBase::AutomaticSelection):
346                    viewerBase->setThreadingModel(viewer->suggestBestThreadingModel());
347                    osg::notify(osg::NOTICE)<<"Threading model 'AutomaticSelection' selected."<<std::endl;
348#endif
349                    break;
350                }
351                return true;
352            }
353            if (viewer && _changeEndBarrierPosition == true && ea.getKey() == _keyEventChangeEndBarrierPosition)
354            {
355                switch(viewer->getEndBarrierPosition())
356                {
357                case(osgViewer::Viewer::BeforeSwapBuffers):
358                    viewer->setEndBarrierPosition(osgViewer::Viewer::AfterSwapBuffers);
359                    osg::notify(osg::NOTICE)<<"Threading model 'AfterSwapBuffers' selected."<<std::endl;
360                    break;
361                case(osgViewer::Viewer::AfterSwapBuffers):
362                    viewer->setEndBarrierPosition(osgViewer::Viewer::BeforeSwapBuffers);
363                    osg::notify(osg::NOTICE)<<"Threading model 'BeforeSwapBuffers' selected."<<std::endl;
364                    break;
365                }
366                return true;
367            }
368            break;
369        }
370    default:
371        break;
372    }
373    return false;
374}
375
376RecordCameraPathHandler::RecordCameraPathHandler(const std::string& filename, float fps):
377    _filename(filename),
378    _autoinc( -1 ),
379    _keyEventToggleRecord('z'),
380    _keyEventTogglePlayback('Z'),
381    _currentlyRecording(false),
382    _currentlyPlaying(false),
383    _delta(0.0f),
384    _animStartTime(0),
385    _lastFrameTime(osg::Timer::instance()->tick())
386{
387    _animPath = new osg::AnimationPath();
388
389    const char* str = getenv("OSG_RECORD_CAMERA_PATH_FPS");
390    if (str)
391    {
392        _interval = 1.0f / atof(str);
393    }
394    else
395    {
396        _interval = 1.0f / fps;
397    }
398}
399
400void RecordCameraPathHandler::getUsage(osg::ApplicationUsage &usage) const
401{
402    usage.addKeyboardMouseBinding(reinterpret_cast<const char*>(&_keyEventToggleRecord), "Toggle camera path recording.");
403    usage.addKeyboardMouseBinding(reinterpret_cast<const char*>(&_keyEventTogglePlayback), "Toggle camera path playback.");
404}
405
406bool RecordCameraPathHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa)
407{
408    osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
409
410    if (view == NULL)
411    {
412        return false;
413    }
414
415    if(ea.getEventType()==osgGA::GUIEventAdapter::FRAME)
416    {
417        // Calculate our current delta (difference) in time between the last frame and
418        // current frame, regardless of whether we actually store a ControlPoint...
419        osg::Timer_t time = osg::Timer::instance()->tick();
420        double delta = osg::Timer::instance()->delta_s(_lastFrameTime, time);
421        _lastFrameTime = time;
422
423        // If our internal _delta is finally large enough to warrant a ControlPoint
424        // insertion, do so now. Be sure and reset the internal _delta, so we can start
425        // calculating when the next insert should happen.
426        if (_currentlyRecording && _delta >= _interval)
427        {
428            const osg::Matrixd& m = view->getCamera()->getInverseViewMatrix();
429            double animationPathTime = osg::Timer::instance()->delta_s(_animStartTime, time);           
430            _animPath->insert(animationPathTime, osg::AnimationPath::ControlPoint(m.getTrans(), m.getRotate()));
431            _delta = 0.0f;
432
433            if (_fout)
434            {
435                _animPath->write(_animPath->getTimeControlPointMap().find(animationPathTime), _fout);
436                _fout.flush();
437            }
438
439        }
440        else _delta += delta;
441       
442        return true;
443    }
444
445    if (ea.getHandled()) return false;
446
447    switch(ea.getEventType())
448    {
449        case(osgGA::GUIEventAdapter::KEYUP):
450        {
451            // The user has requested to toggle recording.
452            if (ea.getKey() ==_keyEventToggleRecord)
453            {
454                // The user has requested to BEGIN recording.
455                if (!_currentlyRecording)
456                {
457                    _currentlyRecording = true;
458                    _animStartTime = osg::Timer::instance()->tick();
459                    _animPath->clear();
460                   
461                    if (!_filename.empty())
462                    {
463                        std::stringstream ss;
464                        ss << osgDB::getNameLessExtension(_filename);
465                        if ( _autoinc != -1 )
466                        {
467                            ss << "_"<<std::setfill( '0' ) << std::setw( 2 ) << _autoinc;
468                            _autoinc++;
469                        }
470                        ss << "."<<osgDB::getFileExtension(_filename);
471                       
472                        osg::notify(osg::NOTICE) << "Recording camera path to file " << ss.str() << std::endl;
473                        _fout.open( ss.str().c_str() );
474
475                        // make sure doubles are not trucated by default stream precision = 6
476                        _fout.precision( 15 );
477                    }
478                    else
479                    {
480                        osg::notify(osg::NOTICE)<<"Recording camera path."<<std::endl;
481                    }
482                }
483
484                // The user has requested to STOP recording, write the file!
485                else
486                {
487                    _currentlyRecording = false;
488                    _delta = 0.0f;
489
490                    if (_fout) _fout.close();
491                }
492
493                return true;
494            }
495
496            // The user has requested to toggle playback. You'll notice in the code below that
497            // we take over the current manipulator; it was originally recommended that we
498            // check for a KeySwitchManipulator, create one if not present, and then add this
499            // to either the newly created one or the existing one. However, the code do that was
500            // EXTREMELY dirty, so I opted for a simpler solution. At a later date, someone may
501            // want to implement the original recommendation (which is in a mailing list reply
502            // from June 1st by Robert in a thread called "osgviewer Camera Animation (preliminary)".
503            else if (ea.getKey() == _keyEventTogglePlayback)
504            {
505                if (_currentlyRecording)
506                {
507                    _currentlyRecording = false;
508                    _delta = 0.0f;
509
510                    // In the future this will need to be written continuously, rather
511                    // than all at once.
512                    osgDB::ofstream out(_filename.c_str());
513                    osg::notify(osg::NOTICE)<<"Writing camera file: "<<_filename<<std::endl;
514                    _animPath->write(out);
515                    out.close();
516                }
517
518                // The user has requested to BEGIN playback.
519                if (!_currentlyPlaying)
520                {
521                    _animPathManipulator = new osgGA::AnimationPathManipulator(_animPath.get());
522                    _animPathManipulator->home(ea,aa);
523
524
525                    // If we successfully found our _filename file, set it and keep a copy
526                    // around of the original MatrixManipulator to restore later.
527                    if (_animPathManipulator.valid() && _animPathManipulator->valid())
528                    {
529                        _oldManipulator = view->getCameraManipulator();
530                        view->setCameraManipulator(_animPathManipulator.get());
531                        _currentlyPlaying = true;
532                    }
533                }
534
535                // The user has requested to STOP playback.
536                else
537                {
538                    // Restore the old manipulator if necessary and stop playback.
539                    if(_oldManipulator.valid()) view->setCameraManipulator(_oldManipulator.get());
540                    _currentlyPlaying = false;
541                    _oldManipulator = 0;
542                }
543
544                return true;
545            }       
546
547            break;
548        }
549    default:
550        break;
551    }
552
553    return false;
554}
555
556LODScaleHandler::LODScaleHandler():
557    _keyEventIncreaseLODScale('*'),
558    _keyEventDecreaseLODScale('/')
559{
560}
561
562bool LODScaleHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
563{
564    osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
565    osg::Camera* camera = view ? view->getCamera() : 0;
566    if (!camera) return false;
567
568    if (ea.getHandled()) return false;
569
570    switch(ea.getEventType())
571    {
572        case(osgGA::GUIEventAdapter::KEYUP):
573        {
574            if (ea.getKey() == _keyEventIncreaseLODScale)
575            {
576                camera->setLODScale(camera->getLODScale()*1.1);
577                osg::notify(osg::NOTICE)<<"LODScale = "<<camera->getLODScale()<<std::endl;
578                return true;
579            }
580
581            else if (ea.getKey() == _keyEventDecreaseLODScale)
582            {
583                camera->setLODScale(camera->getLODScale()/1.1);
584                osg::notify(osg::NOTICE)<<"LODScale = "<<camera->getLODScale()<<std::endl;
585                return true;
586            }       
587
588            break;
589        }
590    default:
591        break;
592    }
593
594    return false;
595}
596
597void LODScaleHandler::getUsage(osg::ApplicationUsage& usage) const
598{
599    {
600        std::ostringstream ostr;
601        ostr<<char(_keyEventIncreaseLODScale);
602        usage.addKeyboardMouseBinding(ostr.str(),"Increase LODScale.");
603    }
604   
605    {
606        std::ostringstream ostr;
607        ostr<<char(_keyEventDecreaseLODScale);
608        usage.addKeyboardMouseBinding(ostr.str(),"Decrease LODScale.");
609    }
610}
611
612
613bool InteractiveImageHandler::mousePosition(osgViewer::View* view, osg::NodeVisitor* nv, const osgGA::GUIEventAdapter& ea, int& x, int &y) const
614{
615    osgUtil::LineSegmentIntersector::Intersections intersections;
616    bool foundIntersection = view==0 ? false :
617        (nv==0 ? view->computeIntersections(ea.getX(), ea.getY(), intersections) :
618                 view->computeIntersections(ea.getX(), ea.getY(), nv->getNodePath(), intersections));
619
620    if (foundIntersection)
621    {
622
623        osg::Vec2 tc(0.5f,0.5f);
624
625        // use the nearest intersection                 
626        const osgUtil::LineSegmentIntersector::Intersection& intersection = *(intersections.begin());
627        osg::Drawable* drawable = intersection.drawable.get();
628        osg::Geometry* geometry = drawable ? drawable->asGeometry() : 0;
629        osg::Vec3Array* vertices = geometry ? dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray()) : 0;
630        if (vertices)
631        {
632            // get the vertex indices.
633            const osgUtil::LineSegmentIntersector::Intersection::IndexList& indices = intersection.indexList;
634            const osgUtil::LineSegmentIntersector::Intersection::RatioList& ratios = intersection.ratioList;
635
636            if (indices.size()==3 && ratios.size()==3)
637            {
638                unsigned int i1 = indices[0];
639                unsigned int i2 = indices[1];
640                unsigned int i3 = indices[2];
641
642                float r1 = ratios[0];
643                float r2 = ratios[1];
644                float r3 = ratios[2];
645
646                osg::Array* texcoords = (geometry->getNumTexCoordArrays()>0) ? geometry->getTexCoordArray(0) : 0;
647                osg::Vec2Array* texcoords_Vec2Array = dynamic_cast<osg::Vec2Array*>(texcoords);
648                if (texcoords_Vec2Array)
649                {
650                    // we have tex coord array so now we can compute the final tex coord at the point of intersection.                               
651                    osg::Vec2 tc1 = (*texcoords_Vec2Array)[i1];
652                    osg::Vec2 tc2 = (*texcoords_Vec2Array)[i2];
653                    osg::Vec2 tc3 = (*texcoords_Vec2Array)[i3];
654                    tc = tc1*r1 + tc2*r2 + tc3*r3;
655                }
656            }
657        }
658
659        osg::TexMat* activeTexMat = 0;
660        osg::Texture* activeTexture = 0;
661       
662        if (geometry->getStateSet())
663        {
664            osg::TexMat* texMat = dynamic_cast<osg::TexMat*>(geometry->getStateSet()->getTextureAttribute(0,osg::StateAttribute::TEXMAT));
665            if (texMat) activeTexMat = texMat;
666
667            osg::Texture* texture = dynamic_cast<osg::Texture*>(geometry->getStateSet()->getTextureAttribute(0,osg::StateAttribute::TEXTURE));
668            if (texture) activeTexture = texture;
669        }
670
671        if (activeTexMat)
672        {
673            osg::Vec4 tc_transformed = osg::Vec4(tc.x(), tc.y(), 0.0f,0.0f) * activeTexMat->getMatrix();
674            tc.x() = tc_transformed.x();
675            tc.y() = tc_transformed.y();
676        }
677
678        if (dynamic_cast<osg::TextureRectangle*>(activeTexture))
679        {
680            x = int( tc.x() );
681            y = int( tc.y() );
682        }
683        else if (_image.valid())
684        {
685            x = int( float(_image->s()) * tc.x() );
686            y = int( float(_image->t()) * tc.y() );
687        }
688
689
690        return true;
691    }
692   
693    return false;
694}
695
696
697bool InteractiveImageHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa, osg::Object*, osg::NodeVisitor* nv)
698{
699    if (ea.getHandled()) return false;
700   
701    if (!_image) return false;
702
703    switch(ea.getEventType())
704    {
705        case(osgGA::GUIEventAdapter::MOVE):
706        case(osgGA::GUIEventAdapter::DRAG):
707        case(osgGA::GUIEventAdapter::PUSH):
708        case(osgGA::GUIEventAdapter::RELEASE):
709        {
710            osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
711            int x,y;
712            if (mousePosition(view, nv, ea, x, y))
713            {
714                return _image->sendPointerEvent(x, y, ea.getButtonMask());
715            }
716            break;
717        }
718        case(osgGA::GUIEventAdapter::KEYDOWN):
719        case(osgGA::GUIEventAdapter::KEYUP):
720        {
721            osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
722            int x,y;
723            bool sendKeyEvent = mousePosition(view, nv, ea, x, y);
724       
725            if (sendKeyEvent)
726            {
727                return _image->sendKeyEvent(ea.getKey(), ea.getEventType()==osgGA::GUIEventAdapter::KEYDOWN);
728            }         
729        }
730
731        default:
732            return false;
733    }
734    return false;
735}
736
737bool InteractiveImageHandler::cull(osg::NodeVisitor* nv, osg::Drawable*, osg::RenderInfo*) const
738{
739    if (_image.valid())
740    {
741        _image->setFrameLastRendered(nv->getFrameStamp());
742    }
743
744    return false;
745}
746
747}
Note: See TracBrowser for help on using the browser.