zoukankan      html  css  js  c++  java
  • OSG Qt Widget加载三维模型

    graphicswindowqt.h

    #ifndef GRAPHICSWINDOWQT_H
    #define GRAPHICSWINDOWQT_H
    
    #include <QGLWidget>
    #include <osgViewer/GraphicsWindow>
    
    #include <QMutex>
    #include <QEvent>
    #include <QQueue>
    #include <QSet>
    #include <QGLWidget>
    
    #include <QDragMoveEvent>
    #include <QDragEnterEvent>
    #include <QObject>
    
    class QInputEvent;
    class QGestureEvent;
    
    namespace osgViewer {
      class ViewerBase;
    }
    // forward declarations
    class GraphicsWindowQt;
    
    /// The function sets the WindowingSystem to Qt.
    void initQtWindowingSystem();
    
    /** The function sets the viewer that will be used after entering
    *  the Qt main loop (QCoreApplication::exec()).
    *
    *  The function also initializes internal structures required for proper
    *  scene rendering.
    *
    *  The method must be called from main thread. */
    void setViewer(osgViewer::ViewerBase *viewer);
    
    
    class GLWidget : public QGLWidget {
      Q_OBJECT
    
        typedef QGLWidget inherited;
    
    public:
    
      GLWidget(QWidget* parent = NULL, const QGLWidget* shareWidget = NULL, Qt::WindowFlags f = 0, bool forwardKeyEvents = false);
      GLWidget(QGLContext* context, QWidget* parent = NULL, const QGLWidget* shareWidget = NULL, Qt::WindowFlags f = 0, bool forwardKeyEvents = false);
      GLWidget(const QGLFormat& format, QWidget* parent = NULL, const QGLWidget* shareWidget = NULL, Qt::WindowFlags f = 0, bool forwardKeyEvents = false);
      virtual ~GLWidget();
    
      inline void setGraphicsWindow(GraphicsWindowQt* gw) { _gw = gw; }
      inline GraphicsWindowQt* getGraphicsWindow() { return _gw; }
      inline const GraphicsWindowQt* getGraphicsWindow() const { return _gw; }
    
      inline bool getForwardKeyEvents() const { return _forwardKeyEvents; }
      virtual void setForwardKeyEvents(bool f) { _forwardKeyEvents = f; }
    
      inline bool getTouchEventsEnabled() const { return _touchEventsEnabled; }
      void setTouchEventsEnabled(bool e);
    
      void setKeyboardModifiers(QInputEvent* event);
    
      virtual void keyPressEvent(QKeyEvent* event);
      virtual void keyReleaseEvent(QKeyEvent* event);
      virtual void mousePressEvent(QMouseEvent* event);
      virtual void mouseReleaseEvent(QMouseEvent* event);
      virtual void mouseDoubleClickEvent(QMouseEvent* event);
      virtual void mouseMoveEvent(QMouseEvent* event);
      virtual void wheelEvent(QWheelEvent* event);
      virtual bool gestureEvent(QGestureEvent* event);
    
    protected:
      void dragEnterEvent(QDragEnterEvent *event);
      void dragMoveEvent(QDragMoveEvent *event);
      void dropEvent(QDropEvent *event);
    
    signals:
      void signalEnter(QString str);
      void signalLeave(QString str);
      void signalReturnViewpoint(QString str);
    
      void signalMouseRelease(int button, float x, float y);
      void signalMouseMove(float x, float y);
    
      void signalDropEvent(QVariant var);
    
      void signalDelEvent();
    
      void signalResizeEvent(int width, int height);
    
      public slots:
      void slotHandleEnd(bool bReset);
    
    protected:
    
      int getNumDeferredEvents() {
        QMutexLocker lock(&_deferredEventQueueMutex);
        return _deferredEventQueue.count();
      }
      void enqueueDeferredEvent(QEvent::Type eventType, QEvent::Type removeEventType = QEvent::None) {
        QMutexLocker lock(&_deferredEventQueueMutex);
    
        if (removeEventType != QEvent::None) {
          if (_deferredEventQueue.removeOne(removeEventType))
            _eventCompressor.remove(eventType);
        }
    
        if (_eventCompressor.find(eventType) == _eventCompressor.end()) {
          _deferredEventQueue.enqueue(eventType);
          _eventCompressor.insert(eventType);
        }
      }
      void processDeferredEvents();
    
      friend class GraphicsWindowQt;
      GraphicsWindowQt* _gw;
    
      QMutex _deferredEventQueueMutex;
      QQueue<QEvent::Type> _deferredEventQueue;
      QSet<QEvent::Type> _eventCompressor;
    
      bool _touchEventsEnabled;
    
      bool _forwardKeyEvents;
      qreal _devicePixelRatio;
    
      virtual void resizeEvent(QResizeEvent* event);
      virtual void moveEvent(QMoveEvent* event);
      virtual void glDraw();
      virtual bool event(QEvent* event);
    };
    
    class GraphicsWindowQt : public QObject, public osgViewer::GraphicsWindow {
      Q_OBJECT
    
    public:
      GraphicsWindowQt(osg::GraphicsContext::Traits* traits, QWidget* parent = NULL, const QGLWidget* shareWidget = NULL, Qt::WindowFlags f = 0);
      GraphicsWindowQt(GLWidget* widget);
      virtual ~GraphicsWindowQt();
    
      inline GLWidget* getGLWidget() { return _widget; }
      inline const GLWidget* getGLWidget() const { return _widget; }
    
      /// deprecated
      inline GLWidget* getGraphWidget() { return _widget; }
      /// deprecated
      inline const GLWidget* getGraphWidget() const { return _widget; }
    
      struct WindowData : public osg::Referenced {
        WindowData(GLWidget* widget = NULL, QWidget* parent = NULL) : _widget(widget), _parent(parent) {}
        GLWidget* _widget;
        QWidget* _parent;
      };
    
      bool init(QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f);
    
      static QGLFormat traits2qglFormat(const osg::GraphicsContext::Traits* traits);
      static void qglFormat2traits(const QGLFormat& format, osg::GraphicsContext::Traits* traits);
      static osg::GraphicsContext::Traits* createTraits(const QGLWidget* widget);
    
      virtual bool setWindowRectangleImplementation(int x, int y, int width, int height);
      virtual void getWindowRectangle(int& x, int& y, int& width, int& height);
      virtual bool setWindowDecorationImplementation(bool windowDecoration);
      virtual bool getWindowDecoration() const;
      virtual void grabFocus();
      virtual void grabFocusIfPointerInWindow();
      virtual void raiseWindow();
      virtual void setWindowName(const std::string& name);
      virtual std::string getWindowName();
      virtual void useCursor(bool cursorOn);
      virtual void setCursor(MouseCursor cursor);
      inline bool getTouchEventsEnabled() const { return _widget->getTouchEventsEnabled(); }
      virtual void setTouchEventsEnabled(bool e) { _widget->setTouchEventsEnabled(e); }
    
    
      virtual bool valid() const;
      virtual bool realizeImplementation();
      virtual bool isRealizedImplementation() const;
      virtual void closeImplementation();
      virtual bool makeCurrentImplementation();
      virtual bool releaseContextImplementation();
      virtual void swapBuffersImplementation();
      virtual void runOperations();
    
      virtual void requestWarpPointer(float x, float y);
    
    Q_SIGNALS:
      void moveOpenglContextToNewThread(QThread *newThread);
    
      public slots:
      void onMoveOpenglContextToNewThread(QThread *newThread);
    
    protected:
    
      friend class GLWidget;
      GLWidget* _widget;
      bool _ownsWidget;
      QCursor _currentCursor;
      bool _realized;
    };
    
    
    #endif // GRAPHICSWINDOWQT_H

    graphicswindowqt.cpp

    /* -*-c++-*- OpenSceneGraph - Copyright (C) 2009 Wang Rui
    *
    * This library is open source and may be redistributed and/or modified under
    * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
    * (at your option) any later version.  The full license is in LICENSE file
    * included with this distribution, and on the openscenegraph.org website.
    *
    * This library is distributed in the hope that it will be useful,
    * but WITHOUT ANY WARRANTY; without even the implied warranty of
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    * OpenSceneGraph Public License for more details.
    */
    #include "graphicswindowqt.h"
    #include <osg/DeleteHandler>
    //#include "GraphicsWindowQt.h"
    #include <osgViewer/ViewerBase>
    #include <QInputEvent>
    #include <QPointer>
    
    #include <QDebug>
    #include <QMimeData>
    
    #include <QThread>
    #include <QOpenGLContext>
    #include <QWidget>
    #include <QSurface>
    #include <QWindow>
    
    #if (QT_VERSION>=QT_VERSION_CHECK(4, 6, 0))
    # define USE_GESTURES
    # include <QGestureEvent>
    # include <QGesture>
    #endif
    
    class QtKeyboardMap {
    
    public:
      QtKeyboardMap() {
        mKeyMap[Qt::Key_Escape] = osgGA::GUIEventAdapter::KEY_Escape;
        mKeyMap[Qt::Key_Delete] = osgGA::GUIEventAdapter::KEY_Delete;
        mKeyMap[Qt::Key_Home] = osgGA::GUIEventAdapter::KEY_Home;
        mKeyMap[Qt::Key_Enter] = osgGA::GUIEventAdapter::KEY_KP_Enter;
        mKeyMap[Qt::Key_End] = osgGA::GUIEventAdapter::KEY_End;
        mKeyMap[Qt::Key_Return] = osgGA::GUIEventAdapter::KEY_Return;
        mKeyMap[Qt::Key_PageUp] = osgGA::GUIEventAdapter::KEY_Page_Up;
        mKeyMap[Qt::Key_PageDown] = osgGA::GUIEventAdapter::KEY_Page_Down;
        mKeyMap[Qt::Key_Left] = osgGA::GUIEventAdapter::KEY_Left;
        mKeyMap[Qt::Key_Right] = osgGA::GUIEventAdapter::KEY_Right;
        mKeyMap[Qt::Key_Up] = osgGA::GUIEventAdapter::KEY_Up;
        mKeyMap[Qt::Key_Down] = osgGA::GUIEventAdapter::KEY_Down;
        mKeyMap[Qt::Key_Backspace] = osgGA::GUIEventAdapter::KEY_BackSpace;
        mKeyMap[Qt::Key_Tab] = osgGA::GUIEventAdapter::KEY_Tab;
        mKeyMap[Qt::Key_Space] = osgGA::GUIEventAdapter::KEY_Space;
        mKeyMap[Qt::Key_Delete] = osgGA::GUIEventAdapter::KEY_Delete;
        mKeyMap[Qt::Key_Alt] = osgGA::GUIEventAdapter::KEY_Alt_L;
        mKeyMap[Qt::Key_Shift] = osgGA::GUIEventAdapter::KEY_Shift_L;
        mKeyMap[Qt::Key_Control] = osgGA::GUIEventAdapter::KEY_Control_L;
        mKeyMap[Qt::Key_Meta] = osgGA::GUIEventAdapter::KEY_Meta_L;
    
        mKeyMap[Qt::Key_F1] = osgGA::GUIEventAdapter::KEY_F1;
        mKeyMap[Qt::Key_F2] = osgGA::GUIEventAdapter::KEY_F2;
        mKeyMap[Qt::Key_F3] = osgGA::GUIEventAdapter::KEY_F3;
        mKeyMap[Qt::Key_F4] = osgGA::GUIEventAdapter::KEY_F4;
        mKeyMap[Qt::Key_F5] = osgGA::GUIEventAdapter::KEY_F5;
        mKeyMap[Qt::Key_F6] = osgGA::GUIEventAdapter::KEY_F6;
        mKeyMap[Qt::Key_F7] = osgGA::GUIEventAdapter::KEY_F7;
        mKeyMap[Qt::Key_F8] = osgGA::GUIEventAdapter::KEY_F8;
        mKeyMap[Qt::Key_F9] = osgGA::GUIEventAdapter::KEY_F9;
        mKeyMap[Qt::Key_F10] = osgGA::GUIEventAdapter::KEY_F10;
        mKeyMap[Qt::Key_F11] = osgGA::GUIEventAdapter::KEY_F11;
        mKeyMap[Qt::Key_F12] = osgGA::GUIEventAdapter::KEY_F12;
        mKeyMap[Qt::Key_F13] = osgGA::GUIEventAdapter::KEY_F13;
        mKeyMap[Qt::Key_F14] = osgGA::GUIEventAdapter::KEY_F14;
        mKeyMap[Qt::Key_F15] = osgGA::GUIEventAdapter::KEY_F15;
        mKeyMap[Qt::Key_F16] = osgGA::GUIEventAdapter::KEY_F16;
        mKeyMap[Qt::Key_F17] = osgGA::GUIEventAdapter::KEY_F17;
        mKeyMap[Qt::Key_F18] = osgGA::GUIEventAdapter::KEY_F18;
        mKeyMap[Qt::Key_F19] = osgGA::GUIEventAdapter::KEY_F19;
        mKeyMap[Qt::Key_F20] = osgGA::GUIEventAdapter::KEY_F20;
    
        mKeyMap[Qt::Key_hyphen] = '-';
        mKeyMap[Qt::Key_Equal] = '=';
    
        mKeyMap[Qt::Key_division] = osgGA::GUIEventAdapter::KEY_KP_Divide;
        mKeyMap[Qt::Key_multiply] = osgGA::GUIEventAdapter::KEY_KP_Multiply;
        mKeyMap[Qt::Key_Minus] = '-';
        mKeyMap[Qt::Key_Plus] = '+';
        //mKeyMap[Qt::Key_H              ] = osgGA::GUIEventAdapter::KEY_KP_Home;
        //mKeyMap[Qt::Key_                    ] = osgGA::GUIEventAdapter::KEY_KP_Up;
        //mKeyMap[92                    ] = osgGA::GUIEventAdapter::KEY_KP_Page_Up;
        //mKeyMap[86                    ] = osgGA::GUIEventAdapter::KEY_KP_Left;
        //mKeyMap[87                    ] = osgGA::GUIEventAdapter::KEY_KP_Begin;
        //mKeyMap[88                    ] = osgGA::GUIEventAdapter::KEY_KP_Right;
        //mKeyMap[83                    ] = osgGA::GUIEventAdapter::KEY_KP_End;
        //mKeyMap[84                    ] = osgGA::GUIEventAdapter::KEY_KP_Down;
        //mKeyMap[85                    ] = osgGA::GUIEventAdapter::KEY_KP_Page_Down;
        mKeyMap[Qt::Key_Insert] = osgGA::GUIEventAdapter::KEY_KP_Insert;
        //mKeyMap[Qt::Key_Delete        ] = osgGA::GUIEventAdapter::KEY_KP_Delete;
      }
    
      ~QtKeyboardMap() {
      }
    
      int remapKey(QKeyEvent* event) {
        KeyMap::iterator itr = mKeyMap.find(event->key());
        if (itr == mKeyMap.end()) {
          return int(*(event->text().toLatin1().data()));
        }
        else
          return itr->second;
      }
    
    private:
      typedef std::map<unsigned int, int> KeyMap;
      KeyMap mKeyMap;
    };
    
    static QtKeyboardMap s_QtKeyboardMap;
    
    
    /// The object responsible for the scene re-rendering.
    class HeartBeat : public QObject {
    public:
      int _timerId;
      osg::Timer _lastFrameStartTime;
      osg::observer_ptr< osgViewer::ViewerBase > _viewer;
    
      virtual ~HeartBeat();
    
      void init(osgViewer::ViewerBase *viewer);
      void stopTimer();
      void timerEvent(QTimerEvent *event);
    
      static HeartBeat* instance();
    private:
      HeartBeat();
    
      static QPointer<HeartBeat> heartBeat;
    };
    
    QPointer<HeartBeat> HeartBeat::heartBeat;
    
    #if (QT_VERSION < QT_VERSION_CHECK(5, 2, 0))
    #define GETDEVICEPIXELRATIO() 1.0
    #else
    #define GETDEVICEPIXELRATIO() devicePixelRatio()
    #endif
    
    GLWidget::GLWidget(QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f, bool forwardKeyEvents)
      : QGLWidget(parent, shareWidget, f),
      _gw(NULL),
      _touchEventsEnabled(false),
      _forwardKeyEvents(forwardKeyEvents) {
      _devicePixelRatio = GETDEVICEPIXELRATIO();
    
      setAttribute(Qt::WA_AcceptTouchEvents, true);
    
      setAcceptDrops(true);
    }
    
    GLWidget::GLWidget(QGLContext* context, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f,
      bool forwardKeyEvents)
      : QGLWidget(context, parent, shareWidget, f),
      _gw(NULL),
      _touchEventsEnabled(false),
      _forwardKeyEvents(forwardKeyEvents) {
      _devicePixelRatio = GETDEVICEPIXELRATIO();
    
      setAttribute(Qt::WA_AcceptTouchEvents, true);
    
      setAcceptDrops(true);
    }
    
    GLWidget::GLWidget(const QGLFormat& format, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f,
      bool forwardKeyEvents)
      : QGLWidget(format, parent, shareWidget, f),
      _gw(NULL),
      _touchEventsEnabled(false),
      _forwardKeyEvents(forwardKeyEvents) {
      _devicePixelRatio = GETDEVICEPIXELRATIO();
    
      setAttribute(Qt::WA_AcceptTouchEvents, true);
    
      setAcceptDrops(true);
    }
    
    GLWidget::~GLWidget() {
      // close GraphicsWindowQt and remove the reference to us
      if (_gw) {
        _gw->close();
        _gw->_widget = NULL;
        _gw = NULL;
      }
    }
    
    void GLWidget::setTouchEventsEnabled(bool e) {
    #ifdef USE_GESTURES
      if (e == _touchEventsEnabled)
        return;
    
      _touchEventsEnabled = e;
    
      if (_touchEventsEnabled) {
        grabGesture(Qt::PinchGesture);
      }
      else {
        ungrabGesture(Qt::PinchGesture);
      }
    #endif
    }
    
    void GLWidget::processDeferredEvents() {
      QQueue<QEvent::Type> deferredEventQueueCopy;
      {
        QMutexLocker lock(&_deferredEventQueueMutex);
        deferredEventQueueCopy = _deferredEventQueue;
        _eventCompressor.clear();
        _deferredEventQueue.clear();
      }
    
      while (!deferredEventQueueCopy.isEmpty()) {
        QEvent event(deferredEventQueueCopy.dequeue());
        QGLWidget::event(&event);
      }
    }
    
    bool GLWidget::event(QEvent* event) {
    #ifdef USE_GESTURES
      if (event->type() == QEvent::Gesture)
        return gestureEvent(static_cast<QGestureEvent*>(event));
    #endif
    
      // QEvent::Hide
      //
      // workaround "Qt-workaround" that does glFinish before hiding the widget
      // (the Qt workaround was seen at least in Qt 4.6.3 and 4.7.0)
      //
      // Qt makes the context current, performs glFinish, and releases the context.
      // This makes the problem in OSG multithreaded environment as the context
      // is active in another thread, thus it can not be made current for the purpose
      // of glFinish in this thread.
    
      // QEvent::ParentChange
      //
      // Reparenting GLWidget may create a new underlying window and a new GL context.
      // Qt will then call doneCurrent on the GL context about to be deleted. The thread
      // where old GL context was current has no longer current context to render to and
      // we cannot make new GL context current in this thread.
    
      // We workaround above problems by deferring execution of problematic event requests.
      // These events has to be enqueue and executed later in a main GUI thread (GUI operations
      // outside the main thread are not allowed) just before makeCurrent is called from the
      // right thread. The good place for doing that is right after swap in a swapBuffersImplementation.
    
      if (event->type() == QEvent::Hide) {
        // enqueue only the last of QEvent::Hide and QEvent::Show
        enqueueDeferredEvent(QEvent::Hide, QEvent::Show);
        return true;
      }
      else if (event->type() == QEvent::Show) {
        // enqueue only the last of QEvent::Show or QEvent::Hide
        enqueueDeferredEvent(QEvent::Show, QEvent::Hide);
        return true;
      }
      else if (event->type() == QEvent::ParentChange) {
        // enqueue only the last QEvent::ParentChange
        enqueueDeferredEvent(QEvent::ParentChange);
        return true;
      }
      else if (event->type() == QEvent::Enter) {
        QString objectName = this->objectName();
    
        emit signalEnter(objectName);
    
        //// // qDebug() << "Enter - "<< objectName;
      }
      else if (event->type() == QEvent::Leave) {
        QString objectName = this->objectName();
    
        emit signalLeave(objectName);
    
        //// // qDebug() << "Leave - "<< objectName;
      }
      if (event->type() == QEvent::TouchBegin ||
        event->type() == QEvent::TouchUpdate ||
        event->type() == QEvent::TouchEnd) {
        QList<QTouchEvent::TouchPoint> pts = static_cast<QTouchEvent *>(event)->touchPoints();
        if (pts.size() == 2) {
          const QTouchEvent::TouchPoint &pt1 = pts.first();
          const QTouchEvent::TouchPoint &pt2 = pts.last();
    
          osg::Vec2 pt1_now(pt1.pos().x(), pt1.pos().y());
          osg::Vec2 pt2_now(pt2.pos().x(), pt2.pos().y());
    
          osg::Vec2 pt1_last(pt1.startPos().x(), pt1.startPos().y());
          osg::Vec2 pt2_last(pt2.startPos().x(), pt2.startPos().y());
    
          float gap_now = (pt1_now - pt2_now).length();
          float gap_last = (pt1_last - pt2_last).length();
    
          if (fabs(gap_last - gap_now) >= 10.0) {
            _gw->getEventQueue()->mouseScroll(
              (gap_now - gap_last) > 0 ? osgGA::GUIEventAdapter::SCROLL_DOWN : osgGA::GUIEventAdapter::SCROLL_UP);
          }
    
          if (pt1.state() == Qt::TouchPointReleased ||
            pt2.state() == Qt::TouchPointReleased) {
          }
        }
      }
    
      // perform regular event handling
      return QGLWidget::event(event);
    }
    
    void GLWidget::setKeyboardModifiers(QInputEvent* event) {
      int modkey = event->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier);
      unsigned int mask = 0;
      if (modkey & Qt::ShiftModifier) mask |= osgGA::GUIEventAdapter::MODKEY_SHIFT;
      if (modkey & Qt::ControlModifier) mask |= osgGA::GUIEventAdapter::MODKEY_CTRL;
      if (modkey & Qt::AltModifier) mask |= osgGA::GUIEventAdapter::MODKEY_ALT;
      _gw->getEventQueue()->getCurrentEventState()->setModKeyMask(mask);
    }
    
    void GLWidget::resizeEvent(QResizeEvent* event) {
      const QSize& size = event->size();
    
      int scaled_width = static_cast<int>(size.width()*_devicePixelRatio);
      int scaled_height = static_cast<int>(size.height()*_devicePixelRatio);
      _gw->resized(x(), y(), scaled_width, scaled_height);
      _gw->getEventQueue()->windowResize(x(), y(), scaled_width, scaled_height);
      _gw->requestRedraw();
    
      emit signalResizeEvent(scaled_width, scaled_height);
    }
    
    void GLWidget::moveEvent(QMoveEvent* event) {
      const QPoint& pos = event->pos();
      int scaled_width = static_cast<int>(width()*_devicePixelRatio);
      int scaled_height = static_cast<int>(height()*_devicePixelRatio);
      _gw->resized(pos.x(), pos.y(), scaled_width, scaled_height);
      _gw->getEventQueue()->windowResize(pos.x(), pos.y(), scaled_width, scaled_height);
      emit signalMouseMove(pos.x(), pos.y());
    }
    
    void GLWidget::glDraw() {
      _gw->requestRedraw();
    }
    
    void GLWidget::slotHandleEnd(bool bReset) {
      if (bReset) {
        //发送一个鼠标左键释放事件以便取消双击的状态
        QMouseEvent event(QEvent::MouseButtonRelease, QPoint(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
        mouseReleaseEvent(&event);
      }
    }
    
    void GLWidget::keyPressEvent(QKeyEvent* event) {
      setKeyboardModifiers(event);
    
      if (event->key() == Qt::Key_Space) {
    
      }
      else {
        int value = s_QtKeyboardMap.remapKey(event);
        _gw->getEventQueue()->keyPress(value);
      }
    
      // this passes the event to the regular Qt key event processing,
      // among others, it closes popup windows on ESC and forwards the event to the parent widgets
      if (_forwardKeyEvents)
        inherited::keyPressEvent(event);
    }
    
    void GLWidget::keyReleaseEvent(QKeyEvent* event) {
      if (event->isAutoRepeat()) {
        event->ignore();
      }
      else {
        setKeyboardModifiers(event);
    
        if (event->key() == Qt::Key_Space) {
          QString objectName = this->objectName();
    
          emit signalReturnViewpoint(objectName);
        }
        else if (event->key() == Qt::Key_Delete) {
          emit signalDelEvent();
        }
        else {
          int value = s_QtKeyboardMap.remapKey(event);
          _gw->getEventQueue()->keyRelease(value);
        }
      }
    
      // this passes the event to the regular Qt key event processing,
      // among others, it closes popup windows on ESC and forwards the event to the parent widgets
      if (_forwardKeyEvents)
        inherited::keyReleaseEvent(event);
    }
    
    void GLWidget::mousePressEvent(QMouseEvent* event) {
      int button = 0;
      switch (event->button()) {
      case Qt::LeftButton: button = 1; break;
      case Qt::MidButton: button = 2; break;
      case Qt::RightButton: button = 3; break;
      case Qt::NoButton: button = 0; break;
      default: button = 0; break;
      }
      setKeyboardModifiers(event);
      _gw->getEventQueue()->mouseButtonPress(event->x()*_devicePixelRatio, event->y()*_devicePixelRatio, button);
    }
    
    void GLWidget::mouseReleaseEvent(QMouseEvent* event) {
      int button = 0;
      switch (event->button()) {
      case Qt::LeftButton:
      {
        button = 1;
        emit signalMouseRelease(button, event->x()*_devicePixelRatio, event->y()*_devicePixelRatio);
      }
      break;
    
      case Qt::MidButton: button = 2; break;
      case Qt::RightButton:
      {
        button = 3;
        emit signalMouseRelease(button, event->x()*_devicePixelRatio, event->y()*_devicePixelRatio);
      }
      break;
    
      case Qt::NoButton: button = 0; break;
      default: button = 0; break;
      }
      setKeyboardModifiers(event);
      _gw->getEventQueue()->mouseButtonRelease(event->x()*_devicePixelRatio, event->y()*_devicePixelRatio, button);
    }
    
    void GLWidget::mouseDoubleClickEvent(QMouseEvent* event) {
      int button = 0;
      switch (event->button()) {
      case Qt::LeftButton: button = 1; break;
      case Qt::MidButton: button = 2; break;
      case Qt::RightButton: button = 3; break;
      case Qt::NoButton: button = 0; break;
      default: button = 0; break;
      }
      setKeyboardModifiers(event);
      _gw->getEventQueue()->mouseDoubleButtonPress(event->x()*_devicePixelRatio, event->y()*_devicePixelRatio, button);
    }
    
    void GLWidget::mouseMoveEvent(QMouseEvent* event) {
      double W = this->width();
      double H = this->height();
      if (this->parentWidget()) {
        double PW = this->parentWidget()->width();
        double PH = this->parentWidget()->height();
    
        if (event->pos().x() > 0 && event->pos().x() < PH && event->pos().y() > 0 && event->pos().y() < PH - PH / 10) {
    
        }
        else if (event->pos().x() > PH / 10 && event->pos().x() < PW && event->pos().y() > PH - PH / 10 && event->pos().y() < PH) {
    
        }
      }
    
      setKeyboardModifiers(event);
      _gw->getEventQueue()->mouseMotion(event->x()*_devicePixelRatio, event->y()*_devicePixelRatio);
    
      emit signalMouseMove(event->x()*_devicePixelRatio, event->y()*_devicePixelRatio);
    }
    
    void GLWidget::wheelEvent(QWheelEvent* event) {
      setKeyboardModifiers(event);
      _gw->getEventQueue()->mouseScroll(
        event->orientation() == Qt::Vertical ?
        (event->delta() > 0 ? osgGA::GUIEventAdapter::SCROLL_UP : osgGA::GUIEventAdapter::SCROLL_DOWN) :
        (event->delta() > 0 ? osgGA::GUIEventAdapter::SCROLL_LEFT : osgGA::GUIEventAdapter::SCROLL_RIGHT));
    }
    
    #ifdef USE_GESTURES
    static osgGA::GUIEventAdapter::TouchPhase translateQtGestureState(Qt::GestureState state) {
      osgGA::GUIEventAdapter::TouchPhase touchPhase;
      switch (state) {
      case Qt::GestureStarted:
        touchPhase = osgGA::GUIEventAdapter::TOUCH_BEGAN;
        break;
      case Qt::GestureUpdated:
        touchPhase = osgGA::GUIEventAdapter::TOUCH_MOVED;
        break;
      case Qt::GestureFinished:
      case Qt::GestureCanceled:
        touchPhase = osgGA::GUIEventAdapter::TOUCH_ENDED;
        break;
      default:
        touchPhase = osgGA::GUIEventAdapter::TOUCH_UNKNOWN;
      };
    
      return touchPhase;
    }
    #endif
    
    
    bool GLWidget::gestureEvent(QGestureEvent* qevent) {
    #ifndef USE_GESTURES
      return false;
    #else
    
      bool accept = false;
    
      if (QPinchGesture* pinch = static_cast<QPinchGesture *>(qevent->gesture(Qt::PinchGesture))) {
        const QPointF qcenterf = pinch->centerPoint();
        const float angle = pinch->totalRotationAngle();
        const float scale = pinch->totalScaleFactor();
    
        const QPoint pinchCenterQt = mapFromGlobal(qcenterf.toPoint());
        const osg::Vec2 pinchCenter(pinchCenterQt.x(), pinchCenterQt.y());
    
        //We don't have absolute positions of the two touches, only a scale and rotation
        //Hence we create pseudo-coordinates which are reasonable, and centered around the
        //real position
        const float radius = (width() + height()) / 4;
        const osg::Vec2 vector(scale*cos(angle)*radius, scale*sin(angle)*radius);
        const osg::Vec2 p0 = pinchCenter + vector;
        const osg::Vec2 p1 = pinchCenter - vector;
    
        osg::ref_ptr<osgGA::GUIEventAdapter> event = 0;
        const osgGA::GUIEventAdapter::TouchPhase touchPhase = translateQtGestureState(pinch->state());
        if (touchPhase == osgGA::GUIEventAdapter::TOUCH_BEGAN) {
          event = _gw->getEventQueue()->touchBegan(0, touchPhase, p0[0], p0[1]);
        }
        else if (touchPhase == osgGA::GUIEventAdapter::TOUCH_MOVED) {
          event = _gw->getEventQueue()->touchMoved(0, touchPhase, p0[0], p0[1]);
        }
        else {
          event = _gw->getEventQueue()->touchEnded(0, touchPhase, p0[0], p0[1], 1);
        }
    
        if (event) {
          event->addTouchPoint(1, touchPhase, p1[0], p1[1]);
          accept = true;
        }
      }
    
      if (accept)
        qevent->accept();
    
      return accept;
    #endif
    }
    
    void GLWidget::dragEnterEvent(QDragEnterEvent *event) {
      if (event->mimeData()->hasFormat("SimuFedData"))
        event->accept();
      else
        event->ignore();
    }
    
    void GLWidget::dragMoveEvent(QDragMoveEvent *event) {
      if (event->mimeData()->hasFormat("SimuFedData")) {
        event->setDropAction(Qt::MoveAction);
        event->accept();
      }
      else
        event->ignore();
    }
    
    void GLWidget::dropEvent(QDropEvent *event) {
      if (event->mimeData()->hasFormat("SimuFedData")) {
        QByteArray pieceData = event->mimeData()->data("SimuFedData");
        QDataStream dataStream(&pieceData, QIODevice::ReadOnly);
    
        QPixmap pixmap;
        QString strParent;
        QString strType;
        QString strID;
        QVariant varData;
    
        dataStream >> pixmap >> strParent >> strType >> strID >> varData;
    
        QVariantList varList;
        varList.push_back(QVariant::fromValue(pixmap));
        varList.push_back(QVariant(strParent));
        varList.push_back(QVariant(strType));
        varList.push_back(QVariant(strID));
    
        QPointF pt = event->posF();
        varList.push_back(QVariant(pt));
        varList.push_back(varData);
    
        emit signalDropEvent(QVariant(varList));
      }
      else
        event->ignore();
    
      QGLWidget::dropEvent(event);
    }
    
    GraphicsWindowQt::GraphicsWindowQt(osg::GraphicsContext::Traits* traits, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f)
      : _realized(false) {
    
      _widget = NULL;
      _traits = traits;
      init(parent, shareWidget, f);
    }
    
    GraphicsWindowQt::GraphicsWindowQt(GLWidget* widget)
      : _realized(false) {
      _widget = widget;
      _traits = _widget ? createTraits(_widget) : new osg::GraphicsContext::Traits;
      init(NULL, NULL, 0);
    }
    
    GraphicsWindowQt::~GraphicsWindowQt() {
      close();
    
      // remove reference from GLWidget
      if (_widget)
        _widget->_gw = NULL;
    }
    
    bool GraphicsWindowQt::init(QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f) {
      // update _widget and parent by WindowData
      WindowData* windowData = _traits.get() ? dynamic_cast<WindowData*>(_traits->inheritedWindowData.get()) : 0;
      if (!_widget)
        _widget = windowData ? windowData->_widget : NULL;
      if (!parent)
        parent = windowData ? windowData->_parent : NULL;
    
      // create widget if it does not exist
      _ownsWidget = _widget == NULL;
      if (!_widget) {
        // shareWidget
        if (!shareWidget) {
          GraphicsWindowQt* sharedContextQt = dynamic_cast<GraphicsWindowQt*>(_traits->sharedContext.get());
          if (sharedContextQt)
            shareWidget = sharedContextQt->getGLWidget();
        }
    
        // WindowFlags
        Qt::WindowFlags flags = f | Qt::Window | Qt::CustomizeWindowHint;
        if (_traits->windowDecoration)
          flags |= Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowSystemMenuHint
    #if (QT_VERSION_CHECK(4, 5, 0) <= QT_VERSION)
          | Qt::WindowCloseButtonHint
    #endif
          ;
    
        // create widget
        _widget = new GLWidget(traits2qglFormat(_traits.get()), parent, shareWidget, flags);
      }
    
      // set widget name and position
      // (do not set it when we inherited the widget)
      if (_ownsWidget) {
        _widget->setWindowTitle(_traits->windowName.c_str());
        _widget->move(_traits->x, _traits->y);
        if (!_traits->supportsResize) _widget->setFixedSize(_traits->width, _traits->height);
        else _widget->resize(_traits->width, _traits->height);
      }
    
      // initialize widget properties
      _widget->setAutoBufferSwap(false);
      _widget->setMouseTracking(true);
      _widget->setFocusPolicy(Qt::WheelFocus);
      _widget->setGraphicsWindow(this);
      useCursor(_traits->useCursor);
    
      // initialize State
      setState(new osg::State);
      getState()->setGraphicsContext(this);
    
      // initialize contextID
      if (_traits.valid() && _traits->sharedContext.valid()) {
        getState()->setContextID(_traits->sharedContext->getState()->getContextID());
        incrementContextIDUsageCount(getState()->getContextID());
      }
      else {
        getState()->setContextID(osg::GraphicsContext::createNewContextID());
      }
    
      // make sure the event queue has the correct window rectangle size and input range
      getEventQueue()->syncWindowRectangleWithGraphicsContext();
    
      return true;
    }
    
    QGLFormat GraphicsWindowQt::traits2qglFormat(const osg::GraphicsContext::Traits* traits) {
      QGLFormat format(QGLFormat::defaultFormat());
    
      format.setAlphaBufferSize(traits->alpha);
      format.setRedBufferSize(traits->red);
      format.setGreenBufferSize(traits->green);
      format.setBlueBufferSize(traits->blue);
      format.setDepthBufferSize(traits->depth);
      format.setStencilBufferSize(traits->stencil);
      format.setSampleBuffers(traits->sampleBuffers);
      format.setSamples(traits->samples);
    
      format.setAlpha(traits->alpha > 0);
      format.setDepth(traits->depth > 0);
      format.setStencil(traits->stencil > 0);
      format.setDoubleBuffer(traits->doubleBuffer);
      format.setSwapInterval(traits->vsync ? 1 : 0);
      format.setStereo(traits->quadBufferStereo ? 1 : 0);
    
      return format;
    }
    
    void GraphicsWindowQt::qglFormat2traits(const QGLFormat& format, osg::GraphicsContext::Traits* traits) {
      traits->red = format.redBufferSize();
      traits->green = format.greenBufferSize();
      traits->blue = format.blueBufferSize();
      traits->alpha = format.alpha() ? format.alphaBufferSize() : 0;
      traits->depth = format.depth() ? format.depthBufferSize() : 0;
      traits->stencil = format.stencil() ? format.stencilBufferSize() : 0;
    
      traits->sampleBuffers = format.sampleBuffers() ? 1 : 0;
      traits->samples = format.samples();
    
      traits->quadBufferStereo = format.stereo();
      traits->doubleBuffer = format.doubleBuffer();
    
      traits->vsync = format.swapInterval() >= 1;
    }
    
    osg::GraphicsContext::Traits* GraphicsWindowQt::createTraits(const QGLWidget* widget) {
      osg::GraphicsContext::Traits *traits = new osg::GraphicsContext::Traits;
    
      qglFormat2traits(widget->format(), traits);
    
      QRect r = widget->geometry();
      traits->x = r.x();
      traits->y = r.y();
      traits->width = r.width();
      traits->height = r.height();
    
      traits->windowName = widget->windowTitle().toLocal8Bit().data();
      Qt::WindowFlags f = widget->windowFlags();
      traits->windowDecoration = (f & Qt::WindowTitleHint) &&
        (f & Qt::WindowMinMaxButtonsHint) &&
        (f & Qt::WindowSystemMenuHint);
      QSizePolicy sp = widget->sizePolicy();
      traits->supportsResize = sp.horizontalPolicy() != QSizePolicy::Fixed ||
        sp.verticalPolicy() != QSizePolicy::Fixed;
    
      return traits;
    }
    
    bool GraphicsWindowQt::setWindowRectangleImplementation(int x, int y, int width, int height) {
      if (_widget == NULL)
        return false;
    
      _widget->setGeometry(x, y, width, height);
      return true;
    }
    
    void GraphicsWindowQt::getWindowRectangle(int& x, int& y, int& width, int& height) {
      if (_widget) {
        const QRect& geom = _widget->geometry();
        x = geom.x();
        y = geom.y();
        width = geom.width();
        height = geom.height();
      }
    }
    
    bool GraphicsWindowQt::setWindowDecorationImplementation(bool windowDecoration) {
      Qt::WindowFlags flags = Qt::Window | Qt::CustomizeWindowHint;//|Qt::WindowStaysOnTopHint;
      if (windowDecoration)
        flags |= Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowSystemMenuHint;
      _traits->windowDecoration = windowDecoration;
    
      if (_widget) {
        _widget->setWindowFlags(flags);
    
        return true;
      }
    
      return false;
    }
    
    bool GraphicsWindowQt::getWindowDecoration() const {
      return _traits->windowDecoration;
    }
    
    void GraphicsWindowQt::grabFocus() {
      if (_widget)
        _widget->setFocus(Qt::ActiveWindowFocusReason);
    }
    
    void GraphicsWindowQt::grabFocusIfPointerInWindow() {
      if (_widget->underMouse())
        _widget->setFocus(Qt::ActiveWindowFocusReason);
    }
    
    void GraphicsWindowQt::raiseWindow() {
      if (_widget)
        _widget->raise();
    }
    
    void GraphicsWindowQt::setWindowName(const std::string& name) {
      if (_widget)
        _widget->setWindowTitle(name.c_str());
    }
    
    std::string GraphicsWindowQt::getWindowName() {
      return _widget ? _widget->windowTitle().toStdString() : "";
    }
    
    void GraphicsWindowQt::useCursor(bool cursorOn) {
      if (_widget) {
        _traits->useCursor = cursorOn;
        if (!cursorOn) _widget->setCursor(Qt::BlankCursor);
        else _widget->setCursor(_currentCursor);
      }
    }
    
    void GraphicsWindowQt::setCursor(MouseCursor cursor) {
      if (cursor == InheritCursor && _widget) {
        _widget->unsetCursor();
      }
    
      switch (cursor) {
      case NoCursor: _currentCursor = Qt::BlankCursor; break;
      case RightArrowCursor: case LeftArrowCursor: _currentCursor = Qt::ArrowCursor; break;
      case InfoCursor: _currentCursor = Qt::SizeAllCursor; break;
      case DestroyCursor: _currentCursor = Qt::ForbiddenCursor; break;
      case HelpCursor: _currentCursor = Qt::WhatsThisCursor; break;
      case CycleCursor: _currentCursor = Qt::ForbiddenCursor; break;
      case SprayCursor: _currentCursor = Qt::SizeAllCursor; break;
      case WaitCursor: _currentCursor = Qt::WaitCursor; break;
      case TextCursor: _currentCursor = Qt::IBeamCursor; break;
      case CrosshairCursor: _currentCursor = Qt::CrossCursor; break;
      case HandCursor: _currentCursor = Qt::OpenHandCursor; break;
      case UpDownCursor: _currentCursor = Qt::SizeVerCursor; break;
      case LeftRightCursor: _currentCursor = Qt::SizeHorCursor; break;
      case TopSideCursor: case BottomSideCursor: _currentCursor = Qt::UpArrowCursor; break;
      case LeftSideCursor: case RightSideCursor: _currentCursor = Qt::SizeHorCursor; break;
      case TopLeftCorner: _currentCursor = Qt::SizeBDiagCursor; break;
      case TopRightCorner: _currentCursor = Qt::SizeFDiagCursor; break;
      case BottomRightCorner: _currentCursor = Qt::SizeBDiagCursor; break;
      case BottomLeftCorner: _currentCursor = Qt::SizeFDiagCursor; break;
      default: break;
      };
      if (_widget) _widget->setCursor(_currentCursor);
    }
    
    bool GraphicsWindowQt::valid() const {
      return _widget && _widget->isValid();
    }
    
    bool GraphicsWindowQt::realizeImplementation() {
      // save the current context
      // note: this will save only Qt-based contexts
      const QGLContext *savedContext = QGLContext::currentContext();
    
      // initialize GL context for the widget
      if (!valid())
        _widget->glInit();
    
      // make current
      _realized = true;
      bool result = makeCurrent();
      _realized = false;
    
      // fail if we do not have current context
      if (!result) {
        if (savedContext)
          const_cast<QGLContext*>(savedContext)->makeCurrent();
    
        OSG_WARN << "Window realize: Can make context current." << std::endl;
        return false;
      }
    
      _realized = true;
    
      // make sure the event queue has the correct window rectangle size and input range
      getEventQueue()->syncWindowRectangleWithGraphicsContext();
    
      // make this window's context not current
      // note: this must be done as we will probably make the context current from another thread
      //       and it is not allowed to have one context current in two threads
      if (!releaseContext())
        OSG_WARN << "Window realize: Can not release context." << std::endl;
    
      // restore previous context
      if (savedContext)
        const_cast<QGLContext*>(savedContext)->makeCurrent();
    
      return true;
    }
    
    bool GraphicsWindowQt::isRealizedImplementation() const {
      return _realized;
    }
    
    void GraphicsWindowQt::closeImplementation() {
      if (_widget)
        _widget->close();
      _realized = false;
    }
    
    void GraphicsWindowQt::runOperations() {
      // While in graphics thread this is last chance to do something useful before
      // graphics thread will execute its operations.
      if (_widget->getNumDeferredEvents() > 0)
        _widget->processDeferredEvents();
    
      if (QGLContext::currentContext() != _widget->context())
        _widget->makeCurrent();
    
      GraphicsWindow::runOperations();
    }
    
    bool GraphicsWindowQt::makeCurrentImplementation() {
      if (_widget->getNumDeferredEvents() > 0)
        _widget->processDeferredEvents();
    
      //QOpenGLContext* qglcx = _widget->context()->contextHandle();
      //if (qglcx->thread() != QThread::currentThread()) 
      //{
      //  if (!qglcx->thread()) 
      //    return true;//窗口关闭时
    
      //  //这是在另一个线程中做得,需要让主线程来movetothread,需要用信号槽机制告诉主线程
      //  _moveThread = new MoveThread;
      //  connect(_moveThread, SIGNAL(moveThread(QThread*)), this, SLOT(onMoveOpenglContextToNewThread(QThread*)), Qt::BlockingQueuedConnection);
    
      //  emit _moveThread->moveThread(QThread::currentThread());
    
      //  qglcx->makeCurrent(_widget->windowHandle());
      //}
      //else
      {
        _widget->makeCurrent();
      }
    
      return true;
    }
    
    bool GraphicsWindowQt::releaseContextImplementation() {
      _widget->doneCurrent();
      return true;
    }
    
    void GraphicsWindowQt::swapBuffersImplementation() {
      _widget->swapBuffers();
    
      // FIXME: the processDeferredEvents should really be executed in a GUI (main) thread context but
      // I couln't find any reliable way to do this. For now, lets hope non of *GUI thread only operations* will
      // be executed in a QGLWidget::event handler. On the other hand, calling GUI only operations in the
      // QGLWidget event handler is an indication of a Qt bug.
      if (_widget->getNumDeferredEvents() > 0)
        _widget->processDeferredEvents();
    
      // We need to call makeCurrent here to restore our previously current context
      // which may be changed by the processDeferredEvents function.
      if (QGLContext::currentContext() != _widget->context())
        _widget->makeCurrent();
    }
    
    void GraphicsWindowQt::requestWarpPointer(float x, float y) {
      if (_widget)
        QCursor::setPos(_widget->mapToGlobal(QPoint((int)x, (int)y)));
    }
    
    void GraphicsWindowQt::onMoveOpenglContextToNewThread(QThread *newThread) {
      QOpenGLContext* qglcx = _widget->context()->contextHandle();
      if (qglcx->thread() != newThread) {
        qglcx->doneCurrent();
        qglcx->moveToThread(newThread);
      }
    
      //_mainWindow->onStartTimer();
    }
    
    class QtWindowingSystem : public osg::GraphicsContext::WindowingSystemInterface {
    public:
    
      QtWindowingSystem() {
        OSG_INFO << "QtWindowingSystemInterface()" << std::endl;
      }
    
      ~QtWindowingSystem() {
        if (osg::Referenced::getDeleteHandler()) {
          osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
          osg::Referenced::getDeleteHandler()->flushAll();
        }
      }
    
      // Access the Qt windowing system through this singleton class.
      static QtWindowingSystem* getInterface() {
        static QtWindowingSystem* qtInterface = new QtWindowingSystem;
        return qtInterface;
      }
    
      // Return the number of screens present in the system
      virtual unsigned int getNumScreens(const osg::GraphicsContext::ScreenIdentifier& /*si*/) {
        OSG_WARN << "osgQt: getNumScreens() not implemented yet." << std::endl;
        return 0;
      }
    
      // Return the resolution of specified screen
      // (0,0) is returned if screen is unknown
      virtual void getScreenSettings(const osg::GraphicsContext::ScreenIdentifier& /*si*/, osg::GraphicsContext::ScreenSettings & /*resolution*/) {
        OSG_WARN << "osgQt: getScreenSettings() not implemented yet." << std::endl;
      }
    
      // Set the resolution for given screen
      virtual bool setScreenSettings(const osg::GraphicsContext::ScreenIdentifier& /*si*/, const osg::GraphicsContext::ScreenSettings & /*resolution*/) {
        OSG_WARN << "osgQt: setScreenSettings() not implemented yet." << std::endl;
        return false;
      }
    
      // Enumerates available resolutions
      virtual void enumerateScreenSettings(const osg::GraphicsContext::ScreenIdentifier& /*screenIdentifier*/, osg::GraphicsContext::ScreenSettingsList & /*resolution*/) {
        OSG_WARN << "osgQt: enumerateScreenSettings() not implemented yet." << std::endl;
      }
    
      // Create a graphics context with given traits
      virtual osg::GraphicsContext* createGraphicsContext(osg::GraphicsContext::Traits* traits) {
        if (traits->pbuffer) {
          OSG_WARN << "osgQt: createGraphicsContext - pbuffer not implemented yet." << std::endl;
          return NULL;
        }
        else {
          osg::ref_ptr< GraphicsWindowQt > window = new GraphicsWindowQt(traits);
          if (window->valid()) return window.release();
          else return NULL;
        }
      }
    
    private:
    
      // No implementation for these
      QtWindowingSystem(const QtWindowingSystem&);
      QtWindowingSystem& operator=(const QtWindowingSystem&);
    };
    
    
    // declare C entry point for static compilation.
    void graphicswindow_Qt(void) {
      //osg::GraphicsContext::setWindowingSystemInterface(QtWindowingSystem::getInterface());
      //osg::GraphicsContext::WindowingSystemInterface;
      //osg::GraphicsContext::WindowingSystemInterface;
      //QtWindowingSystem::getInterface()
    
      //static QtWindowingSystem* getInterface() {
      //  static QtWindowingSystem* qtInterface = new QtWindowingSystem;
      //  return qtInterface;
      //}
    
      //osg::GraphicsContext::WindowingSystemInterface = QtWindowingSystem::getInterface();
    }
    
    
    void initQtWindowingSystem() {
      graphicswindow_Qt();
    }
    
    void setViewer(osgViewer::ViewerBase *viewer) {
      HeartBeat::instance()->init(viewer);
    }
    
    
    /// Constructor. Must be called from main thread.
    HeartBeat::HeartBeat() : _timerId(0) {
    }
    
    
    /// Destructor. Must be called from main thread.
    HeartBeat::~HeartBeat() {
      stopTimer();
    }
    
    HeartBeat* HeartBeat::instance() {
      if (!heartBeat) {
        heartBeat = new HeartBeat();
      }
      return heartBeat;
    }
    
    void HeartBeat::stopTimer() {
      if (_timerId != 0) {
        killTimer(_timerId);
        _timerId = 0;
      }
    }
    
    
    /// Initializes the loop for viewer. Must be called from main thread.
    void HeartBeat::init(osgViewer::ViewerBase *viewer) {
      if (_viewer == viewer)
        return;
    
      stopTimer();
    
      _viewer = viewer;
    
      if (viewer) {
        _timerId = startTimer(0);
        _lastFrameStartTime.setStartTick(0);
      }
    }
    
    
    void HeartBeat::timerEvent(QTimerEvent * /*event*/) {
      osg::ref_ptr< osgViewer::ViewerBase > viewer;
      if (!_viewer.lock(viewer)) {
        // viewer has been deleted -> stop timer
        stopTimer();
        return;
      }
    
      // limit the frame rate
      if (viewer->getRunMaxFrameRate() > 0.0) {
        double dt = _lastFrameStartTime.time_s();
        double minFrameTime = 1.0 / viewer->getRunMaxFrameRate();
        if (dt < minFrameTime)
          OpenThreads::Thread::microSleep(static_cast<unsigned int>(1000000.0*(minFrameTime - dt)));
      }
      else {
        // avoid excessive CPU loading when no frame is required in ON_DEMAND mode
        if (viewer->getRunFrameScheme() == osgViewer::ViewerBase::ON_DEMAND) {
          double dt = _lastFrameStartTime.time_s();
          if (dt < 0.01)
            OpenThreads::Thread::microSleep(static_cast<unsigned int>(1000000.0*(0.01 - dt)));
        }
    
        // record start frame time
        _lastFrameStartTime.setStartTick();
    
        // make frame
        if (viewer->getRunFrameScheme() == osgViewer::ViewerBase::ON_DEMAND) {
          if (viewer->checkNeedToDoFrame()) {
            viewer->frame();
          }
        }
        else {
          viewer->frame();
        }
      }
    }

    vcqtosgwidget.h

    #ifndef VCQTOSGWIDGET_H
    #define VCQTOSGWIDGET_H
    
    #include <QObject>
    
    #include <QString>
    #include <QDebug>
    #include <QtWidgets/QMainWindow>
    #include "ui_QtGuiOSG2.h"
    
    #include <osg/Geode>
    #include <osg/Geometry>
    #include <osg/LineWidth>
    #include <osgViewer/Viewer>
    #include <osgDB/ReadFile>
    #include <osgDB/WriteFile>
    #include <osgViewer/ViewerEventHandlers>  
    #include <osg/Geode>
    #include <osg/Geometry>
    #include <osg/LineWidth>
    #include <osgViewer/Viewer>
    #include <osgDB/ReadFile>
    #include <osgViewer/Viewer>
    #include <osgDB/ReadFile>
    #include <osgDB/WriteFile>
    #include <osgViewer/ViewerEventHandlers> 
    #include <osgViewer/CompositeViewer> 
    #include <osg/PositionAttitudeTransform> 
    #include <osg/MatrixTransform> 
    #include <osgFX/Scribe> 
    #include <osgParticle/PrecipitationEffect> 
    #include <osg/NodeCallback> 
    #include <osg/DrawPixels> 
    #include <osg/ComputeBoundsVisitor>
    #include <osgGA/TrackballManipulator>
    
    class VCQtOsgWidget : public QMainWindow {
      Q_OBJECT
    
    public:
      VCQtOsgWidget(QWidget *parent = Q_NULLPTR);
    
    private:
      void init();
    
      osg::LightSource* createLight();
    
      private slots:
      void slotTimeUpdate();
    private:
      //Ui::QtGuiOSGClass ui;
      Ui::QtGuiOSG2Class ui;
    
      osgViewer::Viewer* _viewer = nullptr;
      unsigned int _screenW, _screenH;
      QTimer* _timer;
    };
    
    
    
    #endif // VCQTOSGWIDGET_H

    vcqtosgwidget.cpp

    #include "vcqtosgwidget.h"
    
    #include <osg/GraphicsContext>
    #include "graphicswindowqt.h"
    #include <QTimer>
    
    VCQtOsgWidget::VCQtOsgWidget(QWidget *parent)
      : QMainWindow(parent) {
      ui.setupUi(this);
      init();
    
    }
    
    void VCQtOsgWidget::init() {
      osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface();
      if (!wsi) {
        osg::notify(osg::NOTICE) << "Error, no WindowSystemInterface available, cannot create windows." << std::endl;
        return;
      }
    
      wsi->getScreenResolution(osg::GraphicsContext::ScreenIdentifier(0), _screenW, _screenH);
    
    
      osg::DisplaySettings* ds = osg::DisplaySettings::instance().get();
    
      osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
      traits->x = 0;
      traits->y = 0;
      traits->width = _screenW;
      traits->height = _screenH;
      traits->windowDecoration = false;
      traits->doubleBuffer = true;
      traits->sharedContext = 0;
    
      traits->alpha = ds->getMinimumNumAlphaBits();
      traits->stencil = ds->getMinimumNumStencilBits();
      traits->sampleBuffers = ds->getMultiSamples();
    
      traits->samples = 16;
      traits->vsync = false;
    
      osg::GraphicsContext* gc = new GraphicsWindowQt(traits.get());
    
      osg::ref_ptr<osg::Camera> camera = new osg::Camera;
      camera->setGraphicsContext(gc);
      camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
      camera->setViewport(new osg::Viewport(0, 0, _screenW, _screenH));
      camera->setClearColor(osg::Vec4(128.0 / 255.0, 128.0 / 255.0, 128.0 / 255.0, 0.8));
      camera->setProjectionMatrixAsPerspective(30.0, static_cast<double>(_screenW) / static_cast<double>(_screenH), 1.0, 10000.0);
    
      _viewer = new osgViewer::Viewer;
      osg::ref_ptr<osg::Group> root = new osg::Group;
      //注意:这两句话的先后顺序 先添加模型在添加相机
      //root->addChild(osgDB::readNodeFile("cow.osgt"));
      root->addChild(osgDB::readNodeFile("D:\参考手册\BIM\osg\library.OSGB"));
    
      root->addChild(createLight());
      _viewer->setCamera(camera);//这两句话的先后顺序
      _viewer->setSceneData(root);
      _viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
      _viewer->setCameraManipulator(new osgGA::TrackballManipulator);
      _viewer->addEventHandler(new osgViewer::WindowSizeHandler());
    
      GraphicsWindowQt* gcQT = dynamic_cast<GraphicsWindowQt*>(gc);
      if (gcQT) {
        QWidget *pWgt = gcQT->getGLWidget();
        //ui.verticalLayout->addWidget(pWgt);
        ui.verticalLayout->addWidget(pWgt);
      }
    
    
      _timer = new QTimer;
      connect(_timer, SIGNAL(timeout()), this, SLOT(slotTimeUpdate()));
      _timer->start(5);
    }
    
    osg::LightSource* VCQtOsgWidget::createLight() {
      osg::LightSource* ls = new osg::LightSource;
    
      osg::ref_ptr<osg::Light> light = new osg::Light;
      light->setLightNum(0);
      light->setPosition(osg::Vec4(0.0, -3.0, 0.0, 0.0));
      light->setDirection(osg::Vec3(0.0, -1.0, 0.0));
      light->setDiffuse(osg::Vec4(0.0, 0.0, 1.0, 1.0));
      ls->setLight(light);
      return ls;
    }
    
    void VCQtOsgWidget::slotTimeUpdate() {
      _viewer->frame();
    }

    main.cpp

    #include "vcqtosgwidget.h"
    #include <QtWidgets/QApplication>
    
    int main(int argc, char *argv[])
    {
      QApplication a(argc, argv);
    
      //OSG_QT_Test2019061601 w;
      //w.show();
      VCQtOsgWidget vc_w;
      vc_w.show();
    
      return a.exec();
    }

  • 相关阅读:
    计算机的启动过程
    project
    ERROR
    告别,是另一种体验
    Kean博客2006年9月-2007年8月链接
    AutoCAD .NET开发大师Kean有价值的博客 2006年8月 .NET内容整理
    VS2010 VS2012拖拽NumericUpDown控件直接卡死的解决办法
    2006-7有价值的Kean博客——Calling ObjectARX functions from a .NET Application(PInvoke)
    使用NetApi渲染Cad模型
    Kean专题:拖动一个属性块(JIG拖拽)
  • 原文地址:https://www.cnblogs.com/herd/p/11032714.html
Copyright © 2011-2022 走看看