add more stuff

This commit is contained in:
2026-01-10 23:04:53 -06:00
parent 3fd85a4a30
commit 1cfcdaf4b7
25 changed files with 1584 additions and 17 deletions

15
.gitmodules vendored
View File

@@ -4,3 +4,18 @@
[submodule "magnum"] [submodule "magnum"]
path = magnum path = magnum
url = https://github.com/mosra/magnum.git url = https://github.com/mosra/magnum.git
[submodule "entt"]
path = entt
url = https://github.com/skypjack/entt.git
[submodule "magnum-integration"]
path = magnum-integration
url = https://github.com/mosra/magnum-integration.git
[submodule "imgui"]
path = imgui
url = https://github.com/ocornut/imgui.git
[submodule "magnum-plugins"]
path = magnum-plugins
url = https://github.com/mosra/magnum-plugins.git
[submodule "ImGuiFileDialog"]
path = ImGuiFileDialog
url = https://github.com/aiekick/ImGuiFileDialog.git

View File

@@ -8,7 +8,20 @@ add_subdirectory(corrade EXCLUDE_FROM_ALL)
# Add Magnum as a subproject, enable Sdl2Application # Add Magnum as a subproject, enable Sdl2Application
set(CMAKE_PREFIX_PATH ${PROJECT_SOURCE_DIR}/SDL2-2.32.6 ${CMAKE_PREFIX_PATH}) set(CMAKE_PREFIX_PATH ${PROJECT_SOURCE_DIR}/SDL2-2.32.6 ${CMAKE_PREFIX_PATH})
set(MAGNUM_WITH_ANYIMAGEIMPORTER ON CACHE BOOL "" FORCE)
set(MAGNUM_WITH_ANYSCENEIMPORTER ON CACHE BOOL "" FORCE)
set(MAGNUM_WITH_OBJIMPORTER ON CACHE BOOL "" FORCE)
set(MAGNUM_WITH_SDL2APPLICATION ON CACHE BOOL "" FORCE) set(MAGNUM_WITH_SDL2APPLICATION ON CACHE BOOL "" FORCE)
add_subdirectory(magnum EXCLUDE_FROM_ALL) add_subdirectory(magnum EXCLUDE_FROM_ALL)
set(IMGUI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/imgui)
set(MAGNUM_WITH_IMGUIINTEGRATION ON CACHE BOOL "" FORCE)
add_subdirectory(magnum-integration EXCLUDE_FROM_ALL)
set(MAGNUM_WITH_STBIMAGEIMPORTER ON CACHE BOOL "" FORCE)
set(MAGNUM_WITH_GLTFIMPORTER ON CACHE BOOL "" FORCE)
add_subdirectory(magnum-plugins EXCLUDE_FROM_ALL)
add_subdirectory(entt)
add_subdirectory(src) add_subdirectory(src)

1
ImGuiFileDialog Submodule

Submodule ImGuiFileDialog added at e763838985

1
entt Submodule

Submodule entt added at b4e58bdd36

1
imgui Submodule

Submodule imgui added at 960921f03a

1
magnum-integration Submodule

Submodule magnum-integration added at 0184c8371d

1
magnum-plugins Submodule

Submodule magnum-plugins added at 0d212b5698

View File

@@ -0,0 +1,456 @@
#.rst:
# Find Magnum integration library
# -------------------------------
#
# Finds the Magnum integration library. Basic usage::
#
# find_package(MagnumIntegration REQUIRED)
#
# This command tries to find Magnum integration library and then defines the
# following:
#
# MagnumIntegration_FOUND - Whether the library was found
#
# This command alone is useless without specifying the components:
#
# Bullet - Bullet Physics integration library
# Dart - Dart Physics integration library
# Eigen - Eigen integration library
# Glm - GLM integration library
# ImGui - ImGui integration library
# Ovr - Oculus SDK integration library
# Yoga - Yoga Layout integration library
#
# Example usage with specifying additional components is:
#
# find_package(MagnumIntegration REQUIRED Bullet)
#
# For each component is then defined:
#
# MagnumIntegration_*_FOUND - Whether the component was found
# MagnumIntegration::* - Component imported target
#
# The package is found if either debug or release version of each requested
# 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).
#
# Additionally these variables are defined for internal usage:
#
# MAGNUMINTEGRATION_INCLUDE_DIR - Magnum integration include dir (w/o
# dependencies)
# MAGNUMINTEGRATION_*_LIBRARY_DEBUG - Debug version of given library, if found
# MAGNUMINTEGRATION_*_LIBRARY_RELEASE - Release version of given library, if
# found
#
#
# This file is part of Magnum.
#
# Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
# 2020, 2021, 2022, 2023, 2024, 2025, 2026
# Vladimír Vondruš <mosra@centrum.cz>
# Copyright © 2018 Konstantinos Chatzilygeroudis <costashatz@gmail.com>
#
# 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.
#
# Magnum library dependencies
set(_MAGNUMINTEGRATION_MAGNUM_DEPENDENCIES )
set(_MAGNUMINTEGRATION_MAGNUMEXTRAS_DEPENDENCIES )
foreach(_component ${MagnumIntegration_FIND_COMPONENTS})
if(_component STREQUAL Bullet)
set(_MAGNUMINTEGRATION_${_component}_MAGNUM_DEPENDENCIES SceneGraph Shaders GL)
elseif(_component STREQUAL Dart)
set(_MAGNUMINTEGRATION_${_component}_MAGNUM_DEPENDENCIES SceneGraph Primitives MeshTools GL)
elseif(_component STREQUAL ImGui)
set(_MAGNUMINTEGRATION_${_component}_MAGNUM_DEPENDENCIES GL Shaders)
elseif(_component STREQUAL Yoga)
set(_MAGNUMINTEGRATION_${_component}_MAGNUM_DEPENDENCIES GL Shaders)
set(_MAGNUMINTEGRATION_${_component}_MAGNUMEXTRAS_DEPENDENCIES Ui)
endif()
list(APPEND _MAGNUMINTEGRATION_MAGNUM_DEPENDENCIES ${_MAGNUMINTEGRATION_${_component}_MAGNUM_DEPENDENCIES})
list(APPEND _MAGNUMINTEGRATION_MAGNUMEXTRAS_DEPENDENCIES ${_MAGNUMINTEGRATION_${_component}_MAGNUMEXTRAS_DEPENDENCIES})
endforeach()
find_package(Magnum REQUIRED ${_MAGNUMINTEGRATION_MAGNUM_DEPENDENCIES})
if(_MAGNUMINTEGRATION_MAGNUMEXTRAS_DEPENDENCIES)
find_package(MagnumExtras REQUIRED ${_MAGNUMINTEGRATION_MAGNUMEXTRAS_DEPENDENCIES})
endif()
# Global include dir that's unique to Magnum Integration. Often it will be
# installed alongside Magnum, which is why the hint, but if not, it shouldn't
# just pick MAGNUM_INCLUDE_DIR because then _MAGNUMINTEGRATION_*_INCLUDE_DIR
# will fail to be found. In case of CMake subprojects the versionIntegration.h
# is generated inside the build dir so this won't find it, instead
# src/CMakeLists.txt forcibly sets MAGNUMINTEGRATION_INCLUDE_DIR as an internal
# cache value to make that work.
find_path(MAGNUMINTEGRATION_INCLUDE_DIR Magnum/versionIntegration.h
HINTS ${MAGNUM_INCLUDE_DIR})
mark_as_advanced(MAGNUMINTEGRATION_INCLUDE_DIR)
# CMake module dir for dependencies. It might not be present at all if no
# feature that needs them is enabled, in which case it'll be left at NOTFOUND.
# But in that case it should also not be subsequently needed for any
# find_package(). If this is called from a superproject, the
# _MAGNUMINTEGRATION_DEPENDENCY_MODULE_DIR is already set by
# modules/CMakeLists.txt.
find_path(_MAGNUMINTEGRATION_DEPENDENCY_MODULE_DIR
NAMES
FindBullet.cmake FindGLM.cmake FindImGui.cmake FindOVR.cmake
PATH_SUFFIXES share/cmake/MagnumIntegration/dependencies)
mark_as_advanced(_MAGNUMINTEGRATION_DEPENDENCY_MODULE_DIR)
# If the module dir is found and is not present in CMAKE_MODULE_PATH already
# (such as when someone explicitly added it, or if it's the Magnum's modules/
# dir in case of a superproject), add it as the first before all other. Set a
# flag to remove it again at the end, so the modules don't clash with Find
# modules of the same name from other projects.
if(_MAGNUMINTEGRATION_DEPENDENCY_MODULE_DIR AND NOT _MAGNUMINTEGRATION_DEPENDENCY_MODULE_DIR IN_LIST CMAKE_MODULE_PATH)
set(CMAKE_MODULE_PATH ${_MAGNUMINTEGRATION_DEPENDENCY_MODULE_DIR} ${CMAKE_MODULE_PATH})
set(_MAGNUMINTEGRATION_REMOVE_DEPENDENCY_MODULE_DIR_FROM_CMAKE_PATH ON)
else()
unset(_MAGNUMINTEGRATION_REMOVE_DEPENDENCY_MODULE_DIR_FROM_CMAKE_PATH)
endif()
# Component distinction (listing them explicitly to avoid mistakes with finding
# components from other repositories)
set(_MAGNUMINTEGRATION_LIBRARY_COMPONENTS Bullet Dart Eigen ImGui Glm Yoga)
if(CORRADE_TARGET_WINDOWS)
list(APPEND _MAGNUMINTEGRATION_LIBRARY_COMPONENTS Ovr)
endif()
set(_MAGNUMINTEGRATION_HEADER_ONLY_COMPONENTS Eigen)
# Nothing is enabled by default right now
set(_MAGNUMINTEGRATION_IMPLICITLY_ENABLED_COMPONENTS )
# Inter-component dependencies (none yet)
# set(_MAGNUMINTEGRATION_Component_DEPENDENCIES Dependency)
# Ensure that all inter-component dependencies are specified as well
set(_MAGNUMINTEGRATION_ADDITIONAL_COMPONENTS )
foreach(_component ${MagnumIntegration_FIND_COMPONENTS})
# Mark the dependencies as required if the component is also required
if(MagnumIntegration_FIND_REQUIRED_${_component})
foreach(_dependency ${_MAGNUMINTEGRATION_${_component}_DEPENDENCIES})
set(MagnumIntegration_FIND_REQUIRED_${_dependency} TRUE)
endforeach()
endif()
list(APPEND _MAGNUMINTEGRATION_ADDITIONAL_COMPONENTS ${_MAGNUMINTEGRATION_${_component}_DEPENDENCIES})
endforeach()
# Join the lists, remove duplicate components
set(_MAGNUMINTEGRATION_ORIGINAL_FIND_COMPONENTS ${MagnumIntegration_FIND_COMPONENTS})
if(_MAGNUMINTEGRATION_ADDITIONAL_COMPONENTS)
list(INSERT MagnumIntegration_FIND_COMPONENTS 0 ${_MAGNUMINTEGRATION_ADDITIONAL_COMPONENTS})
endif()
if(MagnumIntegration_FIND_COMPONENTS)
list(REMOVE_DUPLICATES MagnumIntegration_FIND_COMPONENTS)
endif()
# Special cases of include paths for header-only libraries. Libraries not
# listed here have a path suffix and include name derived from the library name
# in the loop below. Non-header-only libraries have a configure.h file.
set(_MAGNUMINTEGRATION_EIGEN_INCLUDE_PATH_NAMES GeometryIntegration.h)
# Find all components
foreach(_component ${MagnumIntegration_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 "MagnumIntegration::${_component}") # Quotes to fix KDE's hiliter
set(MagnumIntegration_${_component}_FOUND TRUE)
else()
# Find library include dir for header-only libraries
if(_component IN_LIST _MAGNUMINTEGRATION_HEADER_ONLY_COMPONENTS)
# Include path names to find, unless specified above
if(NOT _MAGNUMINTEGRATION_${_COMPONENT}_INCLUDE_PATH_NAMES)
set(_MAGNUMINTEGRATION_${_COMPONENT}_INCLUDE_PATH_NAMES ${_component}Integration.h)
endif()
find_path(_MAGNUMINTEGRATION_${_COMPONENT}_INCLUDE_DIR
NAMES ${_MAGNUMINTEGRATION_${_COMPONENT}_INCLUDE_PATH_NAMES}
HINTS ${MAGNUMINTEGRATION_INCLUDE_DIR}/Magnum/${_component}Integration)
mark_as_advanced(_MAGNUMINTEGRATION_${_COMPONENT}_CONFIGURE_FILE)
# Non-header-only libraries have a configure file which we need to
# subsequently read, so find that one directly
elseif(_component IN_LIST _MAGNUMINTEGRATION_LIBRARY_COMPONENTS)
find_file(_MAGNUMINTEGRATION_${_COMPONENT}_CONFIGURE_FILE configure.h
HINTS ${MAGNUMINTEGRATION_INCLUDE_DIR}/Magnum/${_component}Integration)
mark_as_advanced(_MAGNUMINTEGRATION_${_COMPONENT}_CONFIGURE_FILE)
endif()
# Library components
if(_component IN_LIST _MAGNUMINTEGRATION_LIBRARY_COMPONENTS AND NOT _component IN_LIST _MAGNUMINTEGRATION_HEADER_ONLY_COMPONENTS)
# Try to find both debug and release version
find_library(MAGNUMINTEGRATION_${_COMPONENT}_LIBRARY_DEBUG Magnum${_component}Integration-d)
find_library(MAGNUMINTEGRATION_${_COMPONENT}_LIBRARY_RELEASE Magnum${_component}Integration)
mark_as_advanced(MAGNUMINTEGRATION_${_COMPONENT}_LIBRARY_DEBUG
MAGNUMINTEGRATION_${_COMPONENT}_LIBRARY_RELEASE)
# Determine if the library is static or dynamic by reading the
# per-library config file. If the file wasn't found, skip this so
# it fails on the FPHSA below and not right here.
if(_MAGNUMINTEGRATION_${_COMPONENT}_CONFIGURE_FILE)
file(READ ${_MAGNUMINTEGRATION_${_COMPONENT}_CONFIGURE_FILE} _magnumIntegrationConfigure)
string(REGEX REPLACE ";" "\\\\;" _magnumIntegrationConfigure "${_magnumIntegrationConfigure}")
string(REGEX REPLACE "\n" ";" _magnumIntegrationConfigure "${_magnumIntegrationConfigure}")
list(FIND _magnumIntegrationConfigure "#define MAGNUM_${_COMPONENT}INTEGRATION_BUILD_STATIC" _magnumIntegrationBuildStatic)
if(NOT _magnumIntegrationBuildStatic EQUAL -1)
# The variable is inconsistently named between C++ and
# CMake, so keep it underscored / private
set(_MAGNUMINTEGRATION_${_COMPONENT}_BUILD_STATIC ON)
endif()
endif()
# On Windows, if we have a dynamic build of given library, find the
# DLLs as well. Abuse find_program() since the DLLs should be
# alongside usual executables. On MinGW they however have a lib
# prefix.
if(CORRADE_TARGET_WINDOWS AND NOT _MAGNUMINTEGRATION_${_COMPONENT}_BUILD_STATIC)
find_program(MAGNUMINTEGRATION_${_COMPONENT}_DLL_DEBUG ${CMAKE_SHARED_LIBRARY_PREFIX}Magnum${_component}Integration-d.dll)
find_program(MAGNUMINTEGRATION_${_COMPONENT}_DLL_RELEASE ${CMAKE_SHARED_LIBRARY_PREFIX}Magnum${_component}Integration.dll)
mark_as_advanced(MAGNUMINTEGRATION_${_COMPONENT}_DLL_DEBUG
MAGNUMINTEGRATION_${_COMPONENT}_DLL_RELEASE)
# If not on Windows or on a static build, unset the DLL variables
# to avoid leaks when switching shared and static builds
else()
unset(MAGNUMINTEGRATION_${_COMPONENT}_DLL_DEBUG CACHE)
unset(MAGNUMINTEGRATION_${_COMPONENT}_DLL_RELEASE CACHE)
endif()
# If not a header-only component it's something unknown, skip. FPHSA
# will take care of handling this below.
elseif(NOT _component IN_LIST _MAGNUMINTEGRATION_HEADER_ONLY_COMPONENTS)
continue()
endif()
# Decide if the library was found. If not, skip the rest, which
# populates the target properties and finds additional dependencies.
# This means that the rest can also rely on that e.g. FindGLM.cmake is
# present in _MAGNUMPLUGINS_DEPENDENCY_MODULE_DIR -- given that the
# library needing GLM was found, it likely also installed FindGLM for
# itself.
if(
# If the component is a header-only library it should have an
# include dir
(_component IN_LIST _MAGNUMINTEGRATION_HEADER_ONLY_COMPONENTS AND _MAGNUMINTEGRATION_${_COMPONENT}_INCLUDE_DIR) OR
# Or, if it's a real library, it should have a configure file
(_component IN_LIST _MAGNUMINTEGRATION_LIBRARY_COMPONENTS AND _MAGNUMINTEGRATION_${_COMPONENT}_CONFIGURE_FILE AND (
# Or have a debug library, and a DLL found if expected
(MAGNUMINTEGRATION_${_COMPONENT}_LIBRARY_DEBUG AND (
NOT DEFINED MAGNUMINTEGRATION_${_COMPONENT}_DLL_DEBUG OR
MAGNUMINTEGRATION_${_COMPONENT}_DLL_DEBUG)) OR
# Or have a release library, and a DLL found if expected
(MAGNUMINTEGRATION_${_COMPONENT}_LIBRARY_RELEASE AND (
NOT DEFINED MAGNUMINTEGRATION_${_COMPONENT}_DLL_RELEASE OR
MAGNUMINTEGRATION_${_COMPONENT}_DLL_RELEASE))))
)
set(MagnumIntegration_${_component}_FOUND TRUE)
else()
set(MagnumIntegration_${_component}_FOUND FALSE)
continue()
endif()
# Target for header-only library components
if(_component IN_LIST _MAGNUMINTEGRATION_HEADER_ONLY_COMPONENTS)
add_library(MagnumIntegration::${_component} INTERFACE IMPORTED)
# Target and location for libraries
elseif(_component IN_LIST _MAGNUMINTEGRATION_LIBRARY_COMPONENTS)
if(_MAGNUMINTEGRATION_${_COMPONENT}_BUILD_STATIC)
add_library(MagnumIntegration::${_component} STATIC IMPORTED)
else()
add_library(MagnumIntegration::${_component} SHARED IMPORTED)
endif()
foreach(_CONFIG DEBUG RELEASE)
if(NOT MAGNUMINTEGRATION_${_COMPONENT}_LIBRARY_${_CONFIG})
continue()
endif()
set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY
IMPORTED_CONFIGURATIONS ${_CONFIG})
# Unfortunately for a DLL the two properties are swapped out,
# *.lib goes to IMPLIB, so it's duplicated like this
if(DEFINED MAGNUMINTEGRATION_${_COMPONENT}_DLL_${_CONFIG})
# Quotes to "fix" KDE's higlighter
set_target_properties("MagnumIntegration::${_component}" PROPERTIES
IMPORTED_LOCATION_${_CONFIG} ${MAGNUMINTEGRATION_${_COMPONENT}_DLL_${_CONFIG}}
IMPORTED_IMPLIB_${_CONFIG} ${MAGNUMINTEGRATION_${_COMPONENT}_LIBRARY_${_CONFIG}})
else()
set_property(TARGET MagnumIntegration::${_component} PROPERTY
IMPORTED_LOCATION_${_CONFIG} ${MAGNUMINTEGRATION_${_COMPONENT}_LIBRARY_${_CONFIG}})
endif()
endforeach()
endif()
# Bullet integration library
if(_component STREQUAL Bullet)
# On Emscripten, Bullet could be taken from ports. If that's the
# case, propagate proper compiler flag.
if(CORRADE_TARGET_EMSCRIPTEN)
# The library-specific configure file was read above already
list(FIND _magnumIntegrationConfigure "#define MAGNUM_USE_EMSCRIPTEN_PORTS_BULLET" _magnum${_component}Integration_USE_EMSCRIPTEN_PORTS_BULLET)
if(NOT _magnum${_component}Integration_USE_EMSCRIPTEN_PORTS_BULLET EQUAL -1)
set(MAGNUM_USE_EMSCRIPTEN_PORTS_BULLET 1)
endif()
endif()
if(MAGNUM_USE_EMSCRIPTEN_PORTS_BULLET)
if(CMAKE_VERSION VERSION_LESS 3.13)
message(FATAL_ERROR "${_component}Integration was compiled against an emscripten-ports version of Bullet but linking to it requires CMake 3.13 at least")
endif()
set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY
INTERFACE_COMPILE_OPTIONS "SHELL:-s USE_BULLET=1")
set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY
INTERFACE_LINK_OPTIONS "SHELL:-s USE_BULLET=1")
else()
find_package(Bullet)
set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY
INTERFACE_LINK_LIBRARIES Bullet::LinearMath)
endif()
# Eigen integration library
elseif(_component STREQUAL Eigen)
find_package(Eigen3)
# We could drop this once we can use at least 3.3.1 (Ubuntu 16.04
# has only 3.3 beta, which doesn't have this target yet), however
# for Travis and AppVeyor we're using FindEigen3.cmake from the
# downloaded sources (because the Eigen3Config.cmake, which
# produces the actual targets, is not there -- only
# Eigen3Config.cmake.in). See the YML files for an extended rant.
# Also, FindEigen3 only defines EIGEN3_INCLUDE_DIR, not even
# EIGEN3_INCLUDE_DIRS, so be extra careful.
# https://eigen.tuxfamily.org/index.php?title=ChangeLog#Eigen_3.3.1
set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY
INTERFACE_INCLUDE_DIRECTORIES ${EIGEN3_INCLUDE_DIR})
# ImGui integration library
elseif(_component STREQUAL ImGui)
find_package(ImGui)
set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY
INTERFACE_LINK_LIBRARIES ImGui::ImGui)
# GLM integration library
elseif(_component STREQUAL Glm)
find_package(GLM)
set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY
INTERFACE_LINK_LIBRARIES GLM::GLM)
# Dart integration library
elseif(_component STREQUAL Dart)
find_package(DART 6.0.0 CONFIG REQUIRED)
set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY
INTERFACE_LINK_LIBRARIES dart)
# Oculus SDK integration library
elseif(_component STREQUAL Ovr)
find_package(OVR)
set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY
INTERFACE_LINK_LIBRARIES OVR::OVR)
# Yoga integration library
elseif(_component STREQUAL Yoga)
# Since 2.0.0 the project provides a CMake config file, force it.
# Before 2.0 it didn't even have an install target, so assume those
# versions just aren't used at all.
find_package(yoga CONFIG REQUIRED)
set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY
INTERFACE_LINK_LIBRARIES yoga::yogacore)
endif()
if(_component IN_LIST _MAGNUMINTEGRATION_LIBRARY_COMPONENTS)
# Link to core Magnum library, add other Magnum required and
# optional dependencies
set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY
INTERFACE_LINK_LIBRARIES Magnum::Magnum)
foreach(_dependency ${_MAGNUMINTEGRATION_${_component}_MAGNUM_DEPENDENCIES})
set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY
INTERFACE_LINK_LIBRARIES Magnum::${_dependency})
endforeach()
foreach(_dependency ${_MAGNUMINTEGRATION_${_component}_MAGNUMEXTRAS_DEPENDENCIES})
set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY
INTERFACE_LINK_LIBRARIES MagnumExtras::${_dependency})
endforeach()
foreach(_dependency ${_MAGNUMINTEGRATION_${_component}_MAGNUM_OPTIONAL_DEPENDENCIES})
if(Magnum_${_dependency}_FOUND)
set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY
INTERFACE_LINK_LIBRARIES Magnum::${_dependency})
endif()
endforeach()
# Add inter-project dependencies
foreach(_dependency ${_MAGNUMINTEGRATION_${_component}_DEPENDENCIES})
set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY
INTERFACE_LINK_LIBRARIES MagnumIntegration::${_dependency})
endforeach()
endif()
endif()
endforeach()
# For CMake 3.16+ with REASON_FAILURE_MESSAGE, provide additional potentially
# useful info about the failed components.
if(NOT CMAKE_VERSION VERSION_LESS 3.16)
set(_MAGNUMINTEGRATION_REASON_FAILURE_MESSAGE )
# Go only through the originally specified find_package() components, not
# the dependencies added by us afterwards
foreach(_component ${_MAGNUMINTEGRATION_ORIGINAL_FIND_COMPONENTS})
if(MagnumIntegration_${_component}_FOUND)
continue()
endif()
# If it's not known at all, tell the user -- it might be a new library
# and an old Find module, or something platform-specific.
if(NOT _component IN_LIST _MAGNUMINTEGRATION_LIBRARY_COMPONENTS)
list(APPEND _MAGNUMINTEGRATION_REASON_FAILURE_MESSAGE "${_component} is not a known component on this platform.")
# Otherwise, if it's not among implicitly built components, hint that
# the user may need to enable it
# TODO: currently, the _FOUND variable doesn't reflect if dependencies
# were found. When it will, this needs to be updated to avoid
# misleading messages.
elseif(NOT _component IN_LIST _MAGNUMINTEGRATION_IMPLICITLY_ENABLED_COMPONENTS)
string(TOUPPER ${_component} _COMPONENT)
list(APPEND _MAGNUMINTEGRATION_REASON_FAILURE_MESSAGE "${_component} is not built by default. Make sure you enabled MAGNUM_WITH_${_COMPONENT}INTEGRATION when building Magnum Integration.")
# Otherwise we have no idea. Better be silent than to print something
# misleading.
else()
endif()
endforeach()
string(REPLACE ";" " " _MAGNUMINTEGRATION_REASON_FAILURE_MESSAGE "${_MAGNUMINTEGRATION_REASON_FAILURE_MESSAGE}")
set(_MAGNUMINTEGRATION_REASON_FAILURE_MESSAGE REASON_FAILURE_MESSAGE "${_MAGNUMINTEGRATION_REASON_FAILURE_MESSAGE}")
endif()
# Remove Magnum Integration dependency module dir from CMAKE_MODULE_PATH again.
# Do it before the FPHSA call which may exit early in case of a failure.
if(_MAGNUMINTEGRATION_REMOVE_DEPENDENCY_MODULE_DIR_FROM_CMAKE_PATH)
list(REMOVE_ITEM CMAKE_MODULE_PATH ${_MAGNUMINTEGRATION_DEPENDENCY_MODULE_DIR})
unset(_MAGNUMINTEGRATION_REMOVE_DEPENDENCY_MODULE_DIR_FROM_CMAKE_PATH)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(MagnumIntegration
REQUIRED_VARS MAGNUMINTEGRATION_INCLUDE_DIR
HANDLE_COMPONENTS
${_MAGNUMINTEGRATION_REASON_FAILURE_MESSAGE})

4
resources/resources.conf Normal file
View File

@@ -0,0 +1,4 @@
group=texture-resources
[file]
filename=stone.tga

BIN
resources/stone.tga Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

View File

@@ -1,12 +1,55 @@
find_package(Magnum REQUIRED GL Sdl2Application) find_package(Corrade REQUIRED Main)
find_package(Magnum REQUIRED
GL
MeshTools
Shaders
SceneGraph
Trade
Sdl2Application)
find_package(MagnumIntegration REQUIRED ImGui)
set_directory_properties(PROPERTIES CORRADE_USE_PEDANTIC_FLAGS ON) set_directory_properties(PROPERTIES CORRADE_USE_PEDANTIC_FLAGS ON)
add_executable(${PROJECT_NAME} Chocolate.cpp) add_executable(${PROJECT_NAME} WIN32
Chocolate.h
Chocolate.cpp
Camera.h
Camera.cpp
MagnumDrawable.h
MagnumDrawable.cpp
Common.h
${PROJECT_SOURCE_DIR}/ImGuiFileDialog/ImGuiFileDialog.cpp
Components.cpp
Components.h
Scene.cpp
Scene.h
Materials.h
UI.cpp
UI.h
)
target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/ImGuiFileDialog)
add_dependencies(${PROJECT_NAME}
Magnum::AnyImageImporter
Magnum::AnySceneImporter
Magnum::ObjImporter
MagnumPlugins::StbImageImporter
MagnumPlugins::GltfImporter
)
target_link_libraries(${PROJECT_NAME} PRIVATE target_link_libraries(${PROJECT_NAME} PRIVATE
Corrade::Main
Magnum::Application Magnum::Application
Magnum::GL Magnum::GL
Magnum::Magnum) Magnum::Magnum
Magnum::MeshTools
Magnum::SceneGraph
Magnum::Shaders
Magnum::Trade
EnTT::EnTT
MagnumIntegration::ImGui
)
# Make the executable a default target to build & run in Visual Studio # Make the executable a default target to build & run in Visual Studio
set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME}) set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME})

42
src/Camera.cpp Normal file
View File

@@ -0,0 +1,42 @@
#include "Camera.h"
Camera::Camera(Scene3D& scene, const float aspectRatio, const float near, const float far)
{
_cameraObject
.setParent(&scene)
.translate(Vector3::zAxis(5.0f));
(_camera = new SceneGraph::Camera3D{_cameraObject})
->setAspectRatioPolicy(SceneGraph::AspectRatioPolicy::Extend)
.setProjectionMatrix(
Matrix4::perspectiveProjection(35.0_degf, aspectRatio, near, far)
)
.setViewport(GL::defaultFramebuffer.viewport().size());
}
void Camera::Init(Scene3D& scene, float aspectRatio, float near, float far)
{
_cameraObject
.setParent(&scene);
(_camera = new SceneGraph::Camera3D{_cameraObject})
->setAspectRatioPolicy(SceneGraph::AspectRatioPolicy::Extend)
.setProjectionMatrix(
Matrix4::perspectiveProjection(35.0_degf, aspectRatio, near, far)
)
.setViewport(GL::defaultFramebuffer.viewport().size());
}
void Camera::Draw(SceneGraph::DrawableGroup3D& _drawables) const
{
_camera->draw(_drawables);
}
void Camera::SetViewport(const Vector2i& size) const
{
_camera->setViewport(size);
}
void Camera::Translate(const Math::Vector3<Float>& vector)
{
_cameraObject.translate(vector);
}

32
src/Camera.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef CHOCOLATE_CAMERA_H
#define CHOCOLATE_CAMERA_H
#include <Magnum/SceneGraph/Camera.h>
#include <Magnum/SceneGraph/Drawable.h>
#include <Magnum/SceneGraph/MatrixTransformation3D.h>
#include <Magnum/SceneGraph/Scene.h>
#include <Magnum/GL/DefaultFramebuffer.h>
#include "Common.h"
using namespace Magnum;
using namespace Math::Literals;
class Camera
{
public:
explicit Camera(): _camera(nullptr) {}
explicit Camera(Scene3D& scene, float aspectRatio, float near, float far);
void Init(Scene3D& scene, float aspectRatio, float near, float far);
void Draw(SceneGraph::DrawableGroup3D& _drawables) const;
void SetViewport(const Vector2i& size) const;
void Translate(const Math::Vector3<Float>& vector);
private:
Object3D _cameraObject;
SceneGraph::Camera3D* _camera;
};
#endif //CHOCOLATE_CAMERA_H

View File

@@ -1,26 +1,395 @@
#include <Magnum/GL/DefaultFramebuffer.h> #include "Chocolate.h"
#include <Magnum/Platform/Sdl2Application.h> #include "MagnumDrawable.h"
#include "Components.h"
using namespace Magnum; #include <Magnum/GL/Renderbuffer.h>
#include <Magnum/GL/TextureFormat.h>
#include <Magnum/GL/RenderbufferFormat.h>
#include <Magnum/GL/Framebuffer.h>
#include <Magnum/Math/Quaternion.h>
#include <Magnum/Trade/SceneData.h>
#include <Magnum/Trade/LightData.h>
#include <imgui.h>
#include <Magnum/ImGuiIntegration/Context.hpp>
class Chocolate: public Platform::Application { #include "Magnum/ShaderTools/Stage.h"
public: #include "Magnum/Trade/ObjectData2D.h"
explicit Chocolate(const Arguments& arguments); #include <Magnum/Trade/ImageData.h>
private: Chocolate::Chocolate(const Arguments& arguments) :
void drawEvent() override; Platform::Application{
arguments, Configuration{}
.setTitle("Chocolate")
.setSize({1920, 1080})
.setWindowFlags(Configuration::WindowFlag::Resizable)
}
{
_imgui = ImGuiIntegration::Context(Vector2{windowSize()}/dpiScaling(),
windowSize(), framebufferSize());
/* Setup renderer and shader defaults */
GL::Renderer::enable(GL::Renderer::Feature::DepthTest);
GL::Renderer::enable(GL::Renderer::Feature::FaceCulling);
GL::Renderer::setBlendEquation(GL::Renderer::BlendEquation::Add,
GL::Renderer::BlendEquation::Add);
GL::Renderer::setBlendFunction(GL::Renderer::BlendFunction::SourceAlpha,
GL::Renderer::BlendFunction::OneMinusSourceAlpha);
_camera.Init(_scene, 1.f, 0.01f, 1000.f);
_camera.Translate(Vector3::zAxis(10.f));
_materials["matte_rubber"] = PhongMaterialConfig{
{ 0.02, 0.02, 0.02, 1.f},
{0.1, 0.1, 0.1, 1.f},
{0.05, 0.05, 0.05, 1.f},
2.f
}; };
Chocolate::Chocolate(const Arguments& arguments): Platform::Application{arguments} { const auto viewportSize = GL::defaultFramebuffer.viewport().size();
/* TODO: Add your initialization code here */
Vector2i renderWindowSize = {static_cast<int>(viewportSize.x() * (1 - _sidebarWidth)), viewportSize.y()};
Vector2i renderWindowPosition = {static_cast<int>(viewportSize.x() * _sidebarWidth), 0};
_uiSceneRenderer = UI::RenderWindow(renderWindowSize, renderWindowPosition);
_uiComponents.push_back(&_uiSceneRenderer);
Vector2i entityListPanelSize = {static_cast<int>(viewportSize.x() * _sidebarWidth), viewportSize.y() / 2};
Vector2i entityListPanelPosition = {0, 0};
_uiEntityListPanel = UI::EntityListPanel(entityListPanelSize, entityListPanelPosition, &_registry,
[this](const std::string& file)
{
Import(file);
},
[this](entt::entity entitySelected)
{
EntitySelected(entitySelected);
});
_uiComponents.push_back(&_uiEntityListPanel);
Vector2i entityEditorWindowSize = {static_cast<int>(viewportSize.x() * _sidebarWidth), viewportSize.y() / 2};
Vector2i entityEditorWindowPosition = {0, viewportSize.y() / 2};
_uiEntityEditorWindow = UI::EntityEditorWindow(entityEditorWindowSize, entityEditorWindowPosition, &_registry);
_uiComponents.push_back(&_uiEntityEditorWindow);
}
void Chocolate::tickEvent()
{
UpdateMagnumObjects();
} }
void Chocolate::drawEvent() { void Chocolate::drawEvent() {
GL::defaultFramebuffer.clear(GL::FramebufferClear::Color);
/* TODO: Add your drawing code here */ RenderToFramebuffer(_uiSceneRenderer.Framebuffer());
DrawUI();
swapBuffers(); swapBuffers();
redraw();
}
void Chocolate::UpdateMagnumObjects()
{
for (const auto entity : _registry.view<Components::MagnumObject>())
{
const auto obj = _registry.get<Components::MagnumObject>(entity).obj;
if (const auto transform = _registry.try_get<Components::Transform>(entity))
{
Matrix4 matrix = Matrix4::translation(transform->translation) * Matrix4{transform->rotation.toMatrix()} * Matrix4::scaling(transform->scale);
obj->setTransformation(matrix);
}
}
}
void Chocolate::viewportEvent(ViewportEvent& event) {
GL::defaultFramebuffer.setViewport({{}, event.framebufferSize()});
_camera.SetViewport(event.windowSize());
_imgui.relayout(Vector2{event.windowSize()}/event.dpiScaling(),
event.windowSize(), event.framebufferSize());
auto windowSize = event.framebufferSize();
ResizeUI(windowSize);
}
void Chocolate::pointerPressEvent(PointerEvent& event) {
_imgui.handlePointerPressEvent(event);
}
void Chocolate::pointerReleaseEvent(PointerEvent& event) {
_imgui.handlePointerReleaseEvent(event);
}
void Chocolate::pointerMoveEvent(PointerMoveEvent& event) {
_imgui.handlePointerMoveEvent(event);
}
void Chocolate::keyPressEvent(KeyEvent& event) {
if(_imgui.handleKeyPressEvent(event)) return;
}
void Chocolate::keyReleaseEvent(KeyEvent& event) {
if(_imgui.handleKeyReleaseEvent(event)) return;
}
void Chocolate::textInputEvent(TextInputEvent& event) {
if(_imgui.handleTextInputEvent(event)) return;
}
void Chocolate::RenderToFramebuffer(GL::Framebuffer& framebuffer)
{
framebuffer
.clear(GL::FramebufferClear::Color|GL::FramebufferClear::Depth)
.bind();
_camera.Draw(_drawables);
}
void Chocolate::DrawUI()
{
GL::defaultFramebuffer
.clear(GL::FramebufferClear::Color|GL::FramebufferClear::Depth)
.bind();
_imgui.newFrame();
if(ImGui::GetIO().WantTextInput && !isTextInputActive())
startTextInput();
else if(!ImGui::GetIO().WantTextInput && isTextInputActive())
stopTextInput();
for (const auto comp : _uiComponents)
{
comp->Draw();
}
/* Update application cursor */
_imgui.updateApplicationCursor(*this);
GL::Renderer::enable(GL::Renderer::Feature::Blending);
GL::Renderer::enable(GL::Renderer::Feature::ScissorTest);
GL::Renderer::disable(GL::Renderer::Feature::FaceCulling);
GL::Renderer::disable(GL::Renderer::Feature::DepthTest);
_imgui.drawFrame();
GL::Renderer::enable(GL::Renderer::Feature::DepthTest);
GL::Renderer::enable(GL::Renderer::Feature::FaceCulling);
GL::Renderer::disable(GL::Renderer::Feature::ScissorTest);
GL::Renderer::disable(GL::Renderer::Feature::Blending);
}
void Chocolate::ResizeUI(Vector2i windowSize)
{
Vector2i renderWindowSize = {static_cast<int>(windowSize.x() * (1 - _sidebarWidth)), windowSize.y()};
Vector2i renderWindowPosition = {static_cast<int>(windowSize.x() * _sidebarWidth), 0};
_uiSceneRenderer.SetPosition(renderWindowPosition);
_uiSceneRenderer.Resize(renderWindowSize);
Vector2i entityListPanelSize = {static_cast<int>(windowSize.x() * _sidebarWidth), windowSize.y()};
Vector2i entityListPanelPosition = {0, 0};
_uiEntityListPanel.SetPosition(entityListPanelPosition);
_uiEntityListPanel.Resize(entityListPanelSize);
Vector2i entityEditorWindowSize = {static_cast<int>(windowSize.x() * _sidebarWidth), windowSize.y() / 2};
Vector2i entityEditorWindowPosition = {0, windowSize.y() / 2};
_uiEntityEditorWindow.SetPosition(entityEditorWindowPosition);
_uiEntityEditorWindow.Resize(entityEditorWindowSize);
}
void Chocolate::Import(const std::string& file)
{
PluginManager::Manager<Trade::AbstractImporter> manager;
Containers::Pointer<Trade::AbstractImporter> importer =
manager.loadAndInstantiate("AnySceneImporter");
if (!importer || !importer->openFile(file))
std::exit(1);
auto sceneMeshes = Containers::Array<Containers::Optional<GL::Mesh*>>{importer->meshCount()};
for(UnsignedInt i = 0; i != importer->meshCount(); ++i) {
Containers::Optional<Trade::MeshData> meshData = importer->mesh(i);
if(!meshData) {
Warning{} << "Cannot load mesh" << i << importer->meshName(i);
sceneMeshes[i] = nullptr;
continue;
}
MeshTools::CompileFlags flags;
if(!meshData->hasAttribute(Trade::MeshAttribute::Normal))
flags |= MeshTools::CompileFlag::GenerateFlatNormals;
GL::Mesh mesh = MeshTools::compile(*meshData, flags);
_meshes.push_back(std::make_unique<GL::Mesh>(std::move(mesh)));
sceneMeshes[i] = _meshes.back().get();
}
auto sceneTextures = Containers::Array<Containers::Optional<GL::Texture2D*>>{importer->textureCount()};
for(UnsignedInt i = 0; i != importer->textureCount(); ++i) {
Containers::Optional<Trade::TextureData> textureData =
importer->texture(i);
if(!textureData || textureData->type() != Trade::TextureType::Texture2D) {
Warning{} << "Cannot load texture" << i
<< importer->textureName(i);
continue;
}
Containers::Optional<Trade::ImageData2D> imageData =
importer->image2D(textureData->image());
if(!imageData || imageData->isCompressed()) {
Warning{} << "Cannot load image" << textureData->image()
<< importer->image2DName(textureData->image());
continue;
}
_textures.push_back(std::make_unique<GL::Texture2D>(std::move(GL::Texture2D{}
.setMagnificationFilter(textureData->magnificationFilter())
.setMinificationFilter(textureData->minificationFilter(),
textureData->mipmapFilter())
.setWrapping(textureData->wrapping().xy())
.setStorage(Math::log2(imageData->size().max()) + 1,
GL::textureFormat(imageData->format()), imageData->size())
.setSubImage(0, {}, *imageData)
.generateMipmap())));
auto texture = _textures.back().get();
sceneTextures[i] = texture;
}
Containers::Array<Containers::Optional<Trade::PhongMaterialData>> materials{importer->materialCount()};
for(UnsignedInt i = 0; i != importer->materialCount(); ++i) {
Containers::Optional<Trade::MaterialData> materialData = importer->material(i);
if(!materialData) {
Warning{} << "Cannot load material" << i
<< importer->materialName(i);
continue;
}
materials[i] = std::move(*materialData).as<Trade::PhongMaterialData>();
}
if(importer->defaultScene() == -1 && !sceneMeshes.isEmpty() && sceneMeshes[0]) {
const auto& entity = _registry.create();
_registry.emplace<Components::Label>(entity);
_registry.emplace<Components::Transform>(entity);
auto& [mesh] = _registry.emplace<Components::Mesh>(entity);
mesh = *sceneMeshes[0];
auto& [shader, config, texture] = _registry.emplace<Components::Material>(entity);
shader = &_phongShader;
config = &_materials["matte_rubber"];
auto& [obj, drawable] = _registry.emplace<Components::MagnumObject>(entity);
obj = new Object3D{};
obj->setParent(&_scene);
drawable = new Rendering::Magnum::Drawable(obj, &_drawables, _registry, entity);
return;
}
Containers::Optional<Trade::SceneData> scene = importer->scene(importer->defaultScene());
if(!scene ||
!scene->is3D() ||
!scene->hasField(Trade::SceneField::Parent) ||
!scene->hasField(Trade::SceneField::Mesh))
{
Fatal{} << "Couldn't load scene" << importer->defaultScene()
<< importer->sceneName(importer->defaultScene());
}
Containers::Array<Object3D*> objects{scene->mappingBound()};
Containers::Array<Containers::Pair<UnsignedInt, Int>> parents = scene->parentsAsArray();
Containers::Array<Containers::Pair<UnsignedInt, Matrix4>> transforms = scene->transformations3DAsArray();
Containers::Array<Containers::Pair<UnsignedInt, Containers::Pair<UnsignedInt, Int>>> meshMap = scene->meshesMaterialsAsArray();
for (const auto& parent : parents)
{
objects[parent.first()] = new Object3D{};
}
for (const auto& parent : parents)
{
objects[parent.first()]->setParent(parent.second() == -1 ? &_scene : objects[parent.second()]);
}
for (const auto& transform : transforms)
{
if (auto* obj = objects[transform.first()])
{
obj->setTransformation(transform.second());
}
}
for (UnsignedInt i = 0; i != objects.size(); ++i)
{
const auto& entity = _registry.create();
_registry.emplace<Components::Label>(entity);
auto& [obj, drawable] = _registry.emplace<Components::MagnumObject>(entity);
obj = objects[i];
drawable = new Rendering::Magnum::Drawable(obj, &_drawables, _registry, entity);
auto& [translation, rotation, scale] = _registry.emplace<Components::Transform>(entity);
translation = obj->transformation().translation();
scale = obj->transformation().scaling();
rotation = Quaternion::fromMatrix(obj->transformation().rotation());
if (scene->hasFieldObject(Trade::SceneField::MeshMaterial, i))
{
auto meshMaterial = scene->meshesMaterialsFor(i)[0];
auto meshId = meshMaterial.first();
auto materialId = meshMaterial.second();
if (meshId != -1 && sceneMeshes[meshId])
{
auto& [mesh] = _registry.emplace<Components::Mesh>(entity);
mesh = *sceneMeshes[meshId];
}
auto& [shader, config, texture] = _registry.emplace<Components::Material>(entity);
shader = &_phongShader;
if (materialId == -1 || !materials[materialId])
{
config = &_materials["matte_rubber"];
}
else
{
auto& material = materials[materialId];
char buf [64] = {};
sprintf(buf, "Material_%d", materialId);
std::string materialName = buf;
if (_materials.find(materialName) == _materials.end())
{
_materials[materialName] = PhongMaterialConfig{
material->ambientColor(),
material->diffuseColor(),
material->specularColor(),
material->shininess(),
};
}
config = &_materials[materialName];
if (material->hasAttribute(Trade::MaterialAttribute::DiffuseTexture))
{
texture = *sceneTextures[material->diffuseTexture()];
}
}
}
}
}
void Chocolate::EntitySelected(entt::entity entity)
{
_uiEntityEditorWindow.SetEntity(entity);
} }
MAGNUM_APPLICATION_MAIN(Chocolate) MAGNUM_APPLICATION_MAIN(Chocolate)

100
src/Chocolate.h Normal file
View File

@@ -0,0 +1,100 @@
#ifndef CHOCOLATE_CHOCOLATE_H
#define CHOCOLATE_CHOCOLATE_H
#include <Corrade/Containers/Optional.h>
#include <Corrade/Containers/Pair.h>
#include <Corrade/PluginManager/Manager.h>
#include <Corrade/Utility/Arguments.h>
#include <Magnum/GL/Framebuffer.h>
#include <Magnum/ImageView.h>
#include <Magnum/Math/Time.h>
#include <Magnum/Mesh.h>
#include <Magnum/GL/DefaultFramebuffer.h>
#include <Magnum/GL/Mesh.h>
#include <Magnum/GL/Renderer.h>
#include <Magnum/Math/Color.h>
#include <Magnum/MeshTools/Compile.h>
#include <Magnum/Platform/Sdl2Application.h>
#include <Magnum/SceneGraph/Camera.h>
#include <Magnum/SceneGraph/Drawable.h>
#include <Magnum/SceneGraph/MatrixTransformation3D.h>
#include <Magnum/SceneGraph/Scene.h>
#include <Magnum/Shaders/PhongGL.h>
#include <Magnum/Trade/AbstractImporter.h>
#include <Magnum/Trade/MeshData.h>
#include <Magnum/Trade/PhongMaterialData.h>
#include <Magnum/Trade/TextureData.h>
#include <entt/entt.hpp>
#include <imgui.h>
#include <Magnum/ImGuiIntegration/Context.hpp>
#include "Camera.h"
#include "Materials.h"
#include "UI.h"
using namespace Magnum;
using namespace Math::Literals;
class Chocolate: public Platform::Application {
public:
virtual ~Chocolate() = default;
explicit Chocolate(const Arguments& arguments);
private:
//SDL 2 events
void drawEvent() override;
void tickEvent() override;
void viewportEvent(ViewportEvent& event) override;
void pointerPressEvent(PointerEvent& event) override;
void pointerReleaseEvent(PointerEvent& event) override;
void pointerMoveEvent(PointerMoveEvent& event) override;
void keyPressEvent(KeyEvent& event) override;
void keyReleaseEvent(KeyEvent& event) override;
void textInputEvent(TextInputEvent& event) override;
// Render
void RenderToFramebuffer(GL::Framebuffer& framebuffer);
// UI
void DrawUI();
void ResizeUI(Vector2i windowSize);
//Systems
void UpdateMagnumObjects();
// Callbacks
void Import(const std::string& file);
void EntitySelected(entt::entity entity);
//Scene
Scene3D _scene;
SceneGraph::DrawableGroup3D _drawables;
Camera _camera;
// Resources
std::vector<std::unique_ptr<GL::Mesh>> _meshes;
std::vector<std::unique_ptr<GL::Texture2D>> _textures;
std::unordered_map<std::string, PhongMaterialConfig> _materials;
Shaders::PhongGL _phongShader;
entt::registry _registry;
entt::entity selectedEntityToEdit = entt::null;
bool showEntityEditorWindow = false;
ImGuiIntegration::Context _imgui{NoCreate};
float _sidebarWidth = 0.17f;
std::vector<UI::Component*> _uiComponents;
UI::RenderWindow _uiSceneRenderer;
UI::EntityListPanel _uiEntityListPanel;
UI::EntityEditorWindow _uiEntityEditorWindow;
};
#endif //CHOCOLATE_CHOCOLATE_H

12
src/Common.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef CHOCOLATE_COMMON_H
#define CHOCOLATE_COMMON_H
#include <Magnum/SceneGraph/MatrixTransformation3D.h>
#include <Magnum/SceneGraph/Scene.h>
using namespace Magnum;
typedef SceneGraph::Object<SceneGraph::MatrixTransformation3D> Object3D;
typedef SceneGraph::Scene<SceneGraph::MatrixTransformation3D> Scene3D;
#endif //CHOCOLATE_COMMON_H

10
src/Components.cpp Normal file
View File

@@ -0,0 +1,10 @@
//
// Created by lbmas on 1/3/2026.
//
#include "Components.h"
namespace Components
{
}

60
src/Components.h Normal file
View File

@@ -0,0 +1,60 @@
#ifndef CHOCOLATE_COMPONENTS_H
#define CHOCOLATE_COMPONENTS_H
#include <Magnum/Math/Quaternion.h>
#include <Magnum/Math/Vector3.h>
#include <Magnum/GL/Mesh.h>
#include <Magnum/Math/Color.h>
#include <Magnum/Shaders/PhongGL.h>
#include "Common.h"
#include <entt/entt.hpp>
#include "MagnumDrawable.h"
#include "Materials.h"
using namespace Magnum;
namespace Components
{
struct Transform
{
Vector3 translation{0.0f, 0.0f, 0.0f};
Quaternion rotation {};
Vector3 scale{1.0f, 1.0f, 1.0f};
};
struct Mesh
{
GL::Mesh* mesh;
};
struct Material
{
Shaders::PhongGL* _shader {nullptr};
PhongMaterialConfig* phongConfig {nullptr};
GL::Texture2D* texture {nullptr};
};
struct Parent
{
entt::entity entity{entt::null};
};
struct Label
{
std::string content;
static constexpr std::size_t MAX_SIZE = 128;
};
struct MagnumObject
{
Object3D* obj {nullptr};
Rendering::Magnum::Drawable* drawable {nullptr};
};
}
#endif //CHOCOLATE_COMPONENTS_H

40
src/MagnumDrawable.cpp Normal file
View File

@@ -0,0 +1,40 @@
#include "MagnumDrawable.h"
#include <Magnum/SceneGraph/Camera.h>
#include "Components.h"
namespace Rendering::Magnum
{
void Drawable::draw(const Matrix4& transformationMatrix, SceneGraph::Camera3D& camera)
{
const auto mesh = _registry.try_get<Components::Mesh>(_entity);
if (!mesh) return;
if (const auto material = _registry.try_get<Components::Material>(_entity))
{
material->_shader->
setDiffuseColor(material->phongConfig->diffuse)
.setAmbientColor(material->phongConfig->ambient)
.setSpecularColor(material->phongConfig->specular)
.setShininess(material->phongConfig->shininess)
.setLightPositions({
{camera.cameraMatrix().transformPoint({-3.0f, 10.0f, 10.0f}), 0.0f}
})
.setTransformationMatrix(transformationMatrix)
.setNormalMatrix(transformationMatrix.normalMatrix())
.setProjectionMatrix(camera.projectionMatrix())
.draw(*mesh->mesh);
if (material->texture)
{
material->_shader->bindDiffuseTexture(*material->texture);
}
}
else
{
// TODO: Have a default rendering method
}
}
}

30
src/MagnumDrawable.h Normal file
View File

@@ -0,0 +1,30 @@
#ifndef CHOCOLATE_DRAWABLE_H
#define CHOCOLATE_DRAWABLE_H
#include <Magnum/GL/Mesh.h>
#include <Magnum/SceneGraph/Drawable.h>
#include "Common.h"
#include <entt/entt.hpp>
namespace Rendering::Magnum
{
class Drawable : public SceneGraph::Drawable3D{
public:
explicit Drawable(
Object3D* object,
SceneGraph::DrawableGroup3D* group,
entt::registry& registry,
entt::entity entity
): SceneGraph::Drawable3D{*object, group}, _registry(registry), _entity(entity) {}
private:
void draw(const Matrix4& transformationMatrix, SceneGraph::Camera3D& camera) override;
entt::registry& _registry;
entt::entity _entity;
};
}
#endif //CHOCOLATE_DRAWABLE_H

16
src/Materials.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef CHOCOLATE_MATERIALS_H
#define CHOCOLATE_MATERIALS_H
#include <Magnum/Math/Color.h>
using namespace Magnum;
struct PhongMaterialConfig
{
Color4 ambient{1.0f, 1.0f, 1.0f};
Color4 diffuse{1.0f, 1.0f, 1.0f};
Color4 specular{1.0f, 1.0f, 1.0f};
float shininess{0.0f};
};
#endif //CHOCOLATE_MATERIALS_H

5
src/Scene.cpp Normal file
View File

@@ -0,0 +1,5 @@
//
// Created by lbmas on 1/4/2026.
//
#include "Scene.h"

11
src/Scene.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef CHOCOLATE_SCENE_H
#define CHOCOLATE_SCENE_H
struct Scene
{
};
#endif //CHOCOLATE_SCENE_H

215
src/UI.cpp Normal file
View File

@@ -0,0 +1,215 @@
//
// Created by lbmas on 1/5/2026.
//
#include "UI.h"
#include "Components.h"
#include <Magnum/GL/TextureFormat.h>
#include <Magnum/GL/RenderbufferFormat.h>
#include <imgui.h>
#include <Magnum/ImGuiIntegration/Context.hpp>
#include <ImGuiFileDialog.h>
#include "SDL_stdinc.h"
namespace UI
{
// RENDER WINDOW
RenderWindow::RenderWindow() : _framebuffer(NoCreate), _size(Vector2i{}), _position(Vector2i{})
{
}
RenderWindow::RenderWindow(const Vector2i& size, const Vector2i& position) : _framebuffer({{}, size}), _size(size), _position(position)
{
_renderTexture.setStorage(1, GL::TextureFormat::RGBA8, size);
_depthStencil.setStorage(GL::RenderbufferFormat::Depth24Stencil8, size);
_framebuffer.attachTexture(GL::Framebuffer::ColorAttachment{0}, _renderTexture, 0);
_framebuffer.attachRenderbuffer(GL::Framebuffer::BufferAttachment::DepthStencil, _depthStencil);
}
GL::Framebuffer& RenderWindow::Framebuffer()
{
return _framebuffer;
}
void RenderWindow::Resize(const Vector2i& size)
{
_renderTexture.setStorage(1, GL::TextureFormat::RGBA8, size);
_depthStencil.setStorage(GL::RenderbufferFormat::Depth24Stencil8, size);
}
void RenderWindow::SetPosition(const Vector2i& position)
{
_position = position;
}
void RenderWindow::Draw()
{
ImGui::Begin("Scene Preview", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDecoration);
ImGui::SetWindowSize({static_cast<float>(_size.x()), static_cast<float>(_size.y())});
ImGui::SetWindowPos({static_cast<float>(_position.x()), static_cast<float>(_position.y())});
ImGui::Text("%.3f ms/frame (%.1f FPS)",
1000.0/Double(ImGui::GetIO().Framerate), Double(ImGui::GetIO().Framerate));
const ImTextureID textureId = _renderTexture.id();
const ImVec2 previewSize = ImGui::GetContentRegionAvail();
ImGui::Image(textureId, previewSize, ImVec2(0, 1), ImVec2(1, 0));
ImGui::End();
}
// END RENDER WINDOW
// ENTITY LIST PANEL
EntityListPanel::EntityListPanel()
: _size({0, 0}), _position({0, 0}), _reg(nullptr), _importFunc(nullptr), _entitySelectedFunc(nullptr), _selectedEntity(entt::null)
{}
EntityListPanel::EntityListPanel(Vector2i size, Vector2i position, entt::registry* reg, std::function<void(Containers::StringView)> importFunc, std::function<void(entt::entity)> entitySelectedFunc)
: _size(size), _position(position), _selectedEntity(entt::null), _reg(reg), _importFunc(std::move(importFunc)), _entitySelectedFunc(std::move(entitySelectedFunc))
{
}
void EntityListPanel::Resize(const Vector2i& size)
{
_size = size;
}
void EntityListPanel::SetPosition(const Vector2i& position)
{
_position = position;
}
void EntityListPanel::Draw()
{
ImGui::Begin("Entities", nullptr, ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse);
ImGui::SetWindowSize({(float)_size.x(), (float)_size.y()});
ImGui::SetWindowPos({(float)_position.x(), (float)_position.y()});
if (ImGui::BeginMenuBar())
{
if (ImGui::BeginMenu("File"))
{
if (ImGui::MenuItem("Open"))
{
IGFD::FileDialogConfig config;
config.path = ".";
ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Open Object File", ".obj,.glb", config);
}
ImGui::EndMenu();
}
ImGui::EndMenuBar();
}
if (ImGuiFileDialog::Instance()->Display("ChooseFileDlgKey", ImGuiWindowFlags_NoCollapse, ImVec2(800, 600))) {
if (ImGuiFileDialog::Instance()->IsOk()) {
std::string absolutePath = ImGuiFileDialog::Instance()->GetFilePathName();
Debug{} << "Opening file: " << Containers::String(absolutePath);
_importFunc(absolutePath);
}
ImGuiFileDialog::Instance()->Close();
}
if (ImGui::BeginTable("EntityTable", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
// Define columns
ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_WidthFixed, 40.0f);
ImGui::TableSetupColumn("Label");
ImGui::TableHeadersRow();
for (const auto& entity : _reg->view<entt::entity>()) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
// Create a selectable that spans the entire row
char id[32];
sprintf(id, "%u", entity);
bool isSelected = _selectedEntity == entity;
if (ImGui::Selectable(id, isSelected, ImGuiSelectableFlags_SpanAllColumns)) {
_selectedEntity = entity;
_entitySelectedFunc(_selectedEntity);
}
ImGui::TableNextColumn();
const auto* label = _reg->try_get<Components::Label>(entity);
ImGui::Text("%s", label ? label->content.data() : "");
}
ImGui::EndTable();
}
ImGui::End(); // ENTITIES
}
// END ENTITY LIST PANEL
// ENTITY EDITOR WINDOW
EntityEditorWindow::EntityEditorWindow()
: _size({0, 0}), _position({0, 0}), _reg(nullptr), _selectedEntity(entt::null)
{}
EntityEditorWindow::EntityEditorWindow(Vector2i size, Vector2i position, entt::registry* reg)
: _size(size), _position(position), _reg(reg), _selectedEntity(entt::null)
{}
void EntityEditorWindow::SetEntity(entt::entity entity)
{
_selectedEntity = entity;
}
void EntityEditorWindow::Resize(const Vector2i& size)
{
_size = size;
}
void EntityEditorWindow::SetPosition(const Vector2i& position)
{
_position = position;
}
void EntityEditorWindow::Draw()
{
ImGui::Begin("Entity Editor", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse);
ImGui::SetWindowSize({(float)_size.x(), (float)_size.y()});
ImGui::SetWindowPos({(float)_position.x(), (float)_position.y()});
if (_selectedEntity != entt::null)
{
if (auto* label = _reg->try_get<Components::Label>(_selectedEntity))
{
static char entityLabelBuffer[Components::Label::MAX_SIZE] = {};
memcpy(entityLabelBuffer, label->content.data(), label->content.size());
if (ImGui::InputText("Label", entityLabelBuffer, Components::Label::MAX_SIZE))
{
label->content = std::string(entityLabelBuffer);
}
}
if (auto* transform = _reg->try_get<Components::Transform>(_selectedEntity))
{
ImGui::SliderFloat3("Translation", transform->translation.data(), -10, 10);
ImGui::SliderFloat3("Scale", transform->scale.data(), -10, 10);
// Vector3 eulerDegrees = Vector3{transform->rotation.toEuler()} * (180.0f / M_PI);
// if (ImGui::SliderFloat3("Rotation", eulerDegrees.data(), -180.0f, 180.0f)) {
// // 3. If changed, convert Degrees -> Radians -> Quaternion
// Vector3 eulerRadians = eulerDegrees * (M_PI / 180.0f);
//
// // We recreate the quaternion from the updated Euler angles
// transform->rotation = Quaternion::rotation(Rad(eulerRadians.x()), Vector3::xAxis())
// * Quaternion::rotation(Rad(eulerRadians.y()), Vector3::yAxis())
// * Quaternion::rotation(Rad(eulerRadians.z()), Vector3::zAxis());
//}
}
}
ImGui::End();
}
// END ENTITY EDITOR WINDOW
}

89
src/UI.h Normal file
View File

@@ -0,0 +1,89 @@
//
// Created by lbmas on 1/5/2026.
//
#ifndef CHOCOLATE_UI_H
#define CHOCOLATE_UI_H
#include <Magnum/GL/Texture.h>
#include <Magnum/GL/Renderbuffer.h>
#include <Magnum/GL/Framebuffer.h>
#include <entt/entt.hpp>
#include <functional>
using namespace Magnum;
namespace UI
{
class Component
{
public:
virtual ~Component() = default;
virtual void Draw() = 0;
virtual void Resize(const Vector2i& size) = 0;
virtual void SetPosition(const Vector2i& position) = 0;
};
class RenderWindow : public Component
{
public:
RenderWindow();
RenderWindow(const Vector2i& size, const Vector2i& position);
[[nodiscard]] GL::Framebuffer& Framebuffer();
void Draw() final;
void Resize(const Vector2i& size) final;
void SetPosition(const Vector2i& position) final;
private:
GL::Texture2D _renderTexture;
GL::Renderbuffer _depthStencil;
GL::Framebuffer _framebuffer;
Vector2i _size;
Vector2i _position;
};
class EntityListPanel : public Component
{
public:
EntityListPanel();
explicit EntityListPanel(Vector2i size, Vector2i position, entt::registry* reg, std::function<void(Containers::StringView)> importFunc, std::function<void(entt::entity)> entitySelectedFunc);
void Draw() final;
void Resize(const Vector2i& size) final;
void SetPosition(const Vector2i& position) final;
private:
Vector2i _size;
Vector2i _position;
entt::registry* _reg;
std::function<void(Containers::StringView)> _importFunc;
std::function<void(entt::entity)> _entitySelectedFunc;
entt::entity _selectedEntity;
};
class EntityEditorWindow : public Component
{
public:
EntityEditorWindow();
explicit EntityEditorWindow(Vector2i size, Vector2i position, entt::registry* reg);
void SetEntity(entt::entity entity);
void Draw() final;
void Resize(const Vector2i& size) final;
void SetPosition(const Vector2i& position) final;
private:
Vector2i _size;
Vector2i _position;
entt::registry* _reg;
entt::entity _selectedEntity;
};
}
#endif //CHOCOLATE_UI_H