This commit is contained in:
2020-06-18 18:25:03 -06:00
commit e01c09fbcc
17 changed files with 2689 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.cmake
build
CMakeLists.txt.user

25
CMakeLists.txt Normal file
View File

@@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.5)
project(MyApplication LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/modules/" ${CMAKE_MODULE_PATH})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(ANDROID)
set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
if (ANDROID_ABI STREQUAL "armeabi-v7a")
set(ANDROID_EXTRA_LIBS
${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so
${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so)
endif()
endif()
add_subdirectory(src)

569
modules/FindCorrade.cmake Normal file
View File

@@ -0,0 +1,569 @@
#.rst:
# Find Corrade
# ------------
#
# Finds the Corrade library. Basic usage::
#
# find_package(Corrade REQUIRED)
#
# This module tries to find the base Corrade library and then defines the
# following:
#
# Corrade_FOUND - Whether the base library was found
# CORRADE_LIB_SUFFIX_MODULE - Path to CorradeLibSuffix.cmake module
# CORRADE_INCLUDE_INSTALL_PREFIX - Prefix where to put platform-independent
# include and other files, defaults to ``.``. If a relative path is used,
# it's relative to :variable:`CMAKE_INSTALL_PREFIX`.
#
# This command will try to find only the base library, not the optional
# components, which are:
#
# Containers - Containers library
# PluginManager - PluginManager library
# TestSuite - TestSuite library
# Utility - Utility library
# rc - corrade-rc executable
#
# Example usage with specifying additional components is::
#
# find_package(Corrade REQUIRED Utility TestSuite)
#
# For each component is then defined:
#
# Corrade_*_FOUND - Whether the component was found
# Corrade::* - Component imported target
#
# The package is found if either debug or release version of each library is
# found. If both debug and release libraries are found, proper version is
# chosen based on actual build configuration of the project (i.e. Debug build
# is linked to debug libraries, Release build to release libraries).
#
# Corrade conditionally defines ``CORRADE_IS_DEBUG_BUILD`` preprocessor
# variable in case build configuration is ``Debug`` (not Corrade itself, but
# build configuration of the project using it). Useful e.g. for selecting
# proper plugin directory.
#
# Corrade defines the following custom target properties:
#
# CORRADE_CXX_STANDARD - C++ standard to require when compiling given
# target. Does nothing if :variable:`CMAKE_CXX_FLAGS` already contains
# particular standard setting flag or if given target contains
# :prop_tgt:`CMAKE_CXX_STANDARD` property. Allowed value is 11, 14 or 17.
# INTERFACE_CORRADE_CXX_STANDARD - C++ standard to require when using given
# target. Does nothing if :variable:`CMAKE_CXX_FLAGS` already contains
# particular standard setting flag or if given target contains
# :prop_tgt:`CMAKE_CXX_STANDARD` property. Allowed value is 11, 14 or 17.
# CORRADE_USE_PEDANTIC_FLAGS - Enable additional compiler/linker flags.
# Boolean.
#
# These properties are inherited from directory properties, meaning that if you
# set them on directories, they get implicitly set on all targets in given
# directory (with a possibility to do target-specific overrides). All Corrade
# libraries have the :prop_tgt:`INTERFACE_CORRADE_CXX_STANDARD` property set to
# 11, meaning that you will always have at least C++11 enabled once you link to
# any Corrade library.
#
# Features of found Corrade library are exposed in these variables:
#
# CORRADE_MSVC2019_COMPATIBILITY - Defined if compiled with compatibility
# mode for MSVC 2019
# CORRADE_MSVC2017_COMPATIBILITY - Defined if compiled with compatibility
# mode for MSVC 2017
# CORRADE_MSVC2015_COMPATIBILITY - Defined if compiled with compatibility
# mode for MSVC 2015
# CORRADE_BUILD_DEPRECATED - Defined if compiled with deprecated APIs
# included
# CORRADE_BUILD_STATIC - Defined if compiled as static libraries.
# Default are shared libraries.
# CORRADE_BUILD_MULTITHREADED - Defined if compiled in a way that makes it
# possible to safely use certain Corrade features simultaenously in multiple
# threads
# CORRADE_TARGET_UNIX - Defined if compiled for some Unix flavor
# (Linux, BSD, macOS)
# CORRADE_TARGET_APPLE - Defined if compiled for Apple platforms
# CORRADE_TARGET_IOS - Defined if compiled for iOS (device or
# simulator)
# CORRADE_TARGET_IOS_SIMULATOR - Defined if compiled for iOS Simulator
# CORRADE_TARGET_WINDOWS - Defined if compiled for Windows
# CORRADE_TARGET_WINDOWS_RT - Defined if compiled for Windows RT
# CORRADE_TARGET_EMSCRIPTEN - Defined if compiled for Emscripten
# CORRADE_TARGET_ANDROID - Defined if compiled for Android
# CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT - Defined if PluginManager
# doesn't support dynamic plugin loading due to platform limitations
# CORRADE_TESTSUITE_TARGET_XCTEST - Defined if TestSuite is targetting Xcode
# XCTest
# CORRADE_UTILITY_USE_ANSI_COLORS - Defined if ANSI escape sequences are used
# for colored output with Utility::Debug on Windows
#
# Additionally these variables are defined for internal usage:
#
# CORRADE_INCLUDE_DIR - Root include dir
# CORRADE_*_LIBRARY_DEBUG - Debug version of given library, if found
# CORRADE_*_LIBRARY_RELEASE - Release version of given library, if found
# CORRADE_*_EXECUTABLE - Location of given executable, if found
# CORRADE_USE_MODULE - Path to UseCorrade.cmake module (included
# automatically)
# CORRADE_TESTSUITE_XCTEST_RUNNER - Path to XCTestRunner.mm.in file
# CORRADE_TESTSUITE_ADB_RUNNER - Path to AdbRunner.sh file
# CORRADE_PEDANTIC_COMPILER_OPTIONS - List of pedantic compiler options used
# for targets with :prop_tgt:`CORRADE_USE_PEDANTIC_FLAGS` enabled
# CORRADE_PEDANTIC_COMPILER_DEFINITIONS - List of pedantic compiler
# definitions used for targets with :prop_tgt:`CORRADE_USE_PEDANTIC_FLAGS`
# enabled
#
# Workflows without :prop_tgt:`IMPORTED` targets are deprecated and the
# following variables are included just for backwards compatibility and only if
# :variable:`CORRADE_BUILD_DEPRECATED` is enabled:
#
# CORRADE_CXX_FLAGS - Pedantic compile flags. Use
# :prop_tgt:`CORRADE_USE_PEDANTIC_FLAGS` property or
# :variable:`CORRADE_PEDANTIC_COMPILER_DEFINITIONS` /
# :variable:`CORRADE_PEDANTIC_COMPILER_OPTIONS` list variables instead.
#
# Corrade provides these macros and functions:
#
# .. command:: corrade_add_test
#
# Add unit test using Corrade's TestSuite::
#
# corrade_add_test(<test name>
# <sources>...
# [LIBRARIES <libraries>...]
# [FILES <files>...]
# [ARGUMENTS <arguments>...])
#
# Test name is also executable name. You can use ``LIBRARIES`` to specify
# libraries to link with instead of using :command:`target_link_libraries()`.
# The ``Corrade::TestSuite`` target is linked automatically to each test. Note
# that the :command:`enable_testing()` function must be called explicitly.
# Arguments passed after ``ARGUMENTS`` will be appended to the test
# command line. ``ARGUMENTS`` are supported everywhere except when
# ``CORRADE_TESTSUITE_TARGET_XCTEST`` is enabled.
#
# You can list files needed by the test in the ``FILES`` section. If given
# filename is relative, it is treated relatively to `CMAKE_CURRENT_SOURCE_DIR`.
# The files are added to the :prop_test:`REQUIRED_FILES` target property. On
# Emscripten they are bundled to the executable and available in the virtual
# filesystem root. On Android they are copied along the executable to the
# target. In case of Emscripten and Android, if the file is absolute or
# contains ``..``, only the leaf name is used. Alternatively you can have a
# filename formatted as ``<input>@<output>``, in which case the ``<input>`` is
# treated as local filesystem location and ``<output>`` as remote/virtual
# filesystem location. The remote location can't be absolute or contain ``..``
# / ``@`` characters.
#
# Unless :variable:`CORRADE_TESTSUITE_TARGET_XCTEST` is set, test cases on iOS
# targets are created as bundles with bundle identifier set to CMake project
# name by default. Use the cache variable :variable:`CORRADE_TESTSUITE_BUNDLE_IDENTIFIER_PREFIX`
# to change it to something else.
#
# .. command:: corrade_add_resource
#
# Compile data resources into application binary::
#
# corrade_add_resource(<name> <resources.conf>)
#
# Depends on ``Corrade::rc``, which is part of Corrade utilities. This command
# generates resource data using given configuration file in current build
# directory. Argument name is name under which the resources can be explicitly
# loaded. Variable ``<name>`` contains compiled resource filename, which is
# then used for compiling library / executable. On CMake >= 3.1 the
# `resources.conf` file can contain UTF-8-encoded filenames. Example usage::
#
# corrade_add_resource(app_resources resources.conf)
# add_executable(app source1 source2 ... ${app_resources})
#
# .. command:: corrade_add_plugin
#
# Add dynamic plugin::
#
# corrade_add_plugin(<plugin name>
# "<debug binary install dir>;<debug library install dir>"
# "<release binary install dir>;<release library install dir>"
# <metadata file>
# <sources>...)
#
# The macro adds preprocessor directive ``CORRADE_DYNAMIC_PLUGIN``. Additional
# libraries can be linked in via :command:`target_link_libraries(plugin_name ...) <target_link_libraries>`.
# On DLL platforms, the plugin DLLs and metadata files are put into
# ``<debug binary install dir>``/``<release binary install dir>`` and the
# ``*.lib`` files into ``<debug library install dir>``/``<release library install dir>``.
# On non-DLL platforms everything is put into ``<debug library install dir>``/
# ``<release library install dir>``.
#
# corrade_add_plugin(<plugin name>
# <debug install dir>
# <release install dir>
# <metadata file>
# <sources>...)
#
# Unline the above version this puts everything into ``<debug install dir>`` on
# both DLL and non-DLL platforms. If ``<debug install dir>`` is set to
# :variable:`CMAKE_CURRENT_BINARY_DIR` (e.g. for testing purposes), the files
# are copied directly, without the need to perform install step. Note that the
# files are actually put into configuration-based subdirectory, i.e.
# ``${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}``. See documentation of
# :variable:`CMAKE_CFG_INTDIR` variable for more information.
#
# .. command:: corrade_add_static_plugin
#
# Add static plugin::
#
# corrade_add_static_plugin(<plugin name>
# "<binary install dir>;<library install dir>"
# <metadata file>
# <sources>...)
#
# The macro adds preprocessor directive ``CORRADE_STATIC_PLUGIN``. Additional
# libraries can be linked in via :command:`target_link_libraries(plugin_name ...) <target_link_libraries>`.
# The ``<binary install dir>`` is ignored and included just for compatibility
# with the :command:`corrade_add_plugin` command, everything is installed into
# ``<library install dir>``. Note that plugins built in debug configuration
# (e.g. with :variable:`CMAKE_BUILD_TYPE` set to ``Debug``) have ``"-d"``
# suffix to make it possible to have both debug and release plugins installed
# alongside each other.
#
# corrade_add_static_plugin(<plugin name>
# <install dir>
# <metadata file>
# <sources>...)
#
# Equivalent to the above with ``<library install dir>`` set to ``<install dir>``.
# If ``<install dir>`` is set to :variable:`CMAKE_CURRENT_BINARY_DIR` (e.g. for
# testing purposes), no installation rules are added.
#
# .. command:: corrade_find_dlls_for_libs
#
# Find corresponding DLLs for library files::
#
# corrade_find_dlls_for_libs(<output variable> <libs>...)
#
# Available only on Windows, for all ``*.lib`` files tries to find
# corresponding DLL file. Useful for bundling dependencies for e.g. WinRT
# packages.
#
#
# This file is part of Corrade.
#
# Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016,
# 2017, 2018, 2019 Vladimír Vondruš <mosra@centrum.cz>
#
# 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:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# 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.
#
# Root include dir
find_path(CORRADE_INCLUDE_DIR
NAMES Corrade/Corrade.h)
mark_as_advanced(CORRADE_INCLUDE_DIR)
# Configuration file
find_file(_CORRADE_CONFIGURE_FILE configure.h
HINTS ${CORRADE_INCLUDE_DIR}/Corrade/)
mark_as_advanced(_CORRADE_CONFIGURE_FILE)
# We need to open configure.h file from CORRADE_INCLUDE_DIR before we check for
# the components. Bail out with proper error message if it wasn't found. The
# complete check with all components is further below.
if(NOT CORRADE_INCLUDE_DIR)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Corrade
REQUIRED_VARS CORRADE_INCLUDE_DIR _CORRADE_CONFIGURE_FILE)
endif()
# Read flags from configuration
file(READ ${_CORRADE_CONFIGURE_FILE} _corradeConfigure)
set(_corradeFlags
# WARNING: CAREFUL HERE, the string(FIND) succeeds even if a subset is
# found -- so e.g. looking for TARGET_GL will match TARGET_GLES2 as well.
# So far that's not a problem, but might become an issue for new flags.
MSVC2015_COMPATIBILITY
MSVC2017_COMPATIBILITY
MSVC2019_COMPATIBILITY
BUILD_DEPRECATED
BUILD_STATIC
BUILD_MULTITHREADED
TARGET_UNIX
TARGET_APPLE
TARGET_IOS
TARGET_IOS_SIMULATOR
TARGET_WINDOWS
TARGET_WINDOWS_RT
TARGET_EMSCRIPTEN
TARGET_ANDROID
PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
TESTSUITE_TARGET_XCTEST
UTILITY_USE_ANSI_COLORS)
foreach(_corradeFlag ${_corradeFlags})
string(FIND "${_corradeConfigure}" "#define CORRADE_${_corradeFlag}" _corrade_${_corradeFlag})
if(NOT _corrade_${_corradeFlag} EQUAL -1)
set(CORRADE_${_corradeFlag} 1)
endif()
endforeach()
# CMake module dir
find_path(_CORRADE_MODULE_DIR
NAMES UseCorrade.cmake CorradeLibSuffix.cmake
PATH_SUFFIXES share/cmake/Corrade)
mark_as_advanced(_CORRADE_MODULE_DIR)
set(CORRADE_USE_MODULE ${_CORRADE_MODULE_DIR}/UseCorrade.cmake)
set(CORRADE_LIB_SUFFIX_MODULE ${_CORRADE_MODULE_DIR}/CorradeLibSuffix.cmake)
# Ensure that all inter-component dependencies are specified as well
foreach(_component ${Corrade_FIND_COMPONENTS})
string(TOUPPER ${_component} _COMPONENT)
if(_component STREQUAL Containers)
set(_CORRADE_${_COMPONENT}_DEPENDENCIES Utility)
elseif(_component STREQUAL Interconnect)
set(_CORRADE_${_COMPONENT}_DEPENDENCIES Utility)
elseif(_component STREQUAL PluginManager)
set(_CORRADE_${_COMPONENT}_DEPENDENCIES Containers Utility rc)
elseif(_component STREQUAL TestSuite)
set(_CORRADE_${_COMPONENT}_DEPENDENCIES Utility Main) # see below
elseif(_component STREQUAL Utility)
set(_CORRADE_${_COMPONENT}_DEPENDENCIES Containers rc)
endif()
# Mark the dependencies as required if the component is also required
if(Corrade_FIND_REQUIRED_${_component})
foreach(_dependency ${_CORRADE_${_COMPONENT}_DEPENDENCIES})
set(Corrade_FIND_REQUIRED_${_dependency} TRUE)
endforeach()
endif()
list(APPEND _CORRADE_ADDITIONAL_COMPONENTS ${_CORRADE_${_COMPONENT}_DEPENDENCIES})
# Main is linked only in corrade_add_test(), not to everything that depends
# on TestSuite, so remove it from the list again once we filled the above
# variables
if(_component STREQUAL TestSuite)
set(_CORRADE_${_COMPONENT}_DEPENDENCIES Utility)
endif()
endforeach()
# Join the lists, remove duplicate components
if(_CORRADE_ADDITIONAL_COMPONENTS)
list(INSERT Corrade_FIND_COMPONENTS 0 ${_CORRADE_ADDITIONAL_COMPONENTS})
endif()
if(Corrade_FIND_COMPONENTS)
list(REMOVE_DUPLICATES Corrade_FIND_COMPONENTS)
endif()
# Component distinction
set(_CORRADE_LIBRARY_COMPONENTS "^(Containers|Interconnect|Main|PluginManager|TestSuite|Utility)$")
if(CORRADE_TARGET_WINDOWS)
# CorradeMain is a real library only on windows, a dummy target elsewhere
set(_CORRADE_HEADER_ONLY_COMPONENTS "^(Containers)$")
else()
set(_CORRADE_HEADER_ONLY_COMPONENTS "^(Containers|Main)$")
endif()
set(_CORRADE_EXECUTABLE_COMPONENTS "^(rc)$")
# Find all components
foreach(_component ${Corrade_FIND_COMPONENTS})
string(TOUPPER ${_component} _COMPONENT)
# Create imported target in case the library is found. If the project is
# added as subproject to CMake, the target already exists and all the
# required setup is already done from the build tree.
if(TARGET Corrade::${_component})
set(Corrade_${_component}_FOUND TRUE)
else()
# Library (and not header-only) components
if(_component MATCHES ${_CORRADE_LIBRARY_COMPONENTS} AND NOT _component MATCHES ${_CORRADE_HEADER_ONLY_COMPONENTS})
add_library(Corrade::${_component} UNKNOWN IMPORTED)
# Try to find both debug and release version
find_library(CORRADE_${_COMPONENT}_LIBRARY_DEBUG Corrade${_component}-d)
find_library(CORRADE_${_COMPONENT}_LIBRARY_RELEASE Corrade${_component})
mark_as_advanced(CORRADE_${_COMPONENT}_LIBRARY_DEBUG
CORRADE_${_COMPONENT}_LIBRARY_RELEASE)
if(CORRADE_${_COMPONENT}_LIBRARY_RELEASE)
set_property(TARGET Corrade::${_component} APPEND PROPERTY
IMPORTED_CONFIGURATIONS RELEASE)
set_property(TARGET Corrade::${_component} PROPERTY
IMPORTED_LOCATION_RELEASE ${CORRADE_${_COMPONENT}_LIBRARY_RELEASE})
endif()
if(CORRADE_${_COMPONENT}_LIBRARY_DEBUG)
set_property(TARGET Corrade::${_component} APPEND PROPERTY
IMPORTED_CONFIGURATIONS DEBUG)
set_property(TARGET Corrade::${_component} PROPERTY
IMPORTED_LOCATION_DEBUG ${CORRADE_${_COMPONENT}_LIBRARY_DEBUG})
endif()
endif()
# Header-only library components
if(_component MATCHES ${_CORRADE_HEADER_ONLY_COMPONENTS})
add_library(Corrade::${_component} INTERFACE IMPORTED)
endif()
# Default include path names to look for for library / header-only
# components
if(_component MATCHES ${_CORRADE_LIBRARY_COMPONENTS})
set(_CORRADE_${_COMPONENT}_INCLUDE_PATH_SUFFIX Corrade/${_component})
set(_CORRADE_${_COMPONENT}_INCLUDE_PATH_NAMES ${_component}.h)
endif()
# Executable components
if(_component MATCHES ${_CORRADE_EXECUTABLE_COMPONENTS})
add_executable(Corrade::${_component} IMPORTED)
find_program(CORRADE_${_COMPONENT}_EXECUTABLE corrade-${_component})
mark_as_advanced(CORRADE_${_COMPONENT}_EXECUTABLE)
if(CORRADE_${_COMPONENT}_EXECUTABLE)
set_property(TARGET Corrade::${_component} PROPERTY
IMPORTED_LOCATION ${CORRADE_${_COMPONENT}_EXECUTABLE})
endif()
endif()
# No special setup for Containers library
# Interconnect library
if(_component STREQUAL Interconnect)
# Disable /OPT:ICF on MSVC, which merges functions with identical
# contents and thus breaks signal comparison
if(CORRADE_TARGET_WINDOWS AND CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
if(CMAKE_VERSION VERSION_LESS 3.13)
set_property(TARGET Corrade::${_component} PROPERTY
INTERFACE_LINK_LIBRARIES "-OPT:NOICF,REF")
else()
set_property(TARGET Corrade::${_component} PROPERTY
INTERFACE_LINK_OPTIONS "/OPT:NOICF,REF")
endif()
endif()
# Main library
elseif(_component STREQUAL Main)
set(_CORRADE_${_COMPONENT}_INCLUDE_PATH_SUFFIX Corrade)
set(_CORRADE_${_COMPONENT}_INCLUDE_PATH_NAMES Corrade.h)
if(CORRADE_TARGET_WINDOWS)
if(NOT MINGW)
# Abusing INTERFACE_LINK_LIBRARIES because
# INTERFACE_LINK_OPTIONS is only since 3.13. They treat
# things with `-` in front as linker flags and fortunately
# I can use `-ENTRY` instead of `/ENTRY`.
# https://gitlab.kitware.com/cmake/cmake/issues/16543
set_property(TARGET Corrade::${_component} APPEND PROPERTY
INTERFACE_LINK_LIBRARIES "-ENTRY:$<$<NOT:$<BOOL:$<TARGET_PROPERTY:WIN32_EXECUTABLE>>>:wmainCRTStartup>$<$<BOOL:$<TARGET_PROPERTY:WIN32_EXECUTABLE>>:wWinMainCRTStartup>")
else()
set_property(TARGET Corrade::${_component} APPEND PROPERTY
INTERFACE_LINK_LIBRARIES "-municode")
endif()
endif()
# PluginManager library
elseif(_component STREQUAL PluginManager)
# -ldl is handled by Utility now
# TestSuite library has some additional files
elseif(_component STREQUAL TestSuite)
# XCTest runner file
if(CORRADE_TESTSUITE_TARGET_XCTEST)
find_file(CORRADE_TESTSUITE_XCTEST_RUNNER XCTestRunner.mm.in
PATH_SUFFIXES share/corrade/TestSuite)
set(CORRADE_TESTSUITE_XCTEST_RUNNER_NEEDED CORRADE_TESTSUITE_XCTEST_RUNNER)
# ADB runner file
elseif(CORRADE_TARGET_ANDROID)
find_file(CORRADE_TESTSUITE_ADB_RUNNER AdbRunner.sh
PATH_SUFFIXES share/corrade/TestSuite)
set(CORRADE_TESTSUITE_ADB_RUNNER_NEEDED CORRADE_TESTSUITE_ADB_RUNNER)
# Emscripten runner file
elseif(CORRADE_TARGET_EMSCRIPTEN)
find_file(CORRADE_TESTSUITE_EMSCRIPTEN_RUNNER EmscriptenRunner.html.in
PATH_SUFFIXES share/corrade/TestSuite)
set(CORRADE_TESTSUITE_EMSCRIPTEN_RUNNER_NEEDED CORRADE_TESTSUITE_EMSCRIPTEN_RUNNER)
endif()
# Utility library (contains all setup that is used by others)
elseif(_component STREQUAL Utility)
# Top-level include directory
set_property(TARGET Corrade::${_component} APPEND PROPERTY
INTERFACE_INCLUDE_DIRECTORIES ${CORRADE_INCLUDE_DIR})
# Require (at least) C++11 for users
set_property(TARGET Corrade::${_component} PROPERTY
INTERFACE_CORRADE_CXX_STANDARD 11)
set_property(TARGET Corrade::${_component} APPEND PROPERTY
COMPATIBLE_INTERFACE_NUMBER_MAX CORRADE_CXX_STANDARD)
# Directory::libraryLocation() needs this
if(CORRADE_TARGET_UNIX)
set_property(TARGET Corrade::${_component} APPEND PROPERTY
INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS})
endif()
# AndroidLogStreamBuffer class needs to be linked to log library
if(CORRADE_TARGET_ANDROID)
set_property(TARGET Corrade::${_component} APPEND PROPERTY
INTERFACE_LINK_LIBRARIES "log")
endif()
endif()
# Find library includes
if(_component MATCHES ${_CORRADE_LIBRARY_COMPONENTS})
find_path(_CORRADE_${_COMPONENT}_INCLUDE_DIR
NAMES ${_CORRADE_${_COMPONENT}_INCLUDE_PATH_NAMES}
HINTS ${CORRADE_INCLUDE_DIR}/${_CORRADE_${_COMPONENT}_INCLUDE_PATH_SUFFIX})
mark_as_advanced(_CORRADE_${_COMPONENT}_INCLUDE_DIR)
endif()
# Add inter-library dependencies
if(_component MATCHES ${_CORRADE_LIBRARY_COMPONENTS} OR _component MATCHES ${_CORRADE_HEADER_ONLY_COMPONENTS})
foreach(_dependency ${_CORRADE_${_COMPONENT}_DEPENDENCIES})
if(_dependency MATCHES ${_CORRADE_LIBRARY_COMPONENTS} OR _dependency MATCHES ${_CORRADE_HEADER_ONLY_COMPONENTS})
set_property(TARGET Corrade::${_component} APPEND PROPERTY
INTERFACE_LINK_LIBRARIES Corrade::${_dependency})
endif()
endforeach()
endif()
# Decide if the component was found
if((_component MATCHES ${_CORRADE_LIBRARY_COMPONENTS} AND _CORRADE_${_COMPONENT}_INCLUDE_DIR AND (_component MATCHES ${_CORRADE_HEADER_ONLY_COMPONENTS} OR CORRADE_${_COMPONENT}_LIBRARY_RELEASE OR CORRADE_${_COMPONENT}_LIBRARY_DEBUG)) OR (_component MATCHES ${_CORRADE_EXECUTABLE_COMPONENTS} AND CORRADE_${_COMPONENT}_EXECUTABLE))
set(Corrade_${_component}_FOUND TRUE)
else()
set(Corrade_${_component}_FOUND FALSE)
endif()
endif()
endforeach()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Corrade REQUIRED_VARS
CORRADE_INCLUDE_DIR
_CORRADE_MODULE_DIR
_CORRADE_CONFIGURE_FILE
${CORRADE_TESTSUITE_XCTEST_RUNNER_NEEDED}
${CORRADE_TESTSUITE_ADB_RUNNER_NEEDED}
${CORRADE_TESTSUITE_EMSCRIPTEN_RUNNER_NEEDED}
HANDLE_COMPONENTS)
# Finalize the finding process
include(${CORRADE_USE_MODULE})
# Installation dirs
set(CORRADE_INCLUDE_INSTALL_PREFIX "."
CACHE STRING "Prefix where to put platform-independent include and other files")
set(CORRADE_INCLUDE_INSTALL_DIR ${CORRADE_INCLUDE_INSTALL_PREFIX}/include/Corrade)

1150
modules/FindMagnum.cmake Normal file

File diff suppressed because it is too large Load Diff

57
src/CMakeLists.txt Normal file
View File

@@ -0,0 +1,57 @@
find_package(Corrade REQUIRED Main)
find_package(Magnum REQUIRED
GL
MeshTools
Primitives
SceneGraph
Shaders)
find_package(Qt5 REQUIRED COMPONENTS
Core
Quick)
if(MAGNUM_TARGET_GLES AND NOT MAGNUM_TARGET_DESKTOP_GLES)
find_package(Magnum REQUIRED EglContext)
elseif(CORRADE_TARGET_WINDOWS)
find_package(Magnum REQUIRED WglContext)
elseif(CORRADE_TARGET_APPLE)
find_package(Magnum REQUIRED CglContext)
elseif(CORRADE_TARGET_UNIX)
find_package(Magnum REQUIRED GlxContext)
else()
message(FATAL_ERROR "Magnum context creation is not supported on this platform")
endif()
set_directory_properties(PROPERTIES CORRADE_USE_PEDANTIC_FLAGS ON)
if(ANDROID)
add_library(MyApplication SHARED
arc_ball.cpp
magnum_render.cpp
magnum_item.cpp
qml/main.qrc
main.cpp)
else()
add_executable(MyApplication
arc_ball.cpp
magnum_render.cpp
magnum_item.cpp
qml/main.qrc
main.cpp)
endif()
# set_property(SOURCE usr/include/Magnum/GL/Attribute.h PROPERTY SKIP_AUTOMOC ON)
target_compile_definitions(MyApplication
PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>)
target_link_libraries(MyApplication PRIVATE
Corrade::Main
Magnum::GL
Magnum::GLContext
Magnum::Magnum
Magnum::MeshTools
Magnum::Primitives
Magnum::SceneGraph
Magnum::Shaders
Qt5::Core
Qt5::Quick)

134
src/arc_ball.cpp Normal file
View File

@@ -0,0 +1,134 @@
#include <Magnum/Math/Matrix3.h>
#include "arc_ball.h"
/* Project a point in NDC onto the arcball sphere */
Quaternion ndcToArcBall(const Vector2 &p) {
const Float dist = Math::dot(p, p);
/* Point is on sphere */
if (dist <= 1.0f)
return {{p.x(), p.y(), Math::sqrt(1.0f - dist)}, 0.0f};
/* Point is outside sphere */
else {
const Vector2 proj = p.normalized();
return {{proj.x(), proj.y(), 0.0f}, 0.0f};
}
}
ArcBall::ArcBall(const Vector3 &eye, const Vector3 &viewCenter,
const Vector3 &upDir, Deg fov, const Vector2i &windowSize)
: m_fov{fov}, m_windowSize{windowSize} {
setViewParameters(eye, viewCenter, upDir);
}
void ArcBall::setViewParameters(const Vector3 &eye, const Vector3 &viewCenter,
const Vector3 &upDir) {
const Vector3 dir = viewCenter - eye;
Vector3 zAxis = dir.normalized();
Vector3 xAxis = (Math::cross(zAxis, upDir.normalized())).normalized();
Vector3 yAxis = (Math::cross(xAxis, zAxis)).normalized();
xAxis = (Math::cross(zAxis, yAxis)).normalized();
m_targetPosition = -viewCenter;
m_targetZooming = -dir.length();
m_targetQRotation =
Quaternion::fromMatrix(Matrix3x3{xAxis, yAxis, -zAxis}.transposed())
.normalized();
m_positionT0 = m_currentPosition = m_targetPosition;
m_zoomingT0 = m_currentZooming = m_targetZooming;
m_qRotationT0 = m_currentQRotation = m_targetQRotation;
updateInternalTransformations();
}
void ArcBall::reset() {
m_targetPosition = m_positionT0;
m_targetZooming = m_zoomingT0;
m_targetQRotation = m_qRotationT0;
}
void ArcBall::setLagging(const Float lagging) {
CORRADE_INTERNAL_ASSERT(lagging >= 0.0f && lagging < 1.0f);
m_lagging = lagging;
}
void ArcBall::initTransformation(const Vector2i &mousePos) {
m_prevMousePosNDC = screenCoordToNDC(mousePos);
}
void ArcBall::rotate(const Vector2i &mousePos) {
const Vector2 mousePosNDC = screenCoordToNDC(mousePos);
const Quaternion currentQRotation = ndcToArcBall(mousePosNDC);
const Quaternion prevQRotation = ndcToArcBall(m_prevMousePosNDC);
m_prevMousePosNDC = mousePosNDC;
m_targetQRotation =
(currentQRotation * prevQRotation * m_targetQRotation).normalized();
}
void ArcBall::translate(const Vector2i &mousePos) {
const Vector2 mousePosNDC = screenCoordToNDC(mousePos);
const Vector2 translationNDC = mousePosNDC - m_prevMousePosNDC;
m_prevMousePosNDC = mousePosNDC;
translateDelta(translationNDC);
}
void ArcBall::translateDelta(const Vector2 &translationNDC) {
/* Half size of the screen viewport at the view center and perpendicular
with the viewDir */
const Float hh = Math::abs(m_targetZooming) * Math::tan(m_fov * 0.5f);
const Float hw = hh * Vector2{m_windowSize}.aspectRatio();
m_targetPosition += m_inverseView.transformVector(
{translationNDC.x() * hw, translationNDC.y() * hh, 0.0f});
}
void ArcBall::zoom(const Float delta) { m_targetZooming += delta; }
bool ArcBall::updateTransformation() {
const Vector3 diffViewCenter = m_targetPosition - m_currentPosition;
const Quaternion diffRotation = m_targetQRotation - m_currentQRotation;
const Float diffZooming = m_targetZooming - m_currentZooming;
const Float dViewCenter = Math::dot(diffViewCenter, diffViewCenter);
const Float dRotation = Math::dot(diffRotation, diffRotation);
const Float dZooming = diffZooming * diffZooming;
/* Nothing change */
if (dViewCenter < 1.0e-10f && dRotation < 1.0e-10f && dZooming < 1.0e-10f) {
return false;
}
/* Nearly done: just jump directly to the target */
if (dViewCenter < 1.0e-6f && dRotation < 1.0e-6f && dZooming < 1.0e-6f) {
m_currentPosition = m_targetPosition;
m_currentQRotation = m_targetQRotation;
m_currentZooming = m_targetZooming;
/* Interpolate between the current transformation and the target
transformation */
} else {
const Float t = 1 - m_lagging;
m_currentPosition = Math::lerp(m_currentPosition, m_targetPosition, t);
m_currentZooming = Math::lerp(m_currentZooming, m_targetZooming, t);
m_currentQRotation =
Math::slerpShortestPath(m_currentQRotation, m_targetQRotation, t);
}
updateInternalTransformations();
return true;
}
void ArcBall::updateInternalTransformations() {
m_view = DualQuaternion::translation(Vector3::zAxis(m_currentZooming)) *
DualQuaternion{m_currentQRotation} *
DualQuaternion::translation(m_currentPosition);
m_inverseView = m_view.inverted();
}
Vector2 ArcBall::screenCoordToNDC(const Vector2i &mousePos) const {
return {mousePos.x() * 2.0f / m_windowSize.x() - 1.0f,
1.0f - 2.0f * mousePos.y() / m_windowSize.y()};
}

100
src/arc_ball.h Normal file
View File

@@ -0,0 +1,100 @@
#ifndef ARCBALL_H
#define ARCBALL_H
#include <Magnum/Magnum.h>
#include <Magnum/Math/DualQuaternion.h>
#include <Magnum/Math/Functions.h>
#include <Magnum/Math/Vector2.h>
#include <Magnum/Math/Vector3.h>
using namespace Magnum;
Quaternion ndcToArcBall(const Vector2 &p);
/* Implementation of Ken Shoemake's arcball camera with smooth navigation
feature: https://www.talisman.org/~erlkonig/misc/shoemake92-arcball.pdf */
class ArcBall {
public:
ArcBall(const Vector3 &cameraPosition, const Vector3 &viewCenter,
const Vector3 &upDir, Deg fov, const Vector2i &windowSize);
/* Set the camera view parameters: eye position, view center, up
direction */
void setViewParameters(const Vector3 &eye, const Vector3 &viewCenter,
const Vector3 &upDir);
/* Reset the camera to its initial position, view center, and up dir */
void reset();
/* Update screen size after the window has been resized */
void reshape(const Vector2i &windowSize) { m_windowSize = windowSize; }
/* Update any unfinished transformation due to lagging, return true if
the camera matrices have changed */
bool updateTransformation();
/* Get/set the amount of lagging such that the camera will (slowly)
smoothly navigate. Lagging must be in [0, 1) */
Float lagging() const { return m_lagging; }
void setLagging(Float lagging);
/* Initialize the first (screen) mouse position for camera
transformation. This should be called in mouse pressed event. */
void initTransformation(const Vector2i &mousePos);
/* Rotate the camera from the previous (screen) mouse position to the
current (screen) position */
void rotate(const Vector2i &mousePos);
/* Translate the camera from the previous (screen) mouse position to
the current (screen) mouse position */
void translate(const Vector2i &mousePos);
/* Translate the camera by the delta amount of (NDC) mouse position.
Note that NDC position must be in [-1, -1] to [1, 1]. */
void translateDelta(const Vector2 &translationNDC);
/* Zoom the camera (positive delta = zoom in, negative = zoom out) */
void zoom(Float delta);
/* Get the camera's view transformation as a qual quaternion */
const DualQuaternion &view() const { return m_view; }
/* Get the camera's view transformation as a matrix */
Matrix4 viewMatrix() const { return m_view.toMatrix(); }
/* Get the camera's inverse view matrix (which also produces
transformation of the camera) */
Matrix4 inverseViewMatrix() const { return m_inverseView.toMatrix(); }
/* Get the camera's transformation as a dual quaternion */
const DualQuaternion &transformation() const { return m_inverseView; }
/* Get the camera's transformation matrix */
Matrix4 transformationMatrix() const { return m_inverseView.toMatrix(); }
/* Return the distance from the camera position to the center view */
Float viewDistance() const { return Math::abs(m_targetZooming); }
protected:
/* Update the camera transformations */
void updateInternalTransformations();
/* Transform from screen coordinate to NDC - normalized device
coordinate. The top-left of the screen corresponds to [-1, 1] NDC,
and the bottom right is [1, -1] NDC. */
Vector2 screenCoordToNDC(const Vector2i &mousePos) const;
Deg m_fov;
Vector2i m_windowSize;
Vector2 m_prevMousePosNDC;
Float m_lagging{};
Vector3 m_targetPosition, m_currentPosition, m_positionT0;
Quaternion m_targetQRotation, m_currentQRotation, m_qRotationT0;
Float m_targetZooming, m_currentZooming, m_zoomingT0;
DualQuaternion m_view, m_inverseView;
};
#endif

65
src/arc_ball_camera.h Normal file
View File

@@ -0,0 +1,65 @@
#ifndef ARCBALLCAMERA_H
#define ARCBALLCAMERA_H
#include <Magnum/SceneGraph/AbstractTranslationRotation3D.h>
#include <Magnum/SceneGraph/Camera.h>
#include <Magnum/SceneGraph/Object.h>
#include <Magnum/SceneGraph/Scene.h>
#include "arc_ball.h"
using namespace Magnum;
/* Arcball camera implementation integrated into the SceneGraph */
class ArcBallCamera : public ArcBall {
public:
template <class Transformation>
ArcBallCamera(SceneGraph::Scene<Transformation> &scene,
const Vector3 &cameraPosition, const Vector3 &viewCenter,
const Vector3 &upDir, Deg fov, const Vector2i &windowSize,
const Vector2i &viewportSize)
: ArcBall{cameraPosition, viewCenter, upDir, fov, windowSize} {
/* Create a camera object of a concrete type */
auto *cameraObject = new SceneGraph::Object<Transformation>{&scene};
(*(m_camera = new SceneGraph::Camera3D{*cameraObject}))
.setAspectRatioPolicy(SceneGraph::AspectRatioPolicy::Extend)
.setProjectionMatrix(Matrix4::perspectiveProjection(
fov, Vector2{windowSize}.aspectRatio(), 0.01f, 100.0f))
.setViewport(viewportSize);
/* Save the abstract transformation interface and initialize the
camera position through that */
(*(m_cameraObject = cameraObject))
.rotate(transformation().rotation())
.translate(transformation().translation());
}
/* Update screen and viewport size after the window has been resized */
void reshape(const Vector2i &windowSize, const Vector2i &viewportSize) {
m_windowSize = windowSize;
m_camera->setViewport(viewportSize);
}
/* Update the SceneGraph camera if arcball has been changed */
bool update() {
/* call the internal update */
if (!updateTransformation())
return false;
(*m_cameraObject)
.resetTransformation()
.rotate(transformation().rotation())
.translate(transformation().translation());
return true;
}
/* Draw objects using the internal scenegraph camera */
void draw(SceneGraph::DrawableGroup3D &drawables) {
m_camera->draw(drawables);
}
private:
SceneGraph::AbstractTranslationRotation3D *m_cameraObject{};
SceneGraph::Camera3D *m_camera{};
};
#endif

11
src/glclampf.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef GLCLAMPF_H
#define GLCLAMPF_H
#if 1
typedef GLfloat GLclampf;
#undef __glew_h__ /* shh, Qt, shh */
#undef __GLEW_H__
#include <QOpenGLFunctions>
#endif
#endif // GLCLAMPF_H

126
src/magnum_item.cpp Normal file
View File

@@ -0,0 +1,126 @@
#include <Magnum/GL/Framebuffer.h>
#include <Magnum/Platform/GLContext.h>
#include <QtCore/QRunnable>
#include <QtQuick/QQuickWindow>
#include <QOpenGLFramebufferObject>
#include "magnum_item.h"
#include "magnum_render.h"
using namespace std;
using namespace Magnum;
using namespace Math::Literals;
class MagnumFBORenderer : public QQuickFramebufferObject::Renderer {
public:
MagnumFBORenderer(QQuickWindow *window, MagnumRenderer *renderer) :
m_window(window),
m_renderer(renderer) {}
void render() override {
m_renderer->render();
m_window->resetOpenGLState();
update();
}
void synchronize(QQuickFramebufferObject *item) override {
auto mitem = static_cast<MagnumItem*>(item);
m_renderer->t(mitem->t());
m_renderer->hue(mitem->hue());
m_renderer->count(mitem->count());
}
QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) override {
QOpenGLFramebufferObjectFormat format;
format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
format.setSamples(4);
m_fbo = new QOpenGLFramebufferObject(size, format);
// ---
if (m_ctx == nullptr)
m_ctx = new Platform::GLContext();
Platform::GLContext::makeCurrent(m_ctx);
m_renderer->reset(
m_ctx,
GL::Framebuffer::wrap(
m_fbo->handle(), {{}, {size.width(),
size.height()}}),
Vector2i{m_window->width(), m_window->height()},
Vector2i{size.width(), size.height()});
return m_fbo;
}
private:
QQuickWindow *m_window;
QOpenGLFramebufferObject *m_fbo;
Platform::GLContext *m_ctx{};
MagnumRenderer *m_renderer;
};
MagnumItem::MagnumItem() : m_renderer(new MagnumRenderer()) {
setMirrorVertically(true);
setAcceptHoverEvents(true);
setAcceptedMouseButtons(Qt::AllButtons);
setFlag(ItemAcceptsInputMethod, true);
}
QQuickFramebufferObject::Renderer *MagnumItem::createRenderer() const {
return new MagnumFBORenderer(window(), m_renderer);
}
void MagnumItem::setT(qreal t) {
if (t == m_t) return;
m_t = t;
emit tChanged();
update();
}
void MagnumItem::setHue(qreal hue) {
if (hue == m_hue) return;
m_hue = hue;
emit hueChanged();
update();
}
void MagnumItem::setCount(qint8 count) {
if (count == m_count) return;
m_count = count;
emit countChanged();
update();
}
void MagnumItem::keyPressEvent(QKeyEvent *evt) {
switch (evt->key()) {
case Qt::Key_L:
// if (m_camera->lagging() > 0.0f) {
// m_camera->setLagging(0.0f);
// } else {
// m_camera->setLagging(0.85f);
// }
break;
}
evt->accept();
}
void MagnumItem::mousePressEvent(QMouseEvent *evt) {
}
void MagnumItem::mouseReleaseEvent(QMouseEvent *evt) {
}
void MagnumItem::mouseMoveEvent(QMouseEvent *evt) {}
void MagnumItem::wheelEvent(QWheelEvent *evt) {}
class CleanupJob : public QRunnable {
public:
CleanupJob(MagnumRenderer *renderer) : m_renderer(renderer) {}
void run() override { delete m_renderer; }
private:
MagnumRenderer *m_renderer;
};
void MagnumItem::releaseResources() {
window()->scheduleRenderJob(
new CleanupJob(m_renderer),
QQuickWindow::BeforeSynchronizingStage);
m_renderer = nullptr;
}

55
src/magnum_item.h Normal file
View File

@@ -0,0 +1,55 @@
#ifndef MAGNUM_ITEM_H
#define MAGNUM_ITEM_H
#include <Magnum/GL/Framebuffer.h>
#include <Magnum/Platform/GLContext.h>
#include "glclampf.h"
#include <QOpenGLFunctions>
#include <QtQuick/QQuickFramebufferObject>
// Forward declaring the renderer to avoid CMake's AUTOMOC
// to process Magnum's headers (where it fails)
class MagnumRenderer;
class MagnumItem : public QQuickFramebufferObject {
Q_OBJECT
Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged)
Q_PROPERTY(qreal hue READ hue WRITE setHue NOTIFY hueChanged)
Q_PROPERTY(qreal count READ count WRITE setCount NOTIFY countChanged)
public:
MagnumItem();
Renderer *createRenderer() const override;
inline qreal t() const { return m_t; }
void setT(qreal t);
inline qreal hue() const { return m_hue; }
void setHue(qreal hue);
inline qint8 count() const { return m_count; }
void setCount(qint8 count);
signals:
void tChanged();
void hueChanged();
void countChanged();
protected:
void keyPressEvent(QKeyEvent *evt) override;
void mousePressEvent(QMouseEvent *evt) override;
void mouseReleaseEvent(QMouseEvent *evt) override;
void mouseMoveEvent(QMouseEvent *evt) override;
void wheelEvent(QWheelEvent *evt) override;
private:
void releaseResources() override;
qreal m_t;
qreal m_hue;
qint8 m_count;
MagnumRenderer *m_renderer;
};
#endif // MAGNUM_ITEM_H

149
src/magnum_render.cpp Normal file
View File

@@ -0,0 +1,149 @@
#include <Corrade/Utility/DebugStl.h>
#include <Magnum/GL/Framebuffer.h>
#include <Magnum/GL/Renderer.h>
#include <Magnum/Math/Color.h>
#include <Magnum/MeshTools/Compile.h>
#include <Magnum/Platform/GLContext.h>
#include <Magnum/Primitives/Cube.h>
#include <Magnum/Primitives/Grid.h>
#include <Magnum/Trade/MeshData.h>
#include "magnum_render.h"
using namespace Magnum;
using namespace Math::Literals;
static const auto HUE_BG = 210.0_degf;
static const auto COLOR_BG = Color4::fromHsv({HUE_BG, .3f, .9f}, 1.f);
static const auto COLOR_GRID = Color4::fromHsv({HUE_BG, .3f, .7f}, 1.f);
MagnumRenderer::MagnumRenderer() {}
MagnumRenderer::~MagnumRenderer() {}
void MagnumRenderer::t(const float t) {
if (m_subjectObject != nullptr) {
m_subjectObject->resetTransformation();
m_subjectObject->translate(Vector3{0.f, 1.f, 0.f});
m_subjectObject->rotateY(Rad(t*Math::Constants<float>::pi()));
}
}
void MagnumRenderer::hue(float hue) {
if (m_subjectShader.id()) {
auto const color = Color3::fromHsv({Rad(hue), 1.f, 1.f});
m_subjectShader
.setDiffuseColor(color)
.setAmbientColor(Color3::fromHsv({color.hue(), 1.0f, 0.3f}));
}
}
void MagnumRenderer::count(int count) {
m_count = count;
}
void MagnumRenderer::lazyInitialize() {
if (m_init) return;
// The Cube
{
m_subject = MeshTools::compile(Primitives::cubeSolid());
m_subjectObject = new Object3D{&m_scene};
(*m_subjectObject).translate(Vector3{0.f, 1.f, 0.f});
m_subjectShader = Shaders::Phong{};
m_subjectShader
.setShininess(20.f)
.setLightColor(Color3{1.f})
.setLightPosition(Vector3{-100.f, 100.f, 50.f});
new SubjectDrawable{*m_subjectObject, m_subjectShader, m_subject, m_drawables};
}
// The Grid
{
m_grid = MeshTools::compile(Primitives::grid3DWireframe({15, 15}));
auto obj = new Object3D{&m_scene};
(*obj).rotateX(90.0_degf).scale(Vector3{8.0f});
m_gridShader = Shaders::Flat3D{};
m_gridShader.setColor(COLOR_GRID);
new GridDrawable{*obj, m_gridShader, m_grid, m_drawables};
}
// The Camera
{
const Vector3 eye{-10.0f, 8.f, -6.f};
const Vector3 center{0.f, 1.f, 0.f};
const Vector3 up = Vector3::yAxis();
m_camera.emplace(m_scene, eye, center, up, 45.0_degf,
Vector2i{100, 100}, Vector2i{100, 100});
}
m_init = true;
}
void MagnumRenderer::reset(Platform::GLContext *ctx,
GL::Framebuffer fbo,
Vector2i windowSize,
Vector2i viewportSize) {
lazyInitialize();
m_camera->reshape(windowSize, viewportSize);
m_FBO = std::move(fbo);
m_ctx = ctx;
}
void MagnumRenderer::prepGLState() {
GL::Renderer::setClearColor(COLOR_BG);
GL::Renderer::enable(GL::Renderer::Feature::DepthTest);
GL::Renderer::enable(GL::Renderer::Feature::FaceCulling);
GL::Renderer::enable(GL::Renderer::Feature::Multisampling);
GL::Renderer::setDepthFunction(GL::Renderer::DepthFunction::LessOrEqual);
GL::Renderer::setBlendEquation(GL::Renderer::BlendEquation::Add,
GL::Renderer::BlendEquation::Add);
GL::Renderer::setBlendFunction(
GL::Renderer::BlendFunction::One,
GL::Renderer::BlendFunction::OneMinusSourceAlpha);
GL::Renderer::enable(GL::Renderer::Feature::Blending);
}
void MagnumRenderer::render() {
m_ctx->resetState(GL::Context::State::ExitExternal);
prepGLState();
// ---
m_FBO.bind();
m_FBO.clear(GL::FramebufferClear::Color |
GL::FramebufferClear::Depth);
m_camera->update();
m_camera->draw(m_drawables);
/** Use instead this to limit rendering to camera changes
* bool cameraChanged = m_camera->update();
* m_camera->draw(m_drawables);
* if (cameraChanged) {
* redraw();
* } */
// ---
m_ctx->resetState(GL::Context::State::EnterExternal);
}
void GridDrawable::draw(const Matrix4 &transformation,
SceneGraph::Camera3D &camera) {
m_shader
.setTransformationProjectionMatrix(
camera.projectionMatrix()*transformation)
.draw(m_mesh);
}
void SubjectDrawable::draw(const Matrix4 &transformation,
SceneGraph::Camera3D &camera) {
m_shader
.setTransformationMatrix(transformation)
.setNormalMatrix(transformation.normalMatrix())
.setProjectionMatrix(camera.projectionMatrix())
.draw(m_mesh);
}

91
src/magnum_render.h Normal file
View File

@@ -0,0 +1,91 @@
#ifndef MAGNUM_RENDER_H
#define MAGNUM_RENDER_H
#include <Corrade/Containers/Optional.h>
#include <Magnum/GL/Framebuffer.h>
#include <Magnum/GL/Mesh.h>
#include <Magnum/Math/Vector2.h>
#include <Magnum/Platform/GLContext.h>
#include <Magnum/SceneGraph/Drawable.h>
#include <Magnum/SceneGraph/MatrixTransformation3D.h>
#include <Magnum/SceneGraph/Object.h>
#include <Magnum/SceneGraph/Scene.h>
#include <Magnum/Shaders/Flat.h>
#include <Magnum/Shaders/Phong.h>
#include "arc_ball_camera.h"
using namespace Magnum;
using Object3D = SceneGraph::Object<SceneGraph::MatrixTransformation3D>;
using Scene3D = SceneGraph::Scene<SceneGraph::MatrixTransformation3D>;
class MagnumRenderer {
public:
MagnumRenderer();
~MagnumRenderer();
void reset(Platform::GLContext *ctx,
GL::Framebuffer fbo,
Vector2i windowSize,
Vector2i viewportSize);
void render();
void t(float t);
void hue(float hue);
void count(int count);
private:
void lazyInitialize();
void prepGLState();
bool m_init{false};
float m_count{1};
Platform::GLContext *m_ctx;
GL::Framebuffer m_FBO{NoCreate};
Scene3D m_scene;
SceneGraph::DrawableGroup3D m_drawables;
Containers::Optional<ArcBallCamera> m_camera;
GL::Mesh m_subject{NoCreate};
Shaders::Phong m_subjectShader{NoCreate};
Object3D* m_subjectObject{nullptr};
GL::Mesh m_grid{NoCreate};
Shaders::Flat3D m_gridShader{NoCreate};
};
class GridDrawable : public SceneGraph::Drawable3D {
public:
explicit GridDrawable(Object3D &object, Shaders::Flat3D &shader,
GL::Mesh &mesh, SceneGraph::DrawableGroup3D &drawables)
: SceneGraph::Drawable3D{object, &drawables},
m_shader(shader),
m_mesh(mesh) {}
void draw(const Matrix4 &transformation, SceneGraph::Camera3D &camera);
private:
Shaders::Flat3D &m_shader;
GL::Mesh &m_mesh;
};
class SubjectDrawable : public SceneGraph::Drawable3D {
public:
explicit SubjectDrawable(Object3D &object, Shaders::Phong &shader,
GL::Mesh &mesh, SceneGraph::DrawableGroup3D &drawables)
: SceneGraph::Drawable3D{object, &drawables},
m_shader(shader),
m_mesh(mesh) {}
void draw(const Matrix4 &transformation, SceneGraph::Camera3D &camera);
private:
Shaders::Phong &m_shader;
GL::Mesh &m_mesh;
};
#endif // MAGNUM_RENDER_H

36
src/main.cpp Normal file
View File

@@ -0,0 +1,36 @@
#include <Corrade/Containers/Optional.h>
#include <Magnum/GL/Framebuffer.h>
#include <Magnum/Platform/GLContext.h>
#include "magnum_item.h"
#include "glclampf.h"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QLoggingCategory>
int main(int argc, char *argv[]) {
// Enable AA
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication::setAttribute(Qt::AA_UseOpenGLES);
// Initialize Qt application
QGuiApplication app(argc, argv);
// Enable logging
QLoggingCategory::setFilterRules("qt.scenegraph.general=true");
// Manually register custom types
qmlRegisterType<MagnumItem>("Magnum", 1, 0, "Magnum");
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}

103
src/qml/main.qml Normal file
View File

@@ -0,0 +1,103 @@
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.3
import Magnum 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("My Application")
RowLayout {
id: root
anchors.fill: parent
spacing: 0
ColumnLayout {
Layout.fillHeight: true
Layout.preferredWidth: parent.width * 0.25
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Layout.margins: 20
spacing: 20
Label {
text: "Controls"
font.pointSize: 14
}
GroupBox {
Layout.preferredWidth: parent.width
RowLayout {
anchors.left: parent.left
anchors.right: parent.right
Label {
Layout.preferredWidth: parent.width/4
text: "Hue"
}
Label {
text: qsTr("%1°").arg(Math.round((180/Math.PI)*hue.value))
color: palette.highlight
}
Slider {
id: hue
anchors.right: parent.right
Layout.preferredWidth: parent.width/2
from: 0
to: Math.PI*2
}
}
}
GroupBox {
Layout.preferredWidth: parent.width
RowLayout {
anchors.left: parent.left
anchors.right: parent.right
Label {
Layout.preferredWidth: parent.width/4
text: "Count"
}
Label {
text: count.value
color: palette.highlight
}
Slider {
id: count
anchors.right: parent.right
Layout.preferredWidth: parent.width/2
from: 1
to: 5
stepSize: 1
snapMode: Slider.SnapAlways
}
}
}
Item {
Layout.preferredWidth: parent.width
CheckBox {
text: "Lagging"
}
}
}
Magnum {
Layout.fillHeight: true
Layout.fillWidth: true
hue: hue.value
count: count.value
SequentialAnimation on t {
NumberAnimation { to: 1; duration: 2500; easing.type: Easing.InQuad }
NumberAnimation { to: 0; duration: 2500; easing.type: Easing.OutQuad }
loops: Animation.Infinite
running: true
}
}
}
}

6
src/qml/main.qrc Normal file
View File

@@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/">
<file>main.qml</file>
<file>qtquickcontrols2.conf</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,9 @@
; This file can be edited to change the style of the application
; Read "Qt Quick Controls 2 Configuration File" for details:
; http://doc.qt.io/qt-5/qtquickcontrols2-configuration.html
[Controls]
Style=Fusion
[Fusion\Palette]
Highlight=#ff0000