From 319795c4c98ff5abe2a708d27c03331848564c90 Mon Sep 17 00:00:00 2001 From: Nyx Date: Tue, 6 May 2025 23:52:04 -0600 Subject: [PATCH] updated godot-cpp --- .clang-format | 112 +++++++++ .github/workflows/main.yml | 96 ++++++++ .gitignore | 4 + .gitmodules | 6 + .vscode/extensions.json | 6 + .vscode/godot.natvis | 210 ++++++++++++++++ .vscode/launch.json | 35 +++ .vscode/tasks.json | 17 ++ CHANGELOG.md | 48 ++++ CMakeLists.txt | 164 +++++++++++++ CMakePresets.json | 100 ++++++++ LICENSE.md | 24 ++ README.md | 173 +++++++++++++ cmake/ClangFormat.cmake | 32 +++ cmake/CompilerWarnings.cmake | 115 +++++++++ cmake/GetGitRevisionDescription.cmake | 284 ++++++++++++++++++++++ cmake/GetGitRevisionDescription.cmake.in | 43 ++++ cmake/GitVersionInfo.cmake | 46 ++++ cmake/ccache.cmake | 22 ++ extern/godot-cpp | 1 + extern/steam-audio | 1 + src/CMakeLists.txt | 13 + src/Version.h.in | 45 ++++ src/register_types.cpp | 30 +++ src/register_types.h | 20 ++ src/steam_audio.cpp | 32 +++ src/steam_audio.h | 26 ++ support_files/icons/Example.svg | 1 + templates/CMakeLists.txt | 41 ++++ templates/template.debug.gdextension.in | 11 + templates/template.release.gdextension.in | 11 + 31 files changed, 1769 insertions(+) create mode 100644 .clang-format create mode 100644 .github/workflows/main.yml create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 .vscode/extensions.json create mode 100644 .vscode/godot.natvis create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json create mode 100644 CHANGELOG.md create mode 100644 CMakeLists.txt create mode 100644 CMakePresets.json create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 cmake/ClangFormat.cmake create mode 100644 cmake/CompilerWarnings.cmake create mode 100644 cmake/GetGitRevisionDescription.cmake create mode 100644 cmake/GetGitRevisionDescription.cmake.in create mode 100644 cmake/GitVersionInfo.cmake create mode 100644 cmake/ccache.cmake create mode 160000 extern/godot-cpp create mode 160000 extern/steam-audio create mode 100644 src/CMakeLists.txt create mode 100644 src/Version.h.in create mode 100644 src/register_types.cpp create mode 100644 src/register_types.h create mode 100644 src/steam_audio.cpp create mode 100644 src/steam_audio.h create mode 100644 support_files/icons/Example.svg create mode 100644 templates/CMakeLists.txt create mode 100644 templates/template.debug.gdextension.in create mode 100644 templates/template.release.gdextension.in diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..7692847 --- /dev/null +++ b/.clang-format @@ -0,0 +1,112 @@ +# Options are listed here: +# https://clang.llvm.org/docs/ClangFormatStyleOptions.html +--- +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +BinPackArguments: true +BinPackParameters: true +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: AfterColon +BreakStringLiterals: true +ColumnLimit: 100 +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: false +DeriveLineEnding: false +DerivePointerAlignment: false +EmptyLineBeforeAccessModifier: LogicalBlock +EmptyLineAfterAccessModifier: Never +FixNamespaceComments: false +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + - Regex: '.*' + Priority: 1 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 4 +IndentWrappedFunctionNames: true +InsertBraces: true +KeepEmptyLinesAtTheStartOfBlocks: true +Language: Cpp +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: All +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 1000 +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: true +SpacesInSquareBrackets: false +Standard: c++17 +TabWidth: 4 +UseCRLF: false +UseTab: Never diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..bc30879 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,96 @@ +name: Main + +on: + push: + paths-ignore: + - '.gitignore' + - '*.md' + +jobs: + lint: + name: ๐Ÿงน Lint / ๐Ÿ“œ C++ + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Run clang-format style check + uses: jidicula/clang-format-action@v4.9.0 + with: + clang-format-version: '15' + exclude-regex: 'extern' + + build: + strategy: + fail-fast: false + matrix: + build_type: ['Debug', 'Release'] + config: + - { name: '๐Ÿ macOS Clang', os: macos-latest } + - { name: '๐Ÿง Linux GCC', os: ubuntu-latest } + - { name: '๐ŸชŸ Windows MSVC', os: windows-latest } + + name: ๐Ÿ›  Build / ${{ matrix.config.name }} (${{ matrix.build_type }}) + runs-on: ${{ matrix.config.os }} + + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Install Dependencies (macOS) + if: matrix.config.os == 'macos-latest' + run: brew install ccache ninja + + - name: Install Dependencies (Linux) + if: matrix.config.os == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y ccache ninja-build + + - name: Install Dependencies (Windows) + if: matrix.config.os == 'windows-latest' + run: | + choco upgrade ccache ninja + + - name: Setup MSVC (Windows) + if: matrix.config.os == 'windows-latest' + uses: ilammy/msvc-dev-cmd@v1 + + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + max-size: '10G' + key: ${{ matrix.config.os }}-${{ matrix.build_type }} + + - name: Configure + run: > + mkdir GDExtension-build + + cmake + -B GDExtension-build + -G "Ninja" + -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + --install-prefix ${{ github.workspace }}/install-${{ matrix.build_type }} + . + + - name: Build + run: cmake --build GDExtension-build + + - name: Install + run: cmake --install GDExtension-build + + - name: Upload artifact (Debug) + if: matrix.build_type == 'Debug' + uses: actions/upload-artifact@v3 + with: + name: ${{ github.event.repository.name }}-Debug + path: | + ${{ github.workspace }}/install-${{ matrix.build_type }}/* + + - name: Upload artifact (Release) + if: matrix.build_type == 'Release' + uses: actions/upload-artifact@v3 + with: + name: ${{ github.event.repository.name }}-Release + path: | + ${{ github.workspace }}/install-${{ matrix.build_type }}/* diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2590049 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +CMakeLists.txt.user +.vscode/settings.json +.idea/ +cmake-build-debug/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..b02245d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "extern/godot-cpp"] + path = extern/godot-cpp + url = https://github.com/godotengine/godot-cpp.git +[submodule "extern/steam-audio"] + path = extern/steam-audio + url = https://github.com/ValveSoftware/steam-audio diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..a4ef25e --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "ms-vscode.cpptools-extension-pack", + "ms-vscode.cmake-tools" + ] +} \ No newline at end of file diff --git a/.vscode/godot.natvis b/.vscode/godot.natvis new file mode 100644 index 0000000..36b0919 --- /dev/null +++ b/.vscode/godot.natvis @@ -0,0 +1,210 @@ + + + + + _cowdata._ptr ? (((const unsigned int *)(_cowdata._ptr))[-1]) : 0 + + _cowdata._ptr ? (((const unsigned int *)(_cowdata._ptr))[-1]) : 0 + _cowdata._ptr + + + + + + + count + + count + data + + + + + + + _data ? (_data->size_cache) : 0 + + _data ? (_data->size_cache) : 0 + _data->first + next_ptr + value + + + + + + + num_elements + + num_elements + head_element + next + data + + + + + + + *(reinterpret_cast<int*>(_cowdata._ptr) - 1) + + *(reinterpret_cast<int*>(_cowdata._ptr) - 1) + reinterpret_cast<VMap<$T1,$T2>::Pair*>(_cowdata._ptr) + + + + + + {dynamic_cast<CallableCustomMethodPointerBase*>(key.custom)->text} + + + + + + nil + {_data._bool} + {_data._int} + {_data._float} + {_data._transform2d} + {_data._aabb} + {_data._basis} + {_data._transform3d} + {_data._projection} + {*(String *)_data._mem} + {*(Vector2 *)_data._mem} + {*(Rect2 *)_data._mem} + {*(Vector3 *)_data._mem} + {*(Vector4 *)_data._mem} + {*(Plane *)_data._mem} + {*(Quaternion *)_data._mem} + {*(Color *)_data._mem} + {*(NodePath *)_data._mem} + {*(::RID *)_data._mem} + {*(Object *)_data._mem} + {*(Dictionary *)_data._mem} + {*(Array *)_data._mem} + {reinterpret_cast<const Variant::PackedArrayRef<unsigned char>*>(_data.packed_array)->array} + {reinterpret_cast<const Variant::PackedArrayRef<int>*>(_data.packed_array)->array} + + {reinterpret_cast<const Variant::PackedArrayRef<float>*>(_data.packed_array)->array} + {reinterpret_cast<const Variant::PackedArrayRef<double>*>(_data.packed_array)->array} + {reinterpret_cast<const Variant::PackedArrayRef<String>*>(_data.packed_array)->array} + {reinterpret_cast<const Variant::PackedArrayRef<Vector2>*>(_data.packed_array)->array} + {reinterpret_cast<const Variant::PackedArrayRef<Vector3>*>(_data.packed_array)->array} + {reinterpret_cast<const Variant::PackedArrayRef<Color>*>(_data.packed_array)->array} + + ((String *)(_data._mem))->_cowdata._ptr,s32 + + + _data._bool + _data._int + _data._float + _data._transform2d + _data._aabb + _data._basis + _data._transform3d + *(String *)_data._mem + *(Vector2 *)_data._mem + *(Rect2 *)_data._mem + *(Vector3 *)_data._mem + *(Plane *)_data._mem + *(Quaternion *)_data._mem + *(Color *)_data._mem + *(NodePath *)_data._mem + *(::RID *)_data._mem + *(Object *)_data._mem + *(Dictionary *)_data._mem + *(Array *)_data._mem + reinterpret_cast<const Variant::PackedArrayRef<unsigned char>*>(_data.packed_array)->array + *(PackedInt32Array *)_data._mem + *(PackedInt64Array *)_data._mem + *(PackedFloat32Array *)_data._mem + *(PackedFloat64Array *)_data._mem + *(PackedStringArray *)_data._mem + *(PackedVector2Array *)_data._mem + *(PackedVector3Array *)_data._mem + *(PackedColorArray *)_data._mem + + + + + [empty] + {_cowdata._ptr,s32} + _cowdata._ptr,s32 + + + + {*reinterpret_cast<void**>(opaque),s32} + + *reinterpret_cast<void**>(opaque) + *reinterpret_cast<void**>(opaque),s32 + + + + + {_data->cname} + {_data->name,s32} + [empty] + _data->cname + _data->name,s32 + + + + + {(*reinterpret_cast<const char***>(opaque))[1],s8} + {(*reinterpret_cast<const char***>(opaque))[2],s32} + + *reinterpret_cast<void**>(opaque) + (*reinterpret_cast<const char***>(opaque))+1 + (*reinterpret_cast<const char***>(opaque))[1],s8 + + + + + "{user.name}" {slot_map} + "{slot_map} + + + + {{{x},{y}}} + + x + y + + + + + {{{x},{y},{z}}} + + x + y + z + + + + + Quaternion {{{x},{y},{z},{w}}} + + x + y + z + w + + + + + Color {{{r},{g},{b},{a}}} + + r + g + b + a + + + diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..c67b99c --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,35 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Windows Launch", + "type": "cppvsdbg", + "request": "launch", + "program": "${command:cmake.launchTargetPath}", + "args": [], + "cwd": "${command:cmake.buildDirectory}/bin", + "preLaunchTask": "CMake: build", + "internalConsoleOptions": "openOnSessionStart", + "console": "internalConsole", + "environment": [ + { + "name": "Path", + "value": "${env:Path};" + } + ], + "visualizerFile": "${workspaceFolder}/.vscode/godot.natvis" + }, + { + "name": "macOS/Linux Launch", + "type": "lldb", + "request": "launch", + "program": "${command:cmake.launchTargetPath}", + "args": [], + "cwd": "${command:cmake.buildDirectory}/bin", + "visualizerFile": "${workspaceFolder}/.vscode/godot.natvis" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..e9182cd --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,17 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "cmake", + "label": "CMake: build", + "command": "build", + "targets": [ + "all" + ], + "preset": "${command:cmake.activeBuildPresetName}", + "group": "build", + "problemMatcher": [], + "detail": "CMake template build task" + } + ] +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9508cd4 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,48 @@ +# Changelog + +All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 4.2 - 2023-12-16 + +### New + +- Add CMake preset and VSCode support ([#61](https://github.com/asmaloney/GDExtensionTemplate/pull/61)) + +### Changed + +- Updated example code ([#63](https://github.com/asmaloney/GDExtensionTemplate/pull/63)) +- Updated bindings for Godot 4.1 ([#62](https://github.com/asmaloney/GDExtensionTemplate/pull/62)) + +## 4.1 - 2023-07-06 + +### Changed + +- Updated bindings, updated initialization code, and added compatibility in .gdextensions for Godot 4.1 ([#56](https://github.com/asmaloney/GDExtensionTemplate/pull/56)) + +## 4.0.3 - 2023-05-22 + +### Changed + +- Updated bindings for Godot 4.0.3 ([#53](https://github.com/asmaloney/GDExtensionTemplate/pull/53)) + +## 4.0.2 - 2023-04-04 + +### Changed + +- Updated bindings for Godot 4.0.2 ([#52](https://github.com/asmaloney/GDExtensionTemplate/pull/52)) + +## 4.0.1 - 2023-03-25 + +### Changed + +- Updated bindings for Godot 4.0.1 ([#50](https://github.com/asmaloney/GDExtensionTemplate/pull/50)) + +### Fixed + +- {cmake} Don't override the debug posfix if CMAKE_DEBUG_POSTFIX defined. ([#51](https://github.com/asmaloney/GDExtensionTemplate/pull/51)) + +## 4.0 - 2023-03-01 + +### Changed + +- Updated bindings for Godot 4.0 ([#49](https://github.com/asmaloney/GDExtensionTemplate/pull/49)) diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..9aac251 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,164 @@ +# SPDX-License-Identifier: Unlicense + +cmake_minimum_required( VERSION 3.22 ) + +message( STATUS "Using CMake ${CMAKE_VERSION}" ) + +# Require out-of-source builds +file( TO_CMAKE_PATH "${PROJECT_BINARY_DIR}/CMakeLists.txt" LOC_PATH ) + +if ( EXISTS "${LOC_PATH}" ) + message( FATAL_ERROR "You cannot build in the source directory. Please use a build subdirectory." ) +endif() + +# Add paths to modules +list( APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) + +# Turn on link time optimization for everything +set( CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON ) + +# Output compile commands to compile_commands.json (for debugging CMake issues) +set( CMAKE_EXPORT_COMPILE_COMMANDS ON ) + +# Build universal lib on macOS +# Note that CMAKE_OSX_ARCHITECTURES must be set before project(). +if ( APPLE ) + set( CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "" ) +endif() + +# Main project information +project( SteamAudioGodot + LANGUAGES + CXX + VERSION + 0.1.0 +) + +# Create our library +add_library( ${PROJECT_NAME} SHARED ) + + +target_compile_features( ${PROJECT_NAME} + PRIVATE + cxx_std_17 +) + +# LIB_ARCH is the architecture being built. It is set to the build system's architecture. +# For macOS, we build a universal library (both arm64 and x86_64). +set( LIB_ARCH ${CMAKE_SYSTEM_PROCESSOR} ) +if ( APPLE ) + set( LIB_ARCH "universal" ) +endif() + +# LIB_DIR is where the actual library ends up. This is used in both the build directory and the +# install directory and needs to be consistent with the paths in the gdextension file. +# e.g. linux.release.x86_64 = "lib/Linux-x86_64/libGDExtensionTemplate.so" +set( LIB_DIR "lib/${CMAKE_SYSTEM_NAME}-${LIB_ARCH}" ) + +message( STATUS "Building ${PROJECT_NAME} for ${LIB_ARCH} on ${CMAKE_SYSTEM_NAME}") + +# BUILD_OUTPUT_DIR is where we put the resulting library (in the build directory) +set( BUILD_OUTPUT_DIR "${PROJECT_BINARY_DIR}/${PROJECT_NAME}/" ) + +set_target_properties( ${PROJECT_NAME} + PROPERTIES + CXX_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN true + RUNTIME_OUTPUT_DIRECTORY "${BUILD_OUTPUT_DIR}/${LIB_DIR}" + LIBRARY_OUTPUT_DIRECTORY "${BUILD_OUTPUT_DIR}/${LIB_DIR}" +) + +if( NOT DEFINED CMAKE_DEBUG_POSTFIX ) + set_target_properties( ${PROJECT_NAME} + PROPERTIES + DEBUG_POSTFIX "-d" + ) +endif() + +# Copy over additional files from the support_files directory +add_custom_command( + TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + "${CMAKE_SOURCE_DIR}/support_files" + ${BUILD_OUTPUT_DIR} +) + +# Warnings +include( CompilerWarnings ) + +# Create and include version info file from git +include( GitVersionInfo ) + +add_subdirectory( src ) + +set(STEAMAUDIO_SDK_ROOT "${CMAKE_SOURCE_DIR}/extern/steam-audio") + +target_include_directories(${PROJECT_NAME} + PRIVATE + ${STEAMAUDIO_SDK_ROOT}/include + ${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-cpp/include + ${CMAKE_CURRENT_SOURCE_DIR}/src +) + +# Install library, extension file, and support files in ${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME} +set( INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/" ) + +message( STATUS "Install directory: ${INSTALL_DIR}") + +install( TARGETS ${PROJECT_NAME} + LIBRARY + DESTINATION ${INSTALL_DIR}/${LIB_DIR} + RUNTIME + DESTINATION ${INSTALL_DIR}/${LIB_DIR} +) + +# Copy over support files +install( DIRECTORY "${CMAKE_SOURCE_DIR}/support_files/" + DESTINATION ${INSTALL_DIR} + PATTERN ".*" EXCLUDE +) + +add_subdirectory( templates ) + +# ccache +# Turns on ccache if found +include( ccache ) + +# Formatting +# Adds a custom target to format all the code at once +include( ClangFormat ) + +# godot-cpp +# From here: https://github.com/godotengine/godot-cpp +if ( NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/extern/godot-cpp/Makefile" ) + message( + FATAL_ERROR + "[${PROJECT_NAME}] The godot-cpp submodule was not downloaded. Please update submodules: git submodule update --init --recursive." + ) +endif() + +set( GODOT_CPP_SYSTEM_HEADERS ON CACHE BOOL "" FORCE ) + +add_subdirectory( extern/godot-cpp ) + +set_target_properties( godot-cpp + PROPERTIES + CXX_VISIBILITY_PRESET hidden # visibility needs to be the same as the main library +) + +target_link_libraries( ${PROJECT_NAME} + PRIVATE + godot-cpp + phonon +) + +target_link_directories(${PROJECT_NAME} + PRIVATE + ${STEAMAUDIO_SDK_ROOT}/lib/windows-x64 +) + +add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${STEAMAUDIO_SDK_ROOT}/lib/windows-x64/phonon.dll" + "$" +) \ No newline at end of file diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..23b36b2 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,100 @@ +{ + "version": 5, + "cmakeMinimumRequired": { + "major": 3, + "minor": 23, + "patch": 0 + }, + "configurePresets": [ + { + "name": "default", + "displayName": "default", + "description": "Default preset that are inherited by all", + "generator": "Ninja", + "hidden": true, + "environment": { + "PROJECT_NAME": "MyGodotExtention" + } + }, + { + "name": "windows-debug", + "displayName": "64bit Windows Debug", + "inherits": "default", + "binaryDir": "${sourceDir}/../build_${env:PROJECT_NAME}_Windows-AMD64", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + }, + "toolset": { + "value": "host=x64", + "strategy": "external" + }, + "architecture": { + "value": "x64", + "strategy": "external" + }, + "cacheVariables": { + "CMAKE_C_COMPILER": "cl.exe", + "CMAKE_CXX_COMPILER": "cl.exe", + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "windows-release", + "displayName": "64bit Windows Release", + "inherits": "windows-debug", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "linux-debug", + "displayName": "64bit Linux Debug", + "inherits": "default", + "binaryDir": "${sourceDir}/../build_${env:PROJECT_NAME}_Linux-x86_64", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Linux" + }, + "cacheVariables": { + "CMAKE_CXX_COMPILER": "g++", + "CMAKE_C_COMPILER": "gcc", + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "linux-release", + "displayName": "64bit Linux Release", + "inherits": "linux-debug", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "macOS-debug", + "displayName": "64bit macOS Debug", + "inherits": "default", + "binaryDir": "${sourceDir}/../build_${env:PROJECT_NAME}_Darwin-Universal", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Darwin" + }, + "cacheVariables": { + "CMAKE_CXX_COMPILER": "clang++", + "CMAKE_C_COMPILER": "clang", + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "macOS-release", + "displayName": "64bit macOS Release", + "inherits": "macOS-debug", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + } + ] +} diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..68a49da --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +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 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. + +For more information, please refer to diff --git a/README.md b/README.md new file mode 100644 index 0000000..80a8cc4 --- /dev/null +++ b/README.md @@ -0,0 +1,173 @@ +[![GitHub](https://img.shields.io/github/license/asmaloney/GDExtensionTemplate)](LICENSE) ![Build](https://github.com/asmaloney/GDExtensionTemplate/actions/workflows/main.yml/badge.svg) + +# GDExtensionTemplate + +This project is meant as a starting point for creating new C++/CMake-based Godot 4 extensions. The goal is to lower the barrier to entry to building a GDExtension using [CMake](https://cmake.org). + +It is currently set up to work with the **[Godot 4.2](https://github.com/godotengine/godot/releases/tag/4.2-stable)** release (see [tags](https://github.com/asmaloney/GDExtensionTemplate/tags) for previous versions). + +Since the majority of C++ open source projects use CMake, I wanted to offer an alternative to the _scons_ system for building Godot extensions (if you use _scons_, check out Nathan Franke's [gdextension](https://github.com/nathanfranke/gdextension) template or Patrick's [GDExtensionSummator](https://github.com/paddy-exe/GDExtensionSummator) template). + +> **Note:** This project is not meant to be a dependency. It is intended to be copied (not forked) and made into your own project. Git itself doesn't provide a nice way to do this (as far as I can tell), but GitHub provides a **Use this template** button (beside where you clone a repo). This will [create a copy for you](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-repository-from-a-template) without all the history. + +## Features + +This template project sets up a lot of the build details so you can get started and focus on your code: + +- includes **[godot-cpp](https://github.com/godotengine/godot-cpp) as a submodule** and links it statically to your shared library +- creates `.gdextension` files based on your project name +- copies over any support files from the `support_files` directory into your extension directory +- includes example of adding custom icons to your classes/nodes ([see below](#custom-node-icons)) +- automatically generates a _**Version.h**_ header file which: + - includes a preprocessor macro for conditional compilation + ```cpp + #if GDEXTENSIONTEMPLATE_VERSION < GDEXTENSIONTEMPLATE_VERSION_CHECK(2, 1, 0) + // do stuff + #endif + ``` + - includes git information in the version strings (e.g. `GDExtensionTemplate v1.0.1-gf6446f8`) + - includes an example which exposes the version string to GDScript so you can call it like this + ```py + print( GDExtensionTemplate.version() ) + ``` + - keeps itself up-to-date when the git branch/tag/HEAD changes +- uses **[ccache](https://ccache.dev/)** (if available) for faster rebuilds +- builds **universal library** (x86_64 and arm64) on macOS +- provides **cmake targets**: + - _install_: install all files with the correct structure to `CMAKE_INSTALL_PREFIX` + - _clang-format_: runs `clang-format` on all sources +- includes **GitHub workflows** (CI) for: + - building the extension on **Linux x86_64** (gcc), **macOS universal** (clang), and **Windows x86_64** (MSVC) + - generating debug & release packages on each commit + - using `ccache` to improve CI build times when available + - checking code formatting using `clang-format` + +## Prerequisites + +To use this locally on your machine, you will need the following: + +- **[CMake](https://cmake.org/)** v3.22+ +- C++ Compiler with at least **C++17** support (any recent compiler) +- (optional) **[ccache](https://ccache.dev/)** for faster rebuilds +- (optional) **[clang-format](https://clang.llvm.org/docs/ClangFormat.html)** for linting and automatic code formatting (CI uses clang-format version 15) + +The GitHub actions (CI) are set up to include all of these tools. To see how to download them on your platform, take a look at the [workflow](.github/workflows/main.yml) file. + +## How To Use + +### Setup + +To use this for your own project: + +- _copy_ this repository and rename the directory to the name of your extension + > GitHub provides a **Use this template** button (beside where you clone a repo). This will [create a copy for you](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-repository-from-a-template) without all the history. +- in _CMakeLists.txt_, change `GDExtensionTemplate` in the `project` macro to the name of your extension + ```cmake + project( + LANGUAGES + CXX + VERSION + 0.1.0 + ) + ``` + If you also have plain C files in your project, add `C` to the languages. +- replace the example code in `src` with your own (I would suggest keeping _RegisterExtension.cpp_ and using it to register your classes) + > **Note:** If you change the entry symbol (`GDExtensionInit`) in _RegisterExtension.cpp_, you will need to update your `templates/*.gdextension.in` files. +- replace `CHANGELOG.md` with your own (I would encourage adhering to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) and the use of [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ) +- replace this `README.md` with your own +- replace custom node icon ([see below](#custom-node-icons)) + +Optional: + +- [contribute to the project](#how-to-contribute) (it's not just ๐Ÿ’ฐ!) +- change the platforms/architectures you want to support: + - edit the gdextension templates (`templates/*.gdextension.in`) + - change the GitHub workflows to build the right stuff +- change the `.clang-format` config file to fit your C++ style ([option documentation](https://clang.llvm.org/docs/ClangFormatStyleOptions.html)) +- change the compiler warnings you want to enforce (see [CompilerWarnings.cmake](cmake/CompilerWarnings.cmake)) +- change the LICENSE + +### Custom Node Icons + +I have included a custom icon for the `Example` node (icon is [CC0](https://creativecommons.org/public-domain/cc0/) from [SVGRepo](https://www.svgrepo.com/svg/207485/gardening-autumn)), so you will want to remove or modify it for your own classes/nodes. + +The icon itself is in `support_files/icons` it is referenced in the `templates/*.gdextension.in` files. + +To add an icon for your custom node: + +- add the icon file to `support_files/icons` and name it after your node (e.g. `MyNode.svg`) +- in each of the `templates/*.gdextension.in` files add an entry for your node in the `[icons]` section: + ``` + MyNode = "icons/MyNode.svg" + ``` + +Everything in the `support_files` directory is copied into your extension, so if you don't want to use icons, remove that directory and remove the `[icons]` section from the `templates/*.gdextension.in` files. + +### Build & Install + +Here's an example of how to build & install a release version (use the terminal to run the following commands in the parent directory of this repo): + +#### Not MSVC + +```sh +$ cmake -B GDExtensionTemplate-build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=GDExtensionTemplate-install GDExtensionTemplate +$ cmake --build GDExtensionTemplate-build --parallel +$ cmake --install GDExtensionTemplate-build +``` + +#### MSVC + +```sh +$ cmake -B GDExtensionTemplate-build -G"Visual Studio 17 2022" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=GDExtensionTemplate-install GDExtensionTemplate +$ cmake --build GDExtensionTemplate-build --config Release +$ cmake --install GDExtensionTemplate-build +``` + +This tells CMake to use `Visual Studio 2022`. There is a list of Visual Studio generators [on the CMake site](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#visual-studio-generators) - pick the one you are using. + +### Cmake Options + +This template defines the following additional CMake options: + +| Option | Description | Default | +| ------------------------------------------------------------------------ | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------- | +| `CCACHE_PROGRAM` | Path to `ccache` for faster rebuilds | This is automatically set **ON** if `ccache` is found. If you do not want to use it, set this to "". | +| `CLANG_FORMAT_PROGRAM` | Path to `clang-format` for code formatting. | This is automatically set **ON** if `clang-format` is on. If you do not want to use it, set this to "". | +| `${PROJECT_NAME_UPPERCASE}_WARN_EVERYTHING` (e.g. FOO_WARN_EVERYTHING) | Turns on all warnings. (Not available for MSVC.) | **OFF** (too noisy, but can be useful sometimes) | +| `${PROJECT_NAME_UPPERCASE}_WARNING_AS_ERROR` (e.g. FOO_WARNING_AS_ERROR) | Turns warnings into errors. | **ON** | + +## Ongoing Updates + +Once your project is up and running you might want to keep up with newer versions of Godot & godot-cpp. + +The key thing is that the version of _godot-cpp_ must match the version of Godot you are using (see the [godot-cpp Versioning section](https://github.com/godotengine/godot-cpp#versioning)). So if you want to use _Godot 4.0 stable_, then you need to match that with the [correct tag in godot-cpp](https://github.com/godotengine/godot-cpp/tags). + +Once you know the correct version of godot-cpp, change the submodule (_extern/godot-cpp_) in your extension to point at that version. + +Updating the submodule and making any necessary changes to your code due to changes in the API are the only things you need to pin to a specific version of Godot. + +## How To Contribute + +These are some of the things you can do to contribute to the project: + +### โœ Write About The Project + +If you find the project useful, spread the word! Articles, mastodon posts, tweets, blog posts, instagram photos - whatever you're into. + +### โญ๏ธ Add a Star + +If you found this project useful, please consider starring it! It helps me gauge how useful this project is. + +### โ˜ Raise Issues + +If you run into something which doesn't work as expected, raising [an issue](https://github.com/asmaloney/GDExtensionTemplate/issues) with all the relevant information to reproduce it would be helpful. + +### ๐Ÿž Bug Fixes & ๐Ÿงช New Things + +I am happy to review any [pull requests](https://github.com/asmaloney/GDExtensionTemplate/pulls). Please keep them as short as possible. Each pull request should be atomic and only address one issue. This helps with the review process. + +Note that I will not accept everything, but I welcome discussion. If you are proposing a big change, please raise it as [an issue](https://github.com/asmaloney/GDExtensionTemplate/issues) first for discussion. + +### ๐Ÿ’ฐ Financial + +Given that I'm an independent developer without funding, financial support is always appreciated. If you would like to support the project financially, you can use [GitHub sponsors](https://github.com/sponsors/asmaloney) or [Ko-fi](https://ko-fi.com/asmaloney) for one-off or recurring support. Thank you! diff --git a/cmake/ClangFormat.cmake b/cmake/ClangFormat.cmake new file mode 100644 index 0000000..a6eb8a0 --- /dev/null +++ b/cmake/ClangFormat.cmake @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: Unlicense + +find_program( CLANG_FORMAT_PROGRAM NAMES clang-format ) + +if ( CLANG_FORMAT_PROGRAM ) + # get version information + execute_process( + COMMAND "${CLANG_FORMAT_PROGRAM}" --version + OUTPUT_VARIABLE CLANG_FORMAT_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + message( STATUS "Using clang-format: ${CLANG_FORMAT_PROGRAM} (${CLANG_FORMAT_VERSION})" ) + + get_target_property( CLANG_FORMAT_SOURCES ${PROJECT_NAME} SOURCES ) + + # Remove some files from the list + list( FILTER CLANG_FORMAT_SOURCES EXCLUDE REGEX ".*/extern/.*" ) + list( FILTER CLANG_FORMAT_SOURCES EXCLUDE REGEX ".*/gen/.*" ) + list( FILTER CLANG_FORMAT_SOURCES EXCLUDE REGEX ".*/*.gdextension.in" ) + list( FILTER CLANG_FORMAT_SOURCES EXCLUDE REGEX ".*/Version.h.in" ) + + add_custom_target( clang-format + COMMAND "${CLANG_FORMAT_PROGRAM}" --style=file -i ${CLANG_FORMAT_SOURCES} + COMMENT "Running clang-format..." + COMMAND_EXPAND_LISTS + VERBATIM + ) + + unset( CLANG_FORMAT_VERSION ) + unset( CLANG_FORMAT_SOURCES ) +endif() diff --git a/cmake/CompilerWarnings.cmake b/cmake/CompilerWarnings.cmake new file mode 100644 index 0000000..bee0550 --- /dev/null +++ b/cmake/CompilerWarnings.cmake @@ -0,0 +1,115 @@ +# SPDX-License-Identifier: Unlicense +# by Andy Maloney + +string( TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPERCASE ) + +if ( NOT MSVC ) + option( ${PROJECT_NAME_UPPERCASE}_WARN_EVERYTHING "Turn on all warnings (not recommended - used for lib development)" OFF ) +endif() + +option( ${PROJECT_NAME_UPPERCASE}_WARNING_AS_ERROR "Treat warnings as errors" ON ) + +# Add warnings based on compiler +# Set some helper variables for readability +set( compiler_is_clang "$,$>" ) +set( compiler_is_gnu "$" ) +set( compiler_is_msvc "$" ) + +target_compile_options( ${PROJECT_NAME} + PRIVATE + # MSVC only + $<${compiler_is_msvc}: + /W4 + + /w14263 # 'function': member function does not override any base class virtual member function + /w14296 # 'operator': expression is always 'boolean_value' + /w14311 # 'variable': pointer truncation from 'type1' to 'type2' + /w14545 # expression before comma evaluates to a function which is missing an argument list + /w14546 # function call before comma missing argument list + /w14547 # 'operator': operator before comma has no effect; expected operator with side-effect + /w14549 # 'operator': operator before comma has no effect; did you intend 'operator'? + /w14619 # pragma warning: there is no warning number 'number' + /w14640 # thread un-safe static member initialization + /w14905 # wide string literal cast to 'LPSTR' + /w14906 # string literal cast to 'LPWSTR' + + # Disable warnings which bleed through from godot-cpp's macros. + /wd4100 # unreferenced formal parameter + > + + # Clang and GNU + $<$: + -Wall + -Wcast-align + -Wctor-dtor-privacy + -Wextra + -Wformat=2 + -Wnon-virtual-dtor + -Wnull-dereference + -Woverloaded-virtual + -Wpedantic + -Wshadow + -Wunused + -Wwrite-strings + + # Disable warnings which bleed through from godot-cpp's macros. + -Wno-unused-parameter + > + + # Clang only + $<${compiler_is_clang}: + -Wdocumentation + -Wimplicit-fallthrough + > + + # GNU only + $<${compiler_is_gnu}: + -Walloc-zero + -Wduplicated-branches + -Wduplicated-cond + -Wlogical-op + > +) + +# Turn on (almost) all warnings on Clang, Apple Clang, and GNU. +# Useful for internal development, but too noisy for general development. +function( set_warn_everything ) + message( STATUS "[${PROJECT_NAME}] Turning on (almost) all warnings") + + target_compile_options( ${PROJECT_NAME} + PRIVATE + # Clang and GNU + $<$: + -Weverything + -Wno-c++98-compat + -Wno-c++98-compat-pedantic + -Wno-padded + > + ) +endfunction() + +if ( NOT MSVC AND ${PROJECT_NAME_UPPERCASE}_WARN_EVERYTHING ) + set_warn_everything() +endif() + +# Treat warnings as errors +function( set_warning_as_error ) + message( STATUS "[${PROJECT_NAME}] Treating warnings as errors") + + if ( CMAKE_VERSION VERSION_GREATER_EQUAL "3.24" ) + set_target_properties( ${PROJECT_NAME} + PROPERTIES + COMPILE_WARNING_AS_ERROR ON + ) + else() + target_compile_options( ${PROJECT_NAME} + PRIVATE + $<${compiler_is_msvc}:/WX> + $<$:-Werror> + ) + endif() +endfunction() + +if ( ${PROJECT_NAME_UPPERCASE}_WARNING_AS_ERROR ) + set_warning_as_error() +endif() diff --git a/cmake/GetGitRevisionDescription.cmake b/cmake/GetGitRevisionDescription.cmake new file mode 100644 index 0000000..4fbd90d --- /dev/null +++ b/cmake/GetGitRevisionDescription.cmake @@ -0,0 +1,284 @@ +# - Returns a version string from Git +# +# These functions force a re-configure on each git commit so that you can +# trust the values of the variables in your build system. +# +# get_git_head_revision( [ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR]) +# +# Returns the refspec and sha hash of the current head revision +# +# git_describe( [ ...]) +# +# Returns the results of git describe on the source tree, and adjusting +# the output so that it tests false if an error occurs. +# +# git_describe_working_tree( [ ...]) +# +# Returns the results of git describe on the working tree (--dirty option), +# and adjusting the output so that it tests false if an error occurs. +# +# git_get_exact_tag( [ ...]) +# +# Returns the results of git describe --exact-match on the source tree, +# and adjusting the output so that it tests false if there was no exact +# matching tag. +# +# git_local_changes() +# +# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes. +# Uses the return code of "git diff-index --quiet HEAD --". +# Does not regard untracked files. +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2020 Ryan Pavlik +# http://academic.cleardefinition.com +# +# Copyright 2009-2013, Iowa State University. +# Copyright 2013-2020, Ryan Pavlik +# Copyright 2013-2020, Contributors +# SPDX-License-Identifier: BSL-1.0 +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +if(__get_git_revision_description) + return() +endif() +set(__get_git_revision_description YES) + +# We must run the following at "include" time, not at function call time, +# to find the path to this module rather than the path to a calling list file +get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) + +# Function _git_find_closest_git_dir finds the next closest .git directory +# that is part of any directory in the path defined by _start_dir. +# The result is returned in the parent scope variable whose name is passed +# as variable _git_dir_var. If no .git directory can be found, the +# function returns an empty string via _git_dir_var. +# +# Example: Given a path C:/bla/foo/bar and assuming C:/bla/.git exists and +# neither foo nor bar contain a file/directory .git. This wil return +# C:/bla/.git +# +function(_git_find_closest_git_dir _start_dir _git_dir_var) + set(cur_dir "${_start_dir}") + set(git_dir "${_start_dir}/.git") + while(NOT EXISTS "${git_dir}") + # .git dir not found, search parent directories + set(git_previous_parent "${cur_dir}") + get_filename_component(cur_dir "${cur_dir}" DIRECTORY) + if(cur_dir STREQUAL git_previous_parent) + # We have reached the root directory, we are not in git + set(${_git_dir_var} + "" + PARENT_SCOPE) + return() + endif() + set(git_dir "${cur_dir}/.git") + endwhile() + set(${_git_dir_var} + "${git_dir}" + PARENT_SCOPE) +endfunction() + +function(get_git_head_revision _refspecvar _hashvar) + _git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR) + + if("${ARGN}" STREQUAL "ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR") + set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR TRUE) + else() + set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR FALSE) + endif() + if(NOT "${GIT_DIR}" STREQUAL "") + file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_SOURCE_DIR}" + "${GIT_DIR}") + if("${_relative_to_source_dir}" MATCHES "[.][.]" AND NOT ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR) + # We've gone above the CMake root dir. + set(GIT_DIR "") + endif() + endif() + if("${GIT_DIR}" STREQUAL "") + set(${_refspecvar} + "GITDIR-NOTFOUND" + PARENT_SCOPE) + set(${_hashvar} + "GITDIR-NOTFOUND" + PARENT_SCOPE) + return() + endif() + + # Check if the current source dir is a git submodule or a worktree. + # In both cases .git is a file instead of a directory. + # + if(NOT IS_DIRECTORY ${GIT_DIR}) + # The following git command will return a non empty string that + # points to the super project working tree if the current + # source dir is inside a git submodule. + # Otherwise the command will return an empty string. + # + execute_process( + COMMAND "${GIT_EXECUTABLE}" rev-parse + --show-superproject-working-tree + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + OUTPUT_VARIABLE out + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT "${out}" STREQUAL "") + # If out is empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule + file(READ ${GIT_DIR} submodule) + string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE + ${submodule}) + string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE) + get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH) + get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} + ABSOLUTE) + set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD") + else() + # GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree + file(READ ${GIT_DIR} worktree_ref) + # The .git directory contains a path to the worktree information directory + # inside the parent git repo of the worktree. + # + string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir + ${worktree_ref}) + string(STRIP ${git_worktree_dir} git_worktree_dir) + _git_find_closest_git_dir("${git_worktree_dir}" GIT_DIR) + set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD") + endif() + else() + set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD") + endif() + set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") + if(NOT EXISTS "${GIT_DATA}") + file(MAKE_DIRECTORY "${GIT_DATA}") + endif() + + if(NOT EXISTS "${HEAD_SOURCE_FILE}") + return() + endif() + set(HEAD_FILE "${GIT_DATA}/HEAD") + configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY) + + configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" + "${GIT_DATA}/grabRef.cmake" @ONLY) + include("${GIT_DATA}/grabRef.cmake") + + set(${_refspecvar} + "${HEAD_REF}" + PARENT_SCOPE) + set(${_hashvar} + "${HEAD_HASH}" + PARENT_SCOPE) +endfunction() + +function(git_describe _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + get_git_head_revision(refspec hash) + if(NOT GIT_FOUND) + set(${_var} + "GIT-NOTFOUND" + PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_var} + "HEAD-HASH-NOTFOUND" + PARENT_SCOPE) + return() + endif() + + # TODO sanitize + #if((${ARGN}" MATCHES "&&") OR + # (ARGN MATCHES "||") OR + # (ARGN MATCHES "\\;")) + # message("Please report the following error to the project!") + # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") + #endif() + + #message(STATUS "Arguments to execute_process: ${ARGN}") + + execute_process( + COMMAND "${GIT_EXECUTABLE}" describe --tags --always ${hash} ${ARGN} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE res + OUTPUT_VARIABLE out + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT res EQUAL 0) + set(out "${out}-${res}-NOTFOUND") + endif() + + set(${_var} + "${out}" + PARENT_SCOPE) +endfunction() + +function(git_describe_working_tree _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + if(NOT GIT_FOUND) + set(${_var} + "GIT-NOTFOUND" + PARENT_SCOPE) + return() + endif() + + execute_process( + COMMAND "${GIT_EXECUTABLE}" describe --dirty ${ARGN} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE res + OUTPUT_VARIABLE out + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT res EQUAL 0) + set(out "${out}-${res}-NOTFOUND") + endif() + + set(${_var} + "${out}" + PARENT_SCOPE) +endfunction() + +function(git_get_exact_tag _var) + git_describe(out --exact-match ${ARGN}) + set(${_var} + "${out}" + PARENT_SCOPE) +endfunction() + +function(git_local_changes _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + get_git_head_revision(refspec hash) + if(NOT GIT_FOUND) + set(${_var} + "GIT-NOTFOUND" + PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_var} + "HEAD-HASH-NOTFOUND" + PARENT_SCOPE) + return() + endif() + + execute_process( + COMMAND "${GIT_EXECUTABLE}" diff-index --quiet HEAD -- + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE res + OUTPUT_VARIABLE out + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + if(res EQUAL 0) + set(${_var} + "CLEAN" + PARENT_SCOPE) + else() + set(${_var} + "DIRTY" + PARENT_SCOPE) + endif() +endfunction() diff --git a/cmake/GetGitRevisionDescription.cmake.in b/cmake/GetGitRevisionDescription.cmake.in new file mode 100644 index 0000000..116efc4 --- /dev/null +++ b/cmake/GetGitRevisionDescription.cmake.in @@ -0,0 +1,43 @@ +# +# Internal file for GetGitRevisionDescription.cmake +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright 2009-2012, Iowa State University +# Copyright 2011-2015, Contributors +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +# SPDX-License-Identifier: BSL-1.0 + +set(HEAD_HASH) + +file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) + +string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) +if(HEAD_CONTENTS MATCHES "ref") + # named branch + string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") + if(EXISTS "@GIT_DIR@/${HEAD_REF}") + configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) + else() + configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY) + file(READ "@GIT_DATA@/packed-refs" PACKED_REFS) + if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}") + set(HEAD_HASH "${CMAKE_MATCH_1}") + endif() + endif() +else() + # detached HEAD + configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) +endif() + +if(NOT HEAD_HASH) + file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) + string(STRIP "${HEAD_HASH}" HEAD_HASH) +endif() diff --git a/cmake/GitVersionInfo.cmake b/cmake/GitVersionInfo.cmake new file mode 100644 index 0000000..c1285ab --- /dev/null +++ b/cmake/GitVersionInfo.cmake @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: Unlicense + +find_program( GIT_PROGRAM git ) + +if ( GIT_PROGRAM ) + # get version information + execute_process( + COMMAND "${GIT_PROGRAM}" --version + OUTPUT_VARIABLE GIT_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + message( STATUS "Using git: ${GIT_PROGRAM} (${GIT_VERSION})" ) + + include( GetGitRevisionDescription ) + + get_git_head_revision( GIT_REFSPEC GIT_SHA1 ) + git_describe( GIT_SHORT ) + + string( TOUPPER ${PROJECT_NAME} UPPER_PROJECT_NAME ) + + set( VERSION_INPUT_FILE "src/Version.h.in" ) + set( VERSION_OUTPUT_FILE "${CMAKE_BINARY_DIR}/gen/Version.h" ) + + configure_file( "${VERSION_INPUT_FILE}" "${VERSION_OUTPUT_FILE}" ) + + target_sources( ${PROJECT_NAME} + PRIVATE + "${VERSION_INPUT_FILE}" + "${VERSION_OUTPUT_FILE}" + ) + + get_filename_component( VERSION_OUTPUT_FILE_DIR ${VERSION_OUTPUT_FILE} DIRECTORY ) + + target_include_directories( ${PROJECT_NAME} + PRIVATE + ${VERSION_OUTPUT_FILE_DIR} + ) + + message( STATUS "${PROJECT_NAME} version: ${GIT_SHORT}" ) + + unset( VERSION_INPUT_FILE ) + unset( VERSION_OUTPUT_FILE ) + unset( VERSION_OUTPUT_FILE_DIR ) + unset( GIT_VERSION ) +endif() diff --git a/cmake/ccache.cmake b/cmake/ccache.cmake new file mode 100644 index 0000000..4bb5661 --- /dev/null +++ b/cmake/ccache.cmake @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: Unlicense + +# See: https://crascit.com/2016/04/09/using-ccache-with-cmake/ +find_program( CCACHE_PROGRAM ccache ) + +if ( CCACHE_PROGRAM ) + # get version information + execute_process( + COMMAND "${CCACHE_PROGRAM}" --version + OUTPUT_VARIABLE CCACHE_VERSION + ) + + string( REGEX MATCH "[^\r\n]*" CCACHE_VERSION ${CCACHE_VERSION} ) + + message( STATUS "Using ccache: ${CCACHE_PROGRAM} (${CCACHE_VERSION})" ) + + # Turn on ccache for all targets + set( CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}" ) + set( CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}" ) + + unset( CCACHE_VERSION ) +endif() diff --git a/extern/godot-cpp b/extern/godot-cpp new file mode 160000 index 0000000..e4b7c25 --- /dev/null +++ b/extern/godot-cpp @@ -0,0 +1 @@ +Subproject commit e4b7c25e721ce3435a029087e3917a30aa73f06b diff --git a/extern/steam-audio b/extern/steam-audio new file mode 160000 index 0000000..eba1798 --- /dev/null +++ b/extern/steam-audio @@ -0,0 +1 @@ +Subproject commit eba1798c11b9b3bf0cf2c9cca91c6e9d7bec782e diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..33f0f3f --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Unlicense + +target_sources( ${PROJECT_NAME} + PRIVATE + register_types.cpp + register_types.h + +) + +target_include_directories( ${PROJECT_NAME} + PRIVATE + "src" +) diff --git a/src/Version.h.in b/src/Version.h.in new file mode 100644 index 0000000..10a5243 --- /dev/null +++ b/src/Version.h.in @@ -0,0 +1,45 @@ +#pragma once +// This file is generated by cmake. Changes will be overwritten. +// clang-format off + +#include + +// Creates a version number for use in macro comparisons. +// +// Example: +// +// // Check if the version is less than 2.1.0 +// #if ${UPPER_PROJECT_NAME}_VERSION < ${UPPER_PROJECT_NAME}_VERSION_CHECK(2, 1, 0) +// // do stuff +// #endif +// +// Returns an integer which may be used in comparisons +#define ${UPPER_PROJECT_NAME}_VERSION_CHECK( major, minor, patch ) ( ((major)<<16) | ((minor)<<8) | (patch) ) + +#define ${UPPER_PROJECT_NAME}_VERSION_MAJOR ${PROJECT_VERSION_MAJOR} +#define ${UPPER_PROJECT_NAME}_VERSION_MINOR ${PROJECT_VERSION_MINOR} +#define ${UPPER_PROJECT_NAME}_VERSION_PATCH ${PROJECT_VERSION_PATCH} + +// The version number of this extension. Used for #if comparisons. +// This is generated using the version set in the CMake project macro. +#define ${UPPER_PROJECT_NAME}_VERSION ${UPPER_PROJECT_NAME}_VERSION_CHECK( ${PROJECT_VERSION_MAJOR}, ${PROJECT_VERSION_MINOR}, ${PROJECT_VERSION_PATCH} ) + +namespace VersionInfo { + // Project name and version as a string. + // This is generated using the project name from the cmake project macro and the current git commit information. + // + // It uses the form " -<# commits since last tag>-". + // If there are no commits since the last tag, only the tag is shown. + constexpr std::string_view VERSION_STR = "${PROJECT_NAME} ${GIT_SHORT}"; + + // The version information as a string. + // This is generated using the current git commit information. + // + // It uses the form "-<# commits since last tag>-". + // If there are no commits since the last tag, only the tag is shown. + constexpr std::string_view VERSION_SHORT_STR = "${GIT_SHORT}"; + + // The full git SHA1 hash as a string. + // This is generated using the current git commit information. + constexpr std::string_view GIT_SHA1_STR = "${GIT_SHA1}"; +} diff --git a/src/register_types.cpp b/src/register_types.cpp new file mode 100644 index 0000000..9b73df0 --- /dev/null +++ b/src/register_types.cpp @@ -0,0 +1,30 @@ +๏ปฟ// src/register_types.cpp +#include "register_types.h" +#include "steam_audio.h" // your SteamAudio class declaration + +using namespace godot; + +void register_steam_audio_types() { + ClassDB::register_class(); +} + +extern "C" GDE_EXPORT GDExtensionBool godot_steam_audio_init( + GDExtensionInterfaceGetProcAddress p_get_proc_address, + GDExtensionClassLibraryPtr p_library, + GDExtensionInitialization *p_initialization +) { + // Create the InitObject that drives registration. + GDExtensionBinding::InitObject init_obj{ p_get_proc_address, p_library, p_initialization }; + + // 1) Hook up your initializer + init_obj.register_initializer( register_steam_audio_types ); + + // 2) Hook up your terminator (must match the expected callback signature) + init_obj.register_terminator( [](ModuleInitializationLevel level) {} ); + + // 3) Choose the minimum init level (common choices: SCENE, EDITOR, etc.) + init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE); + + // 4) Actually perform the registrations + return init_obj.init(); +} diff --git a/src/register_types.h b/src/register_types.h new file mode 100644 index 0000000..b498ed4 --- /dev/null +++ b/src/register_types.h @@ -0,0 +1,20 @@ +๏ปฟ// +// Created by bryce on 5/7/2025. +// +#pragma once + +#include +#include +#include // for ClassDB + +using namespace godot; + +// Called by the InitObject below to register your SteamAudio class. +void register_steam_audio_types(); + +// This is the exact symbol Godot will look up in your DLL. +extern "C" GDE_EXPORT GDExtensionBool godot_steam_audio_init( + GDExtensionInterfaceGetProcAddress p_get_proc_address, + GDExtensionClassLibraryPtr p_library, + GDExtensionInitialization *p_initialization +); \ No newline at end of file diff --git a/src/steam_audio.cpp b/src/steam_audio.cpp new file mode 100644 index 0000000..7cc928f --- /dev/null +++ b/src/steam_audio.cpp @@ -0,0 +1,32 @@ +๏ปฟ// +// Created by bryce on 5/7/2025. +// + +#include "steam_audio.h" + +using namespace godot; + + SteamAudio::~SteamAudio() +{ + if (context) + { + steam_audio_release_context(context); + context=nullptr; + } +} +void SteamAudio::_bind_methods() +{ + ClassDB::bind_method(D_METHOD("initialize"), &SteamAudio::initialize); +} +bool SteamAudio::initialize() + { + IPLContextSettings settings{}; + settings.version = STEAMAUDIO_VERSION; + + if ( IPLerror err = iplContextCreate( &settings, &context ); err != IPL_STATUS_SUCCESS) + { + UtilityFunctions::printerr("SteamAudio::initialize()", err); + return false; + } + return true; + } \ No newline at end of file diff --git a/src/steam_audio.h b/src/steam_audio.h new file mode 100644 index 0000000..bc4c5f5 --- /dev/null +++ b/src/steam_audio.h @@ -0,0 +1,26 @@ +๏ปฟ// +// Created by bryce on 5/7/2025. +// + +#pragma once + +#include +#include +#include +#include +#include + +using namespace godot; + +class SteamAudio : RefCounted +{ + GDCLASS( SteamAudio,RefCounted ); + private: + IPLContext context = nullptr; + protected: + static void _bind_methods(); + public: + SteamAudio(); + ~SteamAudio(); + bool initialize(); +}; \ No newline at end of file diff --git a/support_files/icons/Example.svg b/support_files/icons/Example.svg new file mode 100644 index 0000000..ab503da --- /dev/null +++ b/support_files/icons/Example.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/CMakeLists.txt b/templates/CMakeLists.txt new file mode 100644 index 0000000..5467db0 --- /dev/null +++ b/templates/CMakeLists.txt @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: Unlicense + +add_custom_target( templates + SOURCES + template.debug.gdextension.in + template.release.gdextension.in +) + +add_dependencies( ${PROJECT_NAME} templates ) + +# We shouldn't be relying on CMAKE_BUILD_TYPE (see https://github.com/asmaloney/GDExtensionTemplate/issues/25) +# But until we fix it here and in godot-cpp, ensure it's one we expect. +set ( ALLOWED_BUILDS "Debug;Release" ) +if ( NOT "${CMAKE_BUILD_TYPE}" IN_LIST ALLOWED_BUILDS ) + message( FATAL_ERROR "CMAKE_BUILD_TYPE must be set to Debug or Release" ) +endif() + +# Get our gdextension input file name based on build type +string( TOLOWER ${CMAKE_BUILD_TYPE} BUILD_TYPE ) +set( GD_EXTENSION_FILE_INPUT template.${BUILD_TYPE}.gdextension.in ) + +# Workaround to add the "lib" prefix to the library in our template file if using MSYS2. +if ( MINGW ) + set( LIB_PREFIX "lib") +endif() + +# Generate our project's .gdextension file from the template +set( GD_EXTENSION_FILE ${PROJECT_NAME}.gdextension ) +configure_file( ${GD_EXTENSION_FILE_INPUT} ${PROJECT_BINARY_DIR}/${PROJECT_NAME}/${GD_EXTENSION_FILE} ) + +# Install the gdextension file from the build directory +install( + FILES ${BUILD_OUTPUT_DIR}/${GD_EXTENSION_FILE} + DESTINATION ${INSTALL_DIR} +) + +unset( ALLOWED_BUILDS ) +unset( BUILD_TYPE ) +unset( GD_EXTENSION_FILE ) +unset( GD_EXTENSION_FILE_INPUT ) +unset( LIB_PREFIX ) diff --git a/templates/template.debug.gdextension.in b/templates/template.debug.gdextension.in new file mode 100644 index 0000000..42c0811 --- /dev/null +++ b/templates/template.debug.gdextension.in @@ -0,0 +1,11 @@ +[configuration] +entry_symbol = "GDExtensionInit" +compatibility_minimum = 4.1 + +[icons] +Example = "icons/Example.svg" + +[libraries] +linux.debug.x86_64 = "lib/Linux-x86_64/lib${PROJECT_NAME}-d.so" +macos.debug = "lib/Darwin-Universal/lib${PROJECT_NAME}-d.dylib" +windows.debug.x86_64 = "lib/Windows-AMD64/${LIB_PREFIX}${PROJECT_NAME}-d.dll" diff --git a/templates/template.release.gdextension.in b/templates/template.release.gdextension.in new file mode 100644 index 0000000..4d5ba9b --- /dev/null +++ b/templates/template.release.gdextension.in @@ -0,0 +1,11 @@ +[configuration] +entry_symbol = "GDExtensionInit" +compatibility_minimum = 4.1 + +[icons] +Example = "icons/Example.svg" + +[libraries] +linux.release.x86_64 = "lib/Linux-x86_64/lib${PROJECT_NAME}.so" +macos.release = "lib/Darwin-universal/lib${PROJECT_NAME}.dylib" +windows.release.x86_64 = "lib/Windows-AMD64/${LIB_PREFIX}${PROJECT_NAME}.dll"