├── GlobeOsg.cpp ├── GlobeOsg.h ├── README.md ├── main.cpp ├── osgQuickNode.cpp ├── osgQuickNode.h ├── qmlosg.pro ├── qmlosgexample.qml ├── resources.qrc └── shaders ├── globe.frag └── globe.vert /GlobeOsg.cpp: -------------------------------------------------------------------------------- 1 | 2 | // qmlosg 3 | #include 4 | #include 5 | 6 | // qt quick stuff 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | 13 | // osg 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | 21 | // stl 22 | #include 23 | #include 24 | 25 | 26 | 27 | 28 | class RotateCallback : public osg::NodeCallback 29 | { 30 | public: 31 | RotateCallback(osg::PositionAttitudeTransform* pat) : 32 | _pat(pat), 33 | _angle(0.f) 34 | {} 35 | 36 | /** Callback method called by the NodeVisitor when visiting a node.*/ 37 | virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) 38 | { 39 | osg::Quat rotationX; 40 | float delta = osg::PI / 6.0 / 60.f; // 30 degrees in a second 41 | _angle += delta; 42 | rotationX.makeRotate(_angle, osg::Z_AXIS); 43 | _pat->setAttitude(rotationX); 44 | 45 | //std::cout << "current rotation is: " << osg::RadiansToDegrees(_angle) << std::endl; 46 | 47 | // note, callback is responsible for scenegraph traversal so 48 | // they must call traverse(node,nv) to ensure that the 49 | // scene graph subtree (and associated callbacks) are traversed. 50 | traverse(node,nv); 51 | } 52 | 53 | 54 | 55 | protected: 56 | osg::ref_ptr _pat; 57 | float _angle; 58 | }; 59 | 60 | 61 | class PostDrawDebug : public osg::Camera::DrawCallback 62 | { 63 | public: 64 | /** Functor method called by rendering thread. Users will typically override this method to carry tasks such as screen capture.*/ 65 | virtual void operator () (osg::RenderInfo& renderInfo) const 66 | { 67 | std::cout << "YES, I've rendered also frame: " << renderInfo.getState()->getFrameStamp()->getFrameNumber() << std::endl; 68 | } 69 | }; 70 | 71 | 72 | GlobeOsg::GlobeOsg() : 73 | _osgQuickNode(NULL), 74 | _zoomProp(1.0) 75 | { 76 | setFlag(ItemHasContents); 77 | 78 | // start timer to force a render loop 79 | startTimer(16); 80 | } 81 | 82 | 83 | GlobeOsg::~GlobeOsg() 84 | { 85 | } 86 | 87 | void GlobeOsg::setZoom(qreal zoom) 88 | { 89 | _orbit->setDistance(zoom * _defaultDistance); 90 | _zoomProp = zoom; 91 | } 92 | 93 | qreal GlobeOsg::getZoom() 94 | { 95 | return _zoomProp; 96 | } 97 | 98 | void GlobeOsg::setAnimate(bool animate) 99 | { 100 | if(animate) 101 | { 102 | if(_pat->getUpdateCallback() == NULL) 103 | _pat->setUpdateCallback(new RotateCallback(_pat) ); 104 | } 105 | else 106 | _pat->setUpdateCallback(NULL); 107 | } 108 | 109 | bool GlobeOsg::getAnimate() 110 | { 111 | return (_pat->getUpdateCallback() != NULL); 112 | } 113 | 114 | QSGNode* GlobeOsg::updatePaintNode(QSGNode* qNode, UpdatePaintNodeData* qNodeData) 115 | { 116 | //std::cout << "updatePaintNode() " << std::endl; 117 | 118 | if(!_osgQuickNode) 119 | { 120 | _osgQuickNode = new OsgQuickNode; 121 | _osgQuickNode->setQuickWindow(window()); 122 | 123 | setupScene(); 124 | } 125 | 126 | // pass events here if any occured 127 | if(!_mousePressVec.empty()) 128 | { 129 | int x = _mousePressVec[0].x(); 130 | int y = _mousePressVec[0].y(); 131 | _osgQuickNode->getViewer()->getEventQueue()->mouseButtonPress(x, y, osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON); 132 | 133 | _mousePressVec.clear(); 134 | } 135 | 136 | // pass events here if any occured 137 | if(!_mouseDragVec.empty()) 138 | { 139 | int x = _mouseDragVec[0].x(); 140 | int y = _mouseDragVec[0].y(); 141 | _osgQuickNode->getViewer()->getEventQueue()->mouseMotion(x, y); 142 | std::cout << "Mouse Motion at " << x << ", " << y << std::endl; 143 | _mouseDragVec.clear(); 144 | } 145 | 146 | return _osgQuickNode; 147 | 148 | } 149 | 150 | void GlobeOsg::home() 151 | { 152 | // reset to home 153 | _osgQuickNode->getViewer()->home(); 154 | } 155 | 156 | void GlobeOsg::setupScene() 157 | { 158 | // setup a sphere to render 159 | osg::ShapeDrawable* pSD = new osg::ShapeDrawable(new osg::Box(osg::Vec3(0, 0, 0), 10)); 160 | pSD->setColor(osg::Vec4(1, 0, 1, 0.5)); 161 | osg::Geode* geode = new osg::Geode; 162 | geode->addDrawable(pSD); 163 | 164 | osg::StateSet* ss = geode->getOrCreateStateSet(); 165 | ss->setMode(GL_CULL_FACE, osg::StateAttribute::ON); 166 | //geode->getOrCreateStateSet()->setAttributeAndModes(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE)); 167 | //geode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); 168 | 169 | osg::Shader* pvert = new osg::Shader(osg::Shader::VERTEX); 170 | // read vertex shader from resources 171 | { 172 | QFile file(":/shaders/globe.vert"); 173 | file.open(QIODevice::ReadOnly | QIODevice::Text); 174 | 175 | QTextStream in(&file); 176 | QString line = in.readAll(); 177 | pvert->setShaderSource(line.toStdString()); 178 | } 179 | 180 | osg::Shader* pFrag = new osg::Shader(osg::Shader::FRAGMENT); 181 | // read frag shader from resources 182 | { 183 | QFile file(":/shaders/globe.frag"); 184 | file.open(QIODevice::ReadOnly | QIODevice::Text); 185 | 186 | QTextStream in(&file); 187 | QString line = in.readAll(); 188 | pFrag->setShaderSource(line.toStdString()); 189 | } 190 | 191 | osg::Program* pProg = new osg::Program; 192 | pProg->addShader(pvert); 193 | pProg->addShader(pFrag); 194 | geode->getOrCreateStateSet()->setAttributeAndModes(pProg); 195 | 196 | 197 | _pat = new osg::PositionAttitudeTransform; 198 | _pat->addChild(geode); 199 | 200 | osg::Group* sceneRoot = dynamic_cast(_osgQuickNode->getViewer()->getSceneData()); 201 | if(sceneRoot == NULL) 202 | { 203 | std::cout << "Creating NEW scene home" << std::endl; 204 | sceneRoot = new osg::Group; 205 | _osgQuickNode->getViewer()->setSceneData(sceneRoot); 206 | } 207 | 208 | sceneRoot->addChild(_pat.get()); 209 | 210 | // setup a nice default FOV 211 | osg::Camera* pCamera = _osgQuickNode->getViewer()->getCamera(); 212 | double fov, ar, zMin, zMax; 213 | pCamera->getProjectionMatrixAsPerspective(fov, ar, zMin, zMax); 214 | fov = 65.0f / ar; 215 | pCamera->setProjectionMatrixAsPerspective(fov, ar, zMin, zMax); 216 | 217 | //pCamera->setPostDrawCallback(new PostDrawDebug() ); 218 | 219 | // also add an orbit manipulator 220 | _orbit = new osgGA::OrbitManipulator; 221 | _osgQuickNode->getViewer()->setCameraManipulator(_orbit.get()); 222 | _osgQuickNode->getViewer()->home(); 223 | _defaultDistance = _orbit->getDistance(); 224 | } 225 | 226 | void GlobeOsg::timerEvent(QTimerEvent *) 227 | { 228 | update(); 229 | } 230 | 231 | 232 | void GlobeOsg::_mousePressEvent(int x, int y) 233 | { 234 | // fwd mouse event to osg 235 | _mousePressVec.push_back(osg::Vec2(x, y)); 236 | //_osgViewer->getEventQueue()->mouseButtonPress(x, y, osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON); 237 | } 238 | 239 | void GlobeOsg::_mouseDragEvent(int x, int y) 240 | { 241 | // fwd mouse event to osg 242 | //std::cout << "MouseDragged at " << x << ", " << y << std::endl; 243 | _mouseDragVec.push_back(osg::Vec2(x, y)); 244 | //_osgViewer->getEventQueue()->mouseMotion(x, y); 245 | } 246 | -------------------------------------------------------------------------------- /GlobeOsg.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef GLOBE_OSG_H 3 | #define GLOBE_OSG_H 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | // osg 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | 17 | class GlobeOsg : public QQuickItem 18 | { 19 | Q_OBJECT 20 | 21 | Q_PROPERTY(qreal zoom READ getZoom WRITE setZoom) 22 | Q_PROPERTY(bool animate READ getAnimate WRITE setAnimate) 23 | 24 | public: 25 | // default ctor and dtor 26 | GlobeOsg(); 27 | ~GlobeOsg(); 28 | 29 | void setZoom(qreal zoom); 30 | qreal getZoom(); 31 | 32 | void setAnimate(bool animate); 33 | bool getAnimate(); 34 | 35 | // reimplement QuickItem update method 36 | virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); 37 | 38 | // sample qml invokable method 39 | Q_INVOKABLE void home(); 40 | 41 | 42 | protected: 43 | 44 | // NOTE by Riccardo Corsi - this is a workaround to receive mouse events from the qml window. 45 | // I could not find a way to use QuickItem native methods like mousePressEvent(QMouseEvent*) and so on... 46 | Q_INVOKABLE void _mousePressEvent(int x, int y); 47 | Q_INVOKABLE void _mouseDragEvent(int x, int y); 48 | 49 | 50 | void setupScene(); 51 | 52 | // implement timerEvent method to force update on every frame 53 | void timerEvent(QTimerEvent *); 54 | 55 | 56 | qreal _zoomProp; 57 | QImage m_texture; 58 | 59 | // internal render node 60 | OsgQuickNode* _osgQuickNode; 61 | 62 | // local scene root 63 | osg::ref_ptr _pat; 64 | osg::ref_ptr _orbit; 65 | float _defaultDistance; 66 | 67 | 68 | std::vector _mousePressVec; 69 | std::vector _mouseDragVec; 70 | 71 | }; 72 | #endif // GLOBE_OSG_H 73 | 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | qmlosg 2 | ====== 3 | 4 | Integration test of osg and qt quick + qml framework 5 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char **argv) 9 | { 10 | QGuiApplication app(argc, argv); 11 | 12 | qmlRegisterType("qmlosg.globe", 1, 0, "GlobeOsg"); 13 | 14 | QQuickView view; 15 | view.setResizeMode(QQuickView::SizeRootObjectToView); 16 | 17 | view.setSource(QUrl("../../../../qmlosgexample.qml")); 18 | 19 | 20 | view.rootContext()->setContextProperty("Window", &view); 21 | view.show(); 22 | view.raise(); 23 | 24 | return app.exec(); 25 | } 26 | -------------------------------------------------------------------------------- /osgQuickNode.cpp: -------------------------------------------------------------------------------- 1 | 2 | // qmlosg 3 | #include 4 | 5 | // qt 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // osg 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | // stl 21 | #include 22 | 23 | 24 | class RotateLocalSceneCallback : public osg::NodeCallback 25 | { 26 | public: 27 | RotateLocalSceneCallback(osg::PositionAttitudeTransform* pat) : 28 | _pat(pat), 29 | _angle(0.f) 30 | {} 31 | 32 | /** Callback method called by the NodeVisitor when visiting a node.*/ 33 | virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) 34 | { 35 | osg::Quat rotationX; 36 | float delta = osg::PI / 12.0 / 60.f; // 30 degrees in a second 37 | _angle += delta; 38 | rotationX.makeRotate(_angle, osg::Z_AXIS); 39 | _pat->setAttitude(rotationX); 40 | 41 | //std::cout << "local scene rotation is: " << osg::RadiansToDegrees(_angle) << std::endl; 42 | 43 | // note, callback is responsible for scenegraph traversal so 44 | // they must call traverse(node,nv) to ensure that the 45 | // scene graph subtree (and associated callbacks) are traversed. 46 | traverse(node,nv); 47 | } 48 | 49 | protected: 50 | osg::ref_ptr _pat; 51 | float _angle; 52 | }; 53 | 54 | 55 | OsgQuickNode::OsgQuickNode() 56 | : QSGGeometryNode() 57 | , _qGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) 58 | , _qTexture(0) 59 | , _samples(0) 60 | , _quickWindow(0) 61 | , _osgContext(0) 62 | , _qtContext(0) 63 | , _AAEnabled(false) 64 | , _initialized(false) 65 | , _dirtyFBO(false) 66 | { 67 | setMaterial(&_qTexMaterial); 68 | setOpaqueMaterial(&_qOpaqueMaterial); 69 | setGeometry(&_qGeometry); 70 | 71 | setFlag(UsePreprocess); 72 | } 73 | 74 | OsgQuickNode::~OsgQuickNode() 75 | { 76 | // any osg stuff to cleanup here?? 77 | 78 | } 79 | 80 | 81 | void OsgQuickNode::saveOsgState() 82 | { 83 | _osgContext->doneCurrent(); 84 | _qtContext->makeCurrent(_quickWindow); 85 | } 86 | 87 | void OsgQuickNode::restoreOsgState() 88 | { 89 | _qtContext = QOpenGLContext::currentContext(); 90 | _qtContext->doneCurrent(); 91 | 92 | _osgContext->makeCurrent(_quickWindow); 93 | } 94 | 95 | 96 | 97 | void OsgQuickNode::preprocess() 98 | { 99 | //std::cout << "preprocess() " << std::endl; 100 | 101 | renderOsgFrame(); 102 | } 103 | 104 | void OsgQuickNode::setQuickWindow(QQuickWindow *window) 105 | { 106 | _quickWindow = window; 107 | 108 | // create a new shared OpenGL context to be used exclusively by OSG 109 | _osgContext = new QOpenGLContext(); 110 | _osgContext->setFormat(_quickWindow->requestedFormat()); 111 | _osgContext->setShareContext(QOpenGLContext::currentContext()); 112 | _osgContext->create(); 113 | 114 | // ok, now init the viewer as embedded, with render target to FBO 115 | init(); 116 | } 117 | 118 | void OsgQuickNode::renderOsgFrame() 119 | { 120 | // restore the osg gl context 121 | restoreOsgState(); 122 | 123 | if(!_osgViewer->isRealized()) 124 | { 125 | OSG_ALWAYS << "osgViewer REALIZE called!" << std::endl; 126 | _osgViewer->realize(); 127 | } 128 | 129 | 130 | if (_dirtyFBO) 131 | { 132 | updateFBO(); 133 | _dirtyFBO = false; 134 | } 135 | 136 | //std::cout << "viewer->frame()" << std::endl; 137 | _osgViewer->frame(); 138 | 139 | glFlush(); 140 | 141 | // if just inited copy the FBO texture to the Quick texture 142 | if(!_initialized) 143 | { 144 | QSGGeometry::updateTexturedRectGeometry(&_qGeometry, 145 | QRectF(0, 0, _quickWindow->width(), _quickWindow->height()), 146 | // invert uv not to get an y flipped result 147 | QRectF(0, 1, 1, -1)); // normally this would be 0, 0, 1, 1 148 | 149 | _qTexture = _quickWindow->createTextureFromId(getGLtexId(), _quickWindow->size()); 150 | 151 | _qTexMaterial.setTexture(_qTexture); 152 | _qOpaqueMaterial.setTexture(_qTexture); 153 | 154 | _initialized = true; 155 | } 156 | 157 | // we're done with the osg state, restore the Qt one 158 | saveOsgState(); 159 | } 160 | 161 | void OsgQuickNode::updateFBO() 162 | { 163 | // TODO update the FBO after resize 164 | 165 | 166 | // QSGGeometry::updateTexturedRectGeometry(); 167 | 168 | //delete m_texture; 169 | //m_texture = m_quickWindow->createTextureFromId(nativeTexture->getGLID(), m_size); 170 | 171 | //m_material.setTexture(m_texture); 172 | //m_materialO.setTexture(m_texture); 173 | } 174 | 175 | void OsgQuickNode::setSize(const QSize &size) 176 | { 177 | if (size == m_size) 178 | return; 179 | 180 | m_size = size; 181 | _dirtyFBO = true; 182 | markDirty(DirtyGeometry); 183 | } 184 | 185 | void OsgQuickNode::setAAEnabled(bool enable) 186 | { 187 | if (_AAEnabled == enable) 188 | return; 189 | 190 | _AAEnabled = enable; 191 | _dirtyFBO = true; 192 | markDirty(DirtyMaterial); 193 | } 194 | 195 | void OsgQuickNode::init() 196 | { 197 | const QOpenGLContext *ctx = QOpenGLContext::currentContext(); 198 | QSurfaceFormat format = ctx->format(); 199 | _samples = format.samples(); 200 | 201 | int viewWidth = _quickWindow->width(); 202 | int viewHeight = _quickWindow->height(); 203 | 204 | 205 | // create the view of the scene. 206 | _osgViewer = new osgViewer::Viewer; 207 | 208 | // setup as embedded 209 | osgViewer::GraphicsWindowEmbedded* embeddedWin = _osgViewer->setUpViewerAsEmbeddedInWindow(0, 0, viewWidth, viewHeight); 210 | 211 | OSG_ALWAYS << "----> SETTING UP osg Viewer with viewport " << viewWidth << ", " << viewHeight << std::endl; 212 | 213 | 214 | // tell the viewer to render on an FBO 215 | osg::Camera* pCamera = _osgViewer->getCamera(); 216 | pCamera->setViewport(0, 0, viewWidth, viewHeight); 217 | pCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); 218 | 219 | // set a grey background color 220 | pCamera->setClearColor(osg::Vec4(0.7, 0.7, 0.7, 1.0)); 221 | 222 | // attach a texture 223 | osg::Texture2D* texture2D = new osg::Texture2D; 224 | texture2D->setTextureSize(viewWidth, viewHeight); 225 | texture2D->setInternalFormat(GL_RGBA); 226 | texture2D->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); 227 | texture2D->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); 228 | 229 | // attach the texture and use it as the color buffer. 230 | pCamera->attach(osg::Camera::COLOR_BUFFER, texture2D, 231 | 0, 0, false, 232 | _samples, _samples); 233 | 234 | // save a reference to the texture object bound to the fbo 235 | _fboTex = texture2D; 236 | 237 | 238 | #if 1 239 | // create a sample scene 240 | osg::Group* sceneRoot = new osg::Group; 241 | sceneRoot->addChild(createScene()); 242 | _osgViewer->setSceneData(sceneRoot); 243 | #endif 244 | 245 | } 246 | 247 | GLuint OsgQuickNode::getGLtexId() 248 | { 249 | if(_fboTex.valid()) 250 | { 251 | unsigned int ctxId = _osgViewer->getCamera()->getGraphicsContext()->getState()->getContextID(); 252 | return _fboTex->getTextureObject(ctxId)->id(); 253 | } 254 | 255 | return 0; 256 | 257 | } 258 | 259 | 260 | osg::Node* OsgQuickNode::createScene() 261 | { 262 | // setup a sphere to render 263 | osg::ShapeDrawable* pSD = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0, 0, 0), 5)); 264 | pSD->setColor(osg::Vec4(1, 0, 0, 1.0)); 265 | osg::Geode* geode = new osg::Geode; 266 | geode->addDrawable(pSD); 267 | 268 | geode->getOrCreateStateSet()->setAttributeAndModes(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE)); 269 | //geode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); 270 | 271 | osg::Shader* pvert = new osg::Shader(osg::Shader::VERTEX); 272 | // read vertex shader from resources 273 | { 274 | QFile file(":/shaders/globe.vert"); 275 | file.open(QIODevice::ReadOnly | QIODevice::Text); 276 | 277 | QTextStream in(&file); 278 | QString line = in.readAll(); 279 | pvert->setShaderSource(line.toStdString()); 280 | } 281 | 282 | osg::Shader* pFrag = new osg::Shader(osg::Shader::FRAGMENT); 283 | // read frag shader from resources 284 | { 285 | QFile file(":/shaders/globe.frag"); 286 | file.open(QIODevice::ReadOnly | QIODevice::Text); 287 | 288 | QTextStream in(&file); 289 | QString line = in.readAll(); 290 | pFrag->setShaderSource(line.toStdString()); 291 | } 292 | 293 | osg::Program* pProg = new osg::Program; 294 | pProg->addShader(pvert); 295 | pProg->addShader(pFrag); 296 | geode->getOrCreateStateSet()->setAttributeAndModes(pProg); 297 | 298 | _pat = new osg::PositionAttitudeTransform; 299 | _pat->setPosition(osg::Vec3(30, 0, 10)); 300 | _pat->addChild(geode); 301 | 302 | _pat->addUpdateCallback(new RotateLocalSceneCallback(_pat)); 303 | 304 | return _pat.get(); 305 | 306 | } 307 | -------------------------------------------------------------------------------- /osgQuickNode.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef OSG_QUICK_NODE_H 3 | #define OSG_QUICK_NODE_H 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | // osg 13 | #include 14 | #include 15 | 16 | 17 | 18 | class OsgQuickNode : public QSGGeometryNode 19 | { 20 | public: 21 | OsgQuickNode(); 22 | ~OsgQuickNode(); 23 | 24 | // neede to setup the osg viewer correcly 25 | void setQuickWindow(QQuickWindow *window); 26 | 27 | void setSize(const QSize &size); 28 | QSize size() const { return m_size; } 29 | 30 | void setAAEnabled(bool enable); 31 | 32 | // called by qt when the "UsePreprocess" flag is set 33 | void preprocess(); 34 | 35 | // return osg viewer, mainly for setting scene, camera manipulator, etc... 36 | osgViewer::Viewer* getViewer(){ return _osgViewer.get();} 37 | 38 | protected: 39 | 40 | // internal utility for osg rendering/binding 41 | void init(); 42 | void saveOsgState(); 43 | void restoreOsgState(); 44 | GLuint getGLtexId(); 45 | void updateFBO(); 46 | 47 | void renderOsgFrame(); 48 | 49 | 50 | // TEST scene 51 | osg::Node* createScene(); 52 | 53 | // Quick geometry stuff 54 | QSGTextureMaterial _qTexMaterial; 55 | QSGOpaqueTextureMaterial _qOpaqueMaterial; 56 | QSGGeometry _qGeometry; 57 | QSGTexture *_qTexture; 58 | 59 | // QtQuick container window 60 | QQuickWindow *_quickWindow; 61 | 62 | int _samples; 63 | bool _AAEnabled; 64 | QSize m_size; 65 | 66 | bool _initialized; 67 | bool _dirtyFBO; 68 | 69 | // Pointer to QOpenGLContext to be used by OSG. 70 | QOpenGLContext* _osgContext; 71 | // Pointer to QOpenGLContext to be restored after OSG context 72 | QOpenGLContext* _qtContext; 73 | 74 | // osg stuff 75 | osg::ref_ptr _osgViewer; 76 | osg::ref_ptr _pat; 77 | osg::ref_ptr _fboTex; 78 | }; 79 | 80 | #endif // OSG_QUICK_NODE_H 81 | -------------------------------------------------------------------------------- /qmlosg.pro: -------------------------------------------------------------------------------- 1 | CONFIG += qt 2 | QT += qml quick 3 | TEMPLATE = app 4 | TARGET = qmlosg 5 | 6 | RESOURCES += ./resources.qrc 7 | 8 | 9 | INCLUDEPATH += /Users/ricky/sourcecode/OpenSceneGraph-3.1.5/include 10 | 11 | OSG_LIB_PATH = /Users/ricky/sourcecode/OpenSceneGraph-3.1.5/build/lib 12 | LIBS += -L$$OSG_LIB_PATH -losg -losgGA -losgQt -losgViewer -lOpenThreads -losgText 13 | 14 | 15 | 16 | UI_DIR = ./.ui 17 | OBJECTS_DIR = ./.obj 18 | MOC_DIR = ./.moc 19 | 20 | 21 | SOURCES += main.cpp \ 22 | osgQuickNode.cpp \ 23 | GlobeOsg.cpp 24 | 25 | HEADERS += osgQuickNode.h \ 26 | GlobeOsg.h 27 | 28 | OTHER_FILES += ./qmlosgexample.qml 29 | -------------------------------------------------------------------------------- /qmlosgexample.qml: -------------------------------------------------------------------------------- 1 | 2 | import QtQuick 2.0 3 | import qmlosg.globe 1.0 4 | 5 | Rectangle { 6 | id: globeWin 7 | width: 1024 8 | height: 768 9 | 10 | 11 | 12 | GlobeOsg { 13 | id: globe1 14 | width: parent.width 15 | height: parent.height 16 | 17 | focus: true 18 | 19 | MouseArea { 20 | anchors { 21 | top: parent.top 22 | bottom: parent.bottom 23 | right: parent.right 24 | left: parent.left 25 | } 26 | 27 | onPressed: { 28 | globe1._mousePressEvent(mouse.x, mouse.y); 29 | } 30 | 31 | onPositionChanged: { 32 | globe1._mouseDragEvent(mouse.x, mouse.y); 33 | } 34 | } 35 | 36 | 37 | } 38 | 39 | 40 | Rectangle { 41 | id: zoomInButton 42 | color:"#8000FFFF" 43 | width: 150; height: 75 44 | 45 | Text{ 46 | id: zoomInLabel 47 | anchors.centerIn: parent 48 | text: "zoom in" 49 | } 50 | 51 | MouseArea { 52 | anchors.fill: parent 53 | 54 | onClicked: { 55 | globe1.zoom = 0.9*globe1.zoom; 56 | 57 | if(zoomInButton.width == 200) 58 | zoomInButton.width = 150; 59 | else 60 | zoomInButton.width = 200; 61 | } 62 | } 63 | } 64 | 65 | Rectangle { 66 | id: zoomOutButton 67 | color: "#80FFFF00" 68 | width: 150; height: 75 69 | anchors { 70 | top: parent.top 71 | right: parent.right 72 | } 73 | 74 | Text{ 75 | id: zoomOutLabel 76 | anchors.centerIn: parent 77 | text: "zoom out" 78 | } 79 | 80 | MouseArea { 81 | anchors.fill: parent 82 | onClicked: globe1.zoom = 1.1*globe1.zoom; 83 | } 84 | } 85 | 86 | 87 | Rectangle { 88 | id: homeButton 89 | color: "yellow" 90 | width: 150; height: 75 91 | anchors { 92 | bottom: parent.bottom 93 | left: parent.left 94 | } 95 | 96 | Text{ 97 | id: homeLabel 98 | anchors.centerIn: parent 99 | text: "home" 100 | } 101 | 102 | MouseArea { 103 | anchors.fill: parent 104 | onClicked: globe1.home(); 105 | } 106 | } 107 | 108 | 109 | Rectangle { 110 | id: animateButton 111 | color: "green" 112 | width: 150; height: 75 113 | anchors { 114 | bottom: parent.bottom 115 | right: parent.right 116 | } 117 | 118 | Text{ 119 | id: animateLabel 120 | anchors.centerIn: parent 121 | text: "animate" 122 | } 123 | 124 | 125 | MouseArea { 126 | anchors.fill: parent 127 | onClicked: { 128 | var currAnim = globe1.animate; 129 | if(currAnim) 130 | { 131 | globe1.animate = false; 132 | animateLabel = "animate"; 133 | } 134 | else 135 | { 136 | globe1.animate = true; 137 | animateLabel = "stop animation"; 138 | } 139 | } 140 | } 141 | } 142 | 143 | 144 | } 145 | -------------------------------------------------------------------------------- /resources.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | shaders/globe.vert 4 | shaders/globe.frag 5 | 6 | 7 | -------------------------------------------------------------------------------- /shaders/globe.frag: -------------------------------------------------------------------------------- 1 | 2 | // computed varyings 3 | varying vec3 _normalDir; 4 | varying vec3 _viewDir; 5 | varying vec4 _baseColor; 6 | 7 | ////////////////////////////////////////////////////////////////////////////////////// 8 | void main() 9 | { 10 | // Normal (from vertex shader) 11 | vec3 normalDir = normalize(_normalDir); 12 | 13 | // Light dir (fixed) 14 | vec3 lightDir = normalize (vec3(0.0, 0.8, 1.0)); 15 | // vec3 lightDir = normalize (vec3(0.7, 0.5, 3.0)); 16 | vec3 fillLightDir = normalize (vec3(-0.9, 0.5, 1.0)); 17 | // vec3 fillLightDir = normalize (vec3(-0.3, 0.2, -0.5)); 18 | // View dir (from vert shader) 19 | vec3 viewDir = normalize(_viewDir); 20 | 21 | // ambient term 22 | float ambientFactor = 0.5; 23 | vec4 color = vec4(0.2, 0.2, 0.2, 1.0) * ambientFactor; 24 | // diffuse term 25 | float diffuse = max(dot(lightDir, normalDir), 0.0); 26 | float diffuseFill = max(dot(fillLightDir, normalDir), 0.0); 27 | 28 | color.rgb = _baseColor.rgb * (ambientFactor + diffuse * 0.5 + diffuseFill * 0.5); 29 | 30 | // // specular term 31 | // if (diffuse > 0.0) 32 | // { 33 | // vec3 specLightDir = vec3(0.3, 0.6, 1.0); 34 | // vec3 halfDir = normalize(lightDir + viewDir); 35 | // vec3 specColor = vec3(0.9, 0.9, 0.9); 36 | // color.rgb += 0.3*specColor * pow(max(dot(halfDir, normalDir), 0.0), 100.0); 37 | // } 38 | 39 | color.a = _baseColor.a; 40 | 41 | gl_FragColor = color; 42 | } 43 | -------------------------------------------------------------------------------- /shaders/globe.vert: -------------------------------------------------------------------------------- 1 | // computed values 2 | varying vec3 _normalDir; 3 | varying vec3 _viewDir; 4 | varying vec4 _baseColor; 5 | 6 | void main() 7 | { 8 | vec4 vertex = gl_Vertex; 9 | 10 | _baseColor = gl_Color; //colorHeight.rgb; 11 | 12 | // transform the vertex 13 | gl_Position = gl_ModelViewProjectionMatrix * vertex; 14 | 15 | // normal and lightDir computation 16 | _normalDir = gl_NormalMatrix * gl_Normal; 17 | //_normalDir = gl_NormalMatrix * normal; 18 | 19 | vec3 dir = -vec3(gl_ModelViewMatrix * vertex); 20 | _viewDir = dir; 21 | } 22 | --------------------------------------------------------------------------------