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

Revision 13376, 29.7 kB (checked in by robert, 44 hours ago)

Added shaders to support experimental shader based displacement mapping technique osgTerrain::ShaderTerrain?.

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