├── examples ├── CMakeLists.txt ├── vsgqtmdi │ ├── CMakeLists.txt │ └── main.cpp ├── vsgqtviewer │ ├── CMakeLists.txt │ └── main.cpp └── vsgqtwindows │ ├── CMakeLists.txt │ └── main.cpp ├── src └── vsgQt │ ├── vsgQtConfig.cmake.in │ ├── CMakeLists.txt │ ├── Viewer.cpp │ ├── KeyboardMap.cpp │ └── Window.cpp ├── LICENSE.md ├── .gitignore ├── README.md ├── CMakeLists.txt ├── include └── vsgQt │ ├── KeyboardMap.h │ ├── Viewer.h │ └── Window.h └── .clang-format /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(vsgXchange CONFIG) 2 | 3 | add_subdirectory(vsgqtviewer) 4 | add_subdirectory(vsgqtmdi) 5 | add_subdirectory(vsgqtwindows) 6 | -------------------------------------------------------------------------------- /src/vsgQt/vsgQtConfig.cmake.in: -------------------------------------------------------------------------------- 1 | # generated by cmake, do not change 2 | 3 | include(CMakeFindDependencyMacro) 4 | 5 | find_dependency(@QT_PACKAGE_NAME@ COMPONENTS Widgets) 6 | 7 | include("${CMAKE_CURRENT_LIST_DIR}/vsgQtTargets.cmake") 8 | -------------------------------------------------------------------------------- /examples/vsgqtmdi/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | main.cpp 3 | ) 4 | 5 | set(HEADERS 6 | ) 7 | 8 | add_executable(vsgqtmdi ${MODE} ${SOURCES} ${HEADERS} ${FORMS}) 9 | 10 | target_link_libraries(vsgqtmdi vsgQt) 11 | 12 | if (vsgXchange_FOUND) 13 | target_compile_definitions(vsgqtmdi PRIVATE vsgXchange_FOUND) 14 | target_link_libraries(vsgqtmdi vsgXchange::vsgXchange) 15 | endif() 16 | 17 | 18 | install(TARGETS vsgqtmdi DESTINATION bin) 19 | 20 | -------------------------------------------------------------------------------- /examples/vsgqtviewer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | main.cpp 3 | ) 4 | 5 | set(HEADERS 6 | ) 7 | 8 | add_executable(vsgqtviewer ${MODE} ${SOURCES} ${HEADERS} ${FORMS}) 9 | 10 | target_link_libraries(vsgqtviewer vsgQt) 11 | 12 | if (vsgXchange_FOUND) 13 | target_compile_definitions(vsgqtviewer PRIVATE vsgXchange_FOUND) 14 | target_link_libraries(vsgqtviewer vsgXchange::vsgXchange) 15 | endif() 16 | 17 | 18 | install(TARGETS vsgqtviewer DESTINATION bin) 19 | 20 | -------------------------------------------------------------------------------- /examples/vsgqtwindows/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | main.cpp 3 | ) 4 | 5 | set(HEADERS 6 | ) 7 | 8 | add_executable(vsgqtwindows ${MODE} ${SOURCES} ${HEADERS} ${FORMS}) 9 | 10 | target_link_libraries(vsgqtwindows vsgQt) 11 | 12 | if (vsgXchange_FOUND) 13 | target_compile_definitions(vsgqtwindows PRIVATE vsgXchange_FOUND) 14 | target_link_libraries(vsgqtwindows vsgXchange::vsgXchange) 15 | endif() 16 | 17 | 18 | install(TARGETS vsgqtwindows DESTINATION bin) 19 | 20 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | cmake_uninstall.cmake 3 | 4 | lib/ 5 | bin/ 6 | install/ 7 | 8 | # Autogenerated files 9 | *.pc 10 | *.conf 11 | *.backup 12 | CMakeCache.txt 13 | CMakeFiles 14 | CMakeScripts 15 | Makefile 16 | cmake_install.cmake 17 | install_manifest.txt 18 | CMakeDoxyfile.in 19 | CMakeDoxygenDefaults.cmake 20 | Doxyfile.docs 21 | vsgQtConfig.cmake 22 | vsgQtConfigVersion.cmake 23 | *_autogen/ 24 | include/vsgQt/Export.h 25 | Doxyfile.docs-vsgQt 26 | 27 | # Compiled Object files 28 | *.slo 29 | *.lo 30 | *.o 31 | *.obj 32 | 33 | # Precompiled Headers 34 | *.gch 35 | *.pch 36 | 37 | # Compiled Dynamic libraries 38 | *.so 39 | *.dylib 40 | *.dll 41 | 42 | # Fortran module files 43 | *.mod 44 | 45 | # Compiled Static libraries 46 | *.lai 47 | *.la 48 | *.a 49 | *.lib 50 | 51 | # Executables 52 | *.exe 53 | *.out 54 | *.app 55 | 56 | # Visual Studio files 57 | *.sln 58 | *.vcxproj 59 | *.vcxproj.filters 60 | *.vcxproj.user 61 | .vs/ 62 | x64/ 63 | src/vsgGIS/vsgGIS.dir/ 64 | *.pdb 65 | *.tlog 66 | *.log 67 | 68 | # Xcode 69 | DerivedData/ 70 | *.build 71 | *.xcodeproj 72 | 73 | # Gradle 74 | .gradle/ 75 | .idea/ 76 | .externalNativeBuild/ 77 | *.iml 78 | build/ 79 | local.properties 80 | 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vsgQt 2 | Open Source ([MIT Licensed](LICENSE.md)), cross platform C++ library providing integration of VulkanSceneGraph with Qt windowing. Supports Windows, Linux and macOS. 3 | 4 | vsgQt provides full Vulkan support through the VulkanSceneGraph's built in Window/VkSurface support rather than the limited Vulkan support that Qt-5.10 or later provide. Using the VulkanSceneGraph for providing Vulkan support avoids the restriction that Qt's VulkanWindow has with not being able to share VkDevice between windows, and provides compatibility with Qt versions prior to it adding Vulkan support. Sharing vsg::Device/VkDevice between Windows is crucial for providing multiple windows without blowing up GPU memory usage. 5 | 6 | ## Checking out vsgQt 7 | 8 | ~~~ sh 9 | git clone https://github.com/vsg-dev/vsgQt.git 10 | ~~~ 11 | 12 | ## Dependencies: 13 | 14 | * [VulkanSDK](https://www.lunarg.com/vulkan-sdk/) version 1.1.70 or later 15 | * [VulkanSceneGraph](https://github.com/vsg-dev/VulkanSceneGraph) master, 1.0.8 or later. 16 | * [CMake](https://cmake.org/) version 3.7 or later 17 | * [Qt](https://www.qt.io/) version 5 or later 18 | * C++17 capable compiler 19 | 20 | ## Building vsgQt 21 | 22 | ~~~ sh 23 | cd vsgQt 24 | cmake . 25 | make -j 8 26 | ~~~ 27 | 28 | ## Examples 29 | 30 | * [vsgqtviewer](examples/vsgqtviewer/main.cpp) - example of QApplication/QMainWindow usage with single vsgQt::Window. 31 | * [vsgqtmdi](examples/vsgqtmdi/main.cpp) - example of QMdiArea usage with multiple vsgQt::Window. 32 | * [vsgqtwindows](examples/vsgqtwindows/main.cpp) - example of multiple vsgQt::Window. 33 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | project(vsgQt 4 | VERSION 0.5.0 5 | DESCRIPTION "Qt integration with VulkanSceneGraph" 6 | LANGUAGES CXX 7 | ) 8 | 9 | option(VSGQT_BUILD_EXAMPLES "Build examples" ON) 10 | 11 | set(VSGQT_SOVERSION 3) 12 | set(VSGQT_RELEASE_CANDIDATE 0) 13 | 14 | set(VSGQT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "Root source directory of vsgQt") 15 | set(VSGQT_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE INTERNAL "Root binary directory of vsgQt") 16 | 17 | set(QT_PACKAGE_NAME Qt5 CACHE STRING "Set Qt package name, i.e. Qt5 or Qt6.") 18 | 19 | find_package(vsg 1.1.13) 20 | 21 | vsg_setup_dir_vars() 22 | vsg_setup_build_vars() 23 | 24 | # if Qt5 then we need 5.10 or later 25 | find_package(${QT_PACKAGE_NAME} COMPONENTS Widgets REQUIRED) 26 | 27 | vsg_add_target_clang_format( 28 | FILES 29 | include/*/*.h 30 | src/*/*.cpp 31 | ) 32 | vsg_add_target_clobber() 33 | vsg_add_target_cppcheck( 34 | FILES 35 | include/*/*.h 36 | src/*/*.cpp 37 | ) 38 | vsg_add_target_docs( 39 | FILES 40 | src 41 | include/*/*.h 42 | src/*/*.cpp 43 | ) 44 | vsg_add_target_uninstall() 45 | 46 | # only provide custom targets if not building as a submodule/FetchContent 47 | if (${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_SOURCE_DIR}) 48 | 49 | vsg_add_option_maintainer( 50 | PREFIX v 51 | RCLEVEL ${VSGQT_RELEASE_CANDIDATE} 52 | ) 53 | 54 | endif() 55 | 56 | set(CMAKE_AUTOMOC ON) 57 | set(CMAKE_AUTORCC ON) 58 | set(CMAKE_AUTOUIC ON) 59 | 60 | if(WIN32) 61 | add_definitions(-DNOMINMAX) 62 | set(MODE WIN32) 63 | endif() 64 | 65 | add_subdirectory(src/vsgQt) 66 | if (VSGQT_BUILD_EXAMPLES) 67 | add_subdirectory(examples) 68 | endif() 69 | 70 | vsg_add_feature_summary() 71 | -------------------------------------------------------------------------------- /include/vsgQt/KeyboardMap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | 5 | Copyright(c) 2021 Robert Osfield 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 12 | 13 | */ 14 | 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | namespace vsgQt 21 | { 22 | 23 | class VSGQT_DECLSPEC KeyboardMap : public vsg::Inherit 24 | { 25 | public: 26 | KeyboardMap(); 27 | 28 | bool getKeySymbol(const QKeyEvent* e, vsg::KeySymbol& keySymbol, vsg::KeySymbol& modifiedKeySymbol, vsg::KeyModifier& keyModifier); 29 | 30 | protected: 31 | using VirtualKeyToKeySymbolMap = std::map; 32 | VirtualKeyToKeySymbolMap _keycodeMap; 33 | }; 34 | 35 | } // namespace vsgQt 36 | 37 | EVSG_type_name(vsgQt::KeyboardMap); 38 | -------------------------------------------------------------------------------- /src/vsgQt/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # create and install export header which contains export macros for libraries 3 | # 4 | # available arguments: 5 | # 6 | # pattern for generating macro names (_DECLSPEC) 7 | # and install paths (include//Export.h) 8 | # 9 | # In public c++ headers the generated file must be included with 10 | # 11 | # #include </Export.h> 12 | # 13 | # and public classes be decorated with 14 | # 15 | # class _DECLSPEC ... 16 | # 17 | # @TODO: move to vsg 18 | macro(add_library_export_header _TARGET) 19 | 20 | string(TOUPPER ${_TARGET} TARGET_UPPER) 21 | 22 | include(GenerateExportHeader) 23 | generate_export_header(${_TARGET} 24 | EXPORT_MACRO_NAME ${TARGET_UPPER}_DECLSPEC 25 | EXPORT_FILE_NAME ${VSGQT_BINARY_DIR}/include/${_TARGET}/Export.h 26 | ) 27 | install(FILES ${VSGQT_BINARY_DIR}/include/${_TARGET}/Export.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${_TARGET}) 28 | 29 | # pass the creation mode to the corresponding target in the cmake 30 | if(NOT BUILD_SHARED_LIBS) 31 | target_compile_definitions(${_TARGET} INTERFACE ${TARGET_UPPER}_STATIC_DEFINE) 32 | endif() 33 | endmacro() 34 | 35 | set(SOURCES 36 | KeyboardMap.cpp 37 | Window.cpp 38 | Viewer.cpp 39 | ) 40 | 41 | set(HEADERS 42 | ../../include/vsgQt/KeyboardMap.h 43 | ../../include/vsgQt/Window.h 44 | ../../include/vsgQt/Viewer.h 45 | ) 46 | 47 | # shared mode is automatically chosen by setting BUILD_SHARED_LIBS=ON 48 | # POSITION_INDEPENDENT_CODE ON is set by default in shared mode 49 | add_library(vsgQt ${SOURCES} ${HEADERS}) 50 | 51 | # add definitions to enable building vsgQt as part of submodule 52 | add_library(vsgQt::vsgQt ALIAS vsgQt) 53 | set(vsgQt_FOUND TRUE CACHE INTERNAL "vsgQt found.") 54 | set(CMAKE_DISABLE_FIND_PACKAGE_vsgQt TRUE CACHE INTERNAL "Disable find_package(vsgQt) as it's not necessary.") 55 | 56 | set_target_properties(vsgQt 57 | PROPERTIES 58 | VERSION ${VSGQT_VERSION} 59 | SOVERSION ${VSGQT_SOVERSION} 60 | ) 61 | 62 | target_include_directories(vsgQt 63 | PUBLIC 64 | $ 65 | $ 66 | $ 67 | ) 68 | target_link_libraries(vsgQt 69 | PUBLIC 70 | ${QT_PACKAGE_NAME}::Widgets 71 | vsg::vsg 72 | ) 73 | 74 | add_library_export_header(vsgQt) 75 | 76 | install(TARGETS vsgQt ${INSTALL_TARGETS_DEFAULT_FLAGS}) 77 | install(DIRECTORY ${VSGQT_SOURCE_DIR}/include/vsgQt DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 78 | 79 | vsg_add_cmake_support_files( 80 | CONFIG_TEMPLATE vsgQtConfig.cmake.in 81 | ) 82 | -------------------------------------------------------------------------------- /include/vsgQt/Viewer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | 5 | Copyright(c) 2021 Robert Osfield 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 12 | 13 | */ 14 | 15 | #include 16 | 17 | #include 18 | 19 | #include 20 | 21 | namespace vsgQt 22 | { 23 | 24 | // forward declare 25 | class Window; 26 | 27 | class VSGQT_DECLSPEC Viewer : public vsg::Inherit 28 | { 29 | public: 30 | /// Create Viewer. 31 | /// If msecTimerInterval is > 0 then call setInterval(msecTimerInterval) to set up QTime to call Viewer::render() at this interval, 32 | /// otherwise the redraw is left application to call Viewer::render() when required, call Viewer::setInverval() to set up the timer, 33 | /// or to call the underlying vsg::Viewer methods for rendering a framne within the application when the viewer needs to redraw a frame. 34 | Viewer(int msecTimerInterval = 0); 35 | 36 | QTimer timer; 37 | std::atomic_uint requests; 38 | bool continuousUpdate = true; 39 | 40 | /// override pollEvents to prevent the window->pollEvents() from being called by vsg::Viewer 41 | bool pollEvents(bool discardPreviousEvents = true) override; 42 | 43 | /// increment the requests count to signal that a new frame should be rendered on the next timer call. 44 | virtual void request(); 45 | 46 | /// called by the QTimer and will do the viewer frame calls to render all windows associated with the viewer. 47 | /// if continuousUpdate is false then the viewer frame calls are only done if the requests count is > 0 48 | virtual void render(double simulationTime = vsg::Viewer::UseTimeSinceStartPoint); 49 | 50 | /// set the QTimer interval in milliseconds, this controls how often the Viewer::render() is called 51 | void setInterval(int msecTimerInterval); 52 | }; 53 | 54 | } // namespace vsgQt 55 | 56 | EVSG_type_name(vsgQt::Viewer); 57 | -------------------------------------------------------------------------------- /src/vsgQt/Viewer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2021 Robert Osfield, Andre Normann 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #if defined(WIN32) 14 | # define VK_USE_PLATFORM_WIN32_KHR 15 | #elif defined(__APPLE__) 16 | # define VK_USE_PLATFORM_MACOS_MVK 17 | #else 18 | # define VK_USE_PLATFORM_XCB_KHR 19 | // #define VK_USE_PLATFORM_XLIB_KHR 20 | #endif 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | #include 35 | 36 | using namespace vsgQt; 37 | 38 | Viewer::Viewer(int msecTimerInterval) 39 | { 40 | // set the default timer as 8ms. 41 | if (msecTimerInterval > 0) setInterval(msecTimerInterval); 42 | } 43 | 44 | bool Viewer::pollEvents(bool discardPreviousEvents) 45 | { 46 | if (discardPreviousEvents) _events.clear(); 47 | for (auto& window : _windows) 48 | { 49 | _events.splice(_events.end(), window->bufferedEvents); 50 | window->bufferedEvents.clear(); 51 | } 52 | 53 | return !_events.empty(); 54 | } 55 | 56 | void Viewer::request() 57 | { 58 | ++requests; 59 | } 60 | 61 | void Viewer::render(double simulationTime) 62 | { 63 | if (!continuousUpdate && requests.load() == 0) 64 | { 65 | //vsg::info("render() no render : requests = ", requests.load()); 66 | return; 67 | } 68 | 69 | if (advanceToNextFrame(simulationTime)) 70 | { 71 | handleEvents(); 72 | update(); 73 | recordAndSubmit(); 74 | present(); 75 | } 76 | else 77 | { 78 | if (status->cancel()) 79 | { 80 | QCoreApplication::quit(); 81 | } 82 | } 83 | 84 | requests = 0; 85 | } 86 | 87 | void Viewer::setInterval(int msecTimerInterval) 88 | { 89 | timer.setInterval(msecTimerInterval); 90 | timer.connect(&timer, &QTimer::timeout, [&]() { render(); }); 91 | timer.start(); 92 | } 93 | -------------------------------------------------------------------------------- /include/vsgQt/Window.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | 5 | Copyright(c) 2021 Robert Osfield 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 12 | 13 | */ 14 | 15 | //#include 16 | #include 17 | 18 | #include 19 | 20 | #include 21 | #include 22 | 23 | namespace vsgQt 24 | { 25 | 26 | class VSGQT_DECLSPEC Window : public QWindow 27 | { 28 | public: 29 | Window(QScreen* targetScreen = nullptr); 30 | Window(QWindow* parent); 31 | Window(vsg::ref_ptr in_traits, QScreen* targetScreen = nullptr); 32 | Window(vsg::ref_ptr in_traits, QWindow* parent); 33 | Window(vsg::ref_ptr in_viewer, vsg::ref_ptr in_traits, QScreen* targetScreen = nullptr); 34 | Window(vsg::ref_ptr in_viewer, vsg::ref_ptr in_traits, QWindow* parent); 35 | 36 | virtual ~Window(); 37 | 38 | vsg::ref_ptr traits; 39 | vsg::ref_ptr viewer; 40 | 41 | vsg::ref_ptr windowAdapter; 42 | vsg::ref_ptr keyboardMap; 43 | 44 | operator vsg::ref_ptr() { return windowAdapter; } 45 | 46 | /// Initialize the Vulkan integration using VulkanSceneGraph VkInstance/VkSurface support 47 | virtual void initializeWindow(); 48 | 49 | protected: 50 | void cleanup(); 51 | 52 | bool event(QEvent* e) override; 53 | 54 | void exposeEvent(QExposeEvent*) override; 55 | void hideEvent(QHideEvent* ev) override; 56 | 57 | void keyPressEvent(QKeyEvent*) override; 58 | void keyReleaseEvent(QKeyEvent*) override; 59 | void mouseMoveEvent(QMouseEvent*) override; 60 | void mousePressEvent(QMouseEvent*) override; 61 | void mouseReleaseEvent(QMouseEvent*) override; 62 | void resizeEvent(QResizeEvent*) override; 63 | void wheelEvent(QWheelEvent*) override; 64 | 65 | /// convert Qt's window coordinate into Vulkan/VSG ones by scaling by the devicePixelRatio() 66 | template 67 | int32_t convert_coord(T c) const { return static_cast(std::round(static_cast(c) * devicePixelRatio())); } 68 | 69 | std::pair convertMouseButtons(QMouseEvent* e) const; 70 | std::pair convertMousePosition(QMouseEvent* e) const; 71 | 72 | private: 73 | bool _initialized = false; 74 | }; 75 | 76 | } // namespace vsgQt 77 | 78 | EVSG_type_name(vsgQt::Window); 79 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -4 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlines: Right 9 | AlignOperands: true 10 | AlignTrailingComments: true 11 | AllowAllParametersOfDeclarationOnNextLine: true 12 | AllowShortBlocksOnASingleLine: true 13 | AllowShortCaseLabelsOnASingleLine: true 14 | AllowShortFunctionsOnASingleLine: InlineOnly 15 | AllowShortIfStatementsOnASingleLine: true 16 | AllowShortLoopsOnASingleLine: true 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: false 20 | AlwaysBreakTemplateDeclarations: false 21 | BinPackArguments: true 22 | BinPackParameters: true 23 | BraceWrapping: 24 | AfterClass: true 25 | AfterControlStatement: true 26 | AfterEnum: true 27 | AfterFunction: true 28 | AfterNamespace: true 29 | AfterObjCDeclaration: true 30 | AfterStruct: true 31 | AfterUnion: true 32 | AfterExternBlock: true 33 | BeforeCatch: true 34 | BeforeElse: true 35 | IndentBraces: false 36 | SplitEmptyFunction: true 37 | SplitEmptyRecord: true 38 | SplitEmptyNamespace: true 39 | BreakBeforeBinaryOperators: None 40 | BreakBeforeBraces: Custom 41 | BreakBeforeInheritanceComma: false 42 | BreakBeforeTernaryOperators: true 43 | BreakConstructorInitializersBeforeComma: true 44 | BreakConstructorInitializers: AfterColon 45 | BreakAfterJavaFieldAnnotations: false 46 | BreakStringLiterals: true 47 | ColumnLimit: 0 48 | CommentPragmas: '^ IWYU pragma:' 49 | CompactNamespaces: false 50 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 51 | ConstructorInitializerIndentWidth: 4 52 | ContinuationIndentWidth: 4 53 | Cpp11BracedListStyle: true 54 | DerivePointerAlignment: false 55 | DisableFormat: false 56 | ExperimentalAutoDetectBinPacking: false 57 | FixNamespaceComments: true 58 | ForEachMacros: 59 | - foreach 60 | - Q_FOREACH 61 | - BOOST_FOREACH 62 | IncludeBlocks: Preserve 63 | IncludeCategories: 64 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 65 | Priority: 2 66 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 67 | Priority: 3 68 | - Regex: '.*' 69 | Priority: 1 70 | IncludeIsMainRegex: '(Test)?$' 71 | IndentCaseLabels: false 72 | IndentPPDirectives: AfterHash 73 | IndentWidth: 4 74 | IndentWrappedFunctionNames: false 75 | JavaScriptQuotes: Leave 76 | JavaScriptWrapImports: true 77 | KeepEmptyLinesAtTheStartOfBlocks: true 78 | MacroBlockBegin: '' 79 | MacroBlockEnd: '' 80 | MaxEmptyLinesToKeep: 1 81 | NamespaceIndentation: All 82 | ObjCBlockIndentWidth: 4 83 | ObjCSpaceAfterProperty: false 84 | ObjCSpaceBeforeProtocolList: true 85 | PenaltyBreakAssignment: 2 86 | PenaltyBreakBeforeFirstCallParameter: 19 87 | PenaltyBreakComment: 300 88 | PenaltyBreakFirstLessLess: 120 89 | PenaltyBreakString: 1000 90 | PenaltyExcessCharacter: 1000000 91 | PenaltyReturnTypeOnItsOwnLine: 60 92 | PointerAlignment: Left 93 | ReflowComments: false 94 | SortIncludes: true 95 | SortUsingDeclarations: true 96 | SpaceAfterCStyleCast: false 97 | SpaceAfterTemplateKeyword: false 98 | SpaceBeforeAssignmentOperators: true 99 | SpaceBeforeParens: ControlStatements 100 | SpaceInEmptyParentheses: false 101 | SpacesBeforeTrailingComments: 1 102 | SpacesInAngles: false 103 | SpacesInContainerLiterals: true 104 | SpacesInCStyleCastParentheses: false 105 | SpacesInParentheses: false 106 | SpacesInSquareBrackets: false 107 | Standard: Cpp11 108 | TabWidth: 8 109 | UseTab: Never 110 | ... 111 | 112 | -------------------------------------------------------------------------------- /examples/vsgqtviewer/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef vsgXchange_FOUND 4 | # include 5 | #endif 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | vsgQt::Window* createWindow(vsg::ref_ptr viewer, vsg::ref_ptr traits, vsg::ref_ptr vsg_scene, QWindow* parent, const QString& title = {}) 15 | { 16 | auto window = new vsgQt::Window(viewer, traits, parent); 17 | 18 | window->setTitle(title); 19 | 20 | window->initializeWindow(); 21 | 22 | // if this is the first window to be created, use its device for future window creation. 23 | if (!traits->device) traits->device = window->windowAdapter->getOrCreateDevice(); 24 | 25 | // compute the bounds of the scene graph to help position camera 26 | vsg::ComputeBounds computeBounds; 27 | vsg_scene->accept(computeBounds); 28 | vsg::dvec3 centre = (computeBounds.bounds.min + computeBounds.bounds.max) * 0.5; 29 | double radius = vsg::length(computeBounds.bounds.max - computeBounds.bounds.min) * 0.6; 30 | double nearFarRatio = 0.001; 31 | 32 | uint32_t width = window->traits->width; 33 | uint32_t height = window->traits->height; 34 | 35 | vsg::ref_ptr ellipsoidModel(vsg_scene->getObject("EllipsoidModel")); 36 | vsg::ref_ptr camera; 37 | { 38 | // set up the camera 39 | auto lookAt = vsg::LookAt::create(centre + vsg::dvec3(0.0, -radius * 3.5, 0.0), centre, vsg::dvec3(0.0, 0.0, 1.0)); 40 | 41 | vsg::ref_ptr perspective; 42 | if (ellipsoidModel) 43 | { 44 | perspective = vsg::EllipsoidPerspective::create( 45 | lookAt, ellipsoidModel, 30.0, 46 | static_cast(width) / 47 | static_cast(height), 48 | nearFarRatio, false); 49 | } 50 | else 51 | { 52 | perspective = vsg::Perspective::create( 53 | 30.0, 54 | static_cast(width) / 55 | static_cast(height), 56 | nearFarRatio * radius, radius * 4.5); 57 | } 58 | 59 | camera = vsg::Camera::create(perspective, lookAt, vsg::ViewportState::create(VkExtent2D{width, height})); 60 | } 61 | 62 | auto trackball = vsg::Trackball::create(camera, ellipsoidModel); 63 | trackball->addWindow(*window); 64 | 65 | viewer->addEventHandler(trackball); 66 | 67 | auto commandGraph = vsg::createCommandGraphForView(*window, camera, vsg_scene); 68 | 69 | viewer->addRecordAndSubmitTaskAndPresentation({commandGraph}); 70 | 71 | return window; 72 | } 73 | 74 | int main(int argc, char* argv[]) 75 | { 76 | QApplication application(argc, argv); 77 | 78 | vsg::CommandLine arguments(&argc, argv); 79 | 80 | // set up vsg::Options to pass in filepaths, ReaderWriters and other IO 81 | // related options to use when reading and writing files. 82 | auto options = vsg::Options::create(); 83 | options->fileCache = vsg::getEnv("VSG_FILE_CACHE"); 84 | options->paths = vsg::getEnvPaths("VSG_FILE_PATH"); 85 | #ifdef vsgXchange_FOUND 86 | options->add(vsgXchange::all::create()); 87 | #endif 88 | 89 | options->readOptions(arguments); 90 | 91 | auto windowTraits = vsg::WindowTraits::create(); 92 | windowTraits->windowTitle = "vsgQt viewer"; 93 | windowTraits->debugLayer = arguments.read({"--debug", "-d"}); 94 | windowTraits->apiDumpLayer = arguments.read({"--api", "-a"}); 95 | arguments.read("--samples", windowTraits->samples); 96 | arguments.read({"--window", "-w"}, windowTraits->width, windowTraits->height); 97 | if (arguments.read({"--fullscreen", "--fs"})) windowTraits->fullscreen = true; 98 | 99 | bool continuousUpdate = !arguments.read({"--event-driven", "--ed"}); 100 | auto interval = arguments.value(8, "--interval"); 101 | 102 | if (arguments.errors()) 103 | return arguments.writeErrorMessages(std::cerr); 104 | 105 | if (argc <= 1) 106 | { 107 | std::cout << "Please specify a 3d model or image file on the command line." 108 | << std::endl; 109 | return 1; 110 | } 111 | 112 | vsg::Path filename = arguments[1]; 113 | 114 | auto vsg_scene = vsg::read_cast(filename, options); 115 | if (!vsg_scene) 116 | { 117 | std::cout << "Failed to load a valid scene graph. Please specify a valid 3d " 118 | "model or image file on the command line." 119 | << std::endl; 120 | return 1; 121 | } 122 | 123 | 124 | QMainWindow* mainWindow = new QMainWindow(); 125 | 126 | // create the viewer that will manage all the rendering of the views 127 | auto viewer = vsgQt::Viewer::create(); 128 | 129 | auto window = createWindow(viewer, windowTraits, vsg_scene, nullptr, "First Window"); 130 | 131 | auto widget = QWidget::createWindowContainer(window, mainWindow); 132 | 133 | mainWindow->setCentralWidget(widget); 134 | 135 | mainWindow->setGeometry(windowTraits->x, windowTraits->y, windowTraits->width, windowTraits->height); 136 | 137 | mainWindow->show(); 138 | 139 | if (interval >= 0) viewer->setInterval(interval); 140 | viewer->continuousUpdate = continuousUpdate; 141 | 142 | viewer->addEventHandler(vsg::CloseHandler::create(viewer)); 143 | viewer->compile(); 144 | 145 | return application.exec(); 146 | } 147 | -------------------------------------------------------------------------------- /examples/vsgqtwindows/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef vsgXchange_FOUND 4 | # include 5 | #endif 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | vsgQt::Window* createWindow(vsg::ref_ptr viewer, vsg::ref_ptr traits, vsg::ref_ptr vsg_scene, QWindow* parent, const QString& title = {}) 16 | { 17 | auto window = new vsgQt::Window(viewer, traits, parent); 18 | 19 | window->setTitle(title); 20 | 21 | window->initializeWindow(); 22 | 23 | // if this is the first window to be created, use its device for future window creation. 24 | if (!traits->device) traits->device = window->windowAdapter->getOrCreateDevice(); 25 | 26 | // compute the bounds of the scene graph to help position camera 27 | vsg::ComputeBounds computeBounds; 28 | vsg_scene->accept(computeBounds); 29 | vsg::dvec3 centre = (computeBounds.bounds.min + computeBounds.bounds.max) * 0.5; 30 | double radius = vsg::length(computeBounds.bounds.max - computeBounds.bounds.min) * 0.6; 31 | double nearFarRatio = 0.001; 32 | 33 | uint32_t width = window->traits->width; 34 | uint32_t height = window->traits->height; 35 | 36 | vsg::ref_ptr ellipsoidModel(vsg_scene->getObject("EllipsoidModel")); 37 | vsg::ref_ptr camera; 38 | { 39 | // set up the camera 40 | auto lookAt = vsg::LookAt::create(centre + vsg::dvec3(0.0, -radius * 3.5, 0.0), centre, vsg::dvec3(0.0, 0.0, 1.0)); 41 | 42 | vsg::ref_ptr perspective; 43 | if (ellipsoidModel) 44 | { 45 | perspective = vsg::EllipsoidPerspective::create( 46 | lookAt, ellipsoidModel, 30.0, 47 | static_cast(width) / 48 | static_cast(height), 49 | nearFarRatio, false); 50 | } 51 | else 52 | { 53 | perspective = vsg::Perspective::create( 54 | 30.0, 55 | static_cast(width) / 56 | static_cast(height), 57 | nearFarRatio * radius, radius * 4.5); 58 | } 59 | 60 | camera = vsg::Camera::create(perspective, lookAt, vsg::ViewportState::create(VkExtent2D{width, height})); 61 | } 62 | 63 | auto trackball = vsg::Trackball::create(camera, ellipsoidModel); 64 | trackball->addWindow(*window); 65 | 66 | viewer->addEventHandler(trackball); 67 | 68 | auto commandGraph = vsg::createCommandGraphForView(*window, camera, vsg_scene); 69 | 70 | viewer->addRecordAndSubmitTaskAndPresentation({commandGraph}); 71 | 72 | return window; 73 | } 74 | 75 | int main(int argc, char* argv[]) 76 | { 77 | QApplication application(argc, argv); 78 | 79 | vsg::CommandLine arguments(&argc, argv); 80 | 81 | // set up vsg::Options to pass in filepaths, ReaderWriters and other IO 82 | // related options to use when reading and writing files. 83 | auto options = vsg::Options::create(); 84 | options->fileCache = vsg::getEnv("VSG_FILE_CACHE"); 85 | options->paths = vsg::getEnvPaths("VSG_FILE_PATH"); 86 | #ifdef vsgXchange_FOUND 87 | options->add(vsgXchange::all::create()); 88 | #endif 89 | 90 | options->readOptions(arguments); 91 | 92 | auto windowTraits = vsg::WindowTraits::create(); 93 | windowTraits->windowTitle = "vsgQt viewer"; 94 | windowTraits->debugLayer = arguments.read({"--debug", "-d"}); 95 | windowTraits->apiDumpLayer = arguments.read({"--api", "-a"}); 96 | arguments.read("--samples", windowTraits->samples); 97 | arguments.read({"--window", "-w"}, windowTraits->width, windowTraits->height); 98 | if (arguments.read({"--fullscreen", "--fs"})) windowTraits->fullscreen = true; 99 | 100 | bool continuousUpdate = !arguments.read({"--event-driven", "--ed"}); 101 | auto interval = arguments.value(8, "--interval"); 102 | 103 | if (arguments.errors()) 104 | return arguments.writeErrorMessages(std::cerr); 105 | 106 | if (argc <= 1) 107 | { 108 | std::cout << "Please specify a 3d model or image file on the command line." 109 | << std::endl; 110 | return 1; 111 | } 112 | 113 | vsg::Path filename = arguments[1]; 114 | 115 | auto vsg_scene = vsg::read_cast(filename, options); 116 | if (!vsg_scene) 117 | { 118 | std::cout << "Failed to load a valid scene graph. Please specify a valid 3d " 119 | "model or image file on the command line." 120 | << std::endl; 121 | return 1; 122 | } 123 | 124 | 125 | 126 | // create the viewer that will manage all the rendering of the views 127 | auto viewer = vsgQt::Viewer::create(); 128 | 129 | // add close handler to respond to the close window button and pressing escape 130 | viewer->addEventHandler(vsg::CloseHandler::create(viewer)); 131 | 132 | // create the windows 133 | auto firstWindow = createWindow(viewer, windowTraits, vsg_scene, nullptr, "First Window"); 134 | auto secondWindow = createWindow(viewer, windowTraits, vsg_scene, nullptr, "Second Window"); 135 | auto thirdWindow = createWindow(viewer, windowTraits, vsg_scene, nullptr, "Third Window"); 136 | 137 | firstWindow->setGeometry(0, 0, 640, 480); 138 | firstWindow->show(); 139 | 140 | secondWindow->setGeometry(680, 0, 640, 480); 141 | secondWindow->show(); 142 | 143 | thirdWindow->setGeometry(1360, 0, 640, 480); 144 | thirdWindow->show(); 145 | 146 | if (interval >= 0) viewer->setInterval(interval); 147 | viewer->continuousUpdate = continuousUpdate; 148 | 149 | viewer->compile(); 150 | 151 | return application.exec(); 152 | } 153 | -------------------------------------------------------------------------------- /examples/vsgqtmdi/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef vsgXchange_FOUND 4 | # include 5 | #endif 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | class MultiViewArea : public QMdiArea 16 | { 17 | public: 18 | 19 | vsg::ref_ptr traits; 20 | vsg::ref_ptr viewer; 21 | 22 | MultiViewArea(QWidget *parent = nullptr) : 23 | QMdiArea(parent), 24 | viewer(vsgQt::Viewer::create()) 25 | { 26 | viewer->addEventHandler(vsg::CloseHandler::create(viewer)); 27 | } 28 | 29 | struct ViewWindow 30 | { 31 | vsgQt::Window* window = nullptr; 32 | }; 33 | 34 | using Views = std::vector; 35 | Views views; 36 | 37 | size_t addView(vsg::ref_ptr vsg_scene, const QString& title = {}) 38 | { 39 | auto window = new vsgQt::Window(viewer, traits); 40 | 41 | auto widget = QWidget::createWindowContainer(window, this); 42 | widget->setWindowTitle(title); 43 | 44 | addSubWindow(widget); 45 | 46 | if (views.empty()) widget->showMaximized(); 47 | else tileSubWindows(); 48 | 49 | window->initializeWindow(); 50 | 51 | // if this is the first window to be created, use its device for future window creation. 52 | if (!traits->device) traits->device = window->windowAdapter->getOrCreateDevice(); 53 | 54 | // compute the bounds of the scene graph to help position camera 55 | vsg::ComputeBounds computeBounds; 56 | vsg_scene->accept(computeBounds); 57 | vsg::dvec3 centre = (computeBounds.bounds.min + computeBounds.bounds.max) * 0.5; 58 | double radius = vsg::length(computeBounds.bounds.max - computeBounds.bounds.min) * 0.6; 59 | double nearFarRatio = 0.001; 60 | 61 | uint32_t width = window->traits->width; 62 | uint32_t height = window->traits->height; 63 | 64 | vsg::ref_ptr ellipsoidModel(vsg_scene->getObject("EllipsoidModel")); 65 | vsg::ref_ptr camera; 66 | { 67 | // set up the camera 68 | auto lookAt = vsg::LookAt::create(centre + vsg::dvec3(0.0, -radius * 3.5, 0.0), centre, vsg::dvec3(0.0, 0.0, 1.0)); 69 | 70 | vsg::ref_ptr perspective; 71 | if (ellipsoidModel) 72 | { 73 | perspective = vsg::EllipsoidPerspective::create( 74 | lookAt, ellipsoidModel, 30.0, 75 | static_cast(width) / 76 | static_cast(height), 77 | nearFarRatio, false); 78 | } 79 | else 80 | { 81 | perspective = vsg::Perspective::create( 82 | 30.0, 83 | static_cast(width) / 84 | static_cast(height), 85 | nearFarRatio * radius, radius * 4.5); 86 | } 87 | 88 | camera = vsg::Camera::create(perspective, lookAt, vsg::ViewportState::create(VkExtent2D{width, height})); 89 | } 90 | 91 | auto trackball = vsg::Trackball::create(camera, ellipsoidModel); 92 | trackball->addWindow(*window); 93 | 94 | viewer->addEventHandler(trackball); 95 | 96 | auto commandGraph = vsg::createCommandGraphForView(*window, camera, vsg_scene); 97 | 98 | viewer->addRecordAndSubmitTaskAndPresentation({commandGraph}); 99 | 100 | views.push_back(ViewWindow{window}); 101 | 102 | return views.size()-1; 103 | } 104 | }; 105 | 106 | 107 | int main(int argc, char* argv[]) 108 | { 109 | QApplication application(argc, argv); 110 | 111 | vsg::CommandLine arguments(&argc, argv); 112 | 113 | // set up vsg::Options to pass in filepaths, ReaderWriters and other IO 114 | // related options to use when reading and writing files. 115 | auto options = vsg::Options::create(); 116 | options->fileCache = vsg::getEnv("VSG_FILE_CACHE"); 117 | options->paths = vsg::getEnvPaths("VSG_FILE_PATH"); 118 | #ifdef vsgXchange_FOUND 119 | options->add(vsgXchange::all::create()); 120 | #endif 121 | 122 | options->readOptions(arguments); 123 | 124 | auto windowTraits = vsg::WindowTraits::create(); 125 | windowTraits->windowTitle = "vsgQt viewer"; 126 | windowTraits->debugLayer = arguments.read({"--debug", "-d"}); 127 | windowTraits->apiDumpLayer = arguments.read({"--api", "-a"}); 128 | arguments.read("--samples", windowTraits->samples); 129 | arguments.read({"--window", "-w"}, windowTraits->width, windowTraits->height); 130 | if (arguments.read({"--fullscreen", "--fs"})) windowTraits->fullscreen = true; 131 | 132 | bool continuousUpdate = !arguments.read({"--event-driven", "--ed"}); 133 | auto interval = arguments.value(8, "--interval"); 134 | 135 | if (arguments.errors()) 136 | return arguments.writeErrorMessages(std::cerr); 137 | 138 | if (argc <= 1) 139 | { 140 | std::cout << "Please specify a 3d model or image file on the command line." 141 | << std::endl; 142 | return 1; 143 | } 144 | 145 | vsg::Path filename = arguments[1]; 146 | 147 | auto vsg_scene = vsg::read_cast(filename, options); 148 | if (!vsg_scene) 149 | { 150 | std::cout << "Failed to load a valid scene graph. Please specify a valid 3d " 151 | "model or image file on the command line." 152 | << std::endl; 153 | return 1; 154 | } 155 | 156 | QMainWindow* mainWindow = new QMainWindow(); 157 | 158 | auto mdiArea = new MultiViewArea(mainWindow); 159 | 160 | mainWindow->setCentralWidget(mdiArea); 161 | 162 | mdiArea->traits = windowTraits; 163 | 164 | mdiArea->setContextMenuPolicy(Qt::PreventContextMenu); 165 | mdiArea->setViewMode(QMdiArea::ViewMode::SubWindowView); 166 | mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); 167 | mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); 168 | mdiArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); 169 | 170 | mdiArea->addView(vsg_scene, "First Window"); 171 | mdiArea->addView(vsg_scene, "Second Window"); 172 | mdiArea->addView(vsg_scene, "Third Window"); 173 | 174 | mdiArea->viewer->compile(); 175 | 176 | if (interval >= 0) mdiArea->viewer->setInterval(interval); 177 | mdiArea->viewer->continuousUpdate = continuousUpdate; 178 | 179 | mainWindow->show(); 180 | 181 | return application.exec(); 182 | } 183 | -------------------------------------------------------------------------------- /src/vsgQt/KeyboardMap.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2021 Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #include 14 | 15 | using namespace vsgQt; 16 | 17 | KeyboardMap::KeyboardMap() : 18 | _keycodeMap{ 19 | {0x0, vsg::KEY_Undefined}, 20 | {Qt::Key_Space, vsg::KEY_Space}, 21 | 22 | /* Cursor control & motion */ 23 | 24 | {Qt::Key_Home, vsg::KEY_Home}, 25 | {Qt::Key_Left, vsg::KEY_Left}, /* Move left, left arrow */ 26 | {Qt::Key_Up, vsg::KEY_Up}, /* Move up, up arrow */ 27 | {Qt::Key_Right, vsg::KEY_Right}, /* Move right, right arrow */ 28 | {Qt::Key_Down, vsg::KEY_Down}, /* Move down, down arrow */ 29 | //{Qt::Key_Home, vsg::KEY_Prior}, /* Prior, previous */ 30 | {Qt::Key_PageUp, vsg::KEY_Page_Up}, 31 | {Qt::Key_Home, vsg::KEY_Next}, /* Next */ 32 | {Qt::Key_PageDown, vsg::KEY_Page_Down}, 33 | {Qt::Key_End, vsg::KEY_End}, /* EOL */ 34 | //{ KEY_Begin = 0xFF58, /* BOL */ 35 | 36 | {'!', vsg::KEY_Exclaim}, 37 | {'"', vsg::KEY_Quotedbl}, 38 | {'#', vsg::KEY_Hash}, 39 | {'$', vsg::KEY_Dollar}, 40 | {'&', vsg::KEY_Ampersand}, 41 | {Qt::Key_QuoteLeft, vsg::KEY_Quote}, 42 | {'(', vsg::KEY_Leftparen}, 43 | {')', vsg::KEY_Rightparen}, 44 | {'*', vsg::KEY_Asterisk}, 45 | {'+', vsg::KEY_Plus}, 46 | {Qt::Key_Comma, vsg::KEY_Comma}, 47 | {Qt::Key_Minus, vsg::KEY_Minus}, 48 | {Qt::Key_Period, vsg::KEY_Period}, 49 | {Qt::Key_Slash, vsg::KEY_Slash}, 50 | {':', vsg::KEY_Colon}, 51 | {Qt::Key_Semicolon, vsg::KEY_Semicolon}, 52 | {'<', vsg::KEY_Less}, 53 | {Qt::Key_Equal, vsg::KEY_Equals}, // + isn't an unmodded key, why does windows map is as a virtual?? 54 | {'>', vsg::KEY_Greater}, 55 | {'?', vsg::KEY_Question}, 56 | {'@', vsg::KEY_At}, 57 | {Qt::Key_BracketLeft, vsg::KEY_Leftbracket}, 58 | {Qt::Key_Backslash, vsg::KEY_Backslash}, 59 | {Qt::Key_BracketRight, vsg::KEY_Rightbracket}, 60 | {'|', vsg::KEY_Caret}, 61 | {'_', vsg::KEY_Underscore}, 62 | {0xc0, vsg::KEY_Backquote}, 63 | 64 | {Qt::Key_Back, vsg::KEY_BackSpace}, /* back space, back char */ 65 | {Qt::Key_Tab, vsg::KEY_Tab}, 66 | {Qt::Key_Backtab, vsg::KEY_Tab}, 67 | // KEY_Linefeed = 0xFF0A, /* Linefeed, LF */ 68 | {Qt::Key_Clear, vsg::KEY_Clear}, 69 | {Qt::Key_Return, vsg::KEY_Return}, /* Return, enter */ 70 | {Qt::Key_Pause, vsg::KEY_Pause}, /* Pause, hold */ 71 | {Qt::Key_ScrollLock, vsg::KEY_Scroll_Lock}, 72 | // KEY_Sys_Req = 0xFF15, 73 | {Qt::Key_Escape, vsg::KEY_Escape}, 74 | {Qt::Key_Delete, vsg::KEY_Delete}, /* Delete, rubout */ 75 | 76 | /* Misc Functions */ 77 | 78 | {Qt::Key_Select, vsg::KEY_Select}, /* Select, mark */ 79 | {Qt::Key_Print, vsg::KEY_Print}, 80 | {Qt::Key_Execute, vsg::KEY_Execute}, /* Execute, run, do */ 81 | {Qt::Key_Insert, vsg::KEY_Insert}, /* Insert, insert here */ 82 | //{ KEY_Undo = 0xFF65, /* Undo, oops */ 83 | //KEY_Redo = 0xFF66, /* redo, again */ 84 | {Qt::Key_Menu, vsg::KEY_Menu}, /* On Windows, this is VK_APPS, the context-menu key */ 85 | // KEY_Find = 0xFF68, /* Find, search */ 86 | {Qt::Key_Cancel, vsg::KEY_Cancel}, /* Cancel, stop, abort, exit */ 87 | {Qt::Key_Help, vsg::KEY_Help}, /* Help */ 88 | //{ KEY_Break = 0xFF6B, 89 | //KEY_Mode_switch = 0xFF7E, /* Character set switch */ 90 | //KEY_Script_switch = 0xFF7E, /* Alias for mode_switch */ 91 | {Qt::Key_NumLock, vsg::KEY_Num_Lock}, 92 | 93 | #if 0 94 | {Qt::Key_0, vsg::KEY_KP_0}, 95 | {Qt::Key_1, vsg::KEY_KP_1}, 96 | {Qt::Key_2, vsg::KEY_KP_2}, 97 | {Qt::Key_3, vsg::KEY_KP_3}, 98 | {Qt::Key_4, vsg::KEY_KP_4}, 99 | {Qt::Key_5, vsg::KEY_KP_5}, 100 | {Qt::Key_6, vsg::KEY_KP_6}, 101 | {Qt::Key_7, vsg::KEY_KP_7}, 102 | {Qt::Key_8, vsg::KEY_KP_8}, 103 | {Qt::Key_9, vsg::KEY_KP_9}, 104 | 105 | #endif 106 | /* 107 | * Auxiliary Functions; note the duplicate definitions for left and right 108 | * function keys; Sun keyboards and a few other manufacturers have such 109 | * function key groups on the left and/or right sides of the keyboard. 110 | * We've not found a keyboard with more than 35 function keys total. 111 | */ 112 | 113 | {Qt::Key_F1, vsg::KEY_F1}, 114 | {Qt::Key_F2, vsg::KEY_F2}, 115 | {Qt::Key_F3, vsg::KEY_F3}, 116 | {Qt::Key_F4, vsg::KEY_F4}, 117 | {Qt::Key_F5, vsg::KEY_F5}, 118 | {Qt::Key_F6, vsg::KEY_F6}, 119 | {Qt::Key_F7, vsg::KEY_F7}, 120 | {Qt::Key_F8, vsg::KEY_F8}, 121 | {Qt::Key_F9, vsg::KEY_F9}, 122 | {Qt::Key_F10, vsg::KEY_F10}, 123 | {Qt::Key_F11, vsg::KEY_F11}, 124 | {Qt::Key_F12, vsg::KEY_F12}, 125 | {Qt::Key_F13, vsg::KEY_F13}, 126 | {Qt::Key_F14, vsg::KEY_F14}, 127 | {Qt::Key_F15, vsg::KEY_F15}, 128 | {Qt::Key_F16, vsg::KEY_F16}, 129 | {Qt::Key_F17, vsg::KEY_F17}, 130 | {Qt::Key_F18, vsg::KEY_F18}, 131 | {Qt::Key_F19, vsg::KEY_F19}, 132 | {Qt::Key_F20, vsg::KEY_F20}, 133 | {Qt::Key_F21, vsg::KEY_F21}, 134 | {Qt::Key_F22, vsg::KEY_F22}, 135 | {Qt::Key_F23, vsg::KEY_F23}, 136 | {Qt::Key_F24, vsg::KEY_F24}, 137 | 138 | //KEY_F25 = 0xFFD6, 139 | //KEY_F26 = 0xFFD7, 140 | //KEY_F27 = 0xFFD8, 141 | //KEY_F28 = 0xFFD9, 142 | //KEY_F29 = 0xFFDA, 143 | //KEY_F30 = 0xFFDB, 144 | //KEY_F31 = 0xFFDC, 145 | //KEY_F32 = 0xFFDD, 146 | //KEY_F33 = 0xFFDE, 147 | //KEY_F34 = 0xFFDF, 148 | //KEY_F35 = 0xFFE0, 149 | 150 | /* Modifiers */ 151 | 152 | {Qt::Key_Shift, vsg::KEY_Shift_L}, /* Left shift */ 153 | // {VK_RSHIFT, KEY_Shift_R}, /* Right shift */ 154 | // {VK_LCONTROL, KEY_Control_L}, /* Left control */ 155 | {Qt::Key_Control, vsg::KEY_Control_R}, /* Right control */ 156 | {Qt::Key_CapsLock, vsg::KEY_Caps_Lock} /* Caps lock */ 157 | //KEY_Shift_Lock = 0xFFE6, /* Shift lock */ 158 | 159 | //KEY_Meta_L = 0xFFE7, /* Left meta */ 160 | //KEY_Meta_R = 0xFFE8, /* Right meta */ 161 | // {VK_LMENU, KEY_Alt_L}, /* Left alt */ 162 | // {VK_RMENU, KEY_Alt_R}, /* Right alt */ 163 | // {VK_LWIN, KEY_Super_L}, /* Left super */ 164 | // {VK_RWIN, KEY_Super_R} /* Right super */ 165 | //KEY_Hyper_L = 0xFFED, /* Left hyper */ 166 | //KEY_Hyper_R = 0xFFEE /* Right hyper */ 167 | } 168 | { 169 | } 170 | 171 | bool KeyboardMap::getKeySymbol(const QKeyEvent* e, vsg::KeySymbol& keySymbol, vsg::KeySymbol& modifiedKeySymbol, vsg::KeyModifier& keyModifier) 172 | { 173 | uint16_t modifierMask = 0; 174 | if (e->modifiers() & Qt::ShiftModifier) 175 | { 176 | modifierMask |= vsg::KeyModifier::MODKEY_Shift; 177 | } 178 | if (e->modifiers() & Qt::ControlModifier) 179 | { 180 | modifierMask |= vsg::KeyModifier::MODKEY_Control; 181 | } 182 | if (e->modifiers() & Qt::AltModifier) 183 | { 184 | modifierMask |= vsg::KeyModifier::MODKEY_Alt; 185 | } 186 | if (e->modifiers() & Qt::MetaModifier) 187 | { 188 | modifierMask |= vsg::KeyModifier::MODKEY_Meta; 189 | } 190 | 191 | keyModifier = (vsg::KeyModifier)modifierMask; 192 | 193 | auto itr = _keycodeMap.find((uint32_t)e->key()); 194 | if (itr != _keycodeMap.end()) 195 | { 196 | keySymbol = itr->second; 197 | modifiedKeySymbol = keySymbol; 198 | 199 | // std::cout<<"KeyboardMap::getKeySymbol() found in map, keySymbol = "<key()); 204 | if (keySymbol >= 'A' && keySymbol <= 'Z') keySymbol = vsg::KeySymbol(int(keySymbol) + int('a' - 'A')); 205 | 206 | modifiedKeySymbol = vsg::KeySymbol(*(e->text().toLatin1().data())); 207 | 208 | // std::cout<<"KeyboardMap::getKeySymbol() NOT found in map, keySymbol = "< 2 | 3 | Copyright(c) 2021 Robert Osfield, Andre Normann 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #if defined(WIN32) 14 | # define VK_USE_PLATFORM_WIN32_KHR 15 | #elif defined(__APPLE__) 16 | # define VK_USE_PLATFORM_MACOS_MVK 17 | #else 18 | # define VK_USE_PLATFORM_XCB_KHR 19 | // #define VK_USE_PLATFORM_XLIB_KHR 20 | #endif 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | #include 32 | 33 | #include 34 | 35 | using namespace vsgQt; 36 | 37 | Window::Window(QScreen* targetScreen) : 38 | QWindow(targetScreen), 39 | traits(vsg::WindowTraits::create()), 40 | keyboardMap(KeyboardMap::create()) 41 | { 42 | traits->x = x(); 43 | traits->y = y(); 44 | traits->width = width(); 45 | traits->height = height(); 46 | } 47 | 48 | Window::Window(QWindow* parent) : 49 | QWindow(parent), 50 | traits(vsg::WindowTraits::create()), 51 | keyboardMap(KeyboardMap::create()) 52 | { 53 | traits->x = x(); 54 | traits->y = y(); 55 | traits->width = width(); 56 | traits->height = height(); 57 | } 58 | 59 | Window::Window(vsg::ref_ptr in_traits, QScreen* targetScreen) : 60 | QWindow(targetScreen), 61 | keyboardMap(KeyboardMap::create()) 62 | { 63 | if (in_traits) 64 | { 65 | traits = vsg::WindowTraits::create(*in_traits); 66 | setGeometry(traits->x, traits->y, traits->width, traits->height); 67 | } 68 | else 69 | { 70 | traits = vsg::WindowTraits::create(); 71 | traits->x = x(); 72 | traits->y = y(); 73 | traits->width = width(); 74 | traits->height = height(); 75 | } 76 | } 77 | 78 | Window::Window(vsg::ref_ptr in_traits, QWindow* parent) : 79 | QWindow(parent), 80 | keyboardMap(KeyboardMap::create()) 81 | { 82 | if (in_traits) 83 | { 84 | traits = vsg::WindowTraits::create(*in_traits); 85 | setGeometry(traits->x, traits->y, traits->width, traits->height); 86 | } 87 | else 88 | { 89 | traits = vsg::WindowTraits::create(); 90 | traits->x = x(); 91 | traits->y = y(); 92 | traits->width = width(); 93 | traits->height = height(); 94 | } 95 | } 96 | 97 | Window::Window(vsg::ref_ptr in_viewer, vsg::ref_ptr in_traits, QScreen* targetScreen) : 98 | QWindow(targetScreen), 99 | viewer(in_viewer), 100 | keyboardMap(KeyboardMap::create()) 101 | { 102 | if (in_traits) 103 | { 104 | traits = vsg::WindowTraits::create(*in_traits); 105 | setGeometry(traits->x, traits->y, traits->width, traits->height); 106 | } 107 | else 108 | { 109 | traits = vsg::WindowTraits::create(); 110 | traits->x = x(); 111 | traits->y = y(); 112 | traits->width = width(); 113 | traits->height = height(); 114 | } 115 | } 116 | 117 | Window::Window(vsg::ref_ptr in_viewer, vsg::ref_ptr in_traits, QWindow* parent) : 118 | QWindow(parent), 119 | viewer(in_viewer), 120 | keyboardMap(KeyboardMap::create()) 121 | { 122 | if (in_traits) 123 | { 124 | traits = vsg::WindowTraits::create(*in_traits); 125 | setGeometry(traits->x, traits->y, traits->width, traits->height); 126 | } 127 | else 128 | { 129 | traits = vsg::WindowTraits::create(); 130 | traits->x = x(); 131 | traits->y = y(); 132 | traits->width = width(); 133 | traits->height = height(); 134 | } 135 | } 136 | 137 | Window::~Window() 138 | { 139 | cleanup(); 140 | } 141 | 142 | void Window::initializeWindow() 143 | { 144 | if (windowAdapter) return; 145 | 146 | if (!traits) traits = vsg::WindowTraits::create(); 147 | 148 | #if defined(VK_USE_PLATFORM_WIN32_KHR) 149 | traits->nativeWindow = reinterpret_cast(winId()); 150 | #elif defined(VK_USE_PLATFORM_XLIB_KHR) 151 | traits->nativeWindow = static_cast<::Window>(winId()); 152 | #elif defined(VK_USE_PLATFORM_XCB_KHR) 153 | traits->nativeWindow = static_cast(winId()); 154 | #elif defined(VK_USE_PLATFORM_MACOS_MVK) 155 | traits->nativeWindow = winId(); 156 | #endif 157 | 158 | traits->x = convert_coord(x()); 159 | traits->y = convert_coord(y()); 160 | traits->width = convert_coord(width()); 161 | traits->height = convert_coord(height()); 162 | 163 | windowAdapter = vsg::Window::create(traits); 164 | _initialized = true; 165 | } 166 | 167 | void Window::cleanup() 168 | { 169 | // remove links to all the VSG related classes. 170 | if (windowAdapter) 171 | { 172 | // wait for all rendering to be completed before we start cleaning up resources. 173 | if (viewer) 174 | { 175 | viewer->deviceWaitIdle(); 176 | viewer->removeWindow(windowAdapter); 177 | } 178 | 179 | windowAdapter->releaseWindow(); 180 | } 181 | 182 | windowAdapter = {}; 183 | viewer = {}; 184 | } 185 | 186 | bool Window::event(QEvent* e) 187 | { 188 | switch (e->type()) 189 | { 190 | case QEvent::PlatformSurface: { 191 | auto surfaceEvent = dynamic_cast(e); 192 | if (surfaceEvent->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) 193 | { 194 | vsg::clock::time_point event_time = vsg::clock::now(); 195 | windowAdapter->bufferedEvents.push_back(vsg::CloseWindowEvent::create(windowAdapter, event_time)); 196 | 197 | cleanup(); 198 | } 199 | break; 200 | } 201 | 202 | default: 203 | break; 204 | } 205 | 206 | return QWindow::event(e); 207 | } 208 | 209 | void Window::exposeEvent(QExposeEvent* /*e*/) 210 | { 211 | if (!_initialized && isExposed()) 212 | { 213 | initializeWindow(); 214 | } 215 | 216 | if (viewer) viewer->request(); 217 | } 218 | 219 | void Window::hideEvent(QHideEvent* /*e*/) 220 | { 221 | } 222 | 223 | void Window::resizeEvent(QResizeEvent* /*e*/) 224 | { 225 | if (!windowAdapter) return; 226 | 227 | vsg::clock::time_point event_time = vsg::clock::now(); 228 | windowAdapter->bufferedEvents.push_back(vsg::ConfigureWindowEvent::create(windowAdapter, event_time, convert_coord(x()), convert_coord(y()), convert_coord(width()), convert_coord(height()))); 229 | 230 | windowAdapter->resize(); 231 | 232 | if (viewer) viewer->request(); 233 | } 234 | 235 | void Window::keyPressEvent(QKeyEvent* e) 236 | { 237 | if (!windowAdapter) return; 238 | 239 | vsg::KeySymbol keySymbol, modifiedKeySymbol; 240 | vsg::KeyModifier keyModifier; 241 | 242 | if (keyboardMap->getKeySymbol(e, keySymbol, modifiedKeySymbol, keyModifier)) 243 | { 244 | vsg::clock::time_point event_time = vsg::clock::now(); 245 | windowAdapter->bufferedEvents.push_back(vsg::KeyPressEvent::create(windowAdapter, event_time, keySymbol, modifiedKeySymbol, keyModifier)); 246 | } 247 | 248 | if (viewer) viewer->request(); 249 | } 250 | 251 | void Window::keyReleaseEvent(QKeyEvent* e) 252 | { 253 | if (!windowAdapter) return; 254 | 255 | vsg::KeySymbol keySymbol, modifiedKeySymbol; 256 | vsg::KeyModifier keyModifier; 257 | 258 | if (keyboardMap->getKeySymbol(e, keySymbol, modifiedKeySymbol, keyModifier)) 259 | { 260 | vsg::clock::time_point event_time = vsg::clock::now(); 261 | windowAdapter->bufferedEvents.push_back(vsg::KeyReleaseEvent::create(windowAdapter, event_time, keySymbol, modifiedKeySymbol, keyModifier)); 262 | } 263 | 264 | if (viewer) viewer->request(); 265 | } 266 | 267 | void Window::mouseMoveEvent(QMouseEvent* e) 268 | { 269 | if (!windowAdapter) return; 270 | 271 | vsg::clock::time_point event_time = vsg::clock::now(); 272 | 273 | auto [mask, button] = convertMouseButtons(e); 274 | auto [x, y] = convertMousePosition(e); 275 | 276 | windowAdapter->bufferedEvents.push_back(vsg::MoveEvent::create(windowAdapter, event_time, x, y, mask)); 277 | 278 | if (viewer) viewer->request(); 279 | } 280 | 281 | void Window::mousePressEvent(QMouseEvent* e) 282 | { 283 | if (!windowAdapter) return; 284 | 285 | vsg::clock::time_point event_time = vsg::clock::now(); 286 | 287 | auto [mask, button] = convertMouseButtons(e); 288 | auto [x, y] = convertMousePosition(e); 289 | 290 | windowAdapter->bufferedEvents.push_back(vsg::ButtonPressEvent::create(windowAdapter, event_time, x, y, mask, button)); 291 | 292 | if (viewer) viewer->request(); 293 | } 294 | 295 | void Window::mouseReleaseEvent(QMouseEvent* e) 296 | { 297 | if (!windowAdapter) return; 298 | 299 | vsg::clock::time_point event_time = vsg::clock::now(); 300 | 301 | auto [mask, button] = convertMouseButtons(e); 302 | auto [x, y] = convertMousePosition(e); 303 | 304 | windowAdapter->bufferedEvents.push_back(vsg::ButtonReleaseEvent::create(windowAdapter, event_time, x, y, mask, button)); 305 | 306 | if (viewer) viewer->request(); 307 | } 308 | 309 | void Window::wheelEvent(QWheelEvent* e) 310 | { 311 | if (!windowAdapter) return; 312 | 313 | vsg::clock::time_point event_time = vsg::clock::now(); 314 | windowAdapter->bufferedEvents.push_back(vsg::ScrollWheelEvent::create(windowAdapter, event_time, e->angleDelta().y() < 0 ? vsg::vec3(0.0f, -1.0f, 0.0f) : vsg::vec3(0.0f, 1.0f, 0.0f))); 315 | 316 | if (viewer) viewer->request(); 317 | } 318 | 319 | std::pair Window::convertMouseButtons(QMouseEvent* e) const 320 | { 321 | uint16_t mask{0}; 322 | uint32_t button = 0; 323 | 324 | if (e->buttons() & Qt::LeftButton) mask = mask | vsg::BUTTON_MASK_1; 325 | if (e->buttons() & Qt::MiddleButton) mask = mask | vsg::BUTTON_MASK_2; 326 | if (e->buttons() & Qt::RightButton) mask = mask | vsg::BUTTON_MASK_3; 327 | 328 | switch (e->button()) 329 | { 330 | case Qt::LeftButton: button = 1; break; 331 | case Qt::MiddleButton: button = 2; break; 332 | case Qt::RightButton: button = 3; break; 333 | default: break; 334 | } 335 | 336 | return {static_cast(mask), button}; 337 | } 338 | 339 | std::pair Window::convertMousePosition(QMouseEvent* e) const 340 | { 341 | #if QT_VERSION_MAJOR == 6 342 | return {convert_coord(e->position().x()), convert_coord(e->position().y())}; 343 | #else 344 | return {convert_coord(e->x()), convert_coord(e->y())}; 345 | #endif 346 | } 347 | --------------------------------------------------------------------------------