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

Revision 10098, 26.7 kB (checked in by robert, 5 years ago)

Introduce new run frame rate management support to allow control of maximum frame rate and to support on demand rendering of frames

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