From 2ebac092febdd285cb1db249f2f22fbed3c03433 Mon Sep 17 00:00:00 2001 From: Patrick Dawson Date: Wed, 23 Nov 2022 06:15:09 +0100 Subject: [PATCH] WIP C++ example --- .gitignore | 4 ++ Dear ImGui for Godot Demo.csproj | 4 ++ addons/imgui-godot/ImGuiGodot/ImGuiLayer.cs | 24 ++++++++ doc/cpp-demo/.clang-format | 14 +++++ doc/cpp-demo/CMakeLists.txt | 50 ++++++++++++++++ doc/cpp-demo/CMakePresets.json | 40 +++++++++++++ doc/cpp-demo/MyGame/MyGame.csproj | 10 ++++ doc/cpp-demo/MyGame/MyGame.sln | 19 ++++++ doc/cpp-demo/MyGame/default_env.tres | 7 +++ doc/cpp-demo/MyGame/demoext.gdextension | 14 +++++ doc/cpp-demo/MyGame/icon.svg | 1 + doc/cpp-demo/MyGame/icon.svg.import | 37 ++++++++++++ doc/cpp-demo/MyGame/main.tscn | 11 ++++ doc/cpp-demo/MyGame/project.godot | 36 +++++++++++ doc/cpp-demo/README.md | 8 +++ doc/cpp-demo/src/CMakeLists.txt | 5 ++ doc/cpp-demo/src/main.cpp | 36 +++++++++++ doc/cpp-demo/src/mycppnode.cpp | 66 +++++++++++++++++++++ doc/cpp-demo/src/mycppnode.h | 27 +++++++++ doc/cpp-demo/test/test.cpp | 8 +++ doc/cpp-demo/vcpkg.json | 21 +++++++ 21 files changed, 442 insertions(+) create mode 100644 doc/cpp-demo/.clang-format create mode 100644 doc/cpp-demo/CMakeLists.txt create mode 100644 doc/cpp-demo/CMakePresets.json create mode 100644 doc/cpp-demo/MyGame/MyGame.csproj create mode 100644 doc/cpp-demo/MyGame/MyGame.sln create mode 100644 doc/cpp-demo/MyGame/default_env.tres create mode 100644 doc/cpp-demo/MyGame/demoext.gdextension create mode 100644 doc/cpp-demo/MyGame/icon.svg create mode 100644 doc/cpp-demo/MyGame/icon.svg.import create mode 100644 doc/cpp-demo/MyGame/main.tscn create mode 100644 doc/cpp-demo/MyGame/project.godot create mode 100644 doc/cpp-demo/README.md create mode 100644 doc/cpp-demo/src/CMakeLists.txt create mode 100644 doc/cpp-demo/src/main.cpp create mode 100644 doc/cpp-demo/src/mycppnode.cpp create mode 100644 doc/cpp-demo/src/mycppnode.h create mode 100644 doc/cpp-demo/test/test.cpp create mode 100644 doc/cpp-demo/vcpkg.json diff --git a/.gitignore b/.gitignore index 9e6808d..e2c1395 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,7 @@ export_presets.cfg .godot/ *.user Properties/ +build/ +build.*/ +*.dll +doc/cpp-demo/MyGame/addons/ diff --git a/Dear ImGui for Godot Demo.csproj b/Dear ImGui for Godot Demo.csproj index a62941d..c4a6c35 100644 --- a/Dear ImGui for Godot Demo.csproj +++ b/Dear ImGui for Godot Demo.csproj @@ -5,6 +5,10 @@ DearImGuiforGodotDemo True + + + + diff --git a/addons/imgui-godot/ImGuiGodot/ImGuiLayer.cs b/addons/imgui-godot/ImGuiGodot/ImGuiLayer.cs index 240d104..bc197ee 100644 --- a/addons/imgui-godot/ImGuiGodot/ImGuiLayer.cs +++ b/addons/imgui-godot/ImGuiGodot/ImGuiLayer.cs @@ -2,6 +2,7 @@ using Godot; using ImGuiNET; using System; using System.Collections.Generic; +using System.Runtime.InteropServices; namespace ImGuiGodot; @@ -229,6 +230,29 @@ public partial class ImGuiLayer : CanvasLayer } } + // WIP, this will probably be changed or moved + public unsafe Godot.Collections.Array GetImGuiPtrs(string version, int ioSize, int vertSize, int idxSize) + { + if (version != ImGui.GetVersion() || + ioSize != Marshal.SizeOf() || + vertSize != Marshal.SizeOf() || + idxSize != sizeof(ushort)) + { + throw new PlatformNotSupportedException($"ImGui version mismatch, use {ImGui.GetVersion()}-docking"); + } + + IntPtr mem_alloc = IntPtr.Zero; + IntPtr mem_free = IntPtr.Zero; + void* user_data = null; + ImGui.GetAllocatorFunctions(ref mem_alloc, ref mem_free, ref user_data); + + return new(){ + (long)ImGui.GetCurrentContext(), + (long)mem_alloc, + (long)mem_free + }; + } + private static void OnNodeRemoved(Node node) { // signals declared in C# don't (yet?) work like normal Godot signals, diff --git a/doc/cpp-demo/.clang-format b/doc/cpp-demo/.clang-format new file mode 100644 index 0000000..c6eaef4 --- /dev/null +++ b/doc/cpp-demo/.clang-format @@ -0,0 +1,14 @@ +Language: Cpp +BasedOnStyle: Microsoft +AccessModifierOffset: -4 +AllowAllArgumentsOnNextLine: false +AlignEscapedNewlines: Left +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: false +BinPackParameters: true +PointerAlignment: Left + +BreakBeforeBraces: Custom +BraceWrapping: + AfterNamespace: false + AfterExternBlock: false diff --git a/doc/cpp-demo/CMakeLists.txt b/doc/cpp-demo/CMakeLists.txt new file mode 100644 index 0000000..98bb373 --- /dev/null +++ b/doc/cpp-demo/CMakeLists.txt @@ -0,0 +1,50 @@ +cmake_minimum_required(VERSION 3.24) + +# set up vcpkg +if (WIN32) + set(VCPKG_TARGET_TRIPLET x64-windows-static-md) +endif() +file(TO_CMAKE_PATH "$ENV{VCPKG_ROOT}" VCPKG_ROOT) +set(CMAKE_TOOLCHAIN_FILE "${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake") + +project(demoext CXX) + +if (NOT TARGET godot-cpp) + include(FetchContent) + FetchContent_Declare( + godot-cpp + GIT_REPOSITORY https://github.com/godotengine/godot-cpp + GIT_TAG master # watch out, something will break eventually + ) + FetchContent_MakeAvailable(godot-cpp) +endif() + +find_package(imgui CONFIG REQUIRED) +find_package(implot CONFIG REQUIRED) +find_package(freetype CONFIG REQUIRED) +find_package(GTest CONFIG REQUIRED) + +add_library(demoext SHARED) +add_subdirectory(src) + +target_link_libraries(demoext PUBLIC + godot-cpp + imgui::imgui + freetype + implot::implot + ) +target_include_directories(demoext PRIVATE src) +target_compile_features(demoext PRIVATE cxx_std_20) +target_compile_definitions(demoext PUBLIC IMGUI_DISABLE_INCLUDE_IMCONFIG_H) + +set_property(TARGET demoext PROPERTY OUTPUT_NAME "demoext.$,debug,release>") + +install(TARGETS demoext RUNTIME DESTINATION bin) + +enable_testing() +add_executable(demotest test/test.cpp) +target_include_directories(demotest PRIVATE src) +target_link_libraries(demotest PRIVATE GTest::gtest_main demoext) + +include(GoogleTest) +gtest_discover_tests(demotest) diff --git a/doc/cpp-demo/CMakePresets.json b/doc/cpp-demo/CMakePresets.json new file mode 100644 index 0000000..ead05cb --- /dev/null +++ b/doc/cpp-demo/CMakePresets.json @@ -0,0 +1,40 @@ +{ + "version": 1, + "cmakeMinimumRequired": { + "major": 3, + "minor": 20, + "patch": 0 + }, + "configurePresets": [ + { + "name": "debug", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build.debug", + "cacheVariables": { + "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", + "CMAKE_INSTALL_PREFIX": "MyGame", + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "release", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build.release", + "cacheVariables": { + "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", + "CMAKE_INSTALL_PREFIX": "MyGame", + "CMAKE_BUILD_TYPE": "RelWithDebInfo", + "CMAKE_INTERPROCEDURAL_OPTIMIZATION": "ON" + } + }, + { + "name": "msvc", + "generator": "Visual Studio 17 2022", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", + "CMAKE_INSTALL_PREFIX": "MyGame" + } + } + ] +} \ No newline at end of file diff --git a/doc/cpp-demo/MyGame/MyGame.csproj b/doc/cpp-demo/MyGame/MyGame.csproj new file mode 100644 index 0000000..67ed622 --- /dev/null +++ b/doc/cpp-demo/MyGame/MyGame.csproj @@ -0,0 +1,10 @@ + + + net6.0 + true + True + + + + + \ No newline at end of file diff --git a/doc/cpp-demo/MyGame/MyGame.sln b/doc/cpp-demo/MyGame/MyGame.sln new file mode 100644 index 0000000..07b6668 --- /dev/null +++ b/doc/cpp-demo/MyGame/MyGame.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyGame", "MyGame.csproj", "{3FFFFA7D-AD43-4770-AE3F-2BA38FF919E4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + ExportDebug|Any CPU = ExportDebug|Any CPU + ExportRelease|Any CPU = ExportRelease|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3FFFFA7D-AD43-4770-AE3F-2BA38FF919E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3FFFFA7D-AD43-4770-AE3F-2BA38FF919E4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3FFFFA7D-AD43-4770-AE3F-2BA38FF919E4}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU + {3FFFFA7D-AD43-4770-AE3F-2BA38FF919E4}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU + {3FFFFA7D-AD43-4770-AE3F-2BA38FF919E4}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU + {3FFFFA7D-AD43-4770-AE3F-2BA38FF919E4}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU + EndGlobalSection +EndGlobal diff --git a/doc/cpp-demo/MyGame/default_env.tres b/doc/cpp-demo/MyGame/default_env.tres new file mode 100644 index 0000000..0645b88 --- /dev/null +++ b/doc/cpp-demo/MyGame/default_env.tres @@ -0,0 +1,7 @@ +[gd_resource type="Environment" load_steps=2 format=3 uid="uid://dtd3q2x2ulcsi"] + +[sub_resource type="Sky" id="1"] + +[resource] +background_mode = 2 +sky = SubResource("1") diff --git a/doc/cpp-demo/MyGame/demoext.gdextension b/doc/cpp-demo/MyGame/demoext.gdextension new file mode 100644 index 0000000..beef10c --- /dev/null +++ b/doc/cpp-demo/MyGame/demoext.gdextension @@ -0,0 +1,14 @@ +[configuration] + +entry_symbol = "demoext_init" + +[libraries] + +macos.debug = "res://bin/demoext.debug.framework" +macos.release = "res://bin/demoext.release.framework" +windows.debug.x86_64 = "res://bin/demoext.debug.dll" +windows.release.x86_64 = "res://bin/demoext.release.dll" +linux.debug.x86_64 = "res://bin/demoext.debug.so" +linux.release.x86_64 = "res://bin/demoext.release.so" +linux.debug.arm64 = "res://bin/demoext.debug.so" +linux.release.arm64 = "res://bin/demoext.release.so" diff --git a/doc/cpp-demo/MyGame/icon.svg b/doc/cpp-demo/MyGame/icon.svg new file mode 100644 index 0000000..adc26df --- /dev/null +++ b/doc/cpp-demo/MyGame/icon.svg @@ -0,0 +1 @@ + diff --git a/doc/cpp-demo/MyGame/icon.svg.import b/doc/cpp-demo/MyGame/icon.svg.import new file mode 100644 index 0000000..a43c953 --- /dev/null +++ b/doc/cpp-demo/MyGame/icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d08m2uvixtsgf" +path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.svg" +dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/bptc_ldr=0 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/doc/cpp-demo/MyGame/main.tscn b/doc/cpp-demo/MyGame/main.tscn new file mode 100644 index 0000000..cf383cd --- /dev/null +++ b/doc/cpp-demo/MyGame/main.tscn @@ -0,0 +1,11 @@ +[gd_scene format=3 uid="uid://d02ytucir7qh2"] + +[node name="Control" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="MyCppNode" type="MyCppNode" parent="."] diff --git a/doc/cpp-demo/MyGame/project.godot b/doc/cpp-demo/MyGame/project.godot new file mode 100644 index 0000000..02f9404 --- /dev/null +++ b/doc/cpp-demo/MyGame/project.godot @@ -0,0 +1,36 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=5 + +[application] + +config/name="MyGame" +run/main_scene="res://main.tscn" +config/features=PackedStringArray("4.0", "C#") +config/icon="res://icon.svg" + +[autoload] + +ImGuiLayer="*res://addons/imgui-godot/ImGuiLayer.tscn" + +[dotnet] + +project/assembly_name="MyGame" + +[editor_plugins] + +enabled=PackedStringArray("res://addons/imgui-godot/plugin.cfg") + +[native_extensions] + +paths=["res://demoext.gdextension"] + +[rendering] + +environment/defaults/default_environment="res://default_env.tres" diff --git a/doc/cpp-demo/README.md b/doc/cpp-demo/README.md new file mode 100644 index 0000000..02e4ced --- /dev/null +++ b/doc/cpp-demo/README.md @@ -0,0 +1,8 @@ + +A sample GDExtension using ImGui with a context from imgui-godot. Uses vcpkg and CMake for easy setup and fast builds. + +``` +cmake --preset msvc + +cmake --build build --target install --config Debug +``` diff --git a/doc/cpp-demo/src/CMakeLists.txt b/doc/cpp-demo/src/CMakeLists.txt new file mode 100644 index 0000000..fc1c2e3 --- /dev/null +++ b/doc/cpp-demo/src/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(demoext PRIVATE + main.cpp + mycppnode.cpp + mycppnode.h +) diff --git a/doc/cpp-demo/src/main.cpp b/doc/cpp-demo/src/main.cpp new file mode 100644 index 0000000..30f73b5 --- /dev/null +++ b/doc/cpp-demo/src/main.cpp @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include + +using namespace godot; + +void initialize_demo_module(ModuleInitializationLevel p_level) +{ + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) + return; + + ClassDB::register_class(); +} + +void uninitialize_demo_module(ModuleInitializationLevel p_level) +{ + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) + return; +} + +extern "C" { +GDNativeBool GDN_EXPORT demoext_init(const GDNativeInterface* p_interface, + const GDNativeExtensionClassLibraryPtr p_library, + GDNativeInitialization* r_initialization) +{ + godot::GDExtensionBinding::InitObject init_obj(p_interface, p_library, r_initialization); + + init_obj.register_initializer(initialize_demo_module); + init_obj.register_terminator(uninitialize_demo_module); + init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE); + + return init_obj.init(); +} +} diff --git a/doc/cpp-demo/src/mycppnode.cpp b/doc/cpp-demo/src/mycppnode.cpp new file mode 100644 index 0000000..e8087f9 --- /dev/null +++ b/doc/cpp-demo/src/mycppnode.cpp @@ -0,0 +1,66 @@ +#include "mycppnode.h" +#include +#include +#include +#include +#include +using namespace godot; + +struct MyCppNode::Impl +{ +}; + +MyCppNode::MyCppNode() : impl(std::make_unique()) +{ +} + +MyCppNode::~MyCppNode() +{ +} + +void MyCppNode::_bind_methods() +{ +} + +void MyCppNode::_ready() +{ + // TODO: don't run in editor mode + set_process(false); + Node* igl = get_node_or_null("/root/ImGuiLayer"); + if (!igl) + return; + + godot::Array imgui_ptrs = igl->call( + "GetImGuiPtrs", + ImGui::GetVersion(), + sizeof(ImGuiIO), + sizeof(ImDrawVert), + sizeof(ImDrawIdx) + ); + + if (imgui_ptrs.size() < 3) + return; + + int64_t ctx = imgui_ptrs[0]; + int64_t mem_alloc = imgui_ptrs[1]; + int64_t mem_free = imgui_ptrs[2]; + + ImGui::SetCurrentContext((ImGuiContext*)ctx); + ImGui::SetAllocatorFunctions((ImGuiMemAllocFunc)mem_alloc, (ImGuiMemFreeFunc)mem_free); + ImPlot::CreateContext(); + set_process(true); +} + +void MyCppNode::_exit_tree() +{ + ImPlot::DestroyContext(); +} + +void MyCppNode::_process(double delta) +{ + ImPlot::ShowDemoWindow(); + + ImGui::Begin("Cpp Window"); + ImGui::Text("hello from C++"); + ImGui::End(); +} diff --git a/doc/cpp-demo/src/mycppnode.h b/doc/cpp-demo/src/mycppnode.h new file mode 100644 index 0000000..a0e5f90 --- /dev/null +++ b/doc/cpp-demo/src/mycppnode.h @@ -0,0 +1,27 @@ +#pragma once +#include +#include + +using godot::Node; +using godot::InputEvent; +using godot::Ref; + +class MyCppNode : public Node +{ + GDCLASS(MyCppNode, Node); + +protected: + static void _bind_methods(); + +public: + void _ready() override; + void _exit_tree() override; + void _process(double delta) override; + + MyCppNode(); + ~MyCppNode(); + +private: + struct Impl; + std::unique_ptr impl; +}; diff --git a/doc/cpp-demo/test/test.cpp b/doc/cpp-demo/test/test.cpp new file mode 100644 index 0000000..80ca8e9 --- /dev/null +++ b/doc/cpp-demo/test/test.cpp @@ -0,0 +1,8 @@ +#include +#include +#include + +TEST(SomethingTest, DoAThing) +{ + ASSERT_TRUE(true); +} diff --git a/doc/cpp-demo/vcpkg.json b/doc/cpp-demo/vcpkg.json new file mode 100644 index 0000000..b2ee4d4 --- /dev/null +++ b/doc/cpp-demo/vcpkg.json @@ -0,0 +1,21 @@ +{ + "dependencies": [ + { + "name": "imgui", + "features": [ + "docking-experimental", + "freetype" + ] + }, + "implot", + "imguizmo", + "gtest" + ], + "builtin-baseline": "6f7ffeb18f99796233b958aaaf14ec7bd4fb64b2", + "overrides": [ + { + "name": "imgui", + "version": "1.88" + } + ] +} \ No newline at end of file