root/OpenSceneGraph/trunk/src/osgQt/GraphicsWindowQt.cpp @ 13130

Revision 13130, 29.1 kB (checked in by robert, 2 days 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) 2009 Wang Rui
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 <osg/DeleteHandler>
15#include <osgQt/GraphicsWindowQt>
16#include <osgViewer/ViewerBase>
17#include <QtGui/QInputEvent>
18
19using namespace osgQt;
20
21
22class QtKeyboardMap
23{
24
25public:
26    QtKeyboardMap()
27    {
28        mKeyMap[Qt::Key_Escape     ] = osgGA::GUIEventAdapter::KEY_Escape;
29        mKeyMap[Qt::Key_Delete   ] = osgGA::GUIEventAdapter::KEY_Delete;
30        mKeyMap[Qt::Key_Home       ] = osgGA::GUIEventAdapter::KEY_Home;
31        mKeyMap[Qt::Key_Enter      ] = osgGA::GUIEventAdapter::KEY_KP_Enter;
32        mKeyMap[Qt::Key_End        ] = osgGA::GUIEventAdapter::KEY_End;
33        mKeyMap[Qt::Key_Return     ] = osgGA::GUIEventAdapter::KEY_Return;
34        mKeyMap[Qt::Key_PageUp     ] = osgGA::GUIEventAdapter::KEY_Page_Up;
35        mKeyMap[Qt::Key_PageDown   ] = osgGA::GUIEventAdapter::KEY_Page_Down;
36        mKeyMap[Qt::Key_Left       ] = osgGA::GUIEventAdapter::KEY_Left;
37        mKeyMap[Qt::Key_Right      ] = osgGA::GUIEventAdapter::KEY_Right;
38        mKeyMap[Qt::Key_Up         ] = osgGA::GUIEventAdapter::KEY_Up;
39        mKeyMap[Qt::Key_Down       ] = osgGA::GUIEventAdapter::KEY_Down;
40        mKeyMap[Qt::Key_Backspace  ] = osgGA::GUIEventAdapter::KEY_BackSpace;
41        mKeyMap[Qt::Key_Tab        ] = osgGA::GUIEventAdapter::KEY_Tab;
42        mKeyMap[Qt::Key_Space      ] = osgGA::GUIEventAdapter::KEY_Space;
43        mKeyMap[Qt::Key_Delete     ] = osgGA::GUIEventAdapter::KEY_Delete;
44        mKeyMap[Qt::Key_Alt      ] = osgGA::GUIEventAdapter::KEY_Alt_L;
45        mKeyMap[Qt::Key_Shift    ] = osgGA::GUIEventAdapter::KEY_Shift_L;
46        mKeyMap[Qt::Key_Control  ] = osgGA::GUIEventAdapter::KEY_Control_L;
47        mKeyMap[Qt::Key_Meta     ] = osgGA::GUIEventAdapter::KEY_Meta_L;
48
49        mKeyMap[Qt::Key_F1             ] = osgGA::GUIEventAdapter::KEY_F1;
50        mKeyMap[Qt::Key_F2             ] = osgGA::GUIEventAdapter::KEY_F2;
51        mKeyMap[Qt::Key_F3             ] = osgGA::GUIEventAdapter::KEY_F3;
52        mKeyMap[Qt::Key_F4             ] = osgGA::GUIEventAdapter::KEY_F4;
53        mKeyMap[Qt::Key_F5             ] = osgGA::GUIEventAdapter::KEY_F5;
54        mKeyMap[Qt::Key_F6             ] = osgGA::GUIEventAdapter::KEY_F6;
55        mKeyMap[Qt::Key_F7             ] = osgGA::GUIEventAdapter::KEY_F7;
56        mKeyMap[Qt::Key_F8             ] = osgGA::GUIEventAdapter::KEY_F8;
57        mKeyMap[Qt::Key_F9             ] = osgGA::GUIEventAdapter::KEY_F9;
58        mKeyMap[Qt::Key_F10            ] = osgGA::GUIEventAdapter::KEY_F10;
59        mKeyMap[Qt::Key_F11            ] = osgGA::GUIEventAdapter::KEY_F11;
60        mKeyMap[Qt::Key_F12            ] = osgGA::GUIEventAdapter::KEY_F12;
61        mKeyMap[Qt::Key_F13            ] = osgGA::GUIEventAdapter::KEY_F13;
62        mKeyMap[Qt::Key_F14            ] = osgGA::GUIEventAdapter::KEY_F14;
63        mKeyMap[Qt::Key_F15            ] = osgGA::GUIEventAdapter::KEY_F15;
64        mKeyMap[Qt::Key_F16            ] = osgGA::GUIEventAdapter::KEY_F16;
65        mKeyMap[Qt::Key_F17            ] = osgGA::GUIEventAdapter::KEY_F17;
66        mKeyMap[Qt::Key_F18            ] = osgGA::GUIEventAdapter::KEY_F18;
67        mKeyMap[Qt::Key_F19            ] = osgGA::GUIEventAdapter::KEY_F19;
68        mKeyMap[Qt::Key_F20            ] = osgGA::GUIEventAdapter::KEY_F20;
69
70        mKeyMap[Qt::Key_hyphen         ] = '-';
71        mKeyMap[Qt::Key_Equal         ] = '=';
72
73        mKeyMap[Qt::Key_division      ] = osgGA::GUIEventAdapter::KEY_KP_Divide;
74        mKeyMap[Qt::Key_multiply      ] = osgGA::GUIEventAdapter::KEY_KP_Multiply;
75        mKeyMap[Qt::Key_Minus         ] = '-';
76        mKeyMap[Qt::Key_Plus          ] = '+';
77        //mKeyMap[Qt::Key_H              ] = osgGA::GUIEventAdapter::KEY_KP_Home;
78        //mKeyMap[Qt::Key_                    ] = osgGA::GUIEventAdapter::KEY_KP_Up;
79        //mKeyMap[92                    ] = osgGA::GUIEventAdapter::KEY_KP_Page_Up;
80        //mKeyMap[86                    ] = osgGA::GUIEventAdapter::KEY_KP_Left;
81        //mKeyMap[87                    ] = osgGA::GUIEventAdapter::KEY_KP_Begin;
82        //mKeyMap[88                    ] = osgGA::GUIEventAdapter::KEY_KP_Right;
83        //mKeyMap[83                    ] = osgGA::GUIEventAdapter::KEY_KP_End;
84        //mKeyMap[84                    ] = osgGA::GUIEventAdapter::KEY_KP_Down;
85        //mKeyMap[85                    ] = osgGA::GUIEventAdapter::KEY_KP_Page_Down;
86        mKeyMap[Qt::Key_Insert        ] = osgGA::GUIEventAdapter::KEY_KP_Insert;
87        //mKeyMap[Qt::Key_Delete        ] = osgGA::GUIEventAdapter::KEY_KP_Delete;
88    }
89
90    ~QtKeyboardMap()
91    {
92    }
93
94    int remapKey(QKeyEvent* event)
95    {
96        KeyMap::iterator itr = mKeyMap.find(event->key());
97        if (itr == mKeyMap.end())
98        {
99            return int(*(event->text().toAscii().data()));
100        }
101        else
102            return itr->second;
103    }
104
105    private:
106    typedef std::map<unsigned int, int> KeyMap;
107    KeyMap mKeyMap;
108};
109
110static QtKeyboardMap s_QtKeyboardMap;
111
112
113/// The object responsible for the scene re-rendering.
114class HeartBeat : public QObject {
115public:
116int _timerId;
117osg::Timer _lastFrameStartTime;
118osg::observer_ptr< osgViewer::ViewerBase > _viewer;
119
120HeartBeat();
121virtual ~HeartBeat();
122void init( osgViewer::ViewerBase *viewer );
123void stopTimer();
124void timerEvent( QTimerEvent *event );
125};
126
127static HeartBeat heartBeat;
128
129GLWidget::GLWidget( QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f, bool forwardKeyEvents )
130: QGLWidget(parent, shareWidget, f),
131_gw( NULL ),
132_forwardKeyEvents( forwardKeyEvents )
133{
134}
135
136GLWidget::GLWidget( QGLContext* context, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f,
137                    bool forwardKeyEvents )
138: QGLWidget(context, parent, shareWidget, f),
139_gw( NULL ),
140_forwardKeyEvents( forwardKeyEvents )
141{
142}
143
144GLWidget::GLWidget( const QGLFormat& format, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f,
145                    bool forwardKeyEvents )
146: QGLWidget(format, parent, shareWidget, f),
147_gw( NULL ),
148_forwardKeyEvents( forwardKeyEvents )
149{
150}
151
152GLWidget::~GLWidget()
153{
154    // close GraphicsWindowQt and remove the reference to us
155    if( _gw )
156    {
157        _gw->close();
158        _gw->_widget = NULL;
159        _gw = NULL;
160    }
161}
162
163void GLWidget::processDeferredEvents()
164{
165    QQueue<QEvent::Type> deferredEventQueueCopy;
166    {
167        QMutexLocker lock(&_deferredEventQueueMutex);
168        deferredEventQueueCopy = _deferredEventQueue;
169        _eventCompressor.clear();
170        _deferredEventQueue.clear();
171    }
172
173    while (!deferredEventQueueCopy.isEmpty())
174    {
175        QEvent event(deferredEventQueueCopy.dequeue());
176        QGLWidget::event(&event);
177    }
178}
179
180bool GLWidget::event( QEvent* event )
181{
182
183    // QEvent::Hide
184    //
185    // workaround "Qt-workaround" that does glFinish before hiding the widget
186    // (the Qt workaround was seen at least in Qt 4.6.3 and 4.7.0)
187    //
188    // Qt makes the context current, performs glFinish, and releases the context.
189    // This makes the problem in OSG multithreaded environment as the context
190    // is active in another thread, thus it can not be made current for the purpose
191    // of glFinish in this thread.
192
193    // QEvent::ParentChange
194    //
195    // Reparenting GLWidget may create a new underlying window and a new GL context.
196    // Qt will then call doneCurrent on the GL context about to be deleted. The thread
197    // where old GL context was current has no longer current context to render to and
198    // we cannot make new GL context current in this thread.
199
200    // We workaround above problems by deferring execution of problematic event requests.
201    // These events has to be enqueue and executed later in a main GUI thread (GUI operations
202    // outside the main thread are not allowed) just before makeCurrent is called from the
203    // right thread. The good place for doing that is right after swap in a swapBuffersImplementation.
204
205    if (event->type() == QEvent::Hide)
206    {
207        // enqueue only the last of QEvent::Hide and QEvent::Show
208        enqueueDeferredEvent(QEvent::Hide, QEvent::Show);
209        return true;
210    }
211    else if (event->type() == QEvent::Show)
212    {
213        // enqueue only the last of QEvent::Show or QEvent::Hide
214        enqueueDeferredEvent(QEvent::Show, QEvent::Hide);
215        return true;
216    }
217    else if (event->type() == QEvent::ParentChange)
218    {
219        // enqueue only the last QEvent::ParentChange
220        enqueueDeferredEvent(QEvent::ParentChange);
221        return true;
222    }
223
224    // perform regular event handling
225    return QGLWidget::event( event );
226}
227
228void GLWidget::setKeyboardModifiers( QInputEvent* event )
229{
230    int modkey = event->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier);
231    unsigned int mask = 0;
232    if ( modkey & Qt::ShiftModifier ) mask |= osgGA::GUIEventAdapter::MODKEY_SHIFT;
233    if ( modkey & Qt::ControlModifier ) mask |= osgGA::GUIEventAdapter::MODKEY_CTRL;
234    if ( modkey & Qt::AltModifier ) mask |= osgGA::GUIEventAdapter::MODKEY_ALT;
235    _gw->getEventQueue()->getCurrentEventState()->setModKeyMask( mask );
236}
237
238void GLWidget::resizeEvent( QResizeEvent* event )
239{
240    const QSize& size = event->size();
241    _gw->resized( x(), y(), size.width(), size.height() );
242    _gw->getEventQueue()->windowResize( x(), y(), size.width(), size.height() );
243    _gw->requestRedraw();
244}
245
246void GLWidget::moveEvent( QMoveEvent* event )
247{
248    const QPoint& pos = event->pos();
249    _gw->resized( pos.x(), pos.y(), width(), height() );
250    _gw->getEventQueue()->windowResize( pos.x(), pos.y(), width(), height() );
251}
252
253void GLWidget::glDraw()
254{
255    _gw->requestRedraw();
256}
257
258void GLWidget::keyPressEvent( QKeyEvent* event )
259{
260    setKeyboardModifiers( event );
261    int value = s_QtKeyboardMap.remapKey( event );
262    _gw->getEventQueue()->keyPress( value );
263
264    // this passes the event to the regular Qt key event processing,
265    // among others, it closes popup windows on ESC and forwards the event to the parent widgets
266    if( _forwardKeyEvents )
267        inherited::keyPressEvent( event );
268}
269
270void GLWidget::keyReleaseEvent( QKeyEvent* event )
271{
272    setKeyboardModifiers( event );
273    int value = s_QtKeyboardMap.remapKey( event );
274    _gw->getEventQueue()->keyRelease( value );
275
276    // this passes the event to the regular Qt key event processing,
277    // among others, it closes popup windows on ESC and forwards the event to the parent widgets
278    if( _forwardKeyEvents )
279        inherited::keyReleaseEvent( event );
280}
281
282void GLWidget::mousePressEvent( QMouseEvent* event )
283{
284    int button = 0;
285    switch ( event->button() )
286    {
287        case Qt::LeftButton: button = 1; break;
288        case Qt::MidButton: button = 2; break;
289        case Qt::RightButton: button = 3; break;
290        case Qt::NoButton: button = 0; break;
291        default: button = 0; break;
292    }
293    setKeyboardModifiers( event );
294    _gw->getEventQueue()->mouseButtonPress( event->x(), event->y(), button );
295}
296
297void GLWidget::mouseReleaseEvent( QMouseEvent* event )
298{
299    int button = 0;
300    switch ( event->button() )
301    {
302        case Qt::LeftButton: button = 1; break;
303        case Qt::MidButton: button = 2; break;
304        case Qt::RightButton: button = 3; break;
305        case Qt::NoButton: button = 0; break;
306        default: button = 0; break;
307    }
308    setKeyboardModifiers( event );
309    _gw->getEventQueue()->mouseButtonRelease( event->x(), event->y(), button );
310}
311
312void GLWidget::mouseDoubleClickEvent( QMouseEvent* event )
313{
314    int button = 0;
315    switch ( event->button() )
316    {
317        case Qt::LeftButton: button = 1; break;
318        case Qt::MidButton: button = 2; break;
319        case Qt::RightButton: button = 3; break;
320        case Qt::NoButton: button = 0; break;
321        default: button = 0; break;
322    }
323    setKeyboardModifiers( event );
324    _gw->getEventQueue()->mouseDoubleButtonPress( event->x(), event->y(), button );
325}
326
327void GLWidget::mouseMoveEvent( QMouseEvent* event )
328{
329    setKeyboardModifiers( event );
330    _gw->getEventQueue()->mouseMotion( event->x(), event->y() );
331}
332
333void GLWidget::wheelEvent( QWheelEvent* event )
334{
335    setKeyboardModifiers( event );
336    _gw->getEventQueue()->mouseScroll(
337        event->orientation() == Qt::Vertical ?
338            (event->delta()>0 ? osgGA::GUIEventAdapter::SCROLL_UP : osgGA::GUIEventAdapter::SCROLL_DOWN) :
339            (event->delta()>0 ? osgGA::GUIEventAdapter::SCROLL_LEFT : osgGA::GUIEventAdapter::SCROLL_RIGHT) );
340}
341
342
343
344GraphicsWindowQt::GraphicsWindowQt( osg::GraphicsContext::Traits* traits, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f )
345:   _realized(false)
346{
347
348    _widget = NULL;
349    _traits = traits;
350    init( parent, shareWidget, f );
351}
352
353GraphicsWindowQt::GraphicsWindowQt( GLWidget* widget )
354:   _realized(false)
355{
356    _widget = widget;
357    _traits = _widget ? createTraits( _widget ) : new osg::GraphicsContext::Traits;
358    init( NULL, NULL, 0 );
359}
360
361GraphicsWindowQt::~GraphicsWindowQt()
362{
363    close();
364
365    // remove reference from GLWidget
366    if ( _widget )
367        _widget->_gw = NULL;
368}
369
370bool GraphicsWindowQt::init( QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f )
371{
372    // update _widget and parent by WindowData
373    WindowData* windowData = _traits.get() ? dynamic_cast<WindowData*>(_traits->inheritedWindowData.get()) : 0;
374    if ( !_widget )
375        _widget = windowData ? windowData->_widget : NULL;
376    if ( !parent )
377        parent = windowData ? windowData->_parent : NULL;
378
379    // create widget if it does not exist
380    _ownsWidget = _widget == NULL;
381    if ( !_widget )
382    {
383        // shareWidget
384        if ( !shareWidget ) {
385            GraphicsWindowQt* sharedContextQt = dynamic_cast<GraphicsWindowQt*>(_traits->sharedContext.get());
386            if ( sharedContextQt )
387                shareWidget = sharedContextQt->getGLWidget();
388        }
389
390        // WindowFlags
391        Qt::WindowFlags flags = f | Qt::Window | Qt::CustomizeWindowHint;
392        if ( _traits->windowDecoration )
393            flags |= Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowSystemMenuHint
394#if (QT_VERSION_CHECK(4, 5, 0) <= QT_VERSION)
395                | Qt::WindowCloseButtonHint
396#endif
397                ;
398
399        // create widget
400        _widget = new GLWidget( traits2qglFormat( _traits.get() ), parent, shareWidget, flags );
401    }
402
403    // set widget name and position
404    // (do not set it when we inherited the widget)
405    if ( _ownsWidget )
406    {
407        _widget->setWindowTitle( _traits->windowName.c_str() );
408        _widget->move( _traits->x, _traits->y );
409        if ( !_traits->supportsResize ) _widget->setFixedSize( _traits->width, _traits->height );
410        else _widget->resize( _traits->width, _traits->height );
411    }
412
413    // initialize widget properties
414    _widget->setAutoBufferSwap( false );
415    _widget->setMouseTracking( true );
416    _widget->setFocusPolicy( Qt::WheelFocus );
417    _widget->setGraphicsWindow( this );
418    useCursor( _traits->useCursor );
419
420    // initialize State
421    setState( new osg::State );
422    getState()->setGraphicsContext(this);
423
424    // initialize contextID
425    if ( _traits.valid() && _traits->sharedContext.valid() )
426    {
427        getState()->setContextID( _traits->sharedContext->getState()->getContextID() );
428        incrementContextIDUsageCount( getState()->getContextID() );
429    }
430    else
431    {
432        getState()->setContextID( osg::GraphicsContext::createNewContextID() );
433    }
434
435    return true;
436}
437
438QGLFormat GraphicsWindowQt::traits2qglFormat( const osg::GraphicsContext::Traits* traits )
439{
440    QGLFormat format( QGLFormat::defaultFormat() );
441
442    format.setAlphaBufferSize( traits->alpha );
443    format.setRedBufferSize( traits->red );
444    format.setGreenBufferSize( traits->green );
445    format.setBlueBufferSize( traits->blue );
446    format.setDepthBufferSize( traits->depth );
447    format.setStencilBufferSize( traits->stencil );
448    format.setSampleBuffers( traits->sampleBuffers );
449    format.setSamples( traits->samples );
450
451    format.setAlpha( traits->alpha>0 );
452    format.setDepth( traits->depth>0 );
453    format.setStencil( traits->stencil>0 );
454    format.setDoubleBuffer( traits->doubleBuffer );
455    format.setSwapInterval( traits->vsync ? 1 : 0 );
456    format.setStereo( traits->quadBufferStereo ? 1 : 0 );
457
458    return format;
459}
460
461void GraphicsWindowQt::qglFormat2traits( const QGLFormat& format, osg::GraphicsContext::Traits* traits )
462{
463    traits->red = format.redBufferSize();
464    traits->green = format.greenBufferSize();
465    traits->blue = format.blueBufferSize();
466    traits->alpha = format.alpha() ? format.alphaBufferSize() : 0;
467    traits->depth = format.depth() ? format.depthBufferSize() : 0;
468    traits->stencil = format.stencil() ? format.stencilBufferSize() : 0;
469
470    traits->sampleBuffers = format.sampleBuffers() ? 1 : 0;
471    traits->samples = format.samples();
472
473    traits->quadBufferStereo = format.stereo();
474    traits->doubleBuffer = format.doubleBuffer();
475
476    traits->vsync = format.swapInterval() >= 1;
477}
478
479osg::GraphicsContext::Traits* GraphicsWindowQt::createTraits( const QGLWidget* widget )
480{
481    osg::GraphicsContext::Traits *traits = new osg::GraphicsContext::Traits;
482
483    qglFormat2traits( widget->format(), traits );
484
485    QRect r = widget->geometry();
486    traits->x = r.x();
487    traits->y = r.y();
488    traits->width = r.width();
489    traits->height = r.height();
490
491    traits->windowName = widget->windowTitle().toLocal8Bit().data();
492    Qt::WindowFlags f = widget->windowFlags();
493    traits->windowDecoration = ( f & Qt::WindowTitleHint ) &&
494                            ( f & Qt::WindowMinMaxButtonsHint ) &&
495                            ( f & Qt::WindowSystemMenuHint );
496    QSizePolicy sp = widget->sizePolicy();
497    traits->supportsResize = sp.horizontalPolicy() != QSizePolicy::Fixed ||
498                            sp.verticalPolicy() != QSizePolicy::Fixed;
499
500    return traits;
501}
502
503bool GraphicsWindowQt::setWindowRectangleImplementation( int x, int y, int width, int height )
504{
505    if ( _widget == NULL )
506        return false;
507
508    _widget->setGeometry( x, y, width, height );
509    return true;
510}
511
512void GraphicsWindowQt::getWindowRectangle( int& x, int& y, int& width, int& height )
513{
514    if ( _widget )
515    {
516        const QRect& geom = _widget->geometry();
517        x = geom.x();
518        y = geom.y();
519        width = geom.width();
520        height = geom.height();
521    }
522}
523
524bool GraphicsWindowQt::setWindowDecorationImplementation( bool windowDecoration )
525{
526    Qt::WindowFlags flags = Qt::Window|Qt::CustomizeWindowHint;//|Qt::WindowStaysOnTopHint;
527    if ( windowDecoration )
528        flags |= Qt::WindowTitleHint|Qt::WindowMinMaxButtonsHint|Qt::WindowSystemMenuHint;
529    _traits->windowDecoration = windowDecoration;
530
531    if ( _widget )
532    {
533        _widget->setWindowFlags( flags );
534
535        return true;
536    }
537
538    return false;
539}
540
541bool GraphicsWindowQt::getWindowDecoration() const
542{
543    return _traits->windowDecoration;
544}
545
546void GraphicsWindowQt::grabFocus()
547{
548    if ( _widget )
549        _widget->setFocus( Qt::ActiveWindowFocusReason );
550}
551
552void GraphicsWindowQt::grabFocusIfPointerInWindow()
553{
554    if ( _widget->underMouse() )
555        _widget->setFocus( Qt::ActiveWindowFocusReason );
556}
557
558void GraphicsWindowQt::raiseWindow()
559{
560    if ( _widget )
561        _widget->raise();
562}
563
564void GraphicsWindowQt::setWindowName( const std::string& name )
565{
566    if ( _widget )
567        _widget->setWindowTitle( name.c_str() );
568}
569
570std::string GraphicsWindowQt::getWindowName()
571{
572    return _widget ? _widget->windowTitle().toStdString() : "";
573}
574
575void GraphicsWindowQt::useCursor( bool cursorOn )
576{
577    if ( _widget )
578    {
579        _traits->useCursor = cursorOn;
580        if ( !cursorOn ) _widget->setCursor( Qt::BlankCursor );
581        else _widget->setCursor( _currentCursor );
582    }
583}
584
585void GraphicsWindowQt::setCursor( MouseCursor cursor )
586{
587    if ( cursor==InheritCursor && _widget )
588    {
589        _widget->unsetCursor();
590    }
591
592    switch ( cursor )
593    {
594    case NoCursor: _currentCursor = Qt::BlankCursor; break;
595    case RightArrowCursor: case LeftArrowCursor: _currentCursor = Qt::ArrowCursor; break;
596    case InfoCursor: _currentCursor = Qt::SizeAllCursor; break;
597    case DestroyCursor: _currentCursor = Qt::ForbiddenCursor; break;
598    case HelpCursor: _currentCursor = Qt::WhatsThisCursor; break;
599    case CycleCursor: _currentCursor = Qt::ForbiddenCursor; break;
600    case SprayCursor: _currentCursor = Qt::SizeAllCursor; break;
601    case WaitCursor: _currentCursor = Qt::WaitCursor; break;
602    case TextCursor: _currentCursor = Qt::IBeamCursor; break;
603    case CrosshairCursor: _currentCursor = Qt::CrossCursor; break;
604    case HandCursor: _currentCursor = Qt::OpenHandCursor; break;
605    case UpDownCursor: _currentCursor = Qt::SizeVerCursor; break;
606    case LeftRightCursor: _currentCursor = Qt::SizeHorCursor; break;
607    case TopSideCursor: case BottomSideCursor: _currentCursor = Qt::UpArrowCursor; break;
608    case LeftSideCursor: case RightSideCursor: _currentCursor = Qt::SizeHorCursor; break;
609    case TopLeftCorner: _currentCursor = Qt::SizeBDiagCursor; break;
610    case TopRightCorner: _currentCursor = Qt::SizeFDiagCursor; break;
611    case BottomRightCorner: _currentCursor = Qt::SizeBDiagCursor; break;
612    case BottomLeftCorner: _currentCursor = Qt::SizeFDiagCursor; break;
613    default: break;
614    };
615    if ( _widget ) _widget->setCursor( _currentCursor );
616}
617
618bool GraphicsWindowQt::valid() const
619{
620    return _widget && _widget->isValid();
621}
622
623bool GraphicsWindowQt::realizeImplementation()
624{
625    // save the current context
626    // note: this will save only Qt-based contexts
627    const QGLContext *savedContext = QGLContext::currentContext();
628
629    // initialize GL context for the widget
630    if ( !valid() )
631        _widget->glInit();
632
633    // make current
634    _realized = true;
635    bool result = makeCurrent();
636    _realized = false;
637
638    // fail if we do not have current context
639    if ( !result )
640    {
641        if ( savedContext )
642            const_cast< QGLContext* >( savedContext )->makeCurrent();
643
644        OSG_WARN << "Window realize: Can make context current." << std::endl;
645        return false;
646    }
647
648    _realized = true;
649
650    // make this window's context not current
651    // note: this must be done as we will probably make the context current from another thread
652    //       and it is not allowed to have one context current in two threads
653    if( !releaseContext() )
654        OSG_WARN << "Window realize: Can not release context." << std::endl;
655
656    // restore previous context
657    if ( savedContext )
658        const_cast< QGLContext* >( savedContext )->makeCurrent();
659
660    return true;
661}
662
663bool GraphicsWindowQt::isRealizedImplementation() const
664{
665    return _realized;
666}
667
668void GraphicsWindowQt::closeImplementation()
669{
670    if ( _widget )
671        _widget->close();
672    _realized = false;
673}
674
675void GraphicsWindowQt::runOperations()
676{
677    // While in graphics thread this is last chance to do something useful before
678    // graphics thread will execute its operations.
679    if (_widget->getNumDeferredEvents() > 0)
680        _widget->processDeferredEvents();
681
682    if (QGLContext::currentContext() != _widget->context())
683        _widget->makeCurrent();
684
685    GraphicsWindow::runOperations();
686}
687
688bool GraphicsWindowQt::makeCurrentImplementation()
689{
690    if (_widget->getNumDeferredEvents() > 0)
691        _widget->processDeferredEvents();
692
693    _widget->makeCurrent();
694
695    return true;
696}
697
698bool GraphicsWindowQt::releaseContextImplementation()
699{
700    _widget->doneCurrent();
701    return true;
702}
703
704void GraphicsWindowQt::swapBuffersImplementation()
705{
706    _widget->swapBuffers();
707
708    // FIXME: the processDeferredEvents should really be executed in a GUI (main) thread context but
709    // I couln't find any reliable way to do this. For now, lets hope non of *GUI thread only operations* will
710    // be executed in a QGLWidget::event handler. On the other hand, calling GUI only operations in the
711    // QGLWidget event handler is an indication of a Qt bug.
712    if (_widget->getNumDeferredEvents() > 0)
713        _widget->processDeferredEvents();
714
715    // We need to call makeCurrent here to restore our previously current context
716    // which may be changed by the processDeferredEvents function.
717    if (QGLContext::currentContext() != _widget->context())
718        _widget->makeCurrent();
719}
720
721void GraphicsWindowQt::requestWarpPointer( float x, float y )
722{
723    if ( _widget )
724        QCursor::setPos( _widget->mapToGlobal(QPoint((int)x,(int)y)) );
725}
726
727
728class QtWindowingSystem : public osg::GraphicsContext::WindowingSystemInterface
729{
730public:
731
732    QtWindowingSystem()
733    {
734        OSG_INFO << "QtWindowingSystemInterface()" << std::endl;
735    }
736
737    ~QtWindowingSystem()
738    {
739        if (osg::Referenced::getDeleteHandler())
740        {
741            osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
742            osg::Referenced::getDeleteHandler()->flushAll();
743        }
744    }
745
746    // Access the Qt windowing system through this singleton class.
747    static QtWindowingSystem* getInterface()
748    {
749        static QtWindowingSystem* qtInterface = new QtWindowingSystem;
750        return qtInterface;
751    }
752
753    // Return the number of screens present in the system
754    virtual unsigned int getNumScreens( const osg::GraphicsContext::ScreenIdentifier& si )
755    {
756        OSG_WARN << "osgQt: getNumScreens() not implemented yet." << std::endl;
757        return 0;
758    }
759
760    // Return the resolution of specified screen
761    // (0,0) is returned if screen is unknown
762    virtual void getScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution )
763    {
764        OSG_WARN << "osgQt: getScreenSettings() not implemented yet." << std::endl;
765    }
766
767    // Set the resolution for given screen
768    virtual bool setScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, const osg::GraphicsContext::ScreenSettings & resolution )
769    {
770        OSG_WARN << "osgQt: setScreenSettings() not implemented yet." << std::endl;
771        return false;
772    }
773
774    // Enumerates available resolutions
775    virtual void enumerateScreenSettings( const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, osg::GraphicsContext::ScreenSettingsList & resolution )
776    {
777        OSG_WARN << "osgQt: enumerateScreenSettings() not implemented yet." << std::endl;
778    }
779
780    // Create a graphics context with given traits
781    virtual osg::GraphicsContext* createGraphicsContext( osg::GraphicsContext::Traits* traits )
782    {
783        if (traits->pbuffer)
784        {
785            OSG_WARN << "osgQt: createGraphicsContext - pbuffer not implemented yet." << std::endl;
786            return NULL;
787        }
788        else
789        {
790            osg::ref_ptr< GraphicsWindowQt > window = new GraphicsWindowQt( traits );
791            if (window->valid()) return window.release();
792            else return NULL;
793        }
794    }
795
796private:
797
798    // No implementation for these
799    QtWindowingSystem( const QtWindowingSystem& );
800    QtWindowingSystem& operator=( const QtWindowingSystem& );
801};
802
803
804// declare C entry point for static compilation.
805extern "C" void OSGQT_EXPORT graphicswindow_Qt(void)
806{
807    osg::GraphicsContext::setWindowingSystemInterface(QtWindowingSystem::getInterface());
808}
809
810
811void osgQt::initQtWindowingSystem()
812{
813    graphicswindow_Qt();
814}
815
816
817
818void osgQt::setViewer( osgViewer::ViewerBase *viewer )
819{
820    heartBeat.init( viewer );
821}
822
823
824/// Constructor. Must be called from main thread.
825HeartBeat::HeartBeat() : _timerId( 0 )
826{
827}
828
829
830/// Destructor. Must be called from main thread.
831HeartBeat::~HeartBeat()
832{
833    stopTimer();
834}
835
836
837void HeartBeat::stopTimer()
838{
839    if ( _timerId != 0 )
840    {
841        killTimer( _timerId );
842        _timerId = 0;
843    }
844}
845
846
847/// Initializes the loop for viewer. Must be called from main thread.
848void HeartBeat::init( osgViewer::ViewerBase *viewer )
849{
850    if( _viewer == viewer )
851        return;
852
853    stopTimer();
854
855    _viewer = viewer;
856
857    if( viewer )
858    {
859        _timerId = startTimer( 0 );
860        _lastFrameStartTime.setStartTick( 0 );
861    }
862}
863
864
865void HeartBeat::timerEvent( QTimerEvent *event )
866{
867    osg::ref_ptr< osgViewer::ViewerBase > viewer;
868    if( !_viewer.lock( viewer ) )
869    {
870        // viewer has been deleted -> stop timer
871        stopTimer();
872        return;
873    }
874
875    // limit the frame rate
876    if( viewer->getRunMaxFrameRate() > 0.0)
877    {
878        double dt = _lastFrameStartTime.time_s();
879        double minFrameTime = 1.0 / viewer->getRunMaxFrameRate();
880        if (dt < minFrameTime)
881            OpenThreads::Thread::microSleep(static_cast<unsigned int>(1000000.0*(minFrameTime-dt)));
882    }
883    else
884    {
885        // avoid excessive CPU loading when no frame is required in ON_DEMAND mode
886        if( viewer->getRunFrameScheme() == osgViewer::ViewerBase::ON_DEMAND )
887        {
888            double dt = _lastFrameStartTime.time_s();
889            if (dt < 0.01)
890                OpenThreads::Thread::microSleep(static_cast<unsigned int>(1000000.0*(0.01-dt)));
891        }
892
893        // record start frame time
894        _lastFrameStartTime.setStartTick();
895
896        // make frame
897        if( viewer->getRunFrameScheme() == osgViewer::ViewerBase::ON_DEMAND )
898        {
899            if( viewer->checkNeedToDoFrame() )
900            {
901                viewer->frame();
902            }
903        }
904        else
905        {
906            viewer->frame();
907        }
908    }
909}
Note: See TracBrowser for help on using the browser.