├── .gitignore ├── README.md ├── fbo ├── fbo.pro ├── fbo.qrc ├── main.cpp ├── main.qml ├── myframebufferobject.cpp └── myframebufferobject.h ├── integrating-qq2-with-opengl.pro ├── lgpl-3.0.txt ├── lib ├── CameraControls.qml ├── assets.qrc ├── assets │ ├── phong.frag │ ├── phong.vert │ └── trefoil.obj ├── axisalignedboundingbox.cpp ├── axisalignedboundingbox.h ├── camera.cpp ├── camera.h ├── lib.pri ├── lib.pro ├── meshrenderer.cpp ├── meshrenderer.h ├── objloader.cpp └── objloader.h ├── rendercontrol ├── main.cpp ├── main.qml ├── rendercontrol.pro ├── rendercontrol.qrc ├── renderwindow.cpp └── renderwindow.h └── underlay ├── main.cpp ├── main.qml ├── myquickview.cpp ├── myquickview.h ├── underlay.pro └── underlay.qrc /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.a 3 | *.la 4 | *.core 5 | *.d 6 | *.dylib 7 | *.moc 8 | *.o 9 | *.obj 10 | *.orig 11 | *.swp 12 | *.rej 13 | *.so 14 | *.so.* 15 | *.pbxuser 16 | *.mode1 17 | *.mode1v3 18 | *_pch.h.cpp 19 | *_resource.rc 20 | .#* 21 | *.*# 22 | *_wrapper.sh 23 | *_wrapper.bat 24 | wrapper.sh 25 | wrapper.bat 26 | core 27 | .qmake.cache 28 | .qmake.vars 29 | .device.vars 30 | *.prl 31 | tags 32 | .DS_Store 33 | *.debug 34 | Makefile* 35 | !qmake/Makefile.win32* 36 | !qmake/Makefile.unix 37 | *.prl 38 | *.app 39 | *.pro.user* 40 | *.qmlproject.user* 41 | *.gcov 42 | *.gcda 43 | *.gcno 44 | moc_*.cpp 45 | ui_*.h 46 | qrc_*.cpp 47 | *.Debug 48 | *.Release 49 | *.ib_pdb_index 50 | *.idb 51 | *.ilk 52 | *.pdb 53 | *.sln 54 | *.suo 55 | *.vcproj 56 | *vcproj.*.*.user 57 | *.ncb 58 | *.vcxproj 59 | *.vcxproj.filters 60 | *.vcxproj.user 61 | *.exe.embed.manifest 62 | *.exe_manifest.rc 63 | *.exe_manifest.res 64 | .DS_Store 65 | .pch 66 | .rcc 67 | *.app 68 | *.autosave 69 | *.qmlproject.user 70 | *.qmlproject.user.* 71 | CMakeLists.txt.user 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Integrating Qt Quick 2 with OpenGL 2 | 3 | This is the code for Giuseppe D'Angelo's talk at the Qt World Summit 2015, 4 | QtCon 2016, Qt World Summit 2017. 5 | 6 | * Slides: http://www.kdab.com/kdab-at-qt-world-summit/ https://conf.qtcon.org/system/attachments/99/original/integrating-opengl-qq2.pdf%3F1473007100 7 | * Video: https://www.youtube.com/watch?v=D-7fVGIBz6k https://www.youtube.com/watch?v=V_idc9BBRuI 8 | * Blog posts: http://www.kdab.com/integrating-opengl-with-qt-quick-2-applications-part-1/ 9 | 10 | 11 | ``` 12 | Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company. 13 | Author: Giuseppe D'Angelo 14 | Contact: info@kdab.com 15 | 16 | This program is free software: you can redistribute it and/or modify 17 | it under the terms of the GNU Lesser General Public License as published by 18 | the Free Software Foundation, either version 3 of the License, or 19 | (at your option) any later version. 20 | 21 | This program is distributed in the hope that it will be useful, 22 | but WITHOUT ANY WARRANTY; without even the implied warranty of 23 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 | GNU Lesser General Public License for more details. 25 | 26 | You should have received a copy of the GNU Lesser General Public License 27 | along with this program. If not, see . 28 | ``` 29 | 30 | -------------------------------------------------------------------------------- /fbo/fbo.pro: -------------------------------------------------------------------------------- 1 | include(../lib/lib.pri) 2 | 3 | TEMPLATE = app 4 | TARGET = fbo 5 | 6 | QT += quick 7 | 8 | SOURCES += \ 9 | main.cpp \ 10 | myframebufferobject.cpp 11 | 12 | HEADERS += \ 13 | myframebufferobject.h 14 | 15 | RESOURCES += \ 16 | fbo.qrc 17 | 18 | 19 | -------------------------------------------------------------------------------- /fbo/fbo.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | main.qml 4 | 5 | 6 | -------------------------------------------------------------------------------- /fbo/main.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company. 4 | ** Author: Giuseppe D'Angelo 5 | ** Contact: info@kdab.com 6 | ** 7 | ** This program is free software: you can redistribute it and/or modify 8 | ** it under the terms of the GNU Lesser General Public License as published by 9 | ** the Free Software Foundation, either version 3 of the License, or 10 | ** (at your option) any later version. 11 | ** 12 | ** This program is distributed in the hope that it will be useful, 13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ** GNU Lesser General Public License for more details. 16 | ** 17 | ** You should have received a copy of the GNU Lesser General Public License 18 | ** along with this program. If not, see . 19 | ** 20 | ****************************************************************************/ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "myframebufferobject.h" 28 | 29 | int main(int argc, char **argv) 30 | { 31 | QGuiApplication app(argc, argv); 32 | 33 | Q_INIT_RESOURCE(assets); 34 | 35 | QSurfaceFormat format; 36 | format.setMajorVersion(3); 37 | format.setMinorVersion(3); 38 | format.setProfile(QSurfaceFormat::CoreProfile); 39 | format.setDepthBufferSize(24); 40 | format.setStencilBufferSize(8); 41 | format.setSamples(4); 42 | QSurfaceFormat::setDefaultFormat(format); 43 | 44 | qmlRegisterType("MyRenderLibrary", 42, 0, "MeshRenderer"); 45 | 46 | QQuickView view; 47 | view.setResizeMode(QQuickView::SizeRootObjectToView); 48 | view.setSource(QUrl("qrc:///qml/main.qml")); 49 | view.resize(600, 600); 50 | view.show(); 51 | 52 | return app.exec(); 53 | } 54 | 55 | -------------------------------------------------------------------------------- /fbo/main.qml: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company. 4 | ** Author: Giuseppe D'Angelo 5 | ** Contact: info@kdab.com 6 | ** 7 | ** This program is free software: you can redistribute it and/or modify 8 | ** it under the terms of the GNU Lesser General Public License as published by 9 | ** the Free Software Foundation, either version 3 of the License, or 10 | ** (at your option) any later version. 11 | ** 12 | ** This program is distributed in the hope that it will be useful, 13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ** GNU Lesser General Public License for more details. 16 | ** 17 | ** You should have received a copy of the GNU Lesser General Public License 18 | ** along with this program. If not, see . 19 | ** 20 | ****************************************************************************/ 21 | 22 | import QtQuick 2.0 23 | import MyRenderLibrary 42.0 24 | 25 | Rectangle { 26 | id: root 27 | width: 600 28 | height: 600 29 | 30 | color: "lightblue" 31 | 32 | MeshRenderer { 33 | id: renderer 34 | width: 200 35 | height: 200 36 | smooth: true 37 | 38 | Text { 39 | text: "OpenGL in QtQuick!" 40 | anchors.top: parent.bottom 41 | anchors.horizontalCenter: parent.horizontalCenter 42 | } 43 | 44 | MouseArea { 45 | anchors.fill: parent 46 | onClicked: flashyThing.flash() 47 | } 48 | 49 | Rectangle { 50 | id: flashyThing 51 | anchors.fill: parent 52 | opacity: 0 53 | 54 | color: "yellow" 55 | 56 | Text { 57 | id: flashyThingText 58 | anchors.centerIn: parent 59 | text: "Clicked!" 60 | font.pointSize: 40 61 | } 62 | 63 | function flash() { 64 | flashyAnimation.restart() 65 | } 66 | 67 | ParallelAnimation { 68 | id: flashyAnimation 69 | 70 | NumberAnimation { 71 | target: flashyThingText 72 | properties: "font.pointSize" 73 | from: 20 74 | to: 60 75 | duration: 2000 76 | easing.type: Easing.OutCubic 77 | } 78 | 79 | SequentialAnimation { 80 | PropertyAction { 81 | target: flashyThing 82 | properties: "opacity" 83 | value: 1 84 | } 85 | 86 | NumberAnimation { 87 | target: flashyThing 88 | properties: "opacity" 89 | to: 0 90 | easing.type: Easing.InCubic 91 | duration: 1500 92 | } 93 | } 94 | } 95 | 96 | } 97 | } 98 | 99 | CameraControls { 100 | camera: renderer 101 | 102 | anchors.bottom: root.bottom 103 | anchors.horizontalCenter: root.horizontalCenter 104 | } 105 | 106 | ParallelAnimation { 107 | loops: Animation.Infinite 108 | running: true 109 | 110 | SequentialAnimation { 111 | loops: Animation.Infinite 112 | 113 | NumberAnimation { 114 | target: renderer 115 | properties: "x" 116 | from: 50 117 | to: root.width - renderer.width 118 | duration: 4000 119 | } 120 | NumberAnimation { 121 | target: renderer 122 | properties: "x" 123 | from: root.width - renderer.width 124 | to: 0 125 | duration: 5000 126 | } 127 | NumberAnimation { 128 | target: renderer 129 | properties: "x" 130 | from: 0 131 | to: 50 132 | duration: 1000 133 | } 134 | } 135 | 136 | SequentialAnimation { 137 | loops: Animation.Infinite 138 | NumberAnimation { 139 | target: renderer 140 | properties: "y" 141 | from: 100 142 | to: 0 143 | duration: 1500 144 | } 145 | 146 | NumberAnimation { 147 | target: renderer 148 | properties: "y" 149 | from: 0 150 | to: root.height - renderer.height 151 | duration: 5000 152 | } 153 | 154 | NumberAnimation { 155 | target: renderer 156 | properties: "y" 157 | from: root.height - renderer.height 158 | to: 100 159 | duration: 4000 160 | } 161 | 162 | } 163 | 164 | SequentialAnimation { 165 | loops: Animation.Infinite 166 | 167 | PauseAnimation { 168 | duration: 10000 169 | } 170 | 171 | RotationAnimation { 172 | target: renderer 173 | properties: "rotation" 174 | from: 0 175 | to: 45 176 | duration: 500 177 | easing.type: Easing.OutBack 178 | } 179 | 180 | RotationAnimation { 181 | target: renderer 182 | properties: "rotation" 183 | to: -45 184 | duration: 1000 185 | easing.type: Easing.OutBack 186 | } 187 | 188 | RotationAnimation { 189 | target: renderer 190 | properties: "rotation" 191 | to: 0 192 | duration: 500 193 | easing.type: Easing.OutBack 194 | } 195 | } 196 | 197 | } 198 | } 199 | 200 | -------------------------------------------------------------------------------- /fbo/myframebufferobject.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company. 4 | ** Author: Giuseppe D'Angelo 5 | ** Contact: info@kdab.com 6 | ** 7 | ** This program is free software: you can redistribute it and/or modify 8 | ** it under the terms of the GNU Lesser General Public License as published by 9 | ** the Free Software Foundation, either version 3 of the License, or 10 | ** (at your option) any later version. 11 | ** 12 | ** This program is distributed in the hope that it will be useful, 13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ** GNU Lesser General Public License for more details. 16 | ** 17 | ** You should have received a copy of the GNU Lesser General Public License 18 | ** along with this program. If not, see . 19 | ** 20 | ****************************************************************************/ 21 | 22 | #include "myframebufferobject.h" 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | class MyFrameBufferObjectRenderer : public QQuickFramebufferObject::Renderer 31 | { 32 | public: 33 | MyFrameBufferObjectRenderer() 34 | { 35 | 36 | m_render.initialize(); 37 | } 38 | 39 | void synchronize(QQuickFramebufferObject *item) Q_DECL_OVERRIDE 40 | { 41 | m_window = item->window(); 42 | 43 | MyFrameBufferObject *i = static_cast(item); 44 | m_render.setAzimuth(i->azimuth()); 45 | m_render.setElevation(i->elevation()); 46 | m_render.setDistance(i->distance()); 47 | } 48 | 49 | void render() Q_DECL_OVERRIDE 50 | { 51 | m_render.render(); 52 | m_window->resetOpenGLState(); 53 | } 54 | 55 | QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) Q_DECL_OVERRIDE 56 | { 57 | QOpenGLFramebufferObjectFormat format; 58 | format.setSamples(4); 59 | format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); 60 | return new QOpenGLFramebufferObject(size, format); 61 | } 62 | 63 | private: 64 | MeshRenderer m_render; 65 | QQuickWindow *m_window; 66 | }; 67 | 68 | 69 | 70 | // MyFrameBufferObject implementation 71 | 72 | MyFrameBufferObject::MyFrameBufferObject(QQuickItem *parent) 73 | : QQuickFramebufferObject(parent) 74 | , m_azimuth(0.0) 75 | , m_elevation(15.0) 76 | , m_distance(5.0) 77 | { 78 | setMirrorVertically(true); 79 | } 80 | 81 | QQuickFramebufferObject::Renderer *MyFrameBufferObject::createRenderer() const 82 | { 83 | return new MyFrameBufferObjectRenderer; 84 | } 85 | 86 | float MyFrameBufferObject::azimuth() const 87 | { 88 | return m_azimuth; 89 | } 90 | 91 | float MyFrameBufferObject::distance() const 92 | { 93 | return m_distance; 94 | } 95 | 96 | float MyFrameBufferObject::elevation() const 97 | { 98 | return m_elevation; 99 | } 100 | 101 | void MyFrameBufferObject::setAzimuth(float azimuth) 102 | { 103 | if (m_azimuth == azimuth) 104 | return; 105 | 106 | m_azimuth = azimuth; 107 | emit azimuthChanged(azimuth); 108 | update(); 109 | } 110 | 111 | void MyFrameBufferObject::setDistance(float distance) 112 | { 113 | if (m_distance == distance) 114 | return; 115 | 116 | m_distance = distance; 117 | emit distanceChanged(distance); 118 | update(); 119 | } 120 | 121 | void MyFrameBufferObject::setElevation(float elevation) 122 | { 123 | if (m_elevation == elevation) 124 | return; 125 | 126 | m_elevation = elevation; 127 | emit elevationChanged(elevation); 128 | update(); 129 | } 130 | -------------------------------------------------------------------------------- /fbo/myframebufferobject.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company. 4 | ** Author: Giuseppe D'Angelo 5 | ** Contact: info@kdab.com 6 | ** 7 | ** This program is free software: you can redistribute it and/or modify 8 | ** it under the terms of the GNU Lesser General Public License as published by 9 | ** the Free Software Foundation, either version 3 of the License, or 10 | ** (at your option) any later version. 11 | ** 12 | ** This program is distributed in the hope that it will be useful, 13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ** GNU Lesser General Public License for more details. 16 | ** 17 | ** You should have received a copy of the GNU Lesser General Public License 18 | ** along with this program. If not, see . 19 | ** 20 | ****************************************************************************/ 21 | 22 | #ifndef MYFRAMEBUFFEROBJECT_H 23 | #define MYFRAMEBUFFEROBJECT_H 24 | 25 | #include 26 | 27 | class MyFrameBufferObject : public QQuickFramebufferObject 28 | { 29 | Q_OBJECT 30 | 31 | Q_PROPERTY(float azimuth READ azimuth WRITE setAzimuth NOTIFY azimuthChanged) 32 | Q_PROPERTY(float elevation READ elevation WRITE setElevation NOTIFY elevationChanged) 33 | Q_PROPERTY(float distance READ distance WRITE setDistance NOTIFY distanceChanged) 34 | 35 | public: 36 | explicit MyFrameBufferObject(QQuickItem *parent = 0); 37 | Renderer *createRenderer() const Q_DECL_OVERRIDE; 38 | 39 | float azimuth() const; 40 | float distance() const; 41 | float elevation() const; 42 | 43 | signals: 44 | void azimuthChanged(float azimuth); 45 | void distanceChanged(float distance); 46 | void elevationChanged(float elevation); 47 | 48 | public slots: 49 | void setAzimuth(float azimuth); 50 | void setDistance(float distance); 51 | void setElevation(float elevation); 52 | 53 | private: 54 | float m_azimuth; 55 | float m_elevation; 56 | float m_distance; 57 | }; 58 | 59 | #endif // MYFRAMEBUFFEROBJECT_H 60 | -------------------------------------------------------------------------------- /integrating-qq2-with-opengl.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | lib \ 5 | underlay \ 6 | fbo \ 7 | rendercontrol \ 8 | 9 | CONFIG += ordered 10 | -------------------------------------------------------------------------------- /lgpl-3.0.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /lib/CameraControls.qml: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company. 4 | ** Author: Giuseppe D'Angelo 5 | ** Contact: info@kdab.com 6 | ** 7 | ** This program is free software: you can redistribute it and/or modify 8 | ** it under the terms of the GNU Lesser General Public License as published by 9 | ** the Free Software Foundation, either version 3 of the License, or 10 | ** (at your option) any later version. 11 | ** 12 | ** This program is distributed in the hope that it will be useful, 13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ** GNU Lesser General Public License for more details. 16 | ** 17 | ** You should have received a copy of the GNU Lesser General Public License 18 | ** along with this program. If not, see . 19 | ** 20 | ****************************************************************************/ 21 | 22 | import QtQuick 2.0 23 | import QtQuick.Controls 2.0 24 | import QtQuick.Layouts 1.0 25 | 26 | Rectangle { 27 | id: cameraControls 28 | property var camera 29 | 30 | border.color: "#000000" 31 | border.width: 2 32 | radius: 5 33 | color: "#55ffffff" 34 | 35 | width: parent ? parent.width - 10 : 400 36 | height: 150 37 | 38 | Component.onCompleted: if (camera) actualStuff.createObject(cameraControls) 39 | 40 | Component { 41 | id: actualStuff 42 | GridLayout { 43 | anchors.fill: parent 44 | anchors.margins: 5 45 | columns: 3 46 | 47 | Label { text: "Azimuth" } 48 | Slider { 49 | Layout.fillWidth: true 50 | from: 0 51 | to: 360 52 | value: 180 53 | onValueChanged: cameraControls.camera.azimuth = value 54 | } 55 | Label { text: cameraControls.camera.azimuth.toFixed(2) } 56 | 57 | Label { text: "Elevation" } 58 | Slider { 59 | Layout.fillWidth: true 60 | from: 0 61 | to: 90 62 | value: 10 63 | onValueChanged: cameraControls.camera.elevation = value 64 | } 65 | Label { text: cameraControls.camera.elevation.toFixed(2) } 66 | 67 | Label { text: "Distance" } 68 | Slider { 69 | id: distanceSlider 70 | Layout.fillWidth: true 71 | from: 1 72 | to: 25 73 | value: 15 74 | onValueChanged: cameraControls.camera.distance = value 75 | } 76 | Label { text: cameraControls.camera.distance.toFixed(2) } 77 | } 78 | } 79 | 80 | 81 | } 82 | 83 | -------------------------------------------------------------------------------- /lib/assets.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | assets/phong.frag 4 | assets/phong.vert 5 | assets/trefoil.obj 6 | 7 | 8 | CameraControls.qml 9 | 10 | 11 | -------------------------------------------------------------------------------- /lib/assets/phong.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | /**************************************************************************** 4 | ** 5 | ** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company. 6 | ** Author: Giuseppe D'Angelo 7 | ** Contact: info@kdab.com 8 | ** 9 | ** This program is free software: you can redistribute it and/or modify 10 | ** it under the terms of the GNU Lesser General Public License as published by 11 | ** the Free Software Foundation, either version 3 of the License, or 12 | ** (at your option) any later version. 13 | ** 14 | ** This program is distributed in the hope that it will be useful, 15 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | ** GNU Lesser General Public License for more details. 18 | ** 19 | ** You should have received a copy of the GNU Lesser General Public License 20 | ** along with this program. If not, see . 21 | ** 22 | ****************************************************************************/ 23 | 24 | uniform struct LightInfo { 25 | vec4 position; 26 | vec3 intensity; 27 | } light; 28 | 29 | struct MaterialInfo 30 | { 31 | vec3 ka; // Ambient reflectivity 32 | vec3 kd; // Diffuse reflectivity 33 | vec3 ks; // Specular reflectivity 34 | float shininess; // Specular shininess factor 35 | }; 36 | uniform MaterialInfo material; 37 | 38 | in vec3 position; 39 | in vec3 normal; 40 | 41 | out vec4 fragColor; 42 | 43 | 44 | vec3 adsModel( const in vec3 pos, const in vec3 n ) 45 | { 46 | vec3 s = normalize( vec3( light.position ) - pos ); 47 | vec3 v = normalize( -pos ); 48 | vec3 r = reflect( -s, n ); 49 | 50 | float diffuse = max( dot( s, n ), 0.0 ); 51 | 52 | float specular = 0.0; 53 | if ( dot( s, n ) > 0.0 ) 54 | specular = pow( max( dot( r, v ), 0.0 ), material.shininess ); 55 | 56 | return light.intensity * ( material.ka + material.kd * diffuse + material.ks * specular ); 57 | } 58 | 59 | void main() 60 | { 61 | fragColor = vec4( adsModel( position, normalize( normal ) ), 1.0 ); 62 | } 63 | -------------------------------------------------------------------------------- /lib/assets/phong.vert: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | /**************************************************************************** 4 | ** 5 | ** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company. 6 | ** Author: Giuseppe D'Angelo 7 | ** Contact: info@kdab.com 8 | ** 9 | ** This program is free software: you can redistribute it and/or modify 10 | ** it under the terms of the GNU Lesser General Public License as published by 11 | ** the Free Software Foundation, either version 3 of the License, or 12 | ** (at your option) any later version. 13 | ** 14 | ** This program is distributed in the hope that it will be useful, 15 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | ** GNU Lesser General Public License for more details. 18 | ** 19 | ** You should have received a copy of the GNU Lesser General Public License 20 | ** along with this program. If not, see . 21 | ** 22 | ****************************************************************************/ 23 | 24 | in vec3 vertexPosition; 25 | in vec3 vertexNormal; 26 | 27 | out vec3 position; 28 | out vec3 normal; 29 | 30 | uniform mat4 modelViewMatrix; 31 | uniform mat3 normalMatrix; 32 | uniform mat4 projectionMatrix; 33 | uniform mat4 mvp; 34 | 35 | void main() 36 | { 37 | normal = normalize( normalMatrix * vertexNormal ); 38 | position = vec3( modelViewMatrix * vec4( vertexPosition, 1.0 ) ); 39 | 40 | gl_Position = mvp * vec4( vertexPosition, 1.0 ); 41 | } 42 | -------------------------------------------------------------------------------- /lib/axisalignedboundingbox.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company. 4 | ** Author: Giuseppe D'Angelo 5 | ** Contact: info@kdab.com 6 | ** 7 | ** This program is free software: you can redistribute it and/or modify 8 | ** it under the terms of the GNU Lesser General Public License as published by 9 | ** the Free Software Foundation, either version 3 of the License, or 10 | ** (at your option) any later version. 11 | ** 12 | ** This program is distributed in the hope that it will be useful, 13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ** GNU Lesser General Public License for more details. 16 | ** 17 | ** You should have received a copy of the GNU Lesser General Public License 18 | ** along with this program. If not, see . 19 | ** 20 | ****************************************************************************/ 21 | 22 | #include "axisalignedboundingbox.h" 23 | 24 | #include 25 | 26 | AxisAlignedBoundingBox::AxisAlignedBoundingBox() 27 | : m_center(), 28 | m_radii() 29 | { 30 | } 31 | 32 | AxisAlignedBoundingBox::AxisAlignedBoundingBox( const QVector& points ) 33 | { 34 | update( points ); 35 | } 36 | 37 | void AxisAlignedBoundingBox::update( const QVector& points ) 38 | { 39 | if (points.isEmpty()) { 40 | m_center = QVector3D(); 41 | m_radii = QVector3D(); 42 | return; 43 | } 44 | 45 | QVector3D minPoint = points.at( 0 ); 46 | QVector3D maxPoint = points.at( 0 ); 47 | 48 | for ( int i = 1; i < points.size(); ++i ) 49 | { 50 | const QVector3D& point = points.at( i ); 51 | if ( point.x() > maxPoint.x() ) 52 | maxPoint.setX( point.x() ); 53 | if ( point.y() > maxPoint.y() ) 54 | maxPoint.setY( point.y() ); 55 | if ( point.z() > maxPoint.z() ) 56 | maxPoint.setZ( point.z() ); 57 | if ( point.x() < minPoint.x() ) 58 | minPoint.setX( point.x() ); 59 | if ( point.y() < minPoint.y() ) 60 | minPoint.setY( point.y() ); 61 | if ( point.z() < minPoint.z() ) 62 | minPoint.setZ( point.z() ); 63 | } 64 | 65 | m_center = 0.5 * ( minPoint + maxPoint ); 66 | m_radii = 0.5 * ( maxPoint - minPoint ); 67 | #if 0 68 | qDebug() << "AABB:"; 69 | qDebug() << " min =" << minPoint; 70 | qDebug() << " max =" << maxPoint; 71 | qDebug() << " center =" << m_center; 72 | qDebug() << " radii =" << m_radii; 73 | #endif 74 | } 75 | 76 | 77 | QDebug &operator<<(QDebug &stream, const AxisAlignedBoundingBox &bbox) 78 | { 79 | stream << "AABB: min=" << bbox.minPoint() << ", max=" << bbox.maxPoint(); 80 | return stream; 81 | } 82 | -------------------------------------------------------------------------------- /lib/axisalignedboundingbox.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company. 4 | ** Author: Giuseppe D'Angelo 5 | ** Contact: info@kdab.com 6 | ** 7 | ** This program is free software: you can redistribute it and/or modify 8 | ** it under the terms of the GNU Lesser General Public License as published by 9 | ** the Free Software Foundation, either version 3 of the License, or 10 | ** (at your option) any later version. 11 | ** 12 | ** This program is distributed in the hope that it will be useful, 13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ** GNU Lesser General Public License for more details. 16 | ** 17 | ** You should have received a copy of the GNU Lesser General Public License 18 | ** along with this program. If not, see . 19 | ** 20 | ****************************************************************************/ 21 | 22 | #ifndef AXIS_ALIGNED_BOUNDING_BOX 23 | #define AXIS_ALIGNED_BOUNDING_BOX 24 | 25 | #include 26 | #include 27 | 28 | class QDebug; 29 | 30 | class AxisAlignedBoundingBox 31 | { 32 | public: 33 | AxisAlignedBoundingBox(); 34 | 35 | AxisAlignedBoundingBox(const QVector& points); 36 | 37 | void update( const QVector& points ); 38 | 39 | QVector3D center() const { return m_center; } 40 | QVector3D radii() const { return m_radii; } 41 | 42 | QVector3D minPoint() const { return m_center - m_radii; } 43 | QVector3D maxPoint() const { return m_center + m_radii; } 44 | 45 | float xExtent() const { return 2.0f * m_radii.x(); } 46 | float yExtent() const { return 2.0f * m_radii.y(); } 47 | float zExtent() const { return 2.0f * m_radii.z(); } 48 | 49 | float maxExtent() const { return qMax( xExtent(), qMax( yExtent(), zExtent() ) ); } 50 | float minExtent() const { return qMin( xExtent(), qMin( yExtent(), zExtent() ) ); } 51 | 52 | private: 53 | QVector3D m_center; 54 | QVector3D m_radii; 55 | }; 56 | 57 | QDebug & operator<<(QDebug & stream, const AxisAlignedBoundingBox & bbox); 58 | 59 | #endif // AXIS_ALIGNED_BOUNDING_BOX 60 | -------------------------------------------------------------------------------- /lib/camera.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company. 4 | ** Author: Giuseppe D'Angelo 5 | ** Contact: info@kdab.com 6 | ** 7 | ** This program is free software: you can redistribute it and/or modify 8 | ** it under the terms of the GNU Lesser General Public License as published by 9 | ** the Free Software Foundation, either version 3 of the License, or 10 | ** (at your option) any later version. 11 | ** 12 | ** This program is distributed in the hope that it will be useful, 13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ** GNU Lesser General Public License for more details. 16 | ** 17 | ** You should have received a copy of the GNU Lesser General Public License 18 | ** along with this program. If not, see . 19 | ** 20 | ****************************************************************************/ 21 | 22 | #include "camera.h" 23 | 24 | Camera::Camera(QObject *parent) 25 | : QObject(parent) 26 | , m_azimuth(0.0) 27 | , m_elevation(15.0) 28 | , m_distance(15.0) 29 | { 30 | } 31 | 32 | float Camera::azimuth() const 33 | { 34 | return m_azimuth; 35 | } 36 | 37 | float Camera::distance() const 38 | { 39 | return m_distance; 40 | } 41 | 42 | float Camera::elevation() const 43 | { 44 | return m_elevation; 45 | } 46 | 47 | void Camera::setAzimuth(float azimuth) 48 | { 49 | if (m_azimuth == azimuth) 50 | return; 51 | 52 | m_azimuth = azimuth; 53 | emit azimuthChanged(azimuth); 54 | } 55 | 56 | void Camera::setDistance(float distance) 57 | { 58 | if (m_distance == distance) 59 | return; 60 | 61 | m_distance = distance; 62 | emit distanceChanged(distance); 63 | } 64 | 65 | void Camera::setElevation(float elevation) 66 | { 67 | if (m_elevation == elevation) 68 | return; 69 | 70 | m_elevation = elevation; 71 | emit elevationChanged(elevation); 72 | } 73 | 74 | -------------------------------------------------------------------------------- /lib/camera.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company. 4 | ** Author: Giuseppe D'Angelo 5 | ** Contact: info@kdab.com 6 | ** 7 | ** This program is free software: you can redistribute it and/or modify 8 | ** it under the terms of the GNU Lesser General Public License as published by 9 | ** the Free Software Foundation, either version 3 of the License, or 10 | ** (at your option) any later version. 11 | ** 12 | ** This program is distributed in the hope that it will be useful, 13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ** GNU Lesser General Public License for more details. 16 | ** 17 | ** You should have received a copy of the GNU Lesser General Public License 18 | ** along with this program. If not, see . 19 | ** 20 | ****************************************************************************/ 21 | 22 | #ifndef CAMERA_H 23 | #define CAMERA_H 24 | 25 | #include 26 | 27 | class Camera : public QObject 28 | { 29 | Q_OBJECT 30 | Q_PROPERTY(float azimuth READ azimuth WRITE setAzimuth NOTIFY azimuthChanged) 31 | Q_PROPERTY(float elevation READ elevation WRITE setElevation NOTIFY elevationChanged) 32 | Q_PROPERTY(float distance READ distance WRITE setDistance NOTIFY distanceChanged) 33 | 34 | public: 35 | explicit Camera(QObject *parent = 0); 36 | 37 | float azimuth() const; 38 | float distance() const; 39 | float elevation() const; 40 | 41 | signals: 42 | void azimuthChanged(float azimuth); 43 | void distanceChanged(float distance); 44 | void elevationChanged(float elevation); 45 | 46 | public slots: 47 | void setAzimuth(float azimuth); 48 | void setDistance(float distance); 49 | void setElevation(float elevation); 50 | 51 | private: 52 | float m_azimuth; 53 | float m_elevation; 54 | float m_distance; 55 | }; 56 | 57 | #endif // CAMERA_H 58 | -------------------------------------------------------------------------------- /lib/lib.pri: -------------------------------------------------------------------------------- 1 | INCLUDEPATH += ../lib/ 2 | 3 | win32 { 4 | CONFIG(debug,debug|release) { 5 | LIBS += $$OUT_PWD/../lib/debug/librenderlib.a 6 | PRE_TARGETDEPS = $$OUT_PWD/../lib/debug/librenderlib.a 7 | } 8 | CONFIG(release,debug|release) { 9 | LIBS += $$OUT_PWD/../lib/release/librenderlib.a 10 | PRE_TARGETDEPS = $$OUT_PWD/../lib/release/librenderlib.a 11 | } 12 | } else { 13 | LIBS += $$OUT_PWD/../lib/librenderlib.a 14 | PRE_TARGETDEPS = $$OUT_PWD/../lib/librenderlib.a 15 | } 16 | -------------------------------------------------------------------------------- /lib/lib.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = lib 2 | CONFIG += static 3 | TARGET = renderlib 4 | 5 | SOURCES += \ 6 | objloader.cpp \ 7 | axisalignedboundingbox.cpp \ 8 | camera.cpp \ 9 | meshrenderer.cpp 10 | 11 | 12 | HEADERS += \ 13 | objloader.h \ 14 | axisalignedboundingbox.h \ 15 | camera.h \ 16 | meshrenderer.h 17 | 18 | DISTFILES += \ 19 | lib.pri 20 | 21 | RESOURCES += \ 22 | assets.qrc 23 | -------------------------------------------------------------------------------- /lib/meshrenderer.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company. 4 | ** Author: Giuseppe D'Angelo 5 | ** Contact: info@kdab.com 6 | ** 7 | ** This program is free software: you can redistribute it and/or modify 8 | ** it under the terms of the GNU Lesser General Public License as published by 9 | ** the Free Software Foundation, either version 3 of the License, or 10 | ** (at your option) any later version. 11 | ** 12 | ** This program is distributed in the hope that it will be useful, 13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ** GNU Lesser General Public License for more details. 16 | ** 17 | ** You should have received a copy of the GNU Lesser General Public License 18 | ** along with this program. If not, see . 19 | ** 20 | ****************************************************************************/ 21 | 22 | #include "meshrenderer.h" 23 | 24 | #include "objloader.h" 25 | 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | 36 | #include 37 | 38 | #include 39 | #include 40 | 41 | MeshRenderer::MeshRenderer(QObject *parent) 42 | : QObject(parent) 43 | , m_positionsBuffer(new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer)) 44 | , m_normalsBuffer(new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer)) 45 | , m_indicesBuffer(new QOpenGLBuffer(QOpenGLBuffer::IndexBuffer)) 46 | , m_shaderProgram() 47 | , m_vao(new QOpenGLVertexArrayObject) 48 | , m_indicesCount(0) 49 | , m_coordinateMirroring(DoNotMirrorCoordinates) 50 | , m_azimuth(0.0) 51 | , m_elevation(15.0) 52 | , m_distance(15.0) 53 | { 54 | } 55 | 56 | MeshRenderer::~MeshRenderer() 57 | { 58 | invalidate(); 59 | } 60 | 61 | void MeshRenderer::initialize(CoordinateMirroring cm) 62 | { 63 | if (m_vao->isCreated()) 64 | return; // already initialized 65 | 66 | m_coordinateMirroring = cm; 67 | 68 | ObjLoader loader; 69 | 70 | if (!loader.load(":/assets/trefoil.obj")) 71 | qFatal("Could not load mesh"); 72 | 73 | if (!m_vao->create()) 74 | qFatal("Unable to create VAO"); 75 | 76 | m_vao->bind(); 77 | 78 | const QVector vertices = loader.vertices(); 79 | if (!m_positionsBuffer->create()) 80 | qFatal("Unable to create position buffer"); 81 | m_positionsBuffer->bind(); 82 | m_positionsBuffer->setUsagePattern(QOpenGLBuffer::StaticDraw); 83 | m_positionsBuffer->allocate(vertices.constData(), vertices.size() * sizeof(QVector3D)); 84 | 85 | const QVector normals = loader.normals(); 86 | m_normalsBuffer->create(); 87 | m_normalsBuffer->bind(); 88 | m_normalsBuffer->setUsagePattern(QOpenGLBuffer::StaticDraw); 89 | m_normalsBuffer->allocate(normals.constData(), normals.size() * sizeof(QVector3D)); 90 | 91 | const QVector indices = loader.indices(); 92 | m_indicesCount = indices.size(); 93 | if (!m_indicesBuffer->create()) 94 | qFatal("Unable to create index buffer"); 95 | 96 | m_indicesBuffer->bind(); 97 | m_indicesBuffer->setUsagePattern(QOpenGLBuffer::StaticDraw); 98 | m_indicesBuffer->allocate(indices.constData(), indices.size() * sizeof(unsigned int)); 99 | 100 | m_shaderProgram.reset(new QOpenGLShaderProgram); 101 | if (!m_shaderProgram->create()) 102 | qFatal("Unable to create shader program"); 103 | if (!m_shaderProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/assets/phong.vert")) 104 | qFatal("Vertex shader compilation failed"); 105 | if (!m_shaderProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/assets/phong.frag")) 106 | qFatal("Fragment shader compilation failed"); 107 | if (!m_shaderProgram->link()) 108 | qFatal("Shader program not linked"); 109 | 110 | m_shaderProgram->bind(); 111 | 112 | m_positionsBuffer->bind(); 113 | m_shaderProgram->enableAttributeArray("vertexPosition"); 114 | m_shaderProgram->setAttributeBuffer("vertexPosition", GL_FLOAT, 0, 3); 115 | 116 | m_normalsBuffer->bind(); 117 | m_shaderProgram->enableAttributeArray("vertexNormal"); 118 | m_shaderProgram->setAttributeBuffer("vertexNormal", GL_FLOAT, 0, 3); 119 | 120 | m_vao->release(); 121 | } 122 | 123 | void MeshRenderer::render() 124 | { 125 | QOpenGLFunctions *functions = QOpenGLContext::currentContext()->functions(); 126 | 127 | QMatrix4x4 modelMatrix; 128 | QMatrix4x4 viewMatrix; 129 | QMatrix4x4 projectionMatrix; 130 | 131 | modelMatrix.rotate(-90, 0, 1, 0); 132 | 133 | const float azimuthInRadians = qDegreesToRadians(m_azimuth); 134 | const float elevationInRadians = qDegreesToRadians(m_elevation); 135 | 136 | const QVector3D eyePosition(std::cos(elevationInRadians) * std::cos(azimuthInRadians), 137 | std::sin(elevationInRadians), 138 | -std::cos(elevationInRadians) * std::sin(azimuthInRadians)); 139 | 140 | QVector3D upVector = qFuzzyCompare(m_elevation, 90.0f) 141 | ? QVector3D(-std::cos(azimuthInRadians), 0, std::sin(azimuthInRadians)) 142 | : QVector3D(0, 1, 0); 143 | 144 | viewMatrix.lookAt(eyePosition * m_distance, 145 | QVector3D(0, 0, 0), 146 | upVector); 147 | 148 | GLint viewportSize[4]; 149 | functions->glGetIntegerv(GL_VIEWPORT, viewportSize); 150 | 151 | projectionMatrix.perspective(30, float(viewportSize[2]) / viewportSize[3], 0.01, 1000); 152 | 153 | switch (m_coordinateMirroring) { 154 | case MeshRenderer::DoNotMirrorCoordinates: 155 | break; 156 | case MeshRenderer::MirrorYCoordinate: 157 | projectionMatrix.scale(1, -1, 1); 158 | break; 159 | } 160 | 161 | const QMatrix4x4 modelViewMatrix = viewMatrix * modelMatrix; 162 | const QMatrix4x4 modelViewProjectionMatrix = projectionMatrix * modelViewMatrix; 163 | 164 | functions->glClearColor(1.0, 1.0, 1.0, 1.0); 165 | functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 166 | functions->glEnable(GL_DEPTH_TEST); 167 | 168 | m_shaderProgram->bind(); 169 | 170 | m_shaderProgram->setUniformValue("modelViewMatrix", modelViewMatrix); 171 | m_shaderProgram->setUniformValue("normalMatrix", modelViewMatrix.normalMatrix()); 172 | m_shaderProgram->setUniformValue("projectionMatrix", projectionMatrix); 173 | m_shaderProgram->setUniformValue("mvp", modelViewProjectionMatrix); 174 | 175 | m_shaderProgram->setUniformValue("light.position", QVector4D(0.0, 0.0, 0.0, 1.0)); 176 | m_shaderProgram->setUniformValue("light.intensity", QVector3D(1.0, 1.0, 1.0)); 177 | 178 | m_shaderProgram->setUniformValue("material.ka", QVector3D(0.1, 0.1, 0.1)); 179 | m_shaderProgram->setUniformValue("material.kd", QVector3D(1.0, 0.1, 0.1)); 180 | m_shaderProgram->setUniformValue("material.ks", QVector3D(1.0, 1.0, 1.0)); 181 | m_shaderProgram->setUniformValue("material.shininess", 32.0f); 182 | 183 | m_vao->bind(); 184 | functions->glDrawElements(GL_TRIANGLES, m_indicesCount, GL_UNSIGNED_INT, Q_NULLPTR); 185 | m_vao->release(); 186 | } 187 | 188 | void MeshRenderer::invalidate() 189 | { 190 | m_positionsBuffer->destroy(); 191 | m_normalsBuffer->destroy(); 192 | m_indicesBuffer->destroy(); 193 | m_shaderProgram.reset(); 194 | m_vao->destroy(); 195 | } 196 | 197 | void MeshRenderer::setAzimuth(float azimuth) 198 | { 199 | m_azimuth = azimuth; 200 | } 201 | 202 | void MeshRenderer::setElevation(float elevation) 203 | { 204 | m_elevation = elevation; 205 | } 206 | 207 | void MeshRenderer::setDistance(float distance) 208 | { 209 | m_distance = distance; 210 | } 211 | -------------------------------------------------------------------------------- /lib/meshrenderer.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company. 4 | ** Author: Giuseppe D'Angelo 5 | ** Contact: info@kdab.com 6 | ** 7 | ** This program is free software: you can redistribute it and/or modify 8 | ** it under the terms of the GNU Lesser General Public License as published by 9 | ** the Free Software Foundation, either version 3 of the License, or 10 | ** (at your option) any later version. 11 | ** 12 | ** This program is distributed in the hope that it will be useful, 13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ** GNU Lesser General Public License for more details. 16 | ** 17 | ** You should have received a copy of the GNU Lesser General Public License 18 | ** along with this program. If not, see . 19 | ** 20 | ****************************************************************************/ 21 | 22 | #ifndef MESHRENDERER_H 23 | #define MESHRENDERER_H 24 | 25 | #include 26 | 27 | #include 28 | 29 | class QOpenGLBuffer; 30 | class QOpenGLShaderProgram; 31 | class QOpenGLVertexArrayObject; 32 | 33 | class MeshRenderer : public QObject 34 | { 35 | Q_OBJECT 36 | public: 37 | explicit MeshRenderer(QObject *parent = 0); 38 | ~MeshRenderer(); 39 | 40 | enum CoordinateMirroring { 41 | DoNotMirrorCoordinates, 42 | MirrorYCoordinate 43 | }; 44 | 45 | // All assume that the GL context is current. 46 | void initialize(CoordinateMirroring cm = DoNotMirrorCoordinates); 47 | void render(); 48 | void invalidate(); 49 | 50 | void setAzimuth(float azimuth); 51 | void setElevation(float elevation); 52 | void setDistance(float distance); 53 | 54 | private: 55 | QScopedPointer m_positionsBuffer; 56 | QScopedPointer m_normalsBuffer; 57 | QScopedPointer m_indicesBuffer; 58 | QScopedPointer m_shaderProgram; 59 | QScopedPointer m_vao; 60 | 61 | int m_indicesCount; 62 | 63 | CoordinateMirroring m_coordinateMirroring; 64 | 65 | float m_azimuth; 66 | float m_elevation; 67 | float m_distance; 68 | }; 69 | 70 | #endif // MESHRENDERER_H 71 | 72 | 73 | -------------------------------------------------------------------------------- /lib/objloader.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company. 4 | ** Author: Giuseppe D'Angelo 5 | ** Contact: info@kdab.com 6 | ** 7 | ** This program is free software: you can redistribute it and/or modify 8 | ** it under the terms of the GNU Lesser General Public License as published by 9 | ** the Free Software Foundation, either version 3 of the License, or 10 | ** (at your option) any later version. 11 | ** 12 | ** This program is distributed in the hope that it will be useful, 13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ** GNU Lesser General Public License for more details. 16 | ** 17 | ** You should have received a copy of the GNU Lesser General Public License 18 | ** along with this program. If not, see . 19 | ** 20 | ****************************************************************************/ 21 | 22 | #include "objloader.h" 23 | 24 | #include "axisalignedboundingbox.h" 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | struct FaceIndices 35 | { 36 | FaceIndices() 37 | : positionIndex(std::numeric_limits::max()) 38 | , texCoordIndex(std::numeric_limits::max()) 39 | , normalIndex(std::numeric_limits::max()) 40 | {} 41 | 42 | FaceIndices(unsigned int posIndex, unsigned int tcIndex, unsigned int nIndex) 43 | : positionIndex(posIndex) 44 | , texCoordIndex(tcIndex) 45 | , normalIndex(nIndex) 46 | {} 47 | 48 | bool operator == (const FaceIndices &other) const 49 | { 50 | return positionIndex == other.positionIndex && 51 | texCoordIndex == other.texCoordIndex && 52 | normalIndex == other.normalIndex; 53 | } 54 | 55 | unsigned int positionIndex; 56 | unsigned int texCoordIndex; 57 | unsigned int normalIndex; 58 | }; 59 | 60 | inline uint qHash(const FaceIndices &faceIndices, uint seed = 0) 61 | { 62 | QtPrivate::QHashCombine hash; 63 | seed = hash(faceIndices.positionIndex, seed); 64 | seed = hash(faceIndices.normalIndex, seed); 65 | seed = hash(faceIndices.texCoordIndex, seed); 66 | return seed; 67 | } 68 | 69 | ObjLoader::ObjLoader() 70 | : m_loadTextureCoords( true ), 71 | m_centerMesh( false ) 72 | { 73 | } 74 | 75 | bool ObjLoader::load( const QString& fileName ) 76 | { 77 | QFile file( fileName ); 78 | if ( !file.open( ::QIODevice::ReadOnly | ::QIODevice::Text ) ) 79 | { 80 | qDebug() << "Could not open file" << fileName << "for reading"; 81 | return false; 82 | } 83 | 84 | return load( &file ); 85 | } 86 | 87 | static void addFaceVertex( const FaceIndices& faceIndices, 88 | QVector& faceIndexVector, 89 | QHash& faceIndexMap ) 90 | { 91 | if (faceIndices.positionIndex != std::numeric_limits::max()) { 92 | faceIndexVector.append(faceIndices); 93 | if (!faceIndexMap.contains(faceIndices)) 94 | faceIndexMap.insert(faceIndices, faceIndexMap.size()); 95 | } else { 96 | qWarning( "Missing position index" ); 97 | } 98 | } 99 | 100 | bool ObjLoader::load( QIODevice* ioDev ) 101 | { 102 | Q_CHECK_PTR(ioDev); 103 | if (!ioDev->isOpen()) { 104 | qWarning() << "iodevice" << ioDev << "not open for reading"; 105 | return false; 106 | } 107 | 108 | int faceCount = 0; 109 | 110 | // Parse faces taking into account each vertex in a face can index different indices 111 | // for the positions, normals and texture coords; 112 | // Generate unique vertices (in OpenGL parlance) and output to m_points, m_texCoords, 113 | // m_normals and calculate mapping from faces to unique indices 114 | QVector positions; 115 | QVector normals; 116 | QVector texCoords; 117 | QHash faceIndexMap; 118 | QVector faceIndexVector; 119 | 120 | QTextStream stream(ioDev); 121 | while (!stream.atEnd()) { 122 | QString line = stream.readLine(); 123 | line = line.simplified(); 124 | 125 | if (line.length() > 0 && line.at(0) != QChar::fromLatin1('#')) { 126 | QTextStream lineStream(&line, QIODevice::ReadOnly); 127 | QString token; 128 | lineStream >> token; 129 | 130 | if (token == QStringLiteral("v")) { 131 | float x, y, z; 132 | lineStream >> x >> y >> z; 133 | positions.append(QVector3D( x, y, z )); 134 | } else if (token == QStringLiteral("vt") && m_loadTextureCoords) { 135 | // Process texture coordinate 136 | float s,t; 137 | lineStream >> s >> t; 138 | texCoords.append(QVector2D(s, t)); 139 | } else if (token == QStringLiteral("vn")) { 140 | float x, y, z; 141 | lineStream >> x >> y >> z; 142 | normals.append(QVector3D( x, y, z )); 143 | } else if (token == QStringLiteral("f")) { 144 | // Process face 145 | ++faceCount; 146 | QVector face; 147 | int faceVertices = 0; 148 | while (!lineStream.atEnd()) { 149 | QString faceString; 150 | lineStream >> faceString; 151 | 152 | FaceIndices faceIndices; 153 | QStringList indices = faceString.split(QChar::fromLatin1('/')); 154 | switch (indices.size()) { 155 | case 3: 156 | faceIndices.normalIndex = indices.at(2).toInt() - 1; // fall through 157 | case 2: 158 | faceIndices.texCoordIndex = indices.at(1).toInt() - 1; // fall through 159 | case 1: 160 | faceIndices.positionIndex = indices.at(0).toInt() - 1; 161 | break; 162 | default: 163 | qWarning() << "Unsupported number of indices in face element"; 164 | } 165 | 166 | face.append(faceIndices); 167 | ++faceVertices; 168 | } 169 | 170 | // If number of edges in face is greater than 3, 171 | // decompose into triangles as a triangle fan. 172 | FaceIndices v0 = face[0]; 173 | FaceIndices v1 = face[1]; 174 | FaceIndices v2 = face[2]; 175 | 176 | // First face 177 | addFaceVertex(v0, faceIndexVector, faceIndexMap); 178 | addFaceVertex(v1, faceIndexVector, faceIndexMap); 179 | addFaceVertex(v2, faceIndexVector, faceIndexMap); 180 | 181 | for ( int i = 3; i < face.size(); ++i ) { 182 | v1 = v2; 183 | v2 = face[i]; 184 | addFaceVertex(v0, faceIndexVector, faceIndexMap); 185 | addFaceVertex(v1, faceIndexVector, faceIndexMap); 186 | addFaceVertex(v2, faceIndexVector, faceIndexMap); 187 | } 188 | } // end of face 189 | } // end of input line 190 | } // while (!stream.atEnd()) 191 | 192 | updateIndices(positions, normals, texCoords, faceIndexMap, faceIndexVector); 193 | 194 | if (m_normals.isEmpty()) 195 | generateAveragedNormals(m_points, m_normals, m_indices); 196 | 197 | if (m_centerMesh) 198 | center(m_points); 199 | 200 | qDebug() << "Loaded mesh:"; 201 | qDebug() << " " << m_points.size() << "points"; 202 | qDebug() << " " << faceCount << "faces"; 203 | qDebug() << " " << m_indices.size() / 3 << "triangles."; 204 | qDebug() << " " << m_normals.size() << "normals"; 205 | qDebug() << " " << m_texCoords.size() << "texture coordinates."; 206 | 207 | return true; 208 | } 209 | 210 | void ObjLoader::updateIndices( const QVector& positions, 211 | const QVector& normals, 212 | const QVector& texCoords, 213 | const QHash& faceIndexMap, 214 | const QVector& faceIndexVector ) 215 | { 216 | // Iterate over the faceIndexMap and pull out pos, texCoord and normal data 217 | // thereby generating unique vertices of data (by OpenGL definition) 218 | const int vertexCount = faceIndexMap.size(); 219 | const bool hasTexCoords = !texCoords.isEmpty(); 220 | const bool hasNormals = !normals.isEmpty(); 221 | 222 | m_points.resize(vertexCount); 223 | m_texCoords.clear(); 224 | if (hasTexCoords) 225 | m_texCoords.resize(vertexCount); 226 | m_normals.clear(); 227 | if (hasNormals) 228 | m_normals.resize(vertexCount); 229 | 230 | foreach (const FaceIndices &faceIndices, faceIndexMap.keys()) { 231 | const int i = faceIndexMap.value(faceIndices); 232 | 233 | m_points[i] = positions[faceIndices.positionIndex]; 234 | if (hasTexCoords) 235 | m_texCoords[i] = texCoords[faceIndices.texCoordIndex]; 236 | if (hasNormals) 237 | m_normals[i] = normals[faceIndices.normalIndex]; 238 | } 239 | 240 | // Now iterate over the face indices and lookup the unique vertex index 241 | const int indexCount = faceIndexVector.size(); 242 | m_indices.clear(); 243 | m_indices.reserve(indexCount); 244 | foreach (const FaceIndices &faceIndices, faceIndexVector) { 245 | const unsigned int i = faceIndexMap.value(faceIndices); 246 | m_indices.append(i); 247 | } 248 | } 249 | 250 | void ObjLoader::generateAveragedNormals( const QVector& points, 251 | QVector& normals, 252 | const QVector& faces ) const 253 | { 254 | for ( int i = 0; i < points.size(); ++i ) 255 | normals.append( QVector3D() ); 256 | 257 | for ( int i = 0; i < faces.size(); i += 3 ) 258 | { 259 | const QVector3D& p1 = points[ faces[i] ]; 260 | const QVector3D& p2 = points[ faces[i+1] ]; 261 | const QVector3D& p3 = points[ faces[i+2] ]; 262 | 263 | QVector3D a = p2 - p1; 264 | QVector3D b = p3 - p1; 265 | QVector3D n = QVector3D::crossProduct( a, b ).normalized(); 266 | 267 | normals[ faces[i] ] += n; 268 | normals[ faces[i+1] ] += n; 269 | normals[ faces[i+2] ] += n; 270 | } 271 | 272 | for ( int i = 0; i < normals.size(); ++i ) 273 | normals[i].normalize(); 274 | } 275 | 276 | void ObjLoader::center( QVector& points ) 277 | { 278 | if ( points.isEmpty() ) 279 | return; 280 | 281 | AxisAlignedBoundingBox bb(points); 282 | QVector3D center = bb.center(); 283 | 284 | // Translate center of the AABB to the origin 285 | for ( int i = 0; i < points.size(); ++i ) 286 | { 287 | QVector3D& point = points[i]; 288 | point = point - center; 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /lib/objloader.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company. 4 | ** Author: Giuseppe D'Angelo 5 | ** Contact: info@kdab.com 6 | ** 7 | ** This program is free software: you can redistribute it and/or modify 8 | ** it under the terms of the GNU Lesser General Public License as published by 9 | ** the Free Software Foundation, either version 3 of the License, or 10 | ** (at your option) any later version. 11 | ** 12 | ** This program is distributed in the hope that it will be useful, 13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ** GNU Lesser General Public License for more details. 16 | ** 17 | ** You should have received a copy of the GNU Lesser General Public License 18 | ** along with this program. If not, see . 19 | ** 20 | ****************************************************************************/ 21 | 22 | #ifndef OBJLOADER_H 23 | #define OBJLOADER_H 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | class QString; 33 | class QIODevice; 34 | 35 | struct FaceIndices; 36 | 37 | class ObjLoader 38 | { 39 | public: 40 | ObjLoader(); 41 | 42 | void setLoadTextureCoordinatesEnabled( bool b ) { m_loadTextureCoords = b; } 43 | bool isLoadTextureCoordinatesEnabled() const { return m_loadTextureCoords; } 44 | 45 | void setMeshCenteringEnabled( bool b ) { m_centerMesh = b; } 46 | bool isMeshCenteringEnabled() const { return m_centerMesh; } 47 | 48 | bool hasNormals() const { return !m_normals.isEmpty(); } 49 | bool hasTextureCoordinates() const { return !m_texCoords.isEmpty(); } 50 | 51 | bool load( const QString& fileName ); 52 | bool load( QIODevice* ioDev ); 53 | 54 | QVector vertices() const { return m_points; } 55 | QVector normals() const { return m_normals; } 56 | QVector textureCoordinates() const { return m_texCoords; } 57 | QVector indices() const { return m_indices; } 58 | 59 | private: 60 | void updateIndices(const QVector &positions, 61 | const QVector &normals, 62 | const QVector &texCoords, 63 | const QHash &faceIndexMap, 64 | const QVector &faceIndexVector); 65 | void generateAveragedNormals( const QVector& points, 66 | QVector& normals, 67 | const QVector& faces ) const; 68 | void center( QVector& points ); 69 | 70 | bool m_loadTextureCoords; 71 | bool m_generateTangents; 72 | bool m_centerMesh; 73 | 74 | QVector m_points; 75 | QVector m_normals; 76 | QVector m_texCoords; 77 | QVector m_indices; 78 | }; 79 | 80 | #endif // OBJLOADER_H 81 | -------------------------------------------------------------------------------- /rendercontrol/main.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company. 4 | ** Author: Giuseppe D'Angelo 5 | ** Contact: info@kdab.com 6 | ** 7 | ** This program is free software: you can redistribute it and/or modify 8 | ** it under the terms of the GNU Lesser General Public License as published by 9 | ** the Free Software Foundation, either version 3 of the License, or 10 | ** (at your option) any later version. 11 | ** 12 | ** This program is distributed in the hope that it will be useful, 13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ** GNU Lesser General Public License for more details. 16 | ** 17 | ** You should have received a copy of the GNU Lesser General Public License 18 | ** along with this program. If not, see . 19 | ** 20 | ****************************************************************************/ 21 | 22 | #include 23 | 24 | #include "renderwindow.h" 25 | 26 | int main(int argc, char **argv) 27 | { 28 | QGuiApplication app(argc, argv); 29 | 30 | Q_INIT_RESOURCE(assets); 31 | 32 | RenderWindow w; 33 | w.resize(600, 600); 34 | w.show(); 35 | 36 | return app.exec(); 37 | } 38 | -------------------------------------------------------------------------------- /rendercontrol/main.qml: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company. 4 | ** Author: Giuseppe D'Angelo 5 | ** Contact: info@kdab.com 6 | ** 7 | ** This program is free software: you can redistribute it and/or modify 8 | ** it under the terms of the GNU Lesser General Public License as published by 9 | ** the Free Software Foundation, either version 3 of the License, or 10 | ** (at your option) any later version. 11 | ** 12 | ** This program is distributed in the hope that it will be useful, 13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ** GNU Lesser General Public License for more details. 16 | ** 17 | ** You should have received a copy of the GNU Lesser General Public License 18 | ** along with this program. If not, see . 19 | ** 20 | ****************************************************************************/ 21 | 22 | import QtQuick 2.4 23 | 24 | Item { 25 | id: root 26 | 27 | width: 400 28 | height: 400 29 | 30 | CameraControls { 31 | camera: _camera 32 | 33 | anchors.bottom: root.bottom 34 | anchors.horizontalCenter: root.horizontalCenter 35 | } 36 | } 37 | 38 | 39 | -------------------------------------------------------------------------------- /rendercontrol/rendercontrol.pro: -------------------------------------------------------------------------------- 1 | include(../lib/lib.pri) 2 | 3 | TEMPLATE = app 4 | TARGET = rendercontrol 5 | 6 | QT += quick 7 | 8 | SOURCES += \ 9 | main.cpp \ 10 | renderwindow.cpp 11 | 12 | HEADERS += \ 13 | renderwindow.h 14 | 15 | RESOURCES += \ 16 | rendercontrol.qrc 17 | 18 | 19 | -------------------------------------------------------------------------------- /rendercontrol/rendercontrol.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | main.qml 4 | 5 | 6 | -------------------------------------------------------------------------------- /rendercontrol/renderwindow.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company. 4 | ** Author: Giuseppe D'Angelo 5 | ** Contact: info@kdab.com 6 | ** 7 | ** This program is free software: you can redistribute it and/or modify 8 | ** it under the terms of the GNU Lesser General Public License as published by 9 | ** the Free Software Foundation, either version 3 of the License, or 10 | ** (at your option) any later version. 11 | ** 12 | ** This program is distributed in the hope that it will be useful, 13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ** GNU Lesser General Public License for more details. 16 | ** 17 | ** You should have received a copy of the GNU Lesser General Public License 18 | ** along with this program. If not, see . 19 | ** 20 | ****************************************************************************/ 21 | 22 | #include "renderwindow.h" 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | #include 40 | 41 | RenderWindow::RenderWindow(QWindow *parent) 42 | : QWindow(parent) 43 | , m_context(0) 44 | , m_renderer(0) 45 | , m_camera(0) 46 | , m_renderControl(0) 47 | , m_quickWindow(0) 48 | , m_qmlComponent(0) 49 | , m_rootItem(0) 50 | { 51 | // set the window up 52 | setSurfaceType(QSurface::OpenGLSurface); 53 | 54 | QSurfaceFormat format; 55 | format.setMajorVersion(3); 56 | format.setMinorVersion(3); 57 | format.setProfile(QSurfaceFormat::CoreProfile); 58 | format.setDepthBufferSize(24); 59 | format.setStencilBufferSize(8); 60 | format.setSamples(4); 61 | 62 | setFormat(format); 63 | create(); 64 | 65 | // create the GL context 66 | 67 | m_context = new QOpenGLContext(this); 68 | m_context->setFormat(format); 69 | if (!m_context->create()) 70 | qFatal("Unable to create context"); 71 | 72 | m_context->makeCurrent(this); 73 | 74 | // set up our stuff 75 | 76 | m_renderer = new MeshRenderer(this); 77 | m_renderer->initialize(); 78 | 79 | m_camera = new Camera(this); 80 | 81 | // set up QtQuick 82 | 83 | m_renderControl = new QQuickRenderControl(this); 84 | m_quickWindow = new QQuickWindow(m_renderControl); 85 | m_quickWindow->setClearBeforeRendering(false); 86 | 87 | // try to "batch" multiple scene changed signals in one sync 88 | QTimer *sceneSyncTimer = new QTimer(this); 89 | sceneSyncTimer->setInterval(5); 90 | sceneSyncTimer->setSingleShot(true); 91 | connect(sceneSyncTimer, &QTimer::timeout, 92 | this, &RenderWindow::syncScene); 93 | 94 | connect(m_renderControl, &QQuickRenderControl::sceneChanged, 95 | sceneSyncTimer, static_cast(&QTimer::start)); 96 | 97 | connect(m_renderControl, &QQuickRenderControl::renderRequested, 98 | this, &RenderWindow::draw); 99 | 100 | m_renderControl->initialize(m_context); 101 | 102 | 103 | // load a QML scene "manually" 104 | QQmlEngine *engine = new QQmlEngine(this); 105 | 106 | if (!engine->incubationController()) 107 | engine->setIncubationController(m_quickWindow->incubationController()); 108 | 109 | engine->rootContext()->setContextProperty("_camera", m_camera); 110 | m_qmlComponent = new QQmlComponent(engine, this); 111 | 112 | connect(m_qmlComponent, &QQmlComponent::statusChanged, 113 | this, &RenderWindow::onQmlComponentLoadingComplete); 114 | 115 | m_qmlComponent->loadUrl(QUrl("qrc:///qml/main.qml")); 116 | 117 | 118 | 119 | // also, just for the sake of it, trigger a redraw every 500 ms no matter what 120 | QTimer *redrawTimer = new QTimer(this); 121 | connect(redrawTimer, &QTimer::timeout, this, &RenderWindow::draw); 122 | redrawTimer->start(500); 123 | } 124 | 125 | RenderWindow::~RenderWindow() 126 | { 127 | m_context->makeCurrent(this); 128 | 129 | m_renderer->invalidate(); 130 | delete m_renderer; 131 | 132 | delete m_rootItem; 133 | delete m_qmlComponent; 134 | delete m_renderControl; 135 | delete m_quickWindow; 136 | 137 | m_context->doneCurrent(); 138 | delete m_context; 139 | } 140 | 141 | void RenderWindow::resizeEvent(QResizeEvent *e) 142 | { 143 | // Simulate the "resize root item to follow window" 144 | updateRootItemSize(); 145 | QWindow::resizeEvent(e); 146 | } 147 | 148 | void RenderWindow::syncScene() 149 | { 150 | m_renderControl->polishItems(); 151 | 152 | m_renderer->setAzimuth(m_camera->azimuth()); 153 | m_renderer->setElevation(m_camera->elevation()); 154 | m_renderer->setDistance(m_camera->distance()); 155 | 156 | m_renderControl->sync(); 157 | draw(); 158 | } 159 | 160 | void RenderWindow::draw() 161 | { 162 | if (!isExposed()) 163 | return; 164 | m_context->makeCurrent(this); 165 | m_context->functions()->glViewport(0, 0, width() * devicePixelRatio(), height() * devicePixelRatio()); 166 | 167 | m_renderer->render(); 168 | m_quickWindow->resetOpenGLState(); 169 | 170 | m_renderControl->render(); 171 | 172 | m_context->swapBuffers(this); 173 | } 174 | 175 | void RenderWindow::onQmlComponentLoadingComplete() 176 | { 177 | if (m_qmlComponent->isLoading()) 178 | return; 179 | if (m_qmlComponent->isError()) { 180 | const QList errorList = m_qmlComponent->errors(); 181 | foreach (const QQmlError &error, errorList) 182 | qWarning() << error.url() << error.line() << error; 183 | 184 | qFatal("Unable to load QML file"); 185 | } 186 | 187 | QObject *rootObject = m_qmlComponent->create(); 188 | m_rootItem = qobject_cast(rootObject); 189 | if (!m_rootItem) 190 | qFatal("Did not load a Qt Quick scene"); 191 | 192 | m_rootItem->setParentItem(m_quickWindow->contentItem()); 193 | } 194 | 195 | void RenderWindow::updateRootItemSize() 196 | { 197 | if (m_rootItem) { 198 | m_rootItem->setWidth(width()); 199 | m_rootItem->setHeight(height()); 200 | } 201 | 202 | m_quickWindow->setHeight(height()); 203 | m_quickWindow->setWidth(width()); 204 | } 205 | 206 | void RenderWindow::mousePressEvent(QMouseEvent *e) 207 | { 208 | qApp->sendEvent(m_quickWindow, e); 209 | if (!e->isAccepted()) 210 | QWindow::mousePressEvent(e); 211 | } 212 | 213 | void RenderWindow::mouseMoveEvent(QMouseEvent *e) 214 | { 215 | qApp->sendEvent(m_quickWindow, e); 216 | if (!e->isAccepted()) 217 | QWindow::mousePressEvent(e); 218 | } 219 | 220 | void RenderWindow::mouseReleaseEvent(QMouseEvent *e) 221 | { 222 | qApp->sendEvent(m_quickWindow, e); 223 | if (!e->isAccepted()) 224 | QWindow::mousePressEvent(e); 225 | } 226 | 227 | -------------------------------------------------------------------------------- /rendercontrol/renderwindow.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company. 4 | ** Author: Giuseppe D'Angelo 5 | ** Contact: info@kdab.com 6 | ** 7 | ** This program is free software: you can redistribute it and/or modify 8 | ** it under the terms of the GNU Lesser General Public License as published by 9 | ** the Free Software Foundation, either version 3 of the License, or 10 | ** (at your option) any later version. 11 | ** 12 | ** This program is distributed in the hope that it will be useful, 13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ** GNU Lesser General Public License for more details. 16 | ** 17 | ** You should have received a copy of the GNU Lesser General Public License 18 | ** along with this program. If not, see . 19 | ** 20 | ****************************************************************************/ 21 | 22 | #ifndef RENDERWINDOW_H 23 | #define RENDERWINDOW_H 24 | 25 | #include 26 | 27 | class MeshRenderer; 28 | class Camera; 29 | class QOpenGLContext; 30 | class QQuickWindow; 31 | class QQuickRenderControl; 32 | class QQmlComponent; 33 | class QQuickItem; 34 | 35 | class RenderWindow : public QWindow 36 | { 37 | public: 38 | RenderWindow(QWindow *parent = 0); 39 | ~RenderWindow(); 40 | 41 | protected: 42 | void resizeEvent(QResizeEvent *e) Q_DECL_OVERRIDE; 43 | 44 | void mousePressEvent(QMouseEvent *e) Q_DECL_OVERRIDE; 45 | void mouseMoveEvent(QMouseEvent *e) Q_DECL_OVERRIDE; 46 | void mouseReleaseEvent(QMouseEvent *e) Q_DECL_OVERRIDE; 47 | 48 | private: 49 | void syncScene(); 50 | void draw(); 51 | 52 | void onQmlComponentLoadingComplete(); 53 | void updateRootItemSize(); 54 | 55 | QOpenGLContext *m_context; 56 | 57 | MeshRenderer *m_renderer; 58 | Camera *m_camera; 59 | 60 | QQuickRenderControl *m_renderControl; 61 | QQuickWindow *m_quickWindow; 62 | QQmlComponent *m_qmlComponent; 63 | QQuickItem *m_rootItem; 64 | }; 65 | 66 | #endif // RENDERWINDOW_H 67 | 68 | -------------------------------------------------------------------------------- /underlay/main.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company. 4 | ** Author: Giuseppe D'Angelo 5 | ** Contact: info@kdab.com 6 | ** 7 | ** This program is free software: you can redistribute it and/or modify 8 | ** it under the terms of the GNU Lesser General Public License as published by 9 | ** the Free Software Foundation, either version 3 of the License, or 10 | ** (at your option) any later version. 11 | ** 12 | ** This program is distributed in the hope that it will be useful, 13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ** GNU Lesser General Public License for more details. 16 | ** 17 | ** You should have received a copy of the GNU Lesser General Public License 18 | ** along with this program. If not, see . 19 | ** 20 | ****************************************************************************/ 21 | 22 | #include "myquickview.h" 23 | 24 | #include 25 | 26 | int main(int argc, char **argv) 27 | { 28 | QGuiApplication app(argc, argv); 29 | 30 | Q_INIT_RESOURCE(assets); 31 | 32 | MyQuickView view; 33 | view.show(); 34 | view.resize(600, 600); 35 | 36 | return app.exec(); 37 | } 38 | -------------------------------------------------------------------------------- /underlay/main.qml: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company. 4 | ** Author: Giuseppe D'Angelo 5 | ** Contact: info@kdab.com 6 | ** 7 | ** This program is free software: you can redistribute it and/or modify 8 | ** it under the terms of the GNU Lesser General Public License as published by 9 | ** the Free Software Foundation, either version 3 of the License, or 10 | ** (at your option) any later version. 11 | ** 12 | ** This program is distributed in the hope that it will be useful, 13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ** GNU Lesser General Public License for more details. 16 | ** 17 | ** You should have received a copy of the GNU Lesser General Public License 18 | ** along with this program. If not, see . 19 | ** 20 | ****************************************************************************/ 21 | 22 | import QtQuick 2.4 23 | 24 | Item { 25 | id: root 26 | 27 | width: 400 28 | height: 400 29 | 30 | CameraControls { 31 | camera: _camera 32 | 33 | anchors.bottom: root.bottom 34 | anchors.horizontalCenter: root.horizontalCenter 35 | } 36 | } 37 | 38 | 39 | -------------------------------------------------------------------------------- /underlay/myquickview.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company. 4 | ** Author: Giuseppe D'Angelo 5 | ** Contact: info@kdab.com 6 | ** 7 | ** This program is free software: you can redistribute it and/or modify 8 | ** it under the terms of the GNU Lesser General Public License as published by 9 | ** the Free Software Foundation, either version 3 of the License, or 10 | ** (at your option) any later version. 11 | ** 12 | ** This program is distributed in the hope that it will be useful, 13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ** GNU Lesser General Public License for more details. 16 | ** 17 | ** You should have received a copy of the GNU Lesser General Public License 18 | ** along with this program. If not, see . 19 | ** 20 | ****************************************************************************/ 21 | 22 | #include "myquickview.h" 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | MyQuickView::MyQuickView(QWindow *parent) 31 | : QQuickView(parent) 32 | , m_camera(new Camera(this)) 33 | , m_renderer(new MeshRenderer(this)) 34 | { 35 | QSurfaceFormat format; 36 | format.setMajorVersion(3); 37 | format.setMinorVersion(3); 38 | format.setProfile(QSurfaceFormat::CoreProfile); 39 | format.setDepthBufferSize(24); 40 | format.setStencilBufferSize(8); 41 | format.setSamples(4); 42 | setFormat(format); 43 | 44 | connect(this, &QQuickWindow::sceneGraphInitialized, 45 | this, &MyQuickView::initializeUnderlay, 46 | Qt::DirectConnection); 47 | 48 | connect(this, &QQuickWindow::beforeSynchronizing, 49 | this, &MyQuickView::synchronizeUnderlay, 50 | Qt::DirectConnection); 51 | 52 | connect(this, &QQuickWindow::beforeRendering, 53 | this, &MyQuickView::renderUnderlay, 54 | Qt::DirectConnection); 55 | 56 | connect(this, &QQuickWindow::sceneGraphInvalidated, 57 | this, &MyQuickView::invalidateUnderlay, 58 | Qt::DirectConnection); 59 | 60 | connect(m_camera, &Camera::azimuthChanged, 61 | this, &QQuickWindow::update); 62 | 63 | connect(m_camera, &Camera::elevationChanged, 64 | this, &QQuickWindow::update); 65 | 66 | connect(m_camera, &Camera::distanceChanged, 67 | this, &QQuickWindow::update); 68 | 69 | setClearBeforeRendering(false); 70 | setPersistentOpenGLContext(true); 71 | 72 | setResizeMode(SizeRootObjectToView); 73 | rootContext()->setContextProperty("_camera", m_camera); 74 | setSource(QUrl("qrc:///qml/main.qml")); 75 | } 76 | 77 | void MyQuickView::initializeUnderlay() 78 | { 79 | m_renderer->initialize(); 80 | resetOpenGLState(); 81 | } 82 | 83 | void MyQuickView::synchronizeUnderlay() 84 | { 85 | m_renderer->setAzimuth(m_camera->azimuth()); 86 | m_renderer->setElevation(m_camera->elevation()); 87 | m_renderer->setDistance(m_camera->distance()); 88 | } 89 | 90 | void MyQuickView::renderUnderlay() 91 | { 92 | m_renderer->render(); 93 | resetOpenGLState(); 94 | } 95 | 96 | void MyQuickView::invalidateUnderlay() 97 | { 98 | m_renderer->invalidate(); 99 | resetOpenGLState(); 100 | } 101 | -------------------------------------------------------------------------------- /underlay/myquickview.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company. 4 | ** Author: Giuseppe D'Angelo 5 | ** Contact: info@kdab.com 6 | ** 7 | ** This program is free software: you can redistribute it and/or modify 8 | ** it under the terms of the GNU Lesser General Public License as published by 9 | ** the Free Software Foundation, either version 3 of the License, or 10 | ** (at your option) any later version. 11 | ** 12 | ** This program is distributed in the hope that it will be useful, 13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ** GNU Lesser General Public License for more details. 16 | ** 17 | ** You should have received a copy of the GNU Lesser General Public License 18 | ** along with this program. If not, see . 19 | ** 20 | ****************************************************************************/ 21 | 22 | #ifndef MYQUICKVIEW_H 23 | #define MYQUICKVIEW_H 24 | 25 | #include 26 | 27 | class MeshRenderer; 28 | class Camera; 29 | 30 | class MyQuickView : public QQuickView 31 | { 32 | Q_OBJECT 33 | public: 34 | explicit MyQuickView(QWindow *parent = 0); 35 | 36 | private: 37 | void initializeUnderlay(); 38 | void synchronizeUnderlay(); 39 | void renderUnderlay(); 40 | void invalidateUnderlay(); 41 | 42 | Camera *m_camera; 43 | MeshRenderer *m_renderer; 44 | }; 45 | 46 | #endif // MYQUICKVIEW_H 47 | -------------------------------------------------------------------------------- /underlay/underlay.pro: -------------------------------------------------------------------------------- 1 | include(../lib/lib.pri) 2 | 3 | TEMPLATE = app 4 | TARGET = underlay 5 | 6 | QT += quick 7 | 8 | SOURCES += \ 9 | main.cpp \ 10 | myquickview.cpp 11 | 12 | HEADERS += \ 13 | myquickview.h 14 | 15 | RESOURCES += \ 16 | underlay.qrc 17 | 18 | 19 | -------------------------------------------------------------------------------- /underlay/underlay.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | main.qml 4 | 5 | 6 | --------------------------------------------------------------------------------