Compare commits

..

144 Commits

Author SHA1 Message Date
David Snopek
714c9e2c16 gdextension: Sync with upstream commit 4c311cbee68c0b66ff8ebb8b0defdd9979dd2a41 (4.4-stable) 2025-03-03 09:30:17 -06:00
David Snopek
06082d7727 Merge pull request #1721 from enetheru/godotcpp
CMake: Rename all GODOT_ to GODOTCPP_
2025-03-01 10:49:38 -06:00
David Snopek
26358b5e3a Merge pull request #1719 from dsnopek/gdvirtual-required-macros
Update `GDVIRTUAL*()` macros to match Godot 4.4
2025-03-01 08:21:53 -06:00
David Snopek
e3816585fe gdextension: Sync with upstream commit 15ff450680a40391aabbffde0a57ead2cd84db56 (4.4-rc3) 2025-02-28 19:24:25 -06:00
Samuel Nicholas
d0dd282d73 CMake: Rename all GODOT_ to GODOTCPP_
This is for discussion primarily at this stage.
2025-03-01 10:50:55 +10:30
David Snopek
c8c25cd312 Merge pull request #1720 from enetheru/generator_target
CMake: Add generate_bindings custom target
2025-02-27 12:57:35 -06:00
David Snopek
4a9409a30f Update GDVIRTUAL*() macros to match Godot 4.4 2025-02-26 12:56:55 -06:00
David Snopek
375c0d1575 gdextension: Sync with upstream commit 01545c995b0612c68f9dfce8f6cc67576c298381 (4.4-rc2) 2025-02-26 07:51:29 -06:00
Samuel Nicholas
e7f07dab87 CMake: Add generate_bindings custom target
I was working on something today and wanted to just generate the bindings separately to compilation.

This PR adds a custom target to do just that.
2025-02-26 23:02:59 +10:30
David Snopek
98ea2f60bb gdextension: Sync with upstream commit 8ed125b42908d0d46d3b8967e3a3bc03f809b3af (4.4-rc1) 2025-02-24 10:35:53 -06:00
David Snopek
48baa0c812 Merge pull request #1713 from Repiteo/style/nodiscard
Style: Replace `_NO_DISCARD_` macro with `[[nodiscard]]`
2025-02-21 14:32:36 -06:00
Thaddeus Crews
89fd27608f Style: Replace _NO_DISCARD_ macro with [[nodiscard]] 2025-02-20 09:23:08 -06:00
David Snopek
5eb6e6bf61 Merge pull request #1709 from enetheru/MinGWMakefiles
CMake: Create destination folder for doc_source.cpp generation
2025-02-17 15:26:44 -06:00
Samuel Nicholas
23c24073f4 CMake: Create destination folder for doc_source.cpp generation
When compiling using 'MinGW Makefiles' the folders aren't created automatically.
2025-02-18 07:11:53 +10:30
David Snopek
79f9bc9600 Merge pull request #1708 from enetheru/arch_confusion
CMake: Fix unknown architecture and simplify OSX_ARCHITECTURES
2025-02-17 11:04:34 -06:00
David Snopek
3f54a86554 Merge pull request #1707 from enetheru/cmake_module
CMake: GodotCPPModule.cmake
2025-02-17 11:04:25 -06:00
David Snopek
847dca4792 Merge pull request #1701 from enetheru/msvc_runtime
CMake: Fix for #1699 msvc runtime selection issues
2025-02-17 11:04:15 -06:00
Samuel Nicholas
18a926e836 CMake: Fix for #1699 msvc runtime selection issues
Previously I eschewed the use of CMAKE_MSVC_RUNTIME_LIBRARY in favour of setting the flags using target_compile_options so that they would propagate to consumers.

However, it has been raised that a dependency( independent to godot-cpp ) that doesn't set any runtime flags, which relies purely on the CMAKE_MSVC_RUNTIME_LIBRARY variable will very likely not have the correct msvc runtime flags set.

Where MSVC documentation states "All modules passed to a given invocation of the linker must have been compiled with the same runtime library compiler option (/MD, /MT, /LD)."

It was also mentioned that message type WARNING is not ideal for notifying consumers.

So I have updated the cmake code to use CMAKE_MSVC_RUNTIME_LIBRARY  over target-compile_options. And set it as a CACHE STRING variable so that it can be overridden if desired. We still message consumers, but as a NOTICE.
2025-02-15 18:28:12 +10:30
Samuel Nicholas
35469fd839 Turn python_callouts.cmake into GodotCPPModule.cmake
Move the find_package for python into it.
Recommend adding godot-cpp/cmake to CMAKE_MODULE_PATH and using include( GodotCPPModule ) to use functions.
Add target_doc_sources function to simplify the addition of documentation to a binary.
2025-02-15 09:04:12 +10:30
Samuel Nicholas
9d9099adcd Simplified architecture naming to reduce confusion 2025-02-09 18:08:53 +10:30
David Snopek
f398ebb8ce gdextension: Sync with upstream commit 06acfccf89ad6b900ae694a4d58ceade1967a85f (4.4-beta3) 2025-02-08 15:02:31 -06:00
David Snopek
560f786599 Merge pull request #1698 from enetheru/threads
CMake: Implement 'threads' Option
2025-02-07 12:07:33 -06:00
Samuel Nicholas
91f81f51e1 CMake: Implement 'threads' Option
Add the GODOT_THREADS option and related supporting code
Includes naming cleanups
2025-02-04 09:08:35 +10:30
David Snopek
ee2a895ea4 Merge pull request #1335 from godotengine/dependabot/github_actions/actions/upload-artifact-4
Bump actions/upload-artifact from 3 to 4
2025-02-03 11:18:23 -06:00
David Snopek
f06af65c87 gdextension: Sync with upstream commit a013481b0911e59cc3f3dea7ebb732450c3e1460 (4.4-beta2) 2025-02-02 08:41:18 -06:00
David Snopek
3c55ca7a14 Merge pull request #1691 from enetheru/fix1690
CMake: Fix #1690 - DEBUG_FEATURES generator expression
2025-01-29 11:14:51 -06:00
Samuel Nicholas
9ce7a71cbf CMake: Fix #1690 - DEBUG_FEATURES generator expression
As described in issue #1690 the expression needs to depend on TARGET_ALIAS not TARGET_NAME.

This was introduced when I was solving the naming conflict issues and I missed this usage.
2025-01-23 14:36:48 +10:30
David Snopek
13cd2d921c Merge pull request #1628 from IvanInventor/typed_dict_regression_fix
fix typed_dictionary compile-time regression
2025-01-21 11:15:42 -06:00
David Snopek
b86cf321d0 Merge pull request #1687 from bgie/enum_size
Fix buffer overrun with enums pointers cast to int64_t* when enum is only 32-bit
2025-01-21 06:28:58 -06:00
David Snopek
faf6facffc Merge pull request #1686 from bgie/readme_precommit
Update README.md with new pre-commit instructions
2025-01-21 06:27:40 -06:00
David Snopek
dfc51960f9 gdextension: Sync with upstream commit d33da79d3f8fe84be2521d25b9ba8e440cf25a88 (4.4-beta1) 2025-01-20 15:23:58 -06:00
Brecht Kuppens
7576dc5930 Fix buffer overrun with enums pointers cast to int64_t* when enum is only 32-bit 2025-01-20 10:29:16 +01:00
Brecht Kuppens
bd3cf478c6 Update README.md with new pre-commit instructions 2025-01-20 09:25:59 +01:00
David Snopek
befe3ee2f2 Merge pull request #1682 from enetheru/gdext-docs-cmake
CMake: Support for XML documentation
2025-01-13 09:06:59 -06:00
Samuel Nicholas
8814ac51ac CMake: Support for XML documentation
Add new function generate_doc_source to python_callouts.cmake
Update Test extension to use generate_doc_source function and include generated file in the build.

Cleanup:
Fix godotcpp.py imports after rebase
Pre-Commit hook sorted python imports in doc_source_generator.py
- replace ${CMAKE_CURRENT_SOURCE_DIR} with ${godot-cpp_SOURCE_DIR} when referencing current working directory and script locations when invoking python scripts.

Co-authored-by: David Snopek <dsnopek@gmail.com>
2025-01-13 08:28:42 +10:30
David Snopek
94a1f4f2fb Merge pull request #1670 from enetheru/build_profile
CMake: Support for using build_profile.json
2025-01-12 05:29:29 -06:00
David Snopek
65046d00a5 Merge pull request #1676 from dsnopek/gdextension-virtual-method-compat
Update for virtual method compatibility system
2025-01-12 05:28:38 -06:00
David Snopek
5c9529fc84 Update for virtual method compatibility system 2025-01-11 16:36:59 -06:00
Samuel Nicholas
ae198fe860 CMake: Support using build_profile.json
Add python_callouts.py to hold functions which call python utilities
- generate trimmed API
- generate file list
- generate bindings

if GODOT_BUILD_PROFILE is specified, a trimmed API file is created in the CMAKE_CURRENT_BINARY_DIR and used as the source for binding generation

Simplify Code Generation Variables
- use generator expressions
- use math for bits
- simplify if statements
2025-01-11 12:22:22 +10:30
David Snopek
012b8ffc3a Merge pull request #1658 from enetheru/name_clash
CMake: Alleviate target name clashes, visibility, and grouping.
2025-01-10 09:05:54 -06:00
David Snopek
7d3870bc87 Merge pull request #1680 from Faless/build/profile_strip_json
[Bindings] Build profile now strips methods and skip files
2025-01-07 14:42:20 -06:00
Fabio Alessandrelli
0cfe01eff2 [CI] Re-add generated files consistency check 2025-01-07 20:33:12 +01:00
Fabio Alessandrelli
c4f1abe3f9 [Bindings] Build profile now strips methods and skip files
This allows removing dependencies that are not explicitly unused by the
gdextension being built and is implemented using an intermediate json
API file with the methods and classes stripped (i.e. without touching
the file generators).
2025-01-07 20:33:12 +01:00
Samuel Nicholas
6f7293cef4 Alleviate CMake target name clashes, visibility, and grouping.
Simplify <platform>_generate cmake function signature, as TARGET_ALIAS and TARGET_NAME are still in scope and do not need to be passed.
Add USE_FOLDERS, and FOLDER properties to group targets in VS and XCode
Guard test target with GODOT_ENABLE_TESTING
Generate all three variants in the form godot-cpp.test.<target> to remove the -DTEST_TARGET option clutter.
Update the docs/cmake.rst with information about the testing target
Update the Github CI
2024-12-29 09:54:55 +10:30
David Snopek
47f11bc5c7 Merge pull request #1666 from raulsntos/set_class_icon
Add a method to set the class icon
2024-12-21 17:17:50 -06:00
Raul Santos
2fd3a80505 Add icon path to class creation info 2024-12-18 01:44:22 +01:00
David Snopek
27ffd8c6be Merge pull request #1668 from dsnopek/print-verbose-conflict
Fix `print_verbose()` macro conflicting with `UtilityFunctions::print_verbose()`
2024-12-10 08:57:32 -06:00
David Snopek
47d9cb9bed Fix print_verbose() macro conflicting with UtilityFunctions::print_verbose() 2024-12-09 11:33:57 -06:00
David Snopek
97c16d3379 Merge pull request #1656 from Ivorforce/gh-action-setup-godot-cpp
Add a separate setup-godot-cpp github action.
2024-12-09 10:39:57 -06:00
Lukas Tenbrink
9943675dcb Add a separate setup-godot-cpp github action. 2024-12-09 16:13:43 +01:00
David Snopek
38056d1086 Merge pull request #1651 from enetheru/clang-cl
CMake: Enable using clang-cl on windows
2024-12-09 08:30:20 -06:00
Samuel Nicholas
ef9778a392 CMake: Enable using clang-cl on windows
detect clang with MSVC frontend using CMAKE_CXX_COMPILER_FRONTEND_VARIANT
2024-12-09 11:58:40 +10:30
David Snopek
ce66e6bb39 Merge pull request #1648 from enetheru/dev_tag
CMake: Handle GODOT_DEV_BUILD flag
2024-12-08 08:18:07 -06:00
Samuel Nicholas
542ab19a21 CMake: Handle GODOT_DEV_BUILD flag correctly
.dev is added to output artifacts
Warn users for specifying dev_build and Release build config
Update documentation with deviations to SCons
Update debug_symbols handling, its rolled into build config
Cleanup helper variables and comments
2024-12-07 09:50:59 +10:30
David Snopek
163189fba9 Merge pull request #1660 from enetheru/exclude_typo
CMake: Replace empty ${EXCLUDE} variable with EXCLUDE_FROM_ALL
2024-12-06 16:08:27 -06:00
David Snopek
4eaef4ca9a Merge pull request #1663 from enetheru/fix_crt_debug
CMake: Fix selection of MSVC Runtime compile flags
2024-12-06 16:08:19 -06:00
David Snopek
72aeb35691 Merge pull request #1655 from Ivorforce/variant-internal
Add variant_internal.hpp.
2024-12-06 16:08:04 -06:00
Samuel Nicholas
9df3a66a88 Replace empty EXCLUDE variable with EXCLUDE_FROM_ALL
This was a mistake left over from the modernise PR
2024-12-05 09:16:11 +10:30
Samuel Nicholas
732df06a81 CMake: Fix selection of MSVC Runtime compile flags
My last attempt at solving this was not correct. I have left lots of comments in the source detailing the issue as it will effect consumers.
2024-12-05 09:15:40 +10:30
David Snopek
bb567060f4 Merge pull request #1616 from dsnopek/ptrtoarg-no-error-for-null-ref
Don't print an error when decoding a null Ref<T>
2024-12-02 12:54:26 -06:00
Lukas Tenbrink
daef7d48ea Add variant_internal.hpp.
This module contains VariantInternalType, VariantInternal, VariantGetInternalPtr, VariantInternalAccessor and VariantDefaultInitializer, allowing to access and manipulate Variant's internal values.
2024-11-28 15:15:03 +01:00
David Snopek
5255034fb0 Merge pull request #1653 from aaronfranke/print
Add `print_line` for compatibility with engine modules
2024-11-28 07:31:06 -06:00
David Snopek
b378d8c21f Merge pull request #1654 from Ivorforce/gdextension-interface-update
Update gdextension_interface.h. Add metadata to GetTypeInfo of char16_t and char32_t.
2024-11-28 06:59:21 -06:00
David Snopek
af4eaa76d7 Merge pull request #1649 from enetheru/fix-backward-break
CMake: fix break for build prior to modernisation PR
2024-11-28 06:58:57 -06:00
David Snopek
3a8d7a25ae Merge pull request #1647 from enetheru/fix#1459
CMake: Align MSVC runtime (MD[d], MT) options to engine
2024-11-28 06:57:53 -06:00
David Snopek
bc6f79c67a Merge pull request #1617 from zhehangd/fix_def_hpp_namespace
Use namespace in defs.hpp
2024-11-28 06:57:20 -06:00
Samuel Nicholas
b7dbd26d8f Align MSVC runtime (MD[d], MT) options to engine #1647
Engine has an option to link to MDd debug_crt
add flag to SCons options
Add flag to CMAKE options
2024-11-28 13:46:41 +10:30
Lukas Tenbrink
f174b4a445 Update gdextension_interface.h. Add metadata to GetTypeInfo of char16_t and char32_t. 2024-11-26 21:43:59 +01:00
Aaron Franke
ac466e4766 Add print_line for compatibility with engine modules 2024-11-26 03:06:22 -08:00
Samuel Nicholas
597055d13c CMake: re-add the godot::cpp alias pointing to template_debug
So that builds that relied on the alias already wont break.
2024-11-26 19:42:33 +10:30
David Snopek
a42b3634d2 Merge pull request #1598 from enetheru/modernise
Modernise existing cmake options
2024-11-22 08:23:46 -06:00
Samuel Nicholas
8534e2104f Modernise Existing CMakeLists.txt
- Added to .gitignore CMakeUserPresets.json

### Configuration:
- Changed python command to use single quotes to make build output log more legible.
- Added GODOT_DEV_BUILD to allow differentiation of debug or Release builds.
- Added find logic for macos Cocoa library

### godot-cpp Changes
- godot-cpp-test is changed to be incorporated into the cmake build as a target.
- Duplicated godot-cpp target into [template_release, template_debug, editor]
- Created {platform}.cmake files mirroring the style of the SCons build.

CMake has a feature called generator expressions for its configuration variables that are evaluated at build time. This allows multi-configuration build systems to properly evaulate options. for msvc, xcode and nijna multi-config.

- Moved configuration options to generator expressions with the notable exclusion of OSX_ARCHITECTURES.
- Remove CMAKE_BUILD_TYPE from msvc CI target as Multi-Config generators ignore it

### godot-cpp-test Changes
- Removed majority of the cmake code, now that the godot-cpp project is setup, the majority of the flags will be propagated as transient dependencies
- Marked with EXCLUDE_FROM_ALL so that it isn't built as part of the 'all' target
- Updated ci to build the godot-cpp-test target from the root directory using cmake
- Tests passing for Windows, Linux, and Macos builds.

### Documentation
Updated with new information
Added Emscripten example
Added Android example
2024-11-21 11:01:00 +10:30
David Snopek
c20a84e483 Merge pull request #1601 from Ivorforce/lto
Add lto scons option
2024-11-12 11:16:10 -06:00
Lukas Tenbrink
5f7cf05043 Add lto scons option, defaulting to "none". 2024-11-12 12:45:35 +01:00
David Snopek
f298ddd3c4 Merge pull request #1639 from AThousandShips/emsdk_cache_fix
[Web] Don't cache emsdk
2024-11-11 10:30:47 -06:00
A Thousand Ships
1e3b24f658 [Web] Don't cache emsdk
Due to how caches are accessed this cache is almost useless, it only
matters if it is from the same branch or a base branch, and is identical
between branches, so caching it just clutters the build cache
2024-11-09 16:21:59 +01:00
David Snopek
253e095c81 Merge pull request #1581 from dsnopek/classdb-add-virtual-method-arg-metadata-size
Fix crash in `ClassDB::add_virtual_method()` if arguments metadata is the wrong size
2024-11-05 09:18:01 -06:00
Zhehang Ding
450c3d65cd Use namespace in defs.hpp
A global alias of godot::real_t is defined for backward compatibility
2024-11-03 15:13:37 +08:00
David Snopek
259c757cce Merge pull request #1609 from Ivorforce/patch-3
Rename Vector4.components -> coords.
2024-10-30 14:51:04 -05:00
Lukas Tenbrink
23c9d41d2a Rename Vector4.components -> coords.
The use of .components is deprecated.
2024-10-30 15:44:44 +01:00
David Snopek
7871cec1e7 Merge pull request #1568 from dsnopek/post-initialize-44
Update for new NOTIFICATION_POSTINITIALIZE handling
2024-10-30 08:49:59 -05:00
David Snopek
688ed4b388 Merge pull request #1626 from ruffenman/remove-unimplemented-variant-functions
Remove unimplemented static variant functions 'blend' and 'interpolate'…
2024-10-30 08:49:38 -05:00
David Snopek
7796fcc890 Merge pull request #1622 from Repiteo/ci/runner
CI: Add `runner` workflow to call other workflows
2024-10-30 08:48:37 -05:00
David Snopek
42e398e4e2 Update for new NOTIFICATION_POSTINITIALIZE handling 2024-10-29 16:29:24 -05:00
David Snopek
ca5179f7d7 Merge pull request #1594 from dsnopek/macos-thread-local
Avoid `thread_local` on MacOS to prevent issues with hot reload
2024-10-29 15:39:49 -05:00
David Snopek
1e169bb809 Fix crash in ClassDB::add_virtual_method() if arguments metadata is the wrong size 2024-10-29 13:22:12 -05:00
David Snopek
fa3dfa0e3c Merge pull request #1591 from dsnopek/variant-object-instance-id
Directly get object instance ID from `Variant` and implement `Variant::get_validated_object()`
2024-10-29 13:10:12 -05:00
David Snopek
7fca545885 Merge pull request #1574 from dsnopek/unicode-class-names
Allow unicode class names
2024-10-29 13:09:45 -05:00
David Snopek
dfdc047459 Merge pull request #1630 from dsnopek/sync-quaternion
Sync `Quaternion` with the version in Godot
2024-10-29 08:36:28 -05:00
David Snopek
2004af63a0 Sync Quaternion with the version in Godot 2024-10-28 15:37:45 -05:00
Vano
7f47d3951e fix typed_dictionary compile-time regression 2024-10-21 04:13:12 +03:00
David Snopek
0602c32986 Directly get object instance ID from Variant and implement Variant::get_validated_object() 2024-10-17 09:58:52 -05:00
David Snopek
91833c852e Avoid thread_local on MacOS to prevent issues with hot reload 2024-10-17 09:06:27 -05:00
David Snopek
a98d41f62b Merge pull request #1590 from dsnopek/reload-instance-bindings
Correctly set instance bindings on reload
2024-10-17 16:05:02 +02:00
David Snopek
96675a814b Merge pull request #1625 from Flarkk/looking_at
Add `p_use_model_front` to `Basis::looking_at()`
2024-10-17 16:02:02 +02:00
David Snopek
291147e21b Merge pull request #1611 from Repiteo/library-no-cache
SCons: Don't cache libraries
2024-10-15 14:42:20 +02:00
ruffenman
42a35a1852 Remove unimplemented static variant functions 'blend' and 'interpolate'. If a user attempts to call either of these it will introduce a linker error and it may not be immediately clear to them why. Also, variant interpolation can already be accessed via 'UtilityFunctions::lerp', making at least the interpolate function unecessary here. 2024-10-14 20:33:20 -04:00
Florent Guiocheau
02fd535454 Add p_use_model_front to Basis::looking_at() 2024-10-14 21:50:12 +02:00
Thaddeus Crews
c1524f7c86 CI: Add runner workflow to call other workflows 2024-10-11 10:58:28 -05:00
David Snopek
7f02301a91 Don't print an error when decoding a null Ref<T> 2024-10-07 11:22:52 -05:00
David Snopek
6facde3c29 Merge pull request #1602 from Faless/build/use_clang_cl_is_use_llvm
[SCons] Remove use_clang_cl windows flag in favor of generic use_llvm
2024-10-03 08:35:35 -05:00
David Snopek
709bad01d1 Merge pull request #1595 from enetheru/restructure
Re-Structure cmake solution to be closer to the scons solution.
2024-10-03 08:34:54 -05:00
Thaddeus Crews
83c0f15ab9 SCons: Don't cache librarys 2024-09-30 11:26:06 -05:00
David Snopek
96565e1de5 Merge pull request #1600 from enetheru/vsproj-ci-config
VSProj Configure type on build command - to resolve #1582
2024-09-26 06:03:56 -07:00
David Snopek
78f5d99fd9 Merge pull request #1599 from enetheru/gitignore
Update .gitignore to add .idea for the Jetbrains CLion IDE
2024-09-24 05:37:41 -05:00
Samuel Nicholas
9f5daa2d90 update .gitignore to add .idea for the Jetbrains CLion IDE
and also the default cmake build directory when building in clion cmake-build-*
2024-09-24 16:28:58 +09:30
Samuel Nicholas
2402a044eb Re-Structure cmake solution to be closer to the scons solution.
This is just a single step, re-arranging the code without actually changing its functionality.

new docs/cmake.md
moved the block of comments from the start of the CMakeLists.txt into the cmake.md file and converted content to markdown.

new cmake/godotcpp.cmake
Moved all exposed options into a new function godotcpp_options()
Moved configuration and generation code into godotcpp_generate()

To get all the options into the godotcpp_options() I changed the logic of GODOT_USE_HOT_RELOAD which I believe is a closer match to scons, that if the options is not set, and the build type is not release, then it defaults to ON.

I msvc builds require the default flags to be modified or it will throw errors. I have added the links to articles in the commit, but its about removing the runtime error checks /RTC1 from the CMAKE_CXX_FLAGS_DEBUG variable. This needs to happen before the files are included.
https://stackoverflow.com/questions/74426638/how-to-remove-rtc1-from-specific-target-or-file-in-cmake
https://discourse.cmake.org/t/how-do-i-remove-compile-options-from-target/5965

Renamed GodotCompilerWarnings.cmake to common_compiler_flags.cmake to match scons

Included files explicitly by path, as we dont need to append to the CMAKE_MODULES_PATH which effects the whole build tree.

This prevents consumers of the library from clobbering the names of the cmake include files and breaking the build.
2024-09-24 16:27:28 +09:30
David Snopek
64221facda Merge pull request #1603 from Faless/build/fix_wasm_bigint
[SCons] Enable WASM_BIGINT in web builds
2024-09-23 10:45:56 -05:00
Fabio Alessandrelli
78498da7c3 [SCons] Enable WASM_BIGINT in web builds
Required since Godot 4.3, which is also the first Godot version with
wide WASM gdnative support (previous versions were Chrome-only, and very
brittle).
2024-09-23 13:29:49 +02:00
Fabio Alessandrelli
4717a78144 [SCons] Remove use_clang_cl windows flag in favor of generic use_llvm
This is consistent with Godot upstream.
2024-09-22 13:39:06 +02:00
Samuel Nicholas
07704f8f48 VSProj Configure type on build command - to resolve #1582
Visual Studio projects are multi-config projects like Ninja-MultiConfig which means you can't set the configuration at configure time as there are multiple, it always chooses the first one by default when not specified in the build command.

Instead of this:
cmake -DCMAKE_BUILD_TYPE=Release -G"Visual Studio 17 2022" .
cmake --build . --verbose

It should be this
cmake -G"Visual Studio 17 2022" .
cmake --build . --verbose --config Release

Update ci.yml

Because the current build system doesnt use generator expressions for multi config builds, both the CMAKE_BUILD_TYPE and the build --config options need to be set
2024-09-21 22:38:07 +09:30
David Snopek
57bd88ad99 Merge pull request #1162 from Repiteo/typed-dictionary
Implement typed dictionaries
2024-09-19 13:46:07 -05:00
David Snopek
536ea8561e Allow unicode class names 2024-09-18 13:24:56 -05:00
David Snopek
b93d6e887e Merge pull request #1583 from enetheru/variable-rename2
Updated all variable names to use GODOT_ prefix
2024-09-17 21:00:36 -05:00
Thaddeus Crews
2ffff669f5 Implement typed dictionaries 2024-09-17 15:05:16 -05:00
David Snopek
730ccaae39 Merge pull request #1593 from Repiteo/4.4.dev2-bindings
Update bindings to 4.4.dev2
2024-09-17 14:38:47 -05:00
Thaddeus Crews
9b98b19913 Update bindings to 4.4.dev2 2024-09-17 12:45:21 -05:00
David Snopek
cb543c192a Correctly set instance bindings on reload 2024-09-17 09:18:08 -05:00
Samuel Nicholas
390a9a5590 Updated all variable names to use GODOT_ prefix
changed cache type for api file and api dir to FILEPATH and PATH respectively.
Minor whitespace.
docstring parity
2024-09-14 09:04:01 +09:30
David Snopek
4131b7f95f Merge pull request #1579 from enetheru/visibility-hidden
add SYMBOL_VISIBILITY cache variable to match scons interface.
2024-09-13 17:49:28 -05:00
Samuel Nicholas
02bdc6665a Add GODOT_SYMBOL_VISIBILITY cache variable to match scons interface. 2024-09-14 07:47:29 +09:30
David Snopek
aed9b5c7df Merge pull request #1563 from APokorny/visibility-hidden
Add visibility-hidden to CMake build
2024-09-11 10:29:12 -05:00
David Snopek
4d8c05f405 Merge pull request #1535 from bruvzg/llvm-mingw-arm64
Add support for LLVM/MinGW and ARM64 Windows builds.
2024-09-10 15:48:22 -05:00
David Snopek
f4d3817d99 Merge pull request #1548 from ytnuf/hot_reload
Add hot reload support when building with GCC and CMake
2024-09-10 15:47:53 -05:00
David Snopek
d477589104 Merge pull request #1520 from dsnopek/test-library-path-absolute
Add a test to ensure that library path is absolute
2024-08-27 17:45:23 -05:00
ytnuf
05571971cc Add hot reload support when building with GCC and CMake 2024-08-26 19:54:55 +01:00
David Snopek
aac0164b7a Merge pull request #1561 from Spartan322/gcc-14-Wtemplate-id-cdtor-warning
Fix GCC 14 -Wtemplate-id-cdtor warning
2024-08-26 12:35:48 -05:00
David Snopek
fd8f196008 Merge pull request #1560 from Faless/fix/build_web_cppflags_is_ccflags
[Web/SCons] Use CCFLAGS for SIDE_MODULE option
2024-08-26 10:34:55 -05:00
David Snopek
16bc0a0fff Merge pull request #1558 from aaronfranke/fix-typed-packed-array-bind
Fix missing MAKE_TYPED_ARRAY_INFO for Packed*Arrays
2024-08-26 10:34:33 -05:00
Andreas Pokorny
d18fa929fb Add visibility-hidden
This should make all symbols that are not marked otherwise have hidden
visibility. There still may be exposed symbols if marked with respective
attributes.
2024-08-26 13:20:51 +02:00
George L. Albany
7b31f39bea Fix GCC 14 -Wtemplate-id-cdtor warning
As was fixed with godotengine/godot#91208
2024-08-25 07:55:58 +00:00
Fabio Alessandrelli
f36acd8e31 [Web/SCons] Use CCFLAGS for SIDE_MODULE option
Was using CPPFLAGS, but should use the explicit scons CCFLAGS which
makes it clear they are applied to both the C and C++ compiler.

CPPFLAGS was also fine (they are preprocessor flags, also applied to
both C and C++), but we should try to stay consistent with what we do
in Godot.
2024-08-24 12:02:36 +02:00
Aaron Franke
10c3d1bc5f Fix missing MAKE_TYPED_ARRAY_INFO for Packed*Arrays 2024-08-22 21:02:48 -07:00
David Snopek
19c83a8837 Merge pull request #1554 from raulsntos/char-metadata
Correct type for `char16` and `char32` meta
2024-08-22 19:17:59 -05:00
Raul Santos
9a89d226c7 Correct type for char16 and char32 meta 2024-08-23 00:33:11 +02:00
David Snopek
265412cc53 Merge pull request #1557 from mihe/cpp-operators
Fix incorrect generation of some C++ operators
2024-08-22 16:45:18 -05:00
David Snopek
92ace04989 Add a test to ensure that library path is absolute 2024-08-22 16:31:35 -05:00
David Snopek
62305943a7 Merge pull request #1555 from raulsntos/fix-r1722784216
Avoid hardcoded type conversion for metadata
2024-08-22 16:30:17 -05:00
Mikael Hermansson
9949d09f3e Fix incorrect generation of some C++ operators 2024-08-21 20:37:52 +02:00
David Snopek
8b80d9146b Merge pull request #1528 from AThousandShips/style_fix_2
Make generated code mostly style compliant
2024-08-21 07:12:59 -05:00
Raul Santos
4829199081 Avoid hardcoded type conversion for metadata
The engine uses the names `int` and `float` to refer to the 64-bit types, so in the bindings generator we have a hardcoded conversion for those types.

But this type conversion should not be used for metadata. Even though the underlying type should still be 64-bit for interop, metadata is meant to specify the correct type to expose. So if metadata says `float` it means the type is really meant to be a 32-bit `float` and not `double`. Other hardcoded type conversions (`int` and `Nil`) won't ever be metadata.

This change corrects the `float` type, to use the right type in the generated C++ code. Before we were always using `double` due to this type conversion.
2024-08-20 14:53:22 +02:00
bruvzg
f2353da5a3 Add support for LLVM/MinGW and ARM64 Windows builds. 2024-08-12 08:53:40 +03:00
A Thousand Ships
f131efb791 Make generated code mostly style compliant 2024-07-17 17:29:31 +02:00
dependabot[bot]
b17e668c15 Bump actions/upload-artifact from 3 to 4
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-14 19:42:29 +00:00
49 changed files with 23219 additions and 1501 deletions

View File

@@ -6,7 +6,10 @@ env:
# Only used for the cache key. Increment version to force clean build.
GODOT_BASE_BRANCH: master
# Used to select the version of Godot to run the tests with.
GODOT_TEST_VERSION: 4.3-stable
GODOT_TEST_VERSION: master
# Use UTF-8 on Linux.
LANG: en_US.UTF-8
LC_ALL: en_US.UTF-8
concurrency:
group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}
@@ -38,7 +41,7 @@ jobs:
cache-name: linux-x86_64-f64
- name: 🏁 Windows (x86_64, MSVC)
os: windows-2022
os: windows-2019
platform: windows
artifact-name: godot-cpp-windows-msvc2019-x86_64-release
artifact-path: bin/libgodot-cpp.windows.template_release.x86_64.lib
@@ -46,7 +49,7 @@ jobs:
cache-name: windows-x86_64-msvc
- name: 🏁 Windows (x86_64, MinGW)
os: windows-2022
os: windows-2019
platform: windows
artifact-name: godot-cpp-linux-mingw-x86_64-release
artifact-path: bin/libgodot-cpp.windows.template_release.x86_64.a
@@ -181,30 +184,6 @@ jobs:
path: ${{ matrix.artifact-path }}
if-no-files-found: error
linux-cmake:
name: 🐧 Build (Linux, GCC, CMake)
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -qqq build-essential pkg-config cmake
- name: Build godot-cpp
run: |
cmake -DCMAKE_BUILD_TYPE=Release .
make -j $(nproc) VERBOSE=1
- name: Build test GDExtension library
run: |
cd test && cmake -DCMAKE_BUILD_TYPE=Release -DGODOT_HEADERS_PATH="../godot-headers" -DCPP_BINDINGS_PATH=".." .
make -j $(nproc) VERBOSE=1
linux-cmake-ninja:
name: 🐧 Build (Linux, GCC, CMake Ninja)
runs-on: ubuntu-22.04
@@ -219,31 +198,25 @@ jobs:
sudo apt-get update -qq
sudo apt-get install -qqq build-essential pkg-config cmake ninja-build
- name: Build godot-cpp
run: |
cmake -DCMAKE_BUILD_TYPE=Release -GNinja .
cmake --build . -j $(nproc) --verbose
- name: Build test GDExtension library
run: |
cd test && cmake -DCMAKE_BUILD_TYPE=Release -DGODOT_HEADERS_PATH="../godot-headers" -DCPP_BINDINGS_PATH=".." -GNinja .
cmake --build . -j $(nproc) --verbose
mkdir cmake-build
cd cmake-build
cmake ../ -DGODOTCPP_ENABLE_TESTING=YES
cmake --build . --verbose -j $(nproc) -t godot-cpp.test.template_release --config Release
windows-msvc-cmake:
name: 🏁 Build (Windows, MSVC, CMake)
runs-on: windows-2022
runs-on: windows-2019
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Build godot-cpp
run: |
cmake -DCMAKE_BUILD_TYPE=Release -G"Visual Studio 17 2022" .
cmake --build . --verbose --config Release
- name: Build test GDExtension library
run: |
cd test && cmake -DCMAKE_BUILD_TYPE=Release -DGODOT_HEADERS_PATH="../godot-headers" -DCPP_BINDINGS_PATH=".." -G"Visual Studio 17 2022" .
cmake --build . --verbose --config Release
mkdir cmake-build
cd cmake-build
cmake ../ -DGODOTCPP_ENABLE_TESTING=YES
cmake --build . --verbose -t godot-cpp.test.template_release --config Release

5
.gitignore vendored
View File

@@ -198,4 +198,7 @@ venv
# Clion Configuration
.idea/
cmake-build-*
cmake-build*/
# CMake related
CMakeUserPresets.json

View File

@@ -1,24 +1,62 @@
cmake_minimum_required(VERSION 3.13)
project(godot-cpp LANGUAGES CXX)
cmake_minimum_required(VERSION 3.17)
# Configure CMake
# https://discourse.cmake.org/t/how-do-i-remove-compile-options-from-target/5965
# https://stackoverflow.com/questions/74426638/how-to-remove-rtc1-from-specific-target-or-file-in-cmake
if(${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)
if(NOT CMAKE_BUILD_TYPE MATCHES Debug)
STRING(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
endif ()
endif ()
#[=======================================================================[.rst:
include( ${PROJECT_SOURCE_DIR}/cmake/godotcpp.cmake )
CMake Version requirements
--------------------------
# I know this doesn't look like a typical CMakeLists.txt, but as we are
# attempting mostly feature parity with SCons, and easy maintenance, the closer
# the two build systems look the easier they will be to keep in lockstep.
To enable use of the emscripten emsdk hack for pseudo shared library support
without polluting options for consumers we need to use the
CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE which was introduced in version 3.17
# The typical target definitions are in ${PROJECT_SOURCE_DIR}/cmake/godotcpp.cmake
Scons Compatibility
-------------------
There is an understandable conflict between build systems as they define
similar concepts in different ways. When there isn't a 1:1 relationship,
compromises need to be made to resolve those differences.
As we are attempting to maintain feature parity, and ease of maintenance, these
CMake scripts are built to resemble the SCons build system wherever possible.
The file structure and file content are made to match, if not in content then
in spirit. The closer the two build systems look the easier they will be to
maintain.
Where the SCons additional scripts in the tools directory, The CMake scripts
are in the cmake directory.
For example, the tools/godotcpp.py is sourced into SCons, and the 'options'
function is run.
.. highlight:: python
cpp_tool = Tool("godotcpp", toolpath=["tools"])
cpp_tool.options(opts, env)
The CMake equivalent is below.
]=======================================================================]
include( cmake/godotcpp.cmake )
godotcpp_options()
# Define our project.
project( godot-cpp
VERSION 4.4
DESCRIPTION "C++ bindings for the Godot Engine's GDExtensions API."
HOMEPAGE_URL "https://github.com/godotengine/godot-cpp"
LANGUAGES CXX)
compiler_detection()
godotcpp_generate()
# Conditionally enable the godot-cpp.test.<target> integration testing targets
if( GODOTCPP_ENABLE_TESTING )
add_subdirectory( test )
endif()
# If this is the top level CMakeLists.txt, Generators which honor the
# USE_FOLDERS flag will organize godot-cpp targets under the subfolder
# 'godot-cpp'. This is enable by default from CMake version 3.26
set_property(GLOBAL PROPERTY USE_FOLDERS ON)

View File

@@ -7,8 +7,6 @@
> from Godot's `master` branch.
>
> For users of stable branches, switch to the branch matching your target Godot version:
> - [`4.4`](https://github.com/godotengine/godot-cpp/tree/4.4)
> - [`4.3`](https://github.com/godotengine/godot-cpp/tree/4.3)
> - [`4.2`](https://github.com/godotengine/godot-cpp/tree/4.2)
> - [`4.1`](https://github.com/godotengine/godot-cpp/tree/4.1)
> - [`4.0`](https://github.com/godotengine/godot-cpp/tree/4.0)
@@ -51,13 +49,20 @@ Godot version.**
## Compatibility
GDExtensions targeting an earlier version of Godot should work in later minor versions,
but not vice-versa. For example, a GDExtension targeting Godot 4.2 should work just fine
in Godot 4.3, but one targeting Godot 4.3 won't work in Godot 4.2.
There is one exception to this: extensions targeting Godot 4.0 will _not_ work with
Godot 4.1 and later.
See [Updating your GDExtension for 4.1](https://docs.godotengine.org/en/latest/tutorials/migrating/upgrading_to_godot_4.1.html#updating-your-gdextension-for-godot-4-1).
> [!WARNING]
>
> The GDExtension API is brand new in Godot 4.0, and is still
considered in **beta** stage, despite Godot 4.0 itself being released.
>
> This applies to both the GDExtension interface header, the API JSON, and this
first-party `godot-cpp` extension.
>
> Some compatibility breakage is to be expected as GDExtension and `godot-cpp`
> get more used, documented, and critical issues get resolved. See the
> [Godot issue tracker](https://github.com/godotengine/godot/issues?q=is%3Aissue+is%3Aopen+label%3Atopic%3Agdextension)
> and the [godot-cpp issue tracker](https://github.com/godotengine/godot-cpp/issues)
> for a list of known issues, and be sure to provide feedback on issues and PRs
> which affect your use of this extension.
## Contributing
@@ -140,4 +145,4 @@ See the [godot-cpp-template](https://github.com/godotengine/godot-cpp-template)
generic reusable template.
Or checkout the code for the [Summator example](https://github.com/paddy-exe/GDExtensionSummator)
as shown in the [official documentation](https://docs.godotengine.org/en/latest/tutorials/scripting/cpp/gdextension_cpp_example.html).
as shown in the [official documentation](https://docs.godotengine.org/en/latest/tutorials/scripting/gdextension/gdextension_cpp_example.html).

View File

@@ -70,10 +70,9 @@ def generate_wrappers(target):
f.write(txt)
def generate_virtual_version(argcount, const=False, returns=False):
def generate_virtual_version(argcount, const=False, returns=False, required=False):
s = """#define GDVIRTUAL$VER($RET m_name $ARG)\\
::godot::StringName _gdvirtual_##m_name##_sn = #m_name;\\
template <bool required>\\
_FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST {\\
if (::godot::internal::gdextension_interface_object_has_script_method(_owner, &_gdvirtual_##m_name##_sn)) { \\
GDExtensionCallError ce;\\
@@ -85,10 +84,8 @@ def generate_virtual_version(argcount, const=False, returns=False):
return true;\\
}\\
}\\
if (required) {\\
ERR_PRINT_ONCE("Required virtual method " + get_class() + "::" + #m_name + " must be overridden before calling.");\\
$RVOID\\
}\\
$REQCHECK\\
$RVOID\\
return false;\\
}\\
_FORCE_INLINE_ bool _gdvirtual_##m_name##_overridden() const {\\
@@ -106,6 +103,7 @@ def generate_virtual_version(argcount, const=False, returns=False):
sproto = str(argcount)
method_info = ""
method_flags = "METHOD_FLAG_VIRTUAL"
if returns:
sproto += "R"
s = s.replace("$RET", "m_ret,")
@@ -114,16 +112,26 @@ def generate_virtual_version(argcount, const=False, returns=False):
method_info += "\t\tmethod_info.return_val_metadata = ::godot::GetTypeInfo<m_ret>::METADATA;"
else:
s = s.replace("$RET ", "")
s = s.replace("\t\t\t$RVOID\\\n", "")
s = s.replace("\t\t$RVOID\\\n", "")
if const:
sproto += "C"
method_flags += " | METHOD_FLAG_CONST"
s = s.replace("$CONST", "const")
s = s.replace("$METHOD_FLAGS", "::godot::METHOD_FLAG_VIRTUAL | ::godot::METHOD_FLAG_CONST")
else:
s = s.replace("$CONST ", "")
s = s.replace("$METHOD_FLAGS", "::godot::METHOD_FLAG_VIRTUAL")
if required:
sproto += "_REQUIRED"
method_flags += " | METHOD_FLAG_VIRTUAL_REQUIRED"
s = s.replace(
"$REQCHECK",
'ERR_PRINT_ONCE("Required virtual method " + get_class() + "::" + #m_name + " must be overridden before calling.");',
)
else:
s = s.replace("\t\t$REQCHECK\\\n", "")
s = s.replace("$METHOD_FLAGS", method_flags)
s = s.replace("$VER", sproto)
argtext = ""
callargtext = ""
@@ -190,6 +198,10 @@ def generate_virtuals(target):
txt += generate_virtual_version(i, False, True)
txt += generate_virtual_version(i, True, False)
txt += generate_virtual_version(i, True, True)
txt += generate_virtual_version(i, False, False, True)
txt += generate_virtual_version(i, False, True, True)
txt += generate_virtual_version(i, True, False, True)
txt += generate_virtual_version(i, True, True, True)
txt += "#endif // GDEXTENSION_GDVIRTUAL_GEN_H\n"
@@ -278,19 +290,14 @@ def generate_bindings(api_filepath, use_template_get_node, bits="64", precision=
api = {}
with open(api_filepath, encoding="utf-8") as api_file:
api = json.load(api_file)
_generate_bindings(api, api_filepath, use_template_get_node, bits, precision, output_dir)
_generate_bindings(api, use_template_get_node, bits, precision, output_dir)
def _generate_bindings(api, api_filepath, use_template_get_node, bits="64", precision="single", output_dir="."):
if "precision" in api["header"] and precision != api["header"]["precision"]:
raise Exception(
f"Cannot do a precision={precision} build using '{api_filepath}' which was generated by Godot built with precision={api['header']['precision']}"
)
def _generate_bindings(api, use_template_get_node, bits="64", precision="single", output_dir="."):
target_dir = Path(output_dir) / "gen"
shutil.rmtree(target_dir, ignore_errors=True)
target_dir.mkdir(parents=True, exist_ok=True)
target_dir.mkdir(parents=True)
real_t = "double" if precision == "double" else "float"
print("Built-in type config: " + real_t + "_" + bits)
@@ -441,8 +448,14 @@ def generate_builtin_bindings(api, output_dir, build_config):
builtin_header.append("")
includes = []
for builtin in builtin_classes:
builtin_header.append(f"#include <godot_cpp/variant/{camel_to_snake(builtin)}.hpp>")
includes.append(f"godot_cpp/variant/{camel_to_snake(builtin)}.hpp")
includes.sort()
for include in includes:
builtin_header.append(f"#include <{include}>")
builtin_header.append("")
@@ -498,11 +511,10 @@ def generate_builtin_class_vararg_method_implements_header(builtin_classes):
continue
result += make_varargs_template(
method, "is_static" in method and method["is_static"], class_name, False, False, True
method, "is_static" in method and method["is_static"], class_name, False, True
)
result.append("")
result.append("")
result.append(f"#endif // ! {header_guard}")
return "\n".join(result)
@@ -527,38 +539,55 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
# Special cases.
if class_name == "String":
result.append("#include <godot_cpp/classes/global_constants.hpp>")
result.append("#include <godot_cpp/variant/char_string.hpp>")
result.append("#include <godot_cpp/variant/char_utils.hpp>")
result.append("#include <godot_cpp/classes/global_constants.hpp>")
result.append("")
if class_name == "PackedStringArray":
result.append("#include <godot_cpp/variant/string.hpp>")
result.append("")
if class_name == "PackedColorArray":
result.append("#include <godot_cpp/variant/color.hpp>")
result.append("")
if class_name == "PackedVector2Array":
result.append("#include <godot_cpp/variant/vector2.hpp>")
result.append("")
if class_name == "PackedVector3Array":
result.append("#include <godot_cpp/variant/vector3.hpp>")
result.append("")
if class_name == "PackedVector4Array":
result.append("#include <godot_cpp/variant/vector4.hpp>")
result.append("")
if is_packed_array(class_name):
result.append("#include <godot_cpp/core/error_macros.hpp>")
result.append("#include <initializer_list>")
result.append("")
if class_name == "Array":
result.append("#include <godot_cpp/variant/array_helpers.hpp>")
result.append("")
if class_name == "Callable":
result.append("#include <godot_cpp/variant/callable_custom.hpp>")
for include in fully_used_classes:
if include == "TypedArray":
result.append("#include <godot_cpp/variant/typed_array.hpp>")
else:
result.append(f"#include <godot_cpp/{get_include_path(include)}>")
result.append("")
if len(fully_used_classes) > 0:
includes = []
for include in fully_used_classes:
if include == "TypedArray":
includes.append("godot_cpp/variant/typed_array.hpp")
elif include == "TypedDictionary":
includes.append("godot_cpp/variant/typed_dictionary.hpp")
else:
includes.append(f"godot_cpp/{get_include_path(include)}")
includes.sort()
for include in includes:
result.append(f"#include <{include}>")
result.append("")
result.append("#include <gdextension_interface.h>")
@@ -636,7 +665,7 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
result.append("public:")
result.append(
f"\t_FORCE_INLINE_ GDExtensionTypePtr _native_ptr() const {{ return const_cast<uint8_t (*)[{snake_class_name}_SIZE]>(&opaque); }}"
f"\t_FORCE_INLINE_ GDExtensionTypePtr _native_ptr() const {{ return const_cast<uint8_t(*)[{snake_class_name}_SIZE]>(&opaque); }}"
)
copy_constructor_index = -1
@@ -817,7 +846,7 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
result.append(f"\tconst {return_type} *ptr() const;")
result.append(f"\t{return_type} *ptrw();")
iterators = """
struct Iterator {
struct Iterator {
_FORCE_INLINE_ $TYPE &operator*() const {
return *elem_ptr;
}
@@ -879,19 +908,17 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
}
_FORCE_INLINE_ ConstIterator end() const {
return ConstIterator(ptr() + size());
}
"""
}"""
result.append(iterators.replace("$TYPE", return_type))
init_list = """
_FORCE_INLINE_ $CLASS(std::initializer_list<$TYPE> p_init) {
_FORCE_INLINE_ $CLASS(std::initializer_list<$TYPE> p_init) {
ERR_FAIL_COND(resize(p_init.size()) != 0);
size_t i = 0;
for (const $TYPE &element : p_init) {
set(i++, element);
}
}
"""
}"""
result.append(init_list.replace("$TYPE", return_type).replace("$CLASS", class_name))
if class_name == "Array":
@@ -903,6 +930,9 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
if class_name == "Dictionary":
result.append("\tconst Variant &operator[](const Variant &p_key) const;")
result.append("\tVariant &operator[](const Variant &p_key);")
result.append(
"\tvoid set_typed(uint32_t p_key_type, const StringName &p_key_class_name, const Variant &p_key_script, uint32_t p_value_type, const StringName &p_value_class_name, const Variant &p_value_script);"
)
result.append("};")
@@ -930,7 +960,9 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
result.append("")
result.append("} // namespace godot")
result.append("")
result.append(f"#endif // ! {header_guard}")
result.append("")
return "\n".join(result)
@@ -944,7 +976,6 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
add_header(f"{snake_class_name}.cpp", result)
result.append("")
result.append(f"#include <godot_cpp/variant/{snake_class_name}.hpp>")
result.append("")
result.append("#include <godot_cpp/core/binder_common.hpp>")
@@ -953,10 +984,16 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
result.append("")
# Only used since the "fully used" is included in header already.
for include in used_classes:
result.append(f"#include <godot_cpp/{get_include_path(include)}>")
if len(used_classes) > 0:
includes = []
for included in used_classes:
includes.append(f"godot_cpp/{get_include_path(included)}")
includes.sort()
for included in includes:
result.append(f"#include <{included}>")
result.append("")
result.append("#include <godot_cpp/core/builtin_ptrcall.hpp>")
@@ -1206,7 +1243,7 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
f'{correct_type(operator["return_type"])} {class_name}::operator{get_operator_cpp_name(operator["name"])}() const {{'
)
result.append(
f'\treturn internal::_call_builtin_operator_ptr<{get_gdextension_type(correct_type(operator["return_type"]))}>(_method_bindings.operator_{get_operator_id_name(operator["name"])}, (GDExtensionConstTypePtr)&opaque, (GDExtensionConstTypePtr)nullptr);'
f'\treturn internal::_call_builtin_operator_ptr<{get_gdextension_type(correct_type(operator["return_type"]))}>(_method_bindings.operator_{get_operator_id_name(operator["name"])}, (GDExtensionConstTypePtr)&opaque, (GDExtensionConstTypePtr) nullptr);'
)
result.append("}")
result.append("")
@@ -1242,6 +1279,7 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
result.append("")
result.append("} //namespace godot")
result.append("")
return "\n".join(result)
@@ -1311,6 +1349,32 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
fully_used_classes.add(array_type_name)
else:
used_classes.add(array_type_name)
elif type_name.startswith("typeddictionary::"):
fully_used_classes.add("TypedDictionary")
dict_type_name = type_name.replace("typeddictionary::", "")
if dict_type_name.startswith("const "):
dict_type_name = dict_type_name[6:]
dict_type_names = dict_type_name.split(";")
dict_type_name = dict_type_names[0]
if dict_type_name.endswith("*"):
dict_type_name = dict_type_name[:-1]
if is_included(dict_type_name, class_name):
if is_enum(dict_type_name):
fully_used_classes.add(get_enum_class(dict_type_name))
elif "default_value" in argument:
fully_used_classes.add(dict_type_name)
else:
used_classes.add(dict_type_name)
dict_type_name = dict_type_names[2]
if dict_type_name.endswith("*"):
dict_type_name = dict_type_name[:-1]
if is_included(dict_type_name, class_name):
if is_enum(dict_type_name):
fully_used_classes.add(get_enum_class(dict_type_name))
elif "default_value" in argument:
fully_used_classes.add(dict_type_name)
else:
used_classes.add(dict_type_name)
elif is_enum(type_name):
fully_used_classes.add(get_enum_class(type_name))
elif "default_value" in argument:
@@ -1340,6 +1404,32 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
fully_used_classes.add(array_type_name)
else:
used_classes.add(array_type_name)
elif type_name.startswith("typeddictionary::"):
fully_used_classes.add("TypedDictionary")
dict_type_name = type_name.replace("typeddictionary::", "")
if dict_type_name.startswith("const "):
dict_type_name = dict_type_name[6:]
dict_type_names = dict_type_name.split(";")
dict_type_name = dict_type_names[0]
if dict_type_name.endswith("*"):
dict_type_name = dict_type_name[:-1]
if is_included(dict_type_name, class_name):
if is_enum(dict_type_name):
fully_used_classes.add(get_enum_class(dict_type_name))
elif is_variant(dict_type_name):
fully_used_classes.add(dict_type_name)
else:
used_classes.add(dict_type_name)
dict_type_name = dict_type_names[2]
if dict_type_name.endswith("*"):
dict_type_name = dict_type_name[:-1]
if is_included(dict_type_name, class_name):
if is_enum(dict_type_name):
fully_used_classes.add(get_enum_class(dict_type_name))
elif is_variant(dict_type_name):
fully_used_classes.add(dict_type_name)
else:
used_classes.add(dict_type_name)
elif is_enum(type_name):
fully_used_classes.add(get_enum_class(type_name))
elif is_variant(type_name):
@@ -1417,11 +1507,18 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
result.append("")
for included in used_classes:
result.append(f"#include <godot_cpp/{get_include_path(included)}>")
if len(used_classes) > 0:
includes = []
for included in used_classes:
includes.append(f"godot_cpp/{get_include_path(included)}")
if len(used_classes) == 0:
includes.sort()
for include in includes:
result.append(f"#include <{include}>")
else:
result.append("#include <godot_cpp/core/method_ptrcall.hpp>")
result.append("")
result.append("namespace godot {")
@@ -1461,16 +1558,25 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
result.append("")
for included in fully_used_classes:
if included == "TypedArray":
result.append("#include <godot_cpp/variant/typed_array.hpp>")
else:
result.append(f"#include <godot_cpp/{get_include_path(included)}>")
if len(fully_used_classes) > 0:
includes = []
for included in fully_used_classes:
if included == "TypedArray":
includes.append("godot_cpp/variant/typed_array.hpp")
elif included == "TypedDictionary":
includes.append("godot_cpp/variant/typed_dictionary.hpp")
else:
includes.append(f"godot_cpp/{get_include_path(included)}")
includes.sort()
for include in includes:
result.append(f"#include <{include}>")
result.append("")
if class_name == "EditorPlugin":
result.append("#include <godot_cpp/classes/editor_plugin_registration.hpp>")
if len(fully_used_classes) > 0:
result.append("")
if class_name != "Object" and class_name != "ClassDBSingleton":
@@ -1509,7 +1615,6 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
result.append("")
result.append("public:")
result.append("")
if "enums" in class_api:
for enum_api in class_api["enums"]:
@@ -1542,6 +1647,10 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
vararg = "is_vararg" in method and method["is_vararg"]
if vararg:
result.append("")
result.append("private:")
method_signature = "\t"
method_signature += make_signature(
class_name, method, for_header=True, use_template_get_node=use_template_get_node
@@ -1549,6 +1658,8 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
result.append(method_signature + ";")
if vararg:
result.append("")
result.append("public:")
# Add templated version.
result += make_varargs_template(method)
@@ -1563,6 +1674,8 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
)
result.append(method_signature + ";")
result.append("")
result.append("protected:")
# T is the custom class we want to register (from which the call initiates, going up the inheritance chain),
# B is its base class (can be a custom class too, that's why we pass it).
@@ -1579,9 +1692,9 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
# If the method is different from the base class, it means T overrides it, so it needs to be bound.
# Note that with an `if constexpr`, the code inside the `if` will not even be compiled if the
# condition returns false (in such cases it can't compile due to ambiguity).
f"\t\tif constexpr (!std::is_same_v<decltype(&B::{method_name}),decltype(&T::{method_name})>) {{"
f"\t\tif constexpr (!std::is_same_v<decltype(&B::{method_name}), decltype(&T::{method_name})>) {{"
)
result.append(f"\t\t\tBIND_VIRTUAL_METHOD(T, {method_name});")
result.append(f"\t\t\tBIND_VIRTUAL_METHOD(T, {method_name}, {method['hash']});")
result.append("\t\t}")
result.append("\t}")
@@ -1591,16 +1704,6 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
result.append(f"\t~{class_name}();")
result.append("")
if class_name == "Object":
result.append('\tString _to_string() const { return "<" + get_class() + "#" + itos(get_instance_id()) + ">"; }')
result.append("")
if class_name == "Node":
result.append(
'\tString _to_string() const { return (!get_name().is_empty() ? String(get_name()) + ":" : "") + Object::_to_string(); }'
)
result.append("")
result.append("public:")
# Special cases.
@@ -1617,7 +1720,7 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
if class_name == "WorkerThreadPool":
result.append("\tenum {")
result.append("\tINVALID_TASK_ID = -1")
result.append("\t\tINVALID_TASK_ID = -1")
result.append("\t};")
result.append("\ttypedef int64_t TaskID;")
result.append("\ttypedef int64_t GroupID;")
@@ -1629,8 +1732,6 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
)
if class_name == "Object":
result.append("")
result.append("\ttemplate <typename T>")
result.append("\tstatic T *cast_to(Object *p_object);")
@@ -1645,7 +1746,6 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
"\tT *get_node(const NodePath &p_path) const { return Object::cast_to<T>(get_node_internal(p_path)); }"
)
result.append("")
result.append("};")
result.append("")
@@ -1729,7 +1829,7 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
result.append(method_body)
result.append("\t} \\")
result.append("\t;")
result.append("\t")
result.append("")
result.append("#define CLASSDB_SINGLETON_VARIANT_CAST \\")
@@ -1741,10 +1841,11 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
else:
result.append(f'\tVARIANT_ENUM_CAST({class_api["alias_for"]}::{enum_api["name"]}); \\')
result.append("\t;")
result.append("\t")
result.append("")
result.append(f"#endif // ! {header_guard}")
result.append("")
return "\n".join(result)
@@ -1766,10 +1867,16 @@ def generate_engine_class_source(class_api, used_classes, fully_used_classes, us
result.append("#include <godot_cpp/core/error_macros.hpp>")
result.append("")
for included in used_classes:
result.append(f"#include <godot_cpp/{get_include_path(included)}>")
if len(used_classes) > 0:
includes = []
for included in used_classes:
includes.append(f"godot_cpp/{get_include_path(included)}")
includes.sort()
for included in includes:
result.append(f"#include <{included}>")
result.append("")
result.append("namespace godot {")
@@ -1919,8 +2026,8 @@ def generate_engine_class_source(class_api, used_classes, fully_used_classes, us
result.append(method_signature)
result.append("")
result.append("} // namespace godot")
result.append("")
result.append("} // namespace godot ")
return "\n".join(result)
@@ -1948,23 +2055,24 @@ def generate_global_constants(api, output_dir):
header.append("namespace godot {")
header.append("")
for constant in api["global_constants"]:
header.append(f'\tconst int64_t {escape_identifier(constant["name"])} = {constant["value"]};')
if len(api["global_constants"]) > 0:
for constant in api["global_constants"]:
header.append(f'const int64_t {escape_identifier(constant["name"])} = {constant["value"]};')
header.append("")
header.append("")
for enum_def in api["global_enums"]:
if enum_def["name"].startswith("Variant."):
continue
if enum_def["is_bitfield"]:
header.append(f'\tenum {enum_def["name"]} : uint64_t {{')
header.append(f'enum {enum_def["name"]} : uint64_t {{')
else:
header.append(f'\tenum {enum_def["name"]} {{')
header.append(f'enum {enum_def["name"]} {{')
for value in enum_def["values"]:
header.append(f'\t\t{value["name"]} = {value["value"]},')
header.append("\t};")
header.append(f'\t{value["name"]} = {value["value"]},')
header.append("};")
header.append("")
header.append("} // namespace godot")
@@ -2075,13 +2183,25 @@ def generate_utility_functions(api, output_dir):
header.append("public:")
for function in api["utility_functions"]:
if function["name"] == "is_instance_valid":
# The `is_instance_valid()` function doesn't work as developers expect, and unless used very
# carefully will cause crashes. Instead, developers should use `ObjectDB::get_instance()`
# with object ids to ensure that an instance is still valid.
continue
vararg = "is_vararg" in function and function["is_vararg"]
if vararg:
header.append("")
header.append("private:")
function_signature = "\t"
function_signature += make_signature("UtilityFunctions", function, for_header=True, static=True)
header.append(function_signature + ";")
if vararg:
header.append("")
header.append("public:")
# Add templated version.
header += make_varargs_template(function, static=True)
@@ -2102,13 +2222,16 @@ def generate_utility_functions(api, output_dir):
source.append("#include <godot_cpp/variant/utility_functions.hpp>")
source.append("")
source.append("#include <godot_cpp/core/error_macros.hpp>")
source.append("#include <godot_cpp/core/engine_ptrcall.hpp>")
source.append("#include <godot_cpp/core/error_macros.hpp>")
source.append("")
source.append("namespace godot {")
source.append("")
for function in api["utility_functions"]:
if function["name"] == "is_instance_valid":
continue
vararg = "is_vararg" in function and function["is_vararg"]
function_signature = make_signature("UtilityFunctions", function)
@@ -2202,7 +2325,7 @@ def make_function_parameters(parameters, include_default=False, for_builtin=Fals
signature.append(parameter)
if is_vararg:
signature.append("const Args&... p_args")
signature.append("const Args &...p_args")
return ", ".join(signature)
@@ -2264,9 +2387,6 @@ def make_signature(
if "is_virtual" in function_data and function_data["is_virtual"]:
function_signature += "virtual "
if is_vararg:
function_signature += "private: "
if static:
function_signature += "static "
@@ -2319,7 +2439,6 @@ def make_varargs_template(
function_data,
static=False,
class_befor_signature="",
with_public_declare=True,
with_indent=True,
for_builtin_classes=False,
):
@@ -2327,10 +2446,7 @@ def make_varargs_template(
function_signature = ""
if with_public_declare:
function_signature = "public: "
function_signature += "template <typename... Args> "
result.append("template <typename... Args>")
if static:
function_signature += "static "
@@ -2373,7 +2489,7 @@ def make_varargs_template(
function_signature += " {"
result.append(function_signature)
args_array = f"\tstd::array<Variant, {len(method_arguments)} + sizeof...(Args)> variant_args {{ "
args_array = f"\tstd::array<Variant, {len(method_arguments)} + sizeof...(Args)> variant_args{{ "
for argument in method_arguments:
if argument["type"] == "Variant":
args_array += escape_argument(argument["name"])
@@ -2541,6 +2657,7 @@ def is_variant(type_name):
or type_name in builtin_classes
or type_name == "Nil"
or type_name.startswith("typedarray::")
or type_name.startswith("typeddictionary::")
)
@@ -2566,6 +2683,8 @@ def is_included(type_name, current_type):
"""
if type_name.startswith("typedarray::"):
return True
if type_name.startswith("typeddictionary::"):
return True
to_include = get_enum_class(type_name) if is_enum(type_name) else type_name
if to_include == current_type or is_pod_type(to_include):
return False
@@ -2604,6 +2723,12 @@ def correct_typed_array(type_name):
return type_name
def correct_typed_dictionary(type_name):
if type_name.startswith("typeddictionary::"):
return type_name.replace("typeddictionary::", "TypedDictionary<").replace(";", ", ") + ">"
return type_name
def correct_type(type_name, meta=None, use_alias=True):
type_conversion = {"float": "double", "int": "int64_t", "Nil": "Variant"}
if meta is not None:
@@ -2617,6 +2742,8 @@ def correct_type(type_name, meta=None, use_alias=True):
return type_conversion[type_name]
if type_name.startswith("typedarray::"):
return type_name.replace("typedarray::", "TypedArray<") + ">"
if type_name.startswith("typeddictionary::"):
return type_name.replace("typeddictionary::", "TypedDictionary<").replace(";", ", ") + ">"
if is_enum(type_name):
if is_bitfield(type_name):
base_class = get_enum_class(type_name)
@@ -2763,6 +2890,8 @@ def get_default_value_for_type(type_name):
return "false"
if type_name.startswith("typedarray::"):
return f"{correct_type(type_name)}()"
if type_name.startswith("typeddictionary::"):
return f"{correct_type(type_name)}()"
if is_enum(type_name):
return f"{correct_type(type_name)}(0)"
if is_variant(type_name):

169
cmake/GodotCPPModule.cmake Normal file
View File

@@ -0,0 +1,169 @@
#[=======================================================================[.rst:
GodotCPPModule.cmake
---------------------
This file contains functions and tests which may be needed by consumers.
* Generate Trimmed API
* Generate File List
* Generate Bindings
If you want to use these functions in your project extend the CMAKE_MODULE_PATH
by adding these two lines into your CMakeLists.txt after the inclusion
godot-cpp
.. highlight:: cmake
list(APPEND CMAKE_MODULE_PATH "${godot-cpp_SOURCE_DIR}/cmake")
include( GodotCPPModule )
]=======================================================================]
find_package(Python3 3.4 REQUIRED) # pathlib should be present
#[[ Generate Trimmed API
The build_profile.py has a __main__ and is used as a tool
Its usage is listed as:
$ python build_profile.py BUILD_PROFILE INPUT_JSON [OUTPUT_JSON]
]]
function( build_profile_generate_trimmed_api BUILD_PROFILE INPUT_JSON OUTPUT_JSON )
execute_process(
COMMAND "${Python3_EXECUTABLE}"
"${godot-cpp_SOURCE_DIR}/build_profile.py"
"${BUILD_PROFILE}"
"${INPUT_JSON}"
"${OUTPUT_JSON}"
WORKING_DIRECTORY ${godot-cpp_SOURCE_DIR}
)
endfunction( )
#[[ Generate File List
Use the binding_generator.py Python script to determine the list of files that
will be passed to the code generator using extension_api.json.
NOTE: This happens for every configure.]]
function( binding_generator_get_file_list OUT_VAR_NAME API_FILEPATH OUTPUT_DIR )
# This code snippet will be squashed into a single line
# The two strings make this a list, in CMake lists are semicolon delimited strings.
set( PYTHON_SCRIPT
"from binding_generator import print_file_list"
"print_file_list( api_filepath='${API_FILEPATH}',
output_dir='${OUTPUT_DIR}',
headers=True,
sources=True)")
message( DEBUG "Python:\n${PYTHON_SCRIPT}" )
# Strip newlines and whitespace to make it a one-liner.
string( REGEX REPLACE "\n *" " " PYTHON_SCRIPT "${PYTHON_SCRIPT}" )
execute_process( COMMAND "${Python3_EXECUTABLE}" "-c" "${PYTHON_SCRIPT}"
WORKING_DIRECTORY "${godot-cpp_SOURCE_DIR}"
OUTPUT_VARIABLE GENERATED_FILES_LIST
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# Debug output
message( DEBUG "FileList-Begin" )
foreach( PATH ${GENERATED_FILES_LIST} )
message( DEBUG ${PATH} )
endforeach()
# Error out if the file list generator returned no files.
list( LENGTH GENERATED_FILES_LIST LIST_LENGTH )
if( NOT LIST_LENGTH GREATER 0 )
message( FATAL_ERROR "File List Generation Failed")
endif()
message( STATUS "There are ${LIST_LENGTH} Files to generate" )
set( ${OUT_VAR_NAME} ${GENERATED_FILES_LIST} PARENT_SCOPE )
endfunction( )
#[[ Generate Bindings
Using the generated file list, use the binding_generator.py to generate the
godot-cpp bindings. This will run at build time only if there are files
missing. ]]
function( binding_generator_generate_bindings API_FILE USE_TEMPLATE_GET_NODE, BITS, PRECISION, OUTPUT_DIR )
# This code snippet will be squashed into a single line
set( PYTHON_SCRIPT
"from binding_generator import generate_bindings"
"generate_bindings(
api_filepath='${API_FILE}',
use_template_get_node='${USE_TEMPLATE_GET_NODE}',
bits='${BITS}',
precision='${PRECISION}',
output_dir='${OUTPUT_DIR}')")
message( DEBUG "Python:\n${PYTHON_SCRIPT}" )
# Strip newlines and whitespace to make it a one-liner.
string( REGEX REPLACE "\n *" " " PYTHON_SCRIPT "${PYTHON_SCRIPT}" )
add_custom_command(OUTPUT ${GENERATED_FILES_LIST}
COMMAND "${Python3_EXECUTABLE}" "-c" "${PYTHON_SCRIPT}"
VERBATIM
WORKING_DIRECTORY ${godot-cpp_SOURCE_DIR}
MAIN_DEPENDENCY ${GODOTCPP_GDEXTENSION_API_FILE}
DEPENDS ${godot-cpp_SOURCE_DIR}/binding_generator.py
COMMENT "Generating bindings"
)
endfunction( )
#[[ Generate doc_data.cpp
The documentation displayed in the Godot editor is compiled into the extension.
It takes a list of XML source files, and transforms them into a cpp file that
is added to the sources list.]]
function( generate_doc_source OUTPUT_PATH SOURCES )
# Transform SOURCES CMake LIST
# quote each path with ''
# join with , to transform into a python list minus the surrounding []
set( PYTHON_LIST "${SOURCES}")
list( TRANSFORM PYTHON_LIST REPLACE "(.*\.xml)" "'\\1'" )
list( JOIN PYTHON_LIST "," PYTHON_LIST )
get_filename_component(OUTPUT_DIR "${OUTPUT_PATH}" DIRECTORY)
file(MAKE_DIRECTORY ${OUTPUT_DIR} )
# Python one-liner to run our command
# lists in CMake are just strings delimited by ';', so this works.
set( PYTHON_SCRIPT "from doc_source_generator import generate_doc_source"
"generate_doc_source( '${OUTPUT_PATH}', [${PYTHON_LIST}] )" )
add_custom_command( OUTPUT "${OUTPUT_PATH}"
COMMAND "${Python3_EXECUTABLE}" "-c" "${PYTHON_SCRIPT}"
VERBATIM
WORKING_DIRECTORY "${godot-cpp_SOURCE_DIR}"
DEPENDS
"${godot-cpp_SOURCE_DIR}/doc_source_generator.py"
"${SOURCES}"
COMMENT "Generating: ${OUTPUT_PATH}"
)
endfunction()
#[[ target_doc_sources
A simpler interface to add xml files as doc source to a output target.
TARGET: The gdexension library target
SOURCES: a list of xml files to use for source generation and inclusion.
This function also adds a doc_gen target to test source generation.]]
function( target_doc_sources TARGET SOURCES )
# set the generated file name
set( DOC_SOURCE_FILE "${CMAKE_CURRENT_BINARY_DIR}/gen/doc_source.cpp" )
# Create the file generation target, this won't be triggered unless a target
# that depends on DOC_SOURCE_FILE is built
generate_doc_source( "${DOC_SOURCE_FILE}" ${SOURCES} )
# Add DOC_SOURCE_FILE as a dependency to TARGET
target_sources( ${TARGET} PRIVATE "${DOC_SOURCE_FILE}" )
# Create a dummy target that depends on the source so that users can
# test the file generation task.
if( TARGET doc_gen )
else()
add_custom_target( doc_gen )
endif()
target_sources( doc_gen PRIVATE "${DOC_SOURCE_FILE}" )
endfunction()

40
cmake/android.cmake Normal file
View File

@@ -0,0 +1,40 @@
#[=======================================================================[.rst:
Android
-------
This file contains functions for options and configuration for targeting the
Android platform
Configuration of the Android toolchain is done using toolchain files,
CMakePresets, or variables on the command line.
The `Android SDK`_ provides toolchain files to help with configuration.
CMake has its own `built-in support`_ for cross compiling to the
Android platforms.
.. warning::
Android does not support or test the CMake built-in workflow, recommend
using their toolchain file.
.. _Android SDK:https://developer.android.com/ndk/guides/cmake
.. _built-in support:https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-android
There is further information and examples in the doc/cmake.rst file.
]=======================================================================]
function( android_options )
# Android Options
endfunction()
function( android_generate )
target_compile_definitions(${TARGET_NAME}
PUBLIC
ANDROID_ENABLED
UNIX_ENABLED
)
common_compiler_flags()
endfunction()

View File

@@ -1,94 +1,177 @@
# Add warnings based on compiler & version
# Set some helper variables for readability
set( compiler_less_than_v8 "$<VERSION_LESS:$<CXX_COMPILER_VERSION>,8>" )
set( compiler_greater_than_or_equal_v9 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,9>" )
set( compiler_greater_than_or_equal_v11 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,11>" )
set( compiler_less_than_v11 "$<VERSION_LESS:$<CXX_COMPILER_VERSION>,11>" )
set( compiler_greater_than_or_equal_v12 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,12>" )
#[=======================================================================[.rst:
Common Compiler Flags
---------------------
# These compiler options reflect what is in godot/SConstruct.
target_compile_options( ${PROJECT_NAME} PRIVATE
# MSVC only
$<${compiler_is_msvc}:
/W4
This file contains host platform toolchain and target platform agnostic
configuration. It includes flags like optimization levels, warnings, and
features. For target platform specific flags look to each of the
``cmake/<platform>.cmake`` files.
# Disable warnings which we don't plan to fix.
/wd4100 # C4100 (unreferenced formal parameter): Doesn't play nice with polymorphism.
/wd4127 # C4127 (conditional expression is constant)
/wd4201 # C4201 (non-standard nameless struct/union): Only relevant for C89.
/wd4244 # C4244 C4245 C4267 (narrowing conversions): Unavoidable at this scale.
/wd4245
/wd4267
/wd4305 # C4305 (truncation): double to float or real_t, too hard to avoid.
/wd4514 # C4514 (unreferenced inline function has been removed)
/wd4714 # C4714 (function marked as __forceinline not inlined)
/wd4820 # C4820 (padding added after construct)
>
]=======================================================================]
# Clang and GNU common options
$<$<OR:${compiler_is_clang},${compiler_is_gnu}>:
-Wall
-Wctor-dtor-privacy
-Wextra
-Wno-unused-parameter
-Wnon-virtual-dtor
-Wwrite-strings
>
#[[ Compiler Configuration, not to be confused with build targets ]]
set( DEBUG_SYMBOLS "$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>" )
# Clang only
$<${compiler_is_clang}:
-Wimplicit-fallthrough
-Wno-ordered-compare-function-pointers
>
#[[ Compiler Identification ]]
set( IS_CLANG "$<CXX_COMPILER_ID:Clang>" )
set( IS_APPLECLANG "$<CXX_COMPILER_ID:AppleClang>" )
set( IS_GNU "$<CXX_COMPILER_ID:GNU>" )
set( IS_MSVC "$<CXX_COMPILER_ID:MSVC>" )
set( NOT_MSVC "$<NOT:$<CXX_COMPILER_ID:MSVC>>" )
# GNU only
$<${compiler_is_gnu}:
-Walloc-zero
-Wduplicated-branches
-Wduplicated-cond
-Wno-misleading-indentation
-Wplacement-new=1
-Wshadow-local
-Wstringop-overflow=4
>
$<$<AND:${compiler_is_gnu},${compiler_less_than_v8}>:
# Bogus warning fixed in 8+.
-Wno-strict-overflow
>
$<$<AND:${compiler_is_gnu},${compiler_greater_than_or_equal_v9}>:
-Wattribute-alias=2
>
$<$<AND:${compiler_is_gnu},${compiler_greater_than_or_equal_v11}>:
# Broke on MethodBind templates before GCC 11.
-Wlogical-op
>
$<$<AND:${compiler_is_gnu},${compiler_less_than_v11}>:
# Regression in GCC 9/10, spams so much in our variadic templates that we need to outright disable it.
-Wno-type-limits
>
$<$<AND:${compiler_is_gnu},${compiler_greater_than_or_equal_v12}>:
# False positives in our error macros, see GH-58747.
-Wno-return-type
>
)
set( GNU_LT_V8 "$<VERSION_LESS:$<CXX_COMPILER_VERSION>,8>" )
set( GNU_GE_V9 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,9>" )
set( GNU_GT_V11 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,11>" )
set( GNU_LT_V11 "$<VERSION_LESS:$<CXX_COMPILER_VERSION>,11>" )
set( GNU_GE_V12 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,12>" )
#[[ Check for clang-cl with MSVC frontend
The compiler is tested and set when the project command is called.
The variable CXX_COMPILER_FRONTEND_VARIANT was introduced in 3.14
The generator expression $<CXX_COMPILER_FRONTEND_VARIANT> wasn't introduced
until CMake 3.30 so we can't use it yet.
So to support clang downloaded from llvm.org which uses the MSVC frontend
by default, we need to test for it. ]]
function( compiler_detection )
if( ${CMAKE_CXX_COMPILER_ID} STREQUAL Clang )
if( ${CMAKE_CXX_COMPILER_FRONTEND_VARIANT} STREQUAL MSVC )
message( "Using clang-cl" )
set( IS_CLANG "0" PARENT_SCOPE )
set( IS_MSVC "1" PARENT_SCOPE )
set( NOT_MSVC "0" PARENT_SCOPE )
endif ()
endif ()
endfunction( )
function( common_compiler_flags )
target_compile_features(${TARGET_NAME}
PUBLIC
cxx_std_17
)
# These compiler options reflect what is in godot/SConstruct.
target_compile_options( ${TARGET_NAME}
PUBLIC
# Disable exception handling. Godot doesn't use exceptions anywhere, and this
# saves around 20% of binary size and very significant build time.
$<${DISABLE_EXCEPTIONS}:
$<${NOT_MSVC}:-fno-exceptions>
>
# Enabling Debug Symbols
$<${DEBUG_SYMBOLS}:
# Adding dwarf-4 explicitly makes stacktraces work with clang builds,
# otherwise addr2line doesn't understand them.
$<${NOT_MSVC}:
-gdwarf-4
$<IF:${IS_DEV_BUILD},-g3,-g2>
>
>
$<${IS_DEV_BUILD}:
$<${NOT_MSVC}:-fno-omit-frame-pointer -O0>
>
$<${HOT_RELOAD}:
$<${IS_GNU}:-fno-gnu-unique>
>
# MSVC only
$<${IS_MSVC}:
# /MP isn't valid for clang-cl with msvc frontend
$<$<CXX_COMPILER_ID:MSVC>:/MP${PROC_N}>
/W4
# Disable warnings which we don't plan to fix.
/wd4100 # C4100 (unreferenced formal parameter): Doesn't play nice with polymorphism.
/wd4127 # C4127 (conditional expression is constant)
/wd4201 # C4201 (non-standard nameless struct/union): Only relevant for C89.
/wd4244 # C4244 C4245 C4267 (narrowing conversions): Unavoidable at this scale.
/wd4245
/wd4267
/wd4305 # C4305 (truncation): double to float or real_t, too hard to avoid.
/wd4514 # C4514 (unreferenced inline function has been removed)
/wd4714 # C4714 (function marked as __forceinline not inlined)
/wd4820 # C4820 (padding added after construct)
/utf-8
>
# Clang and GNU common options
$<$<OR:${IS_CLANG},${IS_GNU}>:
-Wall
-Wctor-dtor-privacy
-Wextra
-Wno-unused-parameter
-Wnon-virtual-dtor
-Wwrite-strings
>
# Clang only
$<${IS_CLANG}:
-Wimplicit-fallthrough
-Wno-ordered-compare-function-pointers
>
# GNU only
$<${IS_GNU}:
-Walloc-zero
-Wduplicated-branches
-Wduplicated-cond
-Wno-misleading-indentation
-Wplacement-new=1
-Wshadow-local
-Wstringop-overflow=4
# Bogus warning fixed in 8+.
$<${GNU_LT_V8}:-Wno-strict-overflow>
$<${GNU_GE_V9}:-Wattribute-alias=2>
# Broke on MethodBind templates before GCC 11.
$<${GNU_GT_V11}:-Wlogical-op>
# Regression in GCC 9/10, spams so much in our variadic templates that we need to outright disable it.
$<${GNU_LT_V11}:-Wno-type-limits>
# False positives in our error macros, see GH-58747.
$<${GNU_GE_V12}:-Wno-return-type>
>
)
target_compile_definitions(${TARGET_NAME}
PUBLIC
GDEXTENSION
# features
$<${DEBUG_FEATURES}:DEBUG_ENABLED DEBUG_METHODS_ENABLED>
$<${IS_DEV_BUILD}:DEV_ENABLED>
$<${HOT_RELOAD}:HOT_RELOAD_ENABLED>
$<$<STREQUAL:${GODOTCPP_PRECISION},double>:REAL_T_IS_DOUBLE>
$<${IS_MSVC}:$<${DISABLE_EXCEPTIONS}:_HAS_EXCEPTIONS=0>>
$<${THREADS_ENABLED}:THREADS_ENABLED>
)
target_link_options( ${TARGET_NAME}
PUBLIC
$<${IS_MSVC}:
/WX # treat link warnings as errors.
/MANIFEST:NO # We dont need a manifest
>
$<${DEBUG_SYMBOLS}:$<${IS_MSVC}:/DEBUG:FULL>>
$<$<NOT:${DEBUG_SYMBOLS}>:
$<${IS_GNU}:-s>
$<${IS_CLANG}:-s>
$<${IS_APPLECLANG}:-Wl,-S -Wl,-x -Wl,-dead_strip>
>
)
# 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>
$<$<OR:${compiler_is_clang},${compiler_is_gnu}>:-Werror>
)
endif()
endfunction()
if ( GODOT_WARNING_AS_ERROR )
set_warning_as_error()
endif()

40
cmake/emsdkHack.cmake Normal file
View File

@@ -0,0 +1,40 @@
#[=======================================================================[.rst:
emsdkHack
---------
The Emscripten platform doesn't support the use of shared libraries as known by cmake.
* https://github.com/emscripten-core/emscripten/issues/15276
* https://github.com/emscripten-core/emscripten/issues/17804
This workaround only works due to the way the cmake scripts are loaded.
Prior to the use of ``project( ... )`` directive we need to set
``CMAKE_PROJECT_INCLUDE=cmake/emscripten.cmake``.
This file will be loaded after the toolchain overriding the settings that
prevent shared library building.
CMAKE_PROJECT_INCLUDE was Added in version 3.15.
``CMAKE_PROJECT_<projectName>_INCLUDE`` was Added in version 3.17:
More information on cmake's `code injection`_
.. _code injection:https://cmake.org/cmake/help/latest/command/project.html#code-injection
Overwrite Shared Library Properties to allow shared libs to be generated.
]=======================================================================]
if( EMSCRIPTEN )
set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE)
set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-sSIDE_MODULE=1")
set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "-sSIDE_MODULE=1")
set(CMAKE_SHARED_LIBRARY_SUFFIX) # remove the suffix from the shared lib
set(CMAKE_STRIP FALSE) # used by default in pybind11 on .so modules
# The Emscripten toolchain sets the default value for EMSCRIPTEN_SYSTEM_PROCESSOR to x86
# and CMAKE_SYSTEM_PROCESSOR to this value. I don't want that.
set(CMAKE_SYSTEM_PROCESSOR "wasm32" )
# the above prevents the need for logic like:
#if( ${CMAKE_SYSTEM_NAME} STREQUAL Emscripten )
# set( SYSTEM_ARCH wasm32 )
#endif ()
endif ()

View File

@@ -1,240 +1,373 @@
function( godotcpp_options )
#[=======================================================================[.rst:
godotcpp.cmake
--------------
#TODO platform
#TODO target
As godot-cpp is a C++ project, there are no C files, and detection of a C
compiler is unnecessary. When CMake performs the configure process, if a
C compiler is specified, like in a toolchain, or from an IDE, then it will
print a warning stating that the CMAKE_C_COMPILER compiler is unused.
This if statement simply silences that warning.
]=======================================================================]
if( CMAKE_C_COMPILER )
endif ()
#[=======================================================================[.rst:
Include Platform Files
----------------------
Because these files are included into the top level CMakelists.txt before the
project directive, it means that
* ``CMAKE_CURRENT_SOURCE_DIR`` is the location of godot-cpp's CMakeLists.txt
* ``CMAKE_SOURCE_DIR`` is the location where any prior ``project(...)``
directive was
]=======================================================================]
include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/GodotCPPModule.cmake)
include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/common_compiler_flags.cmake)
include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/android.cmake)
include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/ios.cmake)
include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/linux.cmake)
include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos.cmake)
include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/web.cmake)
include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/windows.cmake)
# Detect number of processors
include(ProcessorCount)
ProcessorCount(PROC_MAX)
message( "Auto-detected ${PROC_MAX} CPU cores available for build parallelism." )
# List of known platforms
set( PLATFORM_LIST linux macos windows android ios web )
# List of known architectures
set( ARCH_LIST x86_32 x86_64 arm32 arm64 rv64 ppc32 ppc64 wasm32 )
# Function to map processors to known architectures
function( godot_arch_name OUTVAR )
# Special case for macos universal builds that target both x86_64 and arm64
if( DEFINED CMAKE_OSX_ARCHITECTURES)
if( "x86_64" IN_LIST CMAKE_OSX_ARCHITECTURES AND "arm64" IN_LIST CMAKE_OSX_ARCHITECTURES)
set(${OUTVAR} "universal" PARENT_SCOPE )
return()
endif()
endif()
# Direct match early out.
string( TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" ARCH )
if( ARCH IN_LIST ARCH_LIST )
set( ${OUTVAR} "${ARCH}" PARENT_SCOPE)
return()
endif()
# Known aliases
set( x86_64 "w64;amd64;x86-64" )
set( arm32 "armv7;armv7-a" )
set( arm64 "armv8;arm64v8;aarch64;armv8-a" )
set( rv64 "rv;riscv;riscv64" )
set( ppc32 "ppcle;ppc" )
set( ppc64 "ppc64le" )
if( ARCH IN_LIST x86_64 )
set(${OUTVAR} "x86_64" PARENT_SCOPE )
elseif( ARCH IN_LIST arm32 )
set(${OUTVAR} "arm32" PARENT_SCOPE )
elseif( ARCH IN_LIST arm64 )
set(${OUTVAR} "arm64" PARENT_SCOPE )
elseif( ARCH IN_LIST rv64 )
set(${OUTVAR} "rv64" PARENT_SCOPE )
elseif( ARCH IN_LIST ppc32 )
set(${OUTVAR} "ppc32" PARENT_SCOPE )
elseif( ARCH IN_LIST ppc64 )
set(${OUTVAR} "ppc64" PARENT_SCOPE )
elseif( ARCH MATCHES "86")
# Catches x86, i386, i486, i586, i686, etc.
set(${OUTVAR} "x86_32" PARENT_SCOPE )
else()
# Default value is whatever the processor is.
set(${OUTVAR} ${CMAKE_SYSTEM_PROCESSOR} PARENT_SCOPE )
endif ()
endfunction()
# Function to define all the options.
function( godotcpp_options )
#NOTE: platform is managed using toolchain files.
#NOTE: arch is managed by using toolchain files.
# Except for macos universal, which can be set by GODOTCPP_MACOS_UNIVERSAL=YES
# Input from user for GDExtension interface header and the API JSON file
set(GODOT_GDEXTENSION_DIR "gdextension" CACHE PATH
set( GODOTCPP_GDEXTENSION_DIR "gdextension" CACHE PATH
"Path to a custom directory containing GDExtension interface header and API JSON file ( /path/to/gdextension_dir )" )
set(GODOT_CUSTOM_API_FILE "" CACHE FILEPATH
"Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`) ( /path/to/custom_api_file )")
set( GODOTCPP_CUSTOM_API_FILE "" CACHE FILEPATH
"Path to a custom GDExtension API JSON file (takes precedence over `GODOTCPP_GDEXTENSION_DIR`) ( /path/to/custom_api_file )")
#TODO generate_bindings
option(GODOT_GENERATE_TEMPLATE_GET_NODE
option( GODOTCPP_GENERATE_TEMPLATE_GET_NODE
"Generate a template version of the Node class's get_node. (ON|OFF)" ON)
#TODO build_library
set(GODOT_PRECISION "single" CACHE STRING
set( GODOTCPP_PRECISION "single" CACHE STRING
"Set the floating-point precision level (single|double)")
#TODO arch
#TODO threads
set( GODOTCPP_THREADS ON CACHE BOOL "Enable threading support" )
#TODO compiledb
#TODO compiledb_file
#TODO build_profile aka cmake preset
set(GODOT_USE_HOT_RELOAD "" CACHE BOOL
set( GODOTCPP_BUILD_PROFILE "" CACHE PATH
"Path to a file containing a feature build profile" )
set( GODOTCPP_USE_HOT_RELOAD "" CACHE BOOL
"Enable the extra accounting required to support hot reload. (ON|OFF)")
option(GODOT_DISABLE_EXCEPTIONS "Force disabling exception handling code (ON|OFF)" ON )
set( GODOT_SYMBOL_VISIBILITY "hidden" CACHE STRING
"Symbols visibility on GNU platforms. Use 'auto' to apply the default value. (auto|visible|hidden)")
set_property( CACHE GODOT_SYMBOL_VISIBILITY PROPERTY STRINGS "auto;visible;hidden" )
#TODO optimize
#TODO debug_symbols
#TODO dev_build
# FIXME These options are not present in SCons, and perhaps should be added there.
option(GODOT_SYSTEM_HEADERS "Expose headers as SYSTEM." ON)
option(GODOT_WARNING_AS_ERROR "Treat warnings as errors" OFF)
# Run options commands on the following to populate cache for all platforms.
# This type of thing is typically done conditionally
# But as scons shows all options so shall we.
#TODO ios_options()
#TODO linux_options()
#TODO macos_options()
#TODO web_options()
#TODO windows_options()
endfunction()
function( godotcpp_generate )
# Set some helper variables for readability
set( compiler_is_clang "$<OR:$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:Clang>>" )
set( compiler_is_gnu "$<CXX_COMPILER_ID:GNU>" )
set( compiler_is_msvc "$<CXX_COMPILER_ID:MSVC>" )
# CXX_VISIBILITY_PRESET supported values are: default, hidden, protected, and internal
# which is inline with the gcc -fvisibility=
# https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html
# To match the scons options we need to change the text to match the -fvisibility flag
# it is probably worth another PR which changes both to use the flag options
if( ${GODOT_SYMBOL_VISIBILITY} STREQUAL "auto" OR ${GODOT_SYMBOL_VISIBILITY} STREQUAL "visible" )
set( GODOT_SYMBOL_VISIBILITY "default" )
endif ()
# Default build type is Debug in the SConstruct
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
set(CMAKE_BUILD_TYPE Debug)
endif()
# Hot reload is enabled by default in Debug-builds
if( GODOT_USE_HOT_RELOAD STREQUAL "" AND NOT CMAKE_BUILD_TYPE STREQUAL "Release")
set(GODOT_USE_HOT_RELOAD ON)
endif()
if(NOT DEFINED BITS)
set(BITS 32)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(BITS 64)
endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
endif()
set(GODOT_GDEXTENSION_API_FILE "${GODOT_GDEXTENSION_DIR}/extension_api.json")
if (NOT "${GODOT_CUSTOM_API_FILE}" STREQUAL "") # User-defined override.
set(GODOT_GDEXTENSION_API_FILE "${GODOT_CUSTOM_API_FILE}")
endif()
if ("${GODOT_PRECISION}" STREQUAL "double")
add_definitions(-DREAL_T_IS_DOUBLE)
endif()
set( GODOT_COMPILE_FLAGS )
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# using Visual Studio C++
set(GODOT_COMPILE_FLAGS "/utf-8") # /GF /MP
if(CMAKE_BUILD_TYPE MATCHES Debug)
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MDd") # /Od /RTC1 /Zi
else()
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MD /O2") # /Oy /GL /Gy
endif(CMAKE_BUILD_TYPE MATCHES Debug)
add_definitions(-DNOMINMAX)
else() # GCC/Clang
if(CMAKE_BUILD_TYPE MATCHES Debug)
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0 -g")
else()
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -O3")
endif(CMAKE_BUILD_TYPE MATCHES Debug)
endif()
# Disable exception handling. Godot doesn't use exceptions anywhere, and this
# saves around 20% of binary size and very significant build time (GH-80513).
if (GODOT_DISABLE_EXCEPTIONS)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -D_HAS_EXCEPTIONS=0")
else()
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-exceptions")
endif()
else()
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /EHsc")
endif()
endif()
option( GODOTCPP_DISABLE_EXCEPTIONS "Force disabling exception handling code (ON|OFF)" ON )
# Generate source from the bindings file
find_package(Python3 3.4 REQUIRED) # pathlib should be present
if(GODOT_GENERATE_TEMPLATE_GET_NODE)
set(GENERATE_BINDING_PARAMETERS "True")
else()
set(GENERATE_BINDING_PARAMETERS "False")
endif()
set( GODOTCPP_SYMBOL_VISIBILITY "hidden" CACHE STRING
"Symbols visibility on GNU platforms. Use 'auto' to apply the default value. (auto|visible|hidden)")
set_property( CACHE GODOTCPP_SYMBOL_VISIBILITY PROPERTY STRINGS "auto;visible;hidden" )
execute_process(COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.print_file_list(\"${GODOT_GDEXTENSION_API_FILE}\", \"${CMAKE_CURRENT_BINARY_DIR}\", headers=True, sources=True)"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE GENERATED_FILES_LIST
OUTPUT_STRIP_TRAILING_WHITESPACE
)
#TODO optimize
add_custom_command(OUTPUT ${GENERATED_FILES_LIST}
COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.generate_bindings(\"${GODOT_GDEXTENSION_API_FILE}\", \"${GENERATE_BINDING_PARAMETERS}\", \"${BITS}\", \"${GODOT_PRECISION}\", \"${CMAKE_CURRENT_BINARY_DIR}\")"
VERBATIM
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
MAIN_DEPENDENCY ${GODOT_GDEXTENSION_API_FILE}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/binding_generator.py
COMMENT "Generating bindings"
)
option( GODOTCPP_DEV_BUILD "Developer build with dev-only debugging code (DEV_ENABLED)" OFF )
# Get Sources
# As this cmake file was added using 'include(godotcpp)' from the root CMakeLists.txt,
# the ${CMAKE_CURRENT_SOURCE_DIR} is still the root dir.
file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS src/*.c**)
file(GLOB_RECURSE HEADERS CONFIGURE_DEPENDS include/*.h**)
#[[ debug_symbols
Debug symbols are enabled by using the Debug or RelWithDebInfo build configurations.
Single Config Generator is set at configure time
# Define our godot-cpp library
add_library(${PROJECT_NAME} STATIC
${SOURCES}
${HEADERS}
${GENERATED_FILES_LIST}
)
add_library(godot::cpp ALIAS ${PROJECT_NAME})
cmake ../ -DCMAKE_BUILD_TYPE=Debug
include(${PROJECT_SOURCE_DIR}/cmake/common_compiler_flags.cmake)
Multi-Config Generator is set at build time
target_compile_features(${PROJECT_NAME}
PRIVATE
cxx_std_17
)
cmake --build . --config Debug
if(GODOT_USE_HOT_RELOAD)
target_compile_definitions(${PROJECT_NAME} PUBLIC HOT_RELOAD_ENABLED)
target_compile_options(${PROJECT_NAME} PUBLIC $<${compiler_is_gnu}:-fno-gnu-unique>)
endif()
]]
target_compile_definitions(${PROJECT_NAME} PUBLIC
$<$<CONFIG:Debug>:
DEBUG_ENABLED
DEBUG_METHODS_ENABLED
>
$<${compiler_is_msvc}:
TYPED_METHOD_BIND
>
)
# FIXME These options are not present in SCons, and perhaps should be added there.
option( GODOTCPP_SYSTEM_HEADERS "Expose headers as SYSTEM." OFF )
option( GODOTCPP_WARNING_AS_ERROR "Treat warnings as errors" OFF )
target_link_options(${PROJECT_NAME} PRIVATE
$<$<NOT:${compiler_is_msvc}>:
-static-libgcc
-static-libstdc++
-Wl,-R,'$$ORIGIN'
>
)
# Enable Testing
option( GODOTCPP_ENABLE_TESTING "Enable the godot-cpp.test.<target> integration testing targets" OFF )
# Optionally mark headers as SYSTEM
set(GODOT_SYSTEM_HEADERS_ATTRIBUTE "")
if (GODOT_SYSTEM_HEADERS)
set(GODOT_SYSTEM_HEADERS_ATTRIBUTE SYSTEM)
#[[ Target Platform Options ]]
android_options()
ios_options()
linux_options()
macos_options()
web_options()
windows_options()
endfunction()
# Function to configure and generate the targets
function( godotcpp_generate )
#[[ Multi-Threaded MSVC Compilation
When using the MSVC compiler the build command -j <n> only specifies
parallel jobs or targets, and not multi-threaded compilation To speed up
compile times on msvc, the /MP <n> flag can be set. But we need to set it
at configure time.
MSVC is true when the compiler is some version of Microsoft Visual C++ or
another compiler simulating the Visual C++ cl command-line syntax. ]]
if( MSVC )
math( EXPR PROC_N "(${PROC_MAX}-1) | (${X}-2)>>31 & 1" )
message( "Using ${PROC_N} cores for multi-threaded compilation.")
# TODO You can override it at configure time with ...." )
else ()
message( "Using ${CMAKE_BUILD_PARALLEL_LEVEL} cores, You can override"
" it at configure time by using -j <n> or --parallel <n> on the build"
" command.")
message( " eg. cmake --build . -j 7 ...")
endif ()
target_include_directories(${PROJECT_NAME} ${GODOT_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC
include
${CMAKE_CURRENT_BINARY_DIR}/gen/include
${GODOT_GDEXTENSION_DIR}
)
#[[ GODOTCPP_SYMBOL_VISIBLITY
To match the SCons options, the allowed values are "auto", "visible", and "hidden"
This effects the compiler flag_ -fvisibility=[default|internal|hidden|protected]
The corresponding target option CXX_VISIBILITY_PRESET accepts the compiler values.
# Add the compile flags
set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY COMPILE_FLAGS ${GODOT_COMPILE_FLAGS})
TODO: It is probably worth a pull request which changes both to use the compiler values
.. _flag:https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#index-fvisibility
]]
if( ${GODOTCPP_SYMBOL_VISIBILITY} STREQUAL "auto" OR ${GODOTCPP_SYMBOL_VISIBILITY} STREQUAL "visible" )
set( GODOTCPP_SYMBOL_VISIBILITY "default" )
endif ()
# Create the correct name (godot.os.build_type.system_bits)
string(TOLOWER "${CMAKE_SYSTEM_NAME}" SYSTEM_NAME)
string(TOLOWER "${CMAKE_BUILD_TYPE}" BUILD_TYPE)
# Setup variable to optionally mark headers as SYSTEM
set( GODOTCPP_SYSTEM_HEADERS_ATTRIBUTE "")
if( GODOTCPP_SYSTEM_HEADERS)
set( GODOTCPP_SYSTEM_HEADERS_ATTRIBUTE SYSTEM)
endif ()
if(ANDROID)
# Added the android abi after system name
set(SYSTEM_NAME ${SYSTEM_NAME}.${ANDROID_ABI})
# Android does not have the bits at the end if you look at the main godot repo build
set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}")
else()
set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}.${BITS}")
#[[ Configure Binding Variables ]]
# Generate Binding Parameters (True|False)
set( USE_TEMPLATE_GET_NODE "False" )
if( GODOTCPP_GENERATE_TEMPLATE_GET_NODE )
set( USE_TEMPLATE_GET_NODE "True" )
endif()
set_target_properties(${PROJECT_NAME}
PROPERTIES
CXX_EXTENSIONS OFF
POSITION_INDEPENDENT_CODE ON
CXX_VISIBILITY_PRESET ${GODOT_SYMBOL_VISIBILITY}
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin"
OUTPUT_NAME "${OUTPUT_NAME}"
# Bits (32|64)
math( EXPR BITS "${CMAKE_SIZEOF_VOID_P} * 8" ) # CMAKE_SIZEOF_VOID_P refers to target architecture.
# API json File
set( GODOTCPP_GDEXTENSION_API_FILE "${GODOTCPP_GDEXTENSION_DIR}/extension_api.json")
if( GODOTCPP_CUSTOM_API_FILE ) # User-defined override.
set( GODOTCPP_GDEXTENSION_API_FILE "${GODOTCPP_CUSTOM_API_FILE}")
endif()
# Build Profile
if( GODOTCPP_BUILD_PROFILE )
message( STATUS "Using build profile to trim api file")
message( "\tBUILD_PROFILE = '${GODOTCPP_BUILD_PROFILE}'")
message( "\tAPI_SOURCE = '${GODOTCPP_GDEXTENSION_API_FILE}'")
build_profile_generate_trimmed_api(
"${GODOTCPP_BUILD_PROFILE}"
"${GODOTCPP_GDEXTENSION_API_FILE}"
"${CMAKE_CURRENT_BINARY_DIR}/extension_api.json" )
set( GODOTCPP_GDEXTENSION_API_FILE "${CMAKE_CURRENT_BINARY_DIR}/extension_api.json" )
endif()
message( STATUS "GODOTCPP_GDEXTENSION_API_FILE = '${GODOTCPP_GDEXTENSION_API_FILE}'")
# generate the file list to use
binding_generator_get_file_list( GENERATED_FILES_LIST
"${GODOTCPP_GDEXTENSION_API_FILE}"
"${CMAKE_CURRENT_BINARY_DIR}" )
binding_generator_generate_bindings(
"${GODOTCPP_GDEXTENSION_API_FILE}"
"${USE_TEMPLATE_GET_NODE}"
"${BITS}"
"${GODOTCPP_PRECISION}"
"${CMAKE_CURRENT_BINARY_DIR}" )
add_custom_target( godot-cpp.generate_bindings DEPENDS ${GENERATED_FILES_LIST} )
set_target_properties( godot-cpp.generate_bindings PROPERTIES FOLDER "godot-cpp" )
### Platform is derived from the toolchain target
# See GeneratorExpressions PLATFORM_ID and CMAKE_SYSTEM_NAME
string( CONCAT SYSTEM_NAME
"$<$<PLATFORM_ID:Android>:android.${ANDROID_ABI}>"
"$<$<PLATFORM_ID:iOS>:ios>"
"$<$<PLATFORM_ID:Linux>:linux>"
"$<$<PLATFORM_ID:Darwin>:macos>"
"$<$<PLATFORM_ID:Emscripten>:web>"
"$<$<PLATFORM_ID:Windows>:windows>"
"$<$<PLATFORM_ID:Msys>:windows>"
)
# Process CPU architecture argument.
godot_arch_name( ARCH_NAME )
# Transform options into generator expressions
set( HOT_RELOAD-UNSET "$<STREQUAL:${GODOTCPP_USE_HOT_RELOAD},>")
set( DISABLE_EXCEPTIONS "$<BOOL:${GODOTCPP_DISABLE_EXCEPTIONS}>")
set( THREADS_ENABLED "$<BOOL:${GODOTCPP_THREADS}>" )
# GODOTCPP_DEV_BUILD
set( RELEASE_TYPES "Release;MinSizeRel")
get_property( IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG )
if( IS_MULTI_CONFIG )
message( NOTICE "=> Default build type is Debug. For other build types add --config <type> to build command")
elseif( GODOTCPP_DEV_BUILD AND CMAKE_BUILD_TYPE IN_LIST RELEASE_TYPES )
message( WARNING "=> GODOTCPP_DEV_BUILD implies a Debug-like build but CMAKE_BUILD_TYPE is '${CMAKE_BUILD_TYPE}'")
endif ()
set( IS_DEV_BUILD "$<BOOL:${GODOTCPP_DEV_BUILD}>")
### Define our godot-cpp library targets
foreach ( TARGET_ALIAS template_debug template_release editor )
set( TARGET_NAME "godot-cpp.${TARGET_ALIAS}" )
# Generator Expressions that rely on the target
set( DEBUG_FEATURES "$<NOT:$<STREQUAL:${TARGET_ALIAS},template_release>>" )
set( HOT_RELOAD "$<IF:${HOT_RELOAD-UNSET},${DEBUG_FEATURES},$<BOOL:${GODOTCPP_USE_HOT_RELOAD}>>" )
# Suffix
string( CONCAT GODOTCPP_SUFFIX
"$<1:.${SYSTEM_NAME}>"
"$<1:.${TARGET_ALIAS}>"
"$<${IS_DEV_BUILD}:.dev>"
"$<$<STREQUAL:${GODOTCPP_PRECISION},double>:.double>"
"$<1:.${ARCH_NAME}>"
# TODO IOS_SIMULATOR
"$<$<NOT:${THREADS_ENABLED}>:.nothreads>"
)
# the godot-cpp.* library targets
add_library( ${TARGET_NAME} STATIC EXCLUDE_FROM_ALL )
add_library( godot-cpp::${TARGET_ALIAS} ALIAS ${TARGET_NAME} )
file( GLOB_RECURSE GODOTCPP_SOURCES LIST_DIRECTORIES NO CONFIGURE_DEPENDS src/*.cpp )
target_sources( ${TARGET_NAME}
PRIVATE
${GODOTCPP_SOURCES}
${GENERATED_FILES_LIST}
)
target_include_directories( ${TARGET_NAME} ${GODOTCPP_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC
include
${CMAKE_CURRENT_BINARY_DIR}/gen/include
${GODOTCPP_GDEXTENSION_DIR}
)
set_target_properties( ${TARGET_NAME}
PROPERTIES
CXX_STANDARD 17
CXX_EXTENSIONS OFF
CXX_VISIBILITY_PRESET ${GODOTCPP_SYMBOL_VISIBILITY}
COMPILE_WARNING_AS_ERROR ${GODOTCPP_WARNING_AS_ERROR}
POSITION_INDEPENDENT_CODE ON
BUILD_RPATH_USE_ORIGIN ON
PREFIX "lib"
OUTPUT_NAME "${PROJECT_NAME}${GODOTCPP_SUFFIX}"
ARCHIVE_OUTPUT_DIRECTORY "$<1:${CMAKE_BINARY_DIR}/bin>"
# Things that are handy to know for dependent targets
GODOTCPP_PLATFORM "${SYSTEM_NAME}"
GODOTCPP_TARGET "${TARGET_ALIAS}"
GODOTCPP_ARCH "${ARCH_NAME}"
GODOTCPP_PRECISION "${GODOTCPP_PRECISION}"
GODOTCPP_SUFFIX "${GODOTCPP_SUFFIX}"
# Some IDE's respect this property to logically group targets
FOLDER "godot-cpp"
)
if( CMAKE_SYSTEM_NAME STREQUAL Android )
android_generate()
elseif ( CMAKE_SYSTEM_NAME STREQUAL iOS )
ios_generate()
elseif ( CMAKE_SYSTEM_NAME STREQUAL Linux )
linux_generate()
elseif ( CMAKE_SYSTEM_NAME STREQUAL Darwin )
macos_generate()
elseif ( CMAKE_SYSTEM_NAME STREQUAL Emscripten )
web_generate()
elseif ( CMAKE_SYSTEM_NAME STREQUAL Windows )
windows_generate()
endif ()
endforeach ()
# Added for backwards compatibility with prior cmake solution so that builds dont immediately break
# from a missing target.
add_library( godot::cpp ALIAS godot-cpp.template_debug )
endfunction()

21
cmake/ios.cmake Normal file
View File

@@ -0,0 +1,21 @@
#[=======================================================================[.rst:
Ios
---
This file contains functions for options and configuration for targeting the
Ios platform
]=======================================================================]
function(ios_options)
# iOS options
endfunction()
function(ios_generate)
target_compile_definitions(${TARGET_NAME}
PUBLIC
IOS_ENABLED
UNIX_ENABLED
)
common_compiler_flags()
endfunction()

21
cmake/linux.cmake Normal file
View File

@@ -0,0 +1,21 @@
#[=======================================================================[.rst:
Linux
-----
This file contains functions for options and configuration for targeting the
Linux platform
]=======================================================================]
function( linux_options )
# Linux Options
endfunction()
function( linux_generate )
target_compile_definitions( ${TARGET_NAME}
PUBLIC
LINUX_ENABLED
UNIX_ENABLED
)
common_compiler_flags()
endfunction()

46
cmake/macos.cmake Normal file
View File

@@ -0,0 +1,46 @@
#[=======================================================================[.rst:
MacOS
-----
This file contains functions for options and configuration for targeting the
MacOS platform
# To build universal binaries, ie targeting both x86_64 and arm64, use
# the CMAKE_OSX_ARCHITECTURES variable prior to any project calls.
# https://cmake.org/cmake/help/latest/variable/CMAKE_OSX_ARCHITECTURES.html
]=======================================================================]
# Find Requirements
IF(APPLE)
set( CMAKE_OSX_SYSROOT $ENV{SDKROOT} )
find_library( COCOA_LIBRARY REQUIRED
NAMES Cocoa
PATHS ${CMAKE_OSX_SYSROOT}/System/Library
PATH_SUFFIXES Frameworks
NO_DEFAULT_PATH)
ENDIF (APPLE)
function( macos_options )
endfunction()
function( macos_generate )
target_compile_definitions(${TARGET_NAME}
PUBLIC
MACOS_ENABLED
UNIX_ENABLED
)
target_link_options( ${TARGET_NAME}
PUBLIC
-Wl,-undefined,dynamic_lookup
)
target_link_libraries( ${TARGET_NAME}
INTERFACE
${COCOA_LIBRARY}
)
common_compiler_flags()
endfunction()

42
cmake/web.cmake Normal file
View File

@@ -0,0 +1,42 @@
#[=======================================================================[.rst:
Web
---
This file contains functions for options and configuration for targeting the
Web platform
]=======================================================================]
# Emscripten requires this hack for use of the SHARED option
set( CMAKE_PROJECT_godot-cpp_INCLUDE cmake/emsdkHack.cmake )
function( web_options )
# web options
endfunction()
function( web_generate )
target_compile_definitions(${TARGET_NAME}
PUBLIC
WEB_ENABLED
UNIX_ENABLED
)
target_compile_options( ${TARGET_NAME}
PUBLIC
-sSIDE_MODULE
-sSUPPORT_LONGJMP=wasm
-fno-exceptions
$<${THREADS_ENABLED}:-sUSE_PTHREADS=1>
)
target_link_options( ${TARGET_NAME}
INTERFACE
-sWASM_BIGINT
-sSUPPORT_LONGJMP=wasm
-fvisibility=hidden
-shared
)
common_compiler_flags()
endfunction()

103
cmake/windows.cmake Normal file
View File

@@ -0,0 +1,103 @@
#[=======================================================================[.rst:
Windows
-------
This file contains functions for options and configuration for targeting the
Windows platform
Because this file is included into the top level CMakelists.txt before the
project directive, it means that
* ``CMAKE_CURRENT_SOURCE_DIR`` is the location of godot-cpp's CMakeLists.txt
* ``CMAKE_SOURCE_DIR`` is the location where any prior ``project(...)``
directive was
MSVC Runtime Selection
----------------------
There are two main ways to set the msvc runtime library;
Using ``target_compile_options()`` to add the flags
or using the ``CMAKE_MSVC_RUNTIME_LIBRARY`` property_ abstraction, introduced
in CMake version 3.15 with the policy CMP0091_ to remove the flags from
``CMAKE_<LANG>_FLAGS_<CONFIG>``.
Default: ``CMAKE_MSVC_RUNTIME_LIBRARY="MultiThreaded$<$<CONFIG:Debug>:Debug>DLL"``
This initializes each target's ``MSVC_RUNTIME_LIBRARY`` property at the time of
target creation.
it is stated in the msvc_ documentation that: "All modules passed to a given
invocation of the linker must have been compiled with the same runtime library
compiler option (/MD, /MT, /LD)."
This creates a conundrum for us, the ``CMAKE_MSVC_RUNTIME_LIBRARY`` needs to be
correct at the time the target is created, but we have no control over the
consumers CMake scripts, and the per-target ``MSVC_RUNTIME_LIBRARY`` property
is not transient.
It has been raised that not using ``CMAKE_MSVC_RUNTIME_LIBRARY`` can also cause
issues_ when a dependency( independent to godot-cpp ) that doesn't set any
runtime flags, which relies purely on the ``CMAKE_MSVC_RUNTIME_LIBRARY``
variable will very likely not have the correct msvc runtime flags set.
So we'll set ``CMAKE_MSVC_RUNTIME_LIBRARY`` as CACHE STRING so that it will be
available for consumer target definitions, but also be able to be overridden if
needed.
Additionally we message consumers notifying them and pointing to this
documentation.
.. _CMP0091:https://cmake.org/cmake/help/latest/policy/CMP0091.html
.. _property:https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html
.. https://discourse.cmake.org/t/mt-staticrelease-doesnt-match-value-md-dynamicrelease/5428/4
.. _msvc: https://learn.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library
.. _issues: https://github.com/godotengine/godot-cpp/issues/1699
]=======================================================================]
function( windows_options )
option( GODOTCPP_USE_STATIC_CPP "Link MinGW/MSVC C++ runtime libraries statically" ON )
option( GODOTCPP_DEBUG_CRT "Compile with MSVC's debug CRT (/MDd)" OFF )
message( STATUS "If not already cached, setting CMAKE_MSVC_RUNTIME_LIBRARY.\n"
"\tFor more information please read godot-cpp/cmake/windows.cmake")
set( CMAKE_MSVC_RUNTIME_LIBRARY
"MultiThreaded$<IF:$<BOOL:${GODOTCPP_DEBUG_CRT}>,DebugDLL,$<$<NOT:$<BOOL:${GODOTCPP_USE_STATIC_CPP}>>:DLL>>"
CACHE STRING "Select the MSVC runtime library for use by compilers targeting the MSVC ABI.")
endfunction()
#[===========================[ Target Generation ]===========================]
function( windows_generate )
set( STATIC_CPP "$<BOOL:${GODOTCPP_USE_STATIC_CPP}>")
set_target_properties( ${TARGET_NAME}
PROPERTIES
PDB_OUTPUT_DIRECTORY "$<1:${CMAKE_SOURCE_DIR}/bin>"
)
target_compile_definitions( ${TARGET_NAME}
PUBLIC
WINDOWS_ENABLED
$<${IS_MSVC}:
TYPED_METHOD_BIND
NOMINMAX
>
)
target_link_options( ${TARGET_NAME}
PUBLIC
$<${NOT_MSVC}:
-Wl,--no-undefined
$<${STATIC_CPP}:
-static
-static-libgcc
-static-libstdc++
>
>
$<${IS_CLANG}:-lstdc++>
)
common_compiler_flags()
endfunction()

View File

@@ -1,57 +0,0 @@
## CMake
### cmake arguments
`CMAKE_BUILD_TYPE`: Compilation target (Debug or Release defaults to Debug)
### godot-cpp cmake arguments
- `GODOT_GDEXTENSION_DIR`: Path to the directory containing GDExtension interface header and API JSON file
- `GODOT_SYSTEM_HEADERS`: Mark the header files as SYSTEM. This may be useful to suppress warnings in projects including this one.
- `GODOT_WARNING_AS_ERROR`: Treat any warnings as errors
- `GODOT_USE_HOT_RELOAD`: Build with hot reload support. Defaults to YES for Debug-builds and NO for Release-builds.
- `GODOT_CUSTOM_API_FILE`: Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`)
- `GODOT_PRECISION`: Floating-point precision level ("single", "double")
### Android cmake arguments
- `CMAKE_TOOLCHAIN_FILE`: The path to the android cmake toolchain ($ANDROID_NDK/build/cmake/android.toolchain.cmake)
- `ANDROID_NDK`: The path to the android ndk root folder
- `ANDROID_TOOLCHAIN_NAME`: The android toolchain (arm-linux-androideabi-4.9 or aarch64-linux-android-4.9 or x86-4.9 or x86_64-4.9)
- `ANDROID_PLATFORM`: The android platform version (android-23)
- More info [here](https://godot.readthedocs.io/en/latest/development/compiling/compiling_for_android.html)
## Examples
```shell
Builds a debug version:
cmake .
cmake --build .
```
Builds a release version with clang
```shell
CC=/usr/bin/clang CXX=/usr/bin/clang++ cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" .
cmake --build .
```
Builds an android armeabi-v7a debug version:
``` shell
cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake -DANDROID_NDK=$ANDROID_NDK \
-DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.9 -DANDROID_PLATFORM=android-23 -DCMAKE_BUILD_TYPE=Debug .
cmake --build .
```
## Protip
Generate the buildfiles in a sub directory to not clutter the root directory with build files:
```shell
mkdir build && cd build && cmake -G "Unix Makefiles" .. && cmake --build .
```
Ensure that you avoid exposing godot-cpp symbols - this might lead to hard to debug errors if you ever load multiple
plugins using difference godot-cpp versions. Use visibility hidden whenever possible:
```cmake
set_target_properties(<all-my-plugin-related-targets> PROPERTIES CXX_VISIBILITY_PRESET hidden)
```
## Todo
Test build for Windows, Mac and mingw.

377
doc/cmake.rst Normal file
View File

@@ -0,0 +1,377 @@
CMake
=====
.. warning::
The CMake scripts do not have feature parity with the SCons ones at this
stage and are still a work in progress. There are a number of people who
have been working on alternative CMake solutions that are frequently
referenced in the discord chats: Ivan's cmake-rewrite_ branch and
Vorlac's godot-roguelite_ Project
.. _cmake-rewrite: https://github.com/IvanInventor/godot-cpp/tree/cmake-rewrite
.. _godot-roguelite: https://github.com/vorlac/godot-roguelite
Introduction
------------
Compiling godot-cpp independently of an extension project is mainly for
godot-cpp developers, package maintainers, and CI/CD. Look to the
godot-cpp-template_ for a practical example on how to consume the godot-cpp
library as part of a Godot extension.
Configuration examples are listed at the bottom of the page.
.. _godot-cpp-template: https://github.com/godotengine/godot-cpp-template
SCons Deviations
----------------
Not everything from SCons can be perfectly representable in CMake, here are
the notable differences.
- debug_symbols
No longer has an explicit option, and is enabled via Debug-like CMake
build configurations; Debug, RelWithDebInfo.
- dev_build
Does not define NDEBUG when disabled, NDEBUG is set via Release-like
CMake build configurations; Release, MinSizeRel.
Testing Integration
-------------------
When consuming a third party CMake project into yours, an unfortunate side
effect is that the targets of the consumed project appear in the list of
available targets, and are by default included in the ALL meta target
created by most build systems. For this reason, all the targets specified
in godot-cpp are marked with the ``EXCLUDE_FROM_ALL`` tag to prevent
unnecessary compilation. The testing targets ``godot-cpp.test.<target>``
are also guarded by ``GODOTCPP_ENABLE_TESTING`` which is off by default.
To configure and build the godot-cpp project to enable the integration
testing targets the command will look something like:
.. code-block::
# Assuming our current directory is the godot-cpp source root
mkdir cmake-build
cd cmake-build
cmake .. -DGODOTCPP_ENABLE_TESTING=YES
cmake --build . --target godot-cpp.test.template_debug
Basic walkthrough
-----------------
.. topic:: Clone the git repository
.. code-block::
git clone https://github.com/godotengine/godot-cpp.git
Cloning into 'godot-cpp'...
...
cd godot-cpp
.. topic:: Out-of-tree build directory
Create a build directory for CMake to put caches and build artifacts in and
change directory to it. This is typically as a sub-directory of the project
root but can be outside the source tree. This is so that generated files do
not clutter up the source tree.
.. code-block::
mkdir cmake-build
cd cmake-build
.. topic:: Configure the build
CMake doesn't build the code, it generates the files that another tool uses
to build the code. To see the list of generators run ``cmake --help``. The
first phase of which is running through the configuration scripts.
Configure and generate Ninja build files.
.. code-block::
cmake .. -G "Ninja"
To list the available options CMake use the ``-L[AH]`` option. ``A`` is for
advanced, and ``H`` is for help strings.
.. code-block::
cmake .. -LH
Options are specified on the command line when configuring
.. code-block::
cmake .. -DGODOTCPP_USE_HOT_RELOAD:BOOL=ON \
-DGODOTCPP_PRECISION:STRING=double \
-DCMAKE_BUILD_TYPE:STRING=Debug
Review setting-build-variables_ and build-configurations_ for more information.
.. _setting-build-variables: https://cmake.org/cmake/help/latest/guide/user-interaction/index.html#setting-build-variables
.. _build-configurations: https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#build-configurations
A non-exhaustive list of options:
.. code-block::
// Path to a custom GDExtension API JSON file (takes precedence over `GODOTCPP_GDEXTENSION_DIR`) ( /path/to/custom_api_file )
`GODOTCPP_CUSTOM_API_FILE:FILEPATH=`
// Force disabling exception handling code (ON|OFF)
GODOTCPP_DISABLE_EXCEPTIONS:BOOL=ON
// Path to a custom directory containing GDExtension interface header and API JSON file ( /path/to/gdextension_dir )
GODOTCPP_GDEXTENSION_DIR:PATH=gdextension
// Generate a template version of the Node class's get_node. (ON|OFF)
GODOTCPP_GENERATE_TEMPLATE_GET_NODE:BOOL=ON
// Set the floating-point precision level (single|double)
GODOTCPP_PRECISION:STRING=single
// Symbols visibility on GNU platforms. Use 'auto' to apply the default value. (auto|visible|hidden)
GODOTCPP_SYMBOL_VISIBILITY:STRING=hidden
// Expose headers as SYSTEM.
GODOTCPP_SYSTEM_HEADERS:BOOL=ON
// Enable the extra accounting required to support hot reload. (ON|OFF)
GODOTCPP_USE_HOT_RELOAD:BOOL=
// Treat warnings as errors
GODOTCPP_WARNING_AS_ERROR:BOOL=OFF
.. topic:: Compiling
A target and a configuration is required, as the default ``all`` target does
not include anything and when using multi-config generators like ``Ninja
Multi-Config``, ``Visual Studio *`` or ``Xcode`` the build configuration
needs to be specified at build time. Build in Release mode unless you need
debug symbols.
.. code-block::
cmake --build . -t template_debug --config Debug
Examples
--------
Windows and MSVC - Release
~~~~~~~~~~~~~~~~~~~~~~~~~~
So long as CMake is installed from the `CMake Downloads`_ page and in the PATH,
and Microsoft Visual Studio is installed with c++ support, CMake will detect
the MSVC compiler.
Remembering that Visual Studio is a Multi-Config Generator so the build type
needs to be specified at build time.
.. _CMake downloads: https://cmake.org/download/
.. code-block::
# Assuming our current directory is the godot-cpp source root
mkdir build-msvc
cd build-msvc
cmake .. -DGODOTCPP_ENABLE_TESTING=YES
cmake --build . -t godot-cpp.test.template_debug --config Debug
MSys2/clang64, "Ninja" - Debug
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Assumes the ming-w64-clang-x86_64-toolchain is installed
Remembering that Ninja is a Single-Config Generator so the build type
needs to be specified at Configure time.
Using the msys2/clang64 shell
.. code-block::
# Assuming our current directory is the godot-cpp source root
mkdir build-clang
cd build-clang
cmake .. -G"Ninja" -DGODOTCPP_ENABLE_TESTING=YES -DCMAKE_BUILD_TYPE=Debug
cmake --build . -t godot-cpp.test.template_debug
MSys2/clang64, "Ninja Multi-Config" - dev_build, Debug Symbols
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Assumes the ming-w64-clang-x86_64-toolchain is installed
This time we are choosing the 'Ninja Multi-Config' generator, so the build
type is specified at build time.
Using the msys2/clang64 shell
.. code-block::
# Assuming our current directory is the godot-cpp source root
mkdir build-clang
cd build-clang
cmake .. -G"Ninja Multi-Config" -DGODOTCPP_ENABLE_TESTING=YES -DGODOTCPP_DEV_BUILD:BOOL=ON
cmake --build . -t godot-cpp.test.template_debug --config Debug
Emscripten for web platform
~~~~~~~~~~~~~~~~~~~~~~~~~~~
I've only tested this on windows so far.
I cloned and installed the latest Emscripten tools to ``c:\emsdk``
At the time of writing that was v3.1.69
I've been using ``C:\emsdk\emsdk.ps1 activate latest`` to enable the
environment from powershell in the current shell.
The ``emcmake.bat`` utility adds the emscripten toolchain to the CMake command
.. code-block::
# Assuming our current directory is the godot-cpp source root
C:\emsdk\emsdk.ps1 activate latest
mkdir build-wasm32
cd build-wasm32
emcmake.bat cmake ../
cmake --build . --target template_release
Android Cross Compile from Windows
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There are two separate paths you can choose when configuring for android.
Use the ``CMAKE_ANDROID_*`` variables specified on the commandline or in your
own toolchain file as listed in the cmake-toolchains_ documentation
.. _cmake-toolchains: https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-android-with-the-ndk
Or use the toolchain and scripts provided by the Android SDK and make changes
using the ``ANDROID_*`` variables listed there. Where ``<version>`` is whatever
ndk version you have installed (tested with `23.2.8568313`) and ``<platform>``
is for android sdk platform, (tested with ``android-29``)
.. warning::
The Android SDK website explicitly states that they do not support using
the CMake built-in method, and recommends you stick with their toolchain
files.
.. topic:: Using your own toolchain file as described in the CMake documentation
.. code-block::
# Assuming our current directory is the godot-cpp source root
mkdir build-android
cd build-android
cmake .. --toolchain my_toolchain.cmake
cmake --build . -t template_release
Doing the equivalent on just using the command line
.. code-block::
# Assuming our current directory is the godot-cpp source root
mkdir build-android
cd build-android
cmake .. \
-DCMAKE_SYSTEM_NAME=Android \
-DCMAKE_SYSTEM_VERSION=<platform> \
-DCMAKE_ANDROID_ARCH_ABI=<arch> \
-DCMAKE_ANDROID_NDK=/path/to/android-ndk
cmake --build . -t template_release
.. topic:: Using the toolchain file from the Android SDK
Defaults to minimum supported version( android-16 in my case) and armv7-a.
.. code-block::
# Assuming our current directory is the godot-cpp source root
mkdir build-android
cd build-android
cmake .. --toolchain $ANDROID_HOME/ndk/<version>/build/cmake/android.toolchain.cmake
cmake --build . -t template_release
Specify Android platform and ABI
.. code-block::
# Assuming our current directory is the godot-cpp source root
mkdir build-android
cd build-android
cmake .. --toolchain $ANDROID_HOME/ndk/<version>/build/cmake/android.toolchain.cmake \
-DANDROID_PLATFORM:STRING=android-29 \
-DANDROID_ABI:STRING=armeabi-v7a
cmake --build . -t template_release
Toolchains
----------
This section attempts to list the host and target combinations that have been
at tested.
Info on cross compiling triplets indicates that the naming is a little more
freeform that expected, and tailored to its use case. Triplets tend to have the
format ``<arch>[sub][-vendor][-OS][-env]``
* `osdev.org <https://wiki.osdev.org/Target_Triplet>`_
* `stack overflow <https://stackoverflow.com/questions/13819857/does-a-list-of-all-known-target-triplets-in-use-exist>`_
* `LLVM <https://llvm.org/doxygen/classllvm_1_1Triple.html>`_
* `clang target triple <https://clang.llvm.org/docs/CrossCompilation.html#target-triple>`_
* `vcpkg <https://learn.microsoft.com/en-us/vcpkg/concepts/triplets>`_
* `wasm32-unknown-emscripten <https://blog.therocode.net/2020/10/a-guide-to-rust-sdl2-emscripten>`_
Linux Host
~~~~~~~~~~
:Target: x86_64-linux
Macos Host
~~~~~~~~~~
:System: Mac Mini
:OS Name: Sequoia 15.0.1
:Processor: Apple M2
Windows Host
~~~~~~~~~~~~
:OS Name: Microsoft Windows 11 Home, 10.0.22631 N/A Build 22631
:Processor: AMD Ryzen 7 6800HS Creator Edition
`Microsoft Visual Studio 17 2022 <https://visualstudio.microsoft.com/vs/>`_
:Target: x86_64-w64
`LLVM <https://llvm.org/>`_
:Target: x86_64-pc-windows-msvc
`AndroidSDK <https://developer.android.com/studio/#command-tools>`_
armv7-none-linux-androideabi16
`Emscripten <https://emscripten.org/>`_
:Compiler: Emscripten
:Target: wasm32-unknown-emscripten
`MinGW-w64 <https://www.mingw-w64.org/>`_ based toolchains
`MSYS2 <https://www.msys2.org/>`_
Necessary reading about MSYS2 `environments <https://www.msys2.org/docs/environments/>`_
ucrt64
:Compiler: gcc version 14.2.0 (Rev1, Built by MSYS2 project)
:Target: x86_64-w64-mingw32
clang64
:Compiler: clang version 18.1.8
:Target: x86_64-w64-windows-gnu
`LLVM-MinGW <https://github.com/mstorsjo/llvm-mingw/releases>`_
`MinGW-W64-builds <https://github.com/niXman/mingw-builds-binaries/releases>`_
:Compiler: gcc
:Target: x86_64-w64-mingw32-ucrt
`Jetbrains-CLion <https://www.jetbrains.com/clion/>`_
:Target: x86_64-w64-mingw32-msvcrt

55
doc_source_generator.py Normal file
View File

@@ -0,0 +1,55 @@
#!/usr/bin/env python
import glob
import os
import zlib
def generate_doc_source(dst, source):
g = open(dst, "w", encoding="utf-8")
buf = ""
docbegin = ""
docend = ""
for src in source:
src_path = str(src)
if not src_path.endswith(".xml"):
continue
with open(src_path, "r", encoding="utf-8") as f:
content = f.read()
buf += content
buf = (docbegin + buf + docend).encode("utf-8")
decomp_size = len(buf)
# Use maximum zlib compression level to further reduce file size
# (at the cost of initial build times).
buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION)
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
g.write("\n")
g.write("#include <godot_cpp/godot.hpp>\n")
g.write("\n")
g.write('static const char *_doc_data_hash = "' + str(hash(buf)) + '";\n')
g.write("static const int _doc_data_uncompressed_size = " + str(decomp_size) + ";\n")
g.write("static const int _doc_data_compressed_size = " + str(len(buf)) + ";\n")
g.write("static const unsigned char _doc_data_compressed[] = {\n")
for i in range(len(buf)):
g.write("\t" + str(buf[i]) + ",\n")
g.write("};\n")
g.write("\n")
g.write(
"static godot::internal::DocDataRegistration _doc_data_registration(_doc_data_hash, _doc_data_uncompressed_size, _doc_data_compressed_size, _doc_data_compressed);\n"
)
g.write("\n")
g.close()
def scons_generate_doc_source(target, source, env):
generate_doc_source(str(target[0]), source)
def generate_doc_source_from_directory(target, directory):
generate_doc_source(target, glob.glob(os.path.join(directory, "*.xml")))

File diff suppressed because it is too large Load Diff

View File

@@ -198,6 +198,7 @@ typedef struct {
typedef void (*GDExtensionVariantFromTypeConstructorFunc)(GDExtensionUninitializedVariantPtr, GDExtensionTypePtr);
typedef void (*GDExtensionTypeFromVariantConstructorFunc)(GDExtensionUninitializedTypePtr, GDExtensionVariantPtr);
typedef void *(*GDExtensionVariantGetInternalPtrFunc)(GDExtensionVariantPtr);
typedef void (*GDExtensionPtrOperatorEvaluator)(GDExtensionConstTypePtr p_left, GDExtensionConstTypePtr p_right, GDExtensionTypePtr r_result);
typedef void (*GDExtensionPtrBuiltInMethod)(GDExtensionTypePtr p_base, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return, int p_argument_count);
typedef void (*GDExtensionPtrConstructor)(GDExtensionUninitializedTypePtr p_base, const GDExtensionConstTypePtr *p_args);
@@ -268,10 +269,13 @@ typedef void (*GDExtensionClassReference)(GDExtensionClassInstancePtr p_instance
typedef void (*GDExtensionClassUnreference)(GDExtensionClassInstancePtr p_instance);
typedef void (*GDExtensionClassCallVirtual)(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret);
typedef GDExtensionObjectPtr (*GDExtensionClassCreateInstance)(void *p_class_userdata);
typedef GDExtensionObjectPtr (*GDExtensionClassCreateInstance2)(void *p_class_userdata, GDExtensionBool p_notify_postinitialize);
typedef void (*GDExtensionClassFreeInstance)(void *p_class_userdata, GDExtensionClassInstancePtr p_instance);
typedef GDExtensionClassInstancePtr (*GDExtensionClassRecreateInstance)(void *p_class_userdata, GDExtensionObjectPtr p_object);
typedef GDExtensionClassCallVirtual (*GDExtensionClassGetVirtual)(void *p_class_userdata, GDExtensionConstStringNamePtr p_name);
typedef GDExtensionClassCallVirtual (*GDExtensionClassGetVirtual2)(void *p_class_userdata, GDExtensionConstStringNamePtr p_name, uint32_t p_hash);
typedef void *(*GDExtensionClassGetVirtualCallData)(void *p_class_userdata, GDExtensionConstStringNamePtr p_name);
typedef void *(*GDExtensionClassGetVirtualCallData2)(void *p_class_userdata, GDExtensionConstStringNamePtr p_name, uint32_t p_hash);
typedef void (*GDExtensionClassCallVirtualWithData)(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, void *p_virtual_call_userdata, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret);
typedef struct {
@@ -292,7 +296,7 @@ typedef struct {
GDExtensionClassGetVirtual get_virtual_func; // Queries a virtual function by name and returns a callback to invoke the requested virtual function.
GDExtensionClassGetRID get_rid_func;
void *class_userdata; // Per-class user data, later accessible in instance bindings.
} GDExtensionClassCreationInfo; // Deprecated. Use GDExtensionClassCreationInfo3 instead.
} GDExtensionClassCreationInfo; // Deprecated. Use GDExtensionClassCreationInfo4 instead.
typedef struct {
GDExtensionBool is_virtual;
@@ -325,7 +329,7 @@ typedef struct {
GDExtensionClassCallVirtualWithData call_virtual_with_data_func;
GDExtensionClassGetRID get_rid_func;
void *class_userdata; // Per-class user data, later accessible in instance bindings.
} GDExtensionClassCreationInfo2; // Deprecated. Use GDExtensionClassCreationInfo3 instead.
} GDExtensionClassCreationInfo2; // Deprecated. Use GDExtensionClassCreationInfo4 instead.
typedef struct {
GDExtensionBool is_virtual;
@@ -359,7 +363,41 @@ typedef struct {
GDExtensionClassCallVirtualWithData call_virtual_with_data_func;
GDExtensionClassGetRID get_rid_func;
void *class_userdata; // Per-class user data, later accessible in instance bindings.
} GDExtensionClassCreationInfo3;
} GDExtensionClassCreationInfo3; // Deprecated. Use GDExtensionClassCreationInfo4 instead.
typedef struct {
GDExtensionBool is_virtual;
GDExtensionBool is_abstract;
GDExtensionBool is_exposed;
GDExtensionBool is_runtime;
GDExtensionConstStringPtr icon_path;
GDExtensionClassSet set_func;
GDExtensionClassGet get_func;
GDExtensionClassGetPropertyList get_property_list_func;
GDExtensionClassFreePropertyList2 free_property_list_func;
GDExtensionClassPropertyCanRevert property_can_revert_func;
GDExtensionClassPropertyGetRevert property_get_revert_func;
GDExtensionClassValidateProperty validate_property_func;
GDExtensionClassNotification2 notification_func;
GDExtensionClassToString to_string_func;
GDExtensionClassReference reference_func;
GDExtensionClassUnreference unreference_func;
GDExtensionClassCreateInstance2 create_instance_func; // (Default) constructor; mandatory. If the class is not instantiable, consider making it virtual or abstract.
GDExtensionClassFreeInstance free_instance_func; // Destructor; mandatory.
GDExtensionClassRecreateInstance recreate_instance_func;
// Queries a virtual function by name and returns a callback to invoke the requested virtual function.
GDExtensionClassGetVirtual2 get_virtual_func;
// Paired with `call_virtual_with_data_func`, this is an alternative to `get_virtual_func` for extensions that
// need or benefit from extra data when calling virtual functions.
// Returns user data that will be passed to `call_virtual_with_data_func`.
// Returning `NULL` from this function signals to Godot that the virtual function is not overridden.
// Data returned from this function should be managed by the extension and must be valid until the extension is deinitialized.
// You should supply either `get_virtual_func`, or `get_virtual_call_data_func` with `call_virtual_with_data_func`.
GDExtensionClassGetVirtualCallData2 get_virtual_call_data_func;
// Used to call virtual functions when `get_virtual_call_data_func` is not null.
GDExtensionClassCallVirtualWithData call_virtual_with_data_func;
void *class_userdata; // Per-class user data, later accessible in instance bindings.
} GDExtensionClassCreationInfo4;
typedef void *GDExtensionClassLibraryPtr;
@@ -386,7 +424,9 @@ typedef enum {
GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT32,
GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT64,
GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_FLOAT,
GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_DOUBLE
GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_DOUBLE,
GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_CHAR16,
GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_CHAR32,
} GDExtensionClassMethodArgumentMetadata;
typedef void (*GDExtensionClassMethodCall)(void *method_userdata, GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error);
@@ -805,7 +845,7 @@ typedef void (*GDExtensionInterfaceMemFree)(void *p_ptr);
*
* Logs an error to Godot's built-in debugger and to the OS terminal.
*
* @param p_description The code trigging the error.
* @param p_description The code triggering the error.
* @param p_function The function name where the error occurred.
* @param p_file The file where the error occurred.
* @param p_line The line where the error occurred.
@@ -819,7 +859,7 @@ typedef void (*GDExtensionInterfacePrintError)(const char *p_description, const
*
* Logs an error with a message to Godot's built-in debugger and to the OS terminal.
*
* @param p_description The code trigging the error.
* @param p_description The code triggering the error.
* @param p_message The message to show along with the error.
* @param p_function The function name where the error occurred.
* @param p_file The file where the error occurred.
@@ -834,7 +874,7 @@ typedef void (*GDExtensionInterfacePrintErrorWithMessage)(const char *p_descript
*
* Logs a warning to Godot's built-in debugger and to the OS terminal.
*
* @param p_description The code trigging the warning.
* @param p_description The code triggering the warning.
* @param p_function The function name where the warning occurred.
* @param p_file The file where the warning occurred.
* @param p_line The line where the warning occurred.
@@ -848,7 +888,7 @@ typedef void (*GDExtensionInterfacePrintWarning)(const char *p_description, cons
*
* Logs a warning with a message to Godot's built-in debugger and to the OS terminal.
*
* @param p_description The code trigging the warning.
* @param p_description The code triggering the warning.
* @param p_message The message to show along with the warning.
* @param p_function The function name where the warning occurred.
* @param p_file The file where the warning occurred.
@@ -863,7 +903,7 @@ typedef void (*GDExtensionInterfacePrintWarningWithMessage)(const char *p_descri
*
* Logs a script error to Godot's built-in debugger and to the OS terminal.
*
* @param p_description The code trigging the error.
* @param p_description The code triggering the error.
* @param p_function The function name where the error occurred.
* @param p_file The file where the error occurred.
* @param p_line The line where the error occurred.
@@ -877,7 +917,7 @@ typedef void (*GDExtensionInterfacePrintScriptError)(const char *p_description,
*
* Logs a script error with a message to Godot's built-in debugger and to the OS terminal.
*
* @param p_description The code trigging the error.
* @param p_description The code triggering the error.
* @param p_message The message to show along with the error.
* @param p_function The function name where the error occurred.
* @param p_file The file where the error occurred.
@@ -1271,6 +1311,21 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantHasMember)(GDExtensionVaria
*/
typedef GDExtensionBool (*GDExtensionInterfaceVariantHasKey)(GDExtensionConstVariantPtr p_self, GDExtensionConstVariantPtr p_key, GDExtensionBool *r_valid);
/**
* @name variant_get_object_instance_id
* @since 4.4
*
* Gets the object instance ID from a variant of type GDEXTENSION_VARIANT_TYPE_OBJECT.
*
* If the variant isn't of type GDEXTENSION_VARIANT_TYPE_OBJECT, then zero will be returned.
* The instance ID will be returned even if the object is no longer valid - use `object_get_instance_by_id()` to check if the object is still valid.
*
* @param p_self A pointer to the Variant.
*
* @return The instance ID for the contained object.
*/
typedef GDObjectInstanceID (*GDExtensionInterfaceVariantGetObjectInstanceId)(GDExtensionConstVariantPtr p_self);
/**
* @name variant_get_type_name
* @since 4.1
@@ -1332,6 +1387,23 @@ typedef GDExtensionVariantFromTypeConstructorFunc (*GDExtensionInterfaceGetVaria
*/
typedef GDExtensionTypeFromVariantConstructorFunc (*GDExtensionInterfaceGetVariantToTypeConstructor)(GDExtensionVariantType p_type);
/**
* @name variant_get_ptr_internal_getter
* @since 4.4
*
* Provides a function pointer for retrieving a pointer to a variant's internal value.
* Access to a variant's internal value can be used to modify it in-place, or to retrieve its value without the overhead of variant conversion functions.
* It is recommended to cache the getter for all variant types in a function table to avoid retrieval overhead upon use.
*
* @note Each function assumes the variant's type has already been determined and matches the function.
* Invoking the function with a variant of a mismatched type has undefined behavior, and may lead to a segmentation fault.
*
* @param p_type The Variant type.
*
* @return A pointer to a type-specific function that returns a pointer to the internal value of a variant. Check the implementation of this function (gdextension_variant_get_ptr_internal_getter) for pointee type info of each variant type.
*/
typedef GDExtensionVariantGetInternalPtrFunc (*GDExtensionInterfaceGetVariantGetInternalPtrFunc)(GDExtensionVariantType p_type);
/**
* @name variant_get_ptr_operator_evaluator
* @since 4.1
@@ -2337,6 +2409,22 @@ typedef GDExtensionVariantPtr (*GDExtensionInterfaceDictionaryOperatorIndex)(GDE
*/
typedef GDExtensionVariantPtr (*GDExtensionInterfaceDictionaryOperatorIndexConst)(GDExtensionConstTypePtr p_self, GDExtensionConstVariantPtr p_key);
/**
* @name dictionary_set_typed
* @since 4.4
*
* Makes a Dictionary into a typed Dictionary.
*
* @param p_self A pointer to the Dictionary.
* @param p_key_type The type of Variant the Dictionary key will store.
* @param p_key_class_name A pointer to a StringName with the name of the object (if p_key_type is GDEXTENSION_VARIANT_TYPE_OBJECT).
* @param p_key_script A pointer to a Script object (if p_key_type is GDEXTENSION_VARIANT_TYPE_OBJECT and the base class is extended by a script).
* @param p_value_type The type of Variant the Dictionary value will store.
* @param p_value_class_name A pointer to a StringName with the name of the object (if p_value_type is GDEXTENSION_VARIANT_TYPE_OBJECT).
* @param p_value_script A pointer to a Script object (if p_value_type is GDEXTENSION_VARIANT_TYPE_OBJECT and the base class is extended by a script).
*/
typedef void (*GDExtensionInterfaceDictionarySetTyped)(GDExtensionTypePtr p_self, GDExtensionVariantType p_key_type, GDExtensionConstStringNamePtr p_key_class_name, GDExtensionConstVariantPtr p_key_script, GDExtensionVariantType p_value_type, GDExtensionConstStringNamePtr p_value_class_name, GDExtensionConstVariantPtr p_value_script);
/* INTERFACE: Object */
/**
@@ -2680,6 +2768,7 @@ typedef void *(*GDExtensionInterfaceCallableCustomGetUserData)(GDExtensionConstT
/**
* @name classdb_construct_object
* @since 4.1
* @deprecated in Godot 4.4. Use `classdb_construct_object2` instead.
*
* Constructs an Object of the requested class.
*
@@ -2691,6 +2780,22 @@ typedef void *(*GDExtensionInterfaceCallableCustomGetUserData)(GDExtensionConstT
*/
typedef GDExtensionObjectPtr (*GDExtensionInterfaceClassdbConstructObject)(GDExtensionConstStringNamePtr p_classname);
/**
* @name classdb_construct_object2
* @since 4.4
*
* Constructs an Object of the requested class.
*
* The passed class must be a built-in godot class, or an already-registered extension class. In both cases, object_set_instance() should be called to fully initialize the object.
*
* "NOTIFICATION_POSTINITIALIZE" must be sent after construction.
*
* @param p_classname A pointer to a StringName with the class name.
*
* @return A pointer to the newly created Object.
*/
typedef GDExtensionObjectPtr (*GDExtensionInterfaceClassdbConstructObject2)(GDExtensionConstStringNamePtr p_classname);
/**
* @name classdb_get_method_bind
* @since 4.1
@@ -2722,7 +2827,7 @@ typedef void *(*GDExtensionInterfaceClassdbGetClassTag)(GDExtensionConstStringNa
/**
* @name classdb_register_extension_class
* @since 4.1
* @deprecated in Godot 4.2. Use `classdb_register_extension_class3` instead.
* @deprecated in Godot 4.2. Use `classdb_register_extension_class4` instead.
*
* Registers an extension class in the ClassDB.
*
@@ -2738,7 +2843,7 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass)(GDExtensionCla
/**
* @name classdb_register_extension_class2
* @since 4.2
* @deprecated in Godot 4.3. Use `classdb_register_extension_class3` instead.
* @deprecated in Godot 4.3. Use `classdb_register_extension_class4` instead.
*
* Registers an extension class in the ClassDB.
*
@@ -2754,6 +2859,7 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass2)(GDExtensionCl
/**
* @name classdb_register_extension_class3
* @since 4.3
* @deprecated in Godot 4.4. Use `classdb_register_extension_class4` instead.
*
* Registers an extension class in the ClassDB.
*
@@ -2766,6 +2872,21 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass2)(GDExtensionCl
*/
typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass3)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo3 *p_extension_funcs);
/**
* @name classdb_register_extension_class4
* @since 4.4
*
* Registers an extension class in the ClassDB.
*
* Provided struct can be safely freed once the function returns.
*
* @param p_library A pointer the library received by the GDExtension's entry point function.
* @param p_class_name A pointer to a StringName with the class name.
* @param p_parent_class_name A pointer to a StringName with the parent class name.
* @param p_extension_funcs A pointer to a GDExtensionClassCreationInfo2 struct.
*/
typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass4)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo4 *p_extension_funcs);
/**
* @name classdb_register_extension_class_method
* @since 4.1

View File

@@ -94,7 +94,7 @@ protected:
bool _property_can_revert(const StringName &p_name) const { return false; }
bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return false; }
void _validate_property(PropertyInfo &p_property) const {}
String _to_string() const { return "<Wrapped#0>"; }
String _to_string() const { return "[" + String(get_class_static()) + ":" + itos(get_instance_id()) + "]"; }
static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what, GDExtensionBool p_reversed) {}
static GDExtensionBool set_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionConstVariantPtr p_value) { return false; }
@@ -111,7 +111,6 @@ protected:
::godot::List<::godot::PropertyInfo> plist_owned;
void _postinitialize();
virtual void _notificationv(int32_t p_what, bool p_reversed = false) {}
Wrapped(const StringName p_godot_class);
Wrapped(GodotObject *p_godot_object);
@@ -123,6 +122,10 @@ public:
return string_name;
}
uint64_t get_instance_id() const {
return 0;
}
// Must be public but you should not touch this.
GodotObject *_owner = nullptr;
};
@@ -256,7 +259,7 @@ public:
} \
\
static const ::godot::StringName &get_class_static() { \
static const ::godot::StringName string_name = ::godot::StringName(#m_class); \
static const ::godot::StringName string_name = ::godot::StringName(U## #m_class); \
return string_name; \
} \
\
@@ -404,11 +407,6 @@ public:
_gde_binding_reference_callback, \
}; \
\
protected: \
virtual void _notificationv(int32_t p_what, bool p_reversed = false) override { \
m_class::notification_bind(this, p_what, p_reversed); \
} \
\
private:
// Don't use this for your classes, use GDCLASS() instead.
@@ -507,11 +505,8 @@ private:
// Don't use this for your classes, use GDCLASS() instead.
#define GDEXTENSION_CLASS(m_class, m_inherits) GDEXTENSION_CLASS_ALIAS(m_class, m_class, m_inherits)
#define GDVIRTUAL_CALL(m_name, ...) _gdvirtual_##m_name##_call<false>(__VA_ARGS__)
#define GDVIRTUAL_CALL_PTR(m_obj, m_name, ...) m_obj->_gdvirtual_##m_name##_call<false>(__VA_ARGS__)
#define GDVIRTUAL_REQUIRED_CALL(m_name, ...) _gdvirtual_##m_name##_call<true>(__VA_ARGS__)
#define GDVIRTUAL_REQUIRED_CALL_PTR(m_obj, m_name, ...) m_obj->_gdvirtual_##m_name##_call<true>(__VA_ARGS__)
#define GDVIRTUAL_CALL(m_name, ...) _gdvirtual_##m_name##_call(__VA_ARGS__)
#define GDVIRTUAL_CALL_PTR(m_obj, m_name, ...) m_obj->_gdvirtual_##m_name##_call(__VA_ARGS__)
#define GDVIRTUAL_BIND(m_name, ...) ::godot::ClassDB::add_virtual_method(get_class_static(), _gdvirtual_##m_name##_get_method_info(), ::godot::snarray(__VA_ARGS__));
#define GDVIRTUAL_IS_OVERRIDDEN(m_name) _gdvirtual_##m_name##_overridden()

View File

@@ -88,12 +88,17 @@ class ClassDB {
public:
struct ClassInfo {
struct VirtualMethod {
GDExtensionClassCallVirtual func;
uint32_t hash;
};
StringName name;
StringName parent_name;
GDExtensionInitializationLevel level = GDEXTENSION_INITIALIZATION_SCENE;
std::unordered_map<StringName, MethodBind *> method_map;
std::set<StringName> signal_names;
std::unordered_map<StringName, GDExtensionClassCallVirtual> virtual_methods;
std::unordered_map<StringName, VirtualMethod> virtual_methods;
std::set<StringName> property_names;
std::set<StringName> constant_names;
// Pointer to the parent custom class, if any. Will be null if the parent class is a Godot class.
@@ -117,9 +122,13 @@ private:
static void _register_class(bool p_virtual = false, bool p_exposed = true, bool p_runtime = false);
template <typename T>
static GDExtensionObjectPtr _create_instance_func(void *data) {
static GDExtensionObjectPtr _create_instance_func(void *data, GDExtensionBool p_notify_postinitialize) {
if constexpr (!std::is_abstract_v<T>) {
T *new_object = memnew(T);
Wrapped::_set_construct_info<T>();
T *new_object = new ("", "") T;
if (p_notify_postinitialize) {
new_object->_postinitialize();
}
return new_object->_owner;
} else {
return nullptr;
@@ -189,13 +198,13 @@ public:
static void add_signal(const StringName &p_class, const MethodInfo &p_signal);
static void bind_integer_constant(const StringName &p_class_name, const StringName &p_enum_name, const StringName &p_constant_name, GDExtensionInt p_constant_value, bool p_is_bitfield = false);
// Binds an implementation of a virtual method defined in Godot.
static void bind_virtual_method(const StringName &p_class, const StringName &p_method, GDExtensionClassCallVirtual p_call);
static void bind_virtual_method(const StringName &p_class, const StringName &p_method, GDExtensionClassCallVirtual p_call, uint32_t p_hash);
// Add a new virtual method that can be implemented by scripts.
static void add_virtual_method(const StringName &p_class, const MethodInfo &p_method, const Vector<StringName> &p_arg_names = Vector<StringName>());
static MethodBind *get_method(const StringName &p_class, const StringName &p_method);
static GDExtensionClassCallVirtual get_virtual_func(void *p_userdata, GDExtensionConstStringNamePtr p_name);
static GDExtensionClassCallVirtual get_virtual_func(void *p_userdata, GDExtensionConstStringNamePtr p_name, uint32_t p_hash);
static const GDExtensionInstanceBindingCallbacks *get_instance_binding_callbacks(const StringName &p_class);
static void initialize(GDExtensionInitializationLevel p_level);
@@ -213,12 +222,12 @@ public:
#define BIND_BITFIELD_FLAG(m_constant) \
::godot::ClassDB::bind_integer_constant(get_class_static(), ::godot::_gde_constant_get_bitfield_name(m_constant, #m_constant), #m_constant, m_constant, true);
#define BIND_VIRTUAL_METHOD(m_class, m_method) \
#define BIND_VIRTUAL_METHOD(m_class, m_method, m_hash) \
{ \
auto _call##m_method = [](GDExtensionObjectPtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr p_ret) -> void { \
call_with_ptr_args(reinterpret_cast<m_class *>(p_instance), &m_class::m_method, p_args, p_ret); \
}; \
::godot::ClassDB::bind_virtual_method(m_class::get_class_static(), #m_method, _call##m_method); \
::godot::ClassDB::bind_virtual_method(m_class::get_class_static(), #m_method, _call##m_method, m_hash); \
}
template <typename T, bool is_abstract>
@@ -242,11 +251,12 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed, bool p_runtime) {
class_register_order.push_back(cl.name);
// Register this class with Godot
GDExtensionClassCreationInfo3 class_info = {
GDExtensionClassCreationInfo4 class_info = {
p_virtual, // GDExtensionBool is_virtual;
is_abstract, // GDExtensionBool is_abstract;
p_exposed, // GDExtensionBool is_exposed;
p_runtime, // GDExtensionBool is_runtime;
nullptr, // GDExtensionConstStringPtr icon_path;
T::set_bind, // GDExtensionClassSet set_func;
T::get_bind, // GDExtensionClassGet get_func;
T::has_get_property_list() ? T::get_property_list_bind : nullptr, // GDExtensionClassGetPropertyList get_property_list_func;
@@ -264,11 +274,10 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed, bool p_runtime) {
&ClassDB::get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
nullptr, // GDExtensionClassCallVirtualWithData call_virtual_func;
nullptr, // GDExtensionClassGetRID get_rid;
(void *)&T::get_class_static(), // void *class_userdata;
};
internal::gdextension_interface_classdb_register_extension_class3(internal::library, cl.name._native_ptr(), cl.parent_name._native_ptr(), &class_info);
internal::gdextension_interface_classdb_register_extension_class4(internal::library, cl.name._native_ptr(), cl.parent_name._native_ptr(), &class_info);
// call bind_methods etc. to register all members of the class
T::initialize_class();

View File

@@ -56,10 +56,10 @@ O *_call_native_mb_ret_obj(const GDExtensionMethodBindPtr mb, void *instance, co
template <typename R, typename... Args>
R _call_native_mb_ret(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) {
typename PtrToArg<R>::EncodeT ret;
R ret;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
internal::gdextension_interface_object_method_bind_ptrcall(mb, instance, mb_args.data(), &ret);
return static_cast<R>(ret);
return ret;
}
template <typename... Args>
@@ -70,10 +70,10 @@ void _call_native_mb_no_ret(const GDExtensionMethodBindPtr mb, void *instance, c
template <typename R, typename... Args>
R _call_utility_ret(GDExtensionPtrUtilityFunction func, const Args &...args) {
typename PtrToArg<R>::EncodeT ret;
R ret;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
func(&ret, mb_args.data(), mb_args.size());
return static_cast<R>(ret);
return ret;
}
template <typename... Args>

View File

@@ -48,14 +48,14 @@
namespace godot {
class MethodBind {
uint32_t hint_flags = METHOD_FLAGS_DEFAULT;
StringName name;
StringName instance_class;
int argument_count = 0;
uint32_t hint_flags = METHOD_FLAGS_DEFAULT;
bool _static = false;
bool _const = false;
bool _returns = false;
bool _is_const = false;
bool _has_return = false;
bool _vararg = false;
std::vector<StringName> argument_names;
@@ -63,20 +63,20 @@ class MethodBind {
std::vector<Variant> default_arguments;
protected:
void _set_const(bool p_const);
void _set_static(bool p_static);
void _set_returns(bool p_returns);
void _set_vararg(bool p_vararg);
virtual GDExtensionVariantType gen_argument_type(int p_arg) const = 0;
virtual PropertyInfo gen_argument_type_info(int p_arg) const = 0;
void _generate_argument_types(int p_count);
void set_argument_count(int p_count) { argument_count = p_count; }
void generate_argument_types(int p_count);
void set_const(bool p_const);
void set_return(bool p_return);
void set_static(bool p_static);
void set_vararg(bool p_vararg);
void set_argument_count(int p_count);
public:
_FORCE_INLINE_ const std::vector<Variant> &get_default_arguments() const { return default_arguments; }
StringName get_name() const;
void set_name(const StringName &p_name);
_FORCE_INLINE_ int get_default_argument_count() const { return (int)default_arguments.size(); }
_FORCE_INLINE_ const std::vector<Variant> &get_default_arguments() const { return default_arguments; }
_FORCE_INLINE_ Variant has_default_argument(int p_arg) const {
const int num_default_args = (int)(default_arguments.size());
const int idx = p_arg - (argument_count - num_default_args);
@@ -97,6 +97,19 @@ public:
return default_arguments[idx];
}
}
_FORCE_INLINE_ StringName get_instance_class() const { return instance_class; }
_FORCE_INLINE_ void set_instance_class(StringName p_class) { instance_class = p_class; }
_FORCE_INLINE_ int get_argument_count() const { return argument_count; }
_FORCE_INLINE_ bool is_const() const { return _is_const; }
_FORCE_INLINE_ bool is_static() const { return _static; }
_FORCE_INLINE_ bool is_vararg() const { return _vararg; }
_FORCE_INLINE_ bool has_return() const { return _has_return; }
_FORCE_INLINE_ uint32_t get_hint_flags() const { return hint_flags | (is_const() ? GDEXTENSION_METHOD_FLAG_CONST : 0) | (is_vararg() ? GDEXTENSION_METHOD_FLAG_VARARG : 0) | (is_static() ? GDEXTENSION_METHOD_FLAG_STATIC : 0); }
_FORCE_INLINE_ void set_hint_flags(uint32_t p_hint_flags) { hint_flags = p_hint_flags; }
void set_argument_names(const std::vector<StringName> &p_names);
std::vector<StringName> get_argument_names() const;
void set_default_arguments(const std::vector<Variant> &p_default_arguments) { default_arguments = p_default_arguments; }
_FORCE_INLINE_ GDExtensionVariantType get_argument_type(int p_argument) const {
ERR_FAIL_COND_V(p_argument < -1 || p_argument > argument_count, GDEXTENSION_VARIANT_TYPE_NIL);
@@ -104,6 +117,7 @@ public:
}
PropertyInfo get_argument_info(int p_argument) const;
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_argument) const = 0;
std::vector<PropertyInfo> get_arguments_info_list() const {
std::vector<PropertyInfo> vec;
@@ -114,31 +128,6 @@ public:
}
return vec;
}
void set_argument_names(const std::vector<StringName> &p_names);
std::vector<StringName> get_argument_names() const;
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_argument) const = 0;
_FORCE_INLINE_ void set_hint_flags(uint32_t p_hint_flags) { hint_flags = p_hint_flags; }
_FORCE_INLINE_ uint32_t get_hint_flags() const { return hint_flags | (is_const() ? GDEXTENSION_METHOD_FLAG_CONST : 0) | (is_vararg() ? GDEXTENSION_METHOD_FLAG_VARARG : 0) | (is_static() ? GDEXTENSION_METHOD_FLAG_STATIC : 0); }
_FORCE_INLINE_ StringName get_instance_class() const { return instance_class; }
_FORCE_INLINE_ void set_instance_class(StringName p_class) { instance_class = p_class; }
_FORCE_INLINE_ int get_argument_count() const { return argument_count; }
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const = 0;
virtual void ptrcall(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return) const = 0;
StringName get_name() const;
void set_name(const StringName &p_name);
_FORCE_INLINE_ bool is_const() const { return _const; }
_FORCE_INLINE_ bool is_static() const { return _static; }
_FORCE_INLINE_ bool is_vararg() const { return _vararg; }
_FORCE_INLINE_ bool has_return() const { return _returns; }
void set_default_arguments(const std::vector<Variant> &p_default_arguments) { default_arguments = p_default_arguments; }
std::vector<GDExtensionClassMethodArgumentMetadata> get_arguments_metadata_list() const {
std::vector<GDExtensionClassMethodArgumentMetadata> vec;
// First element is return value
@@ -149,6 +138,9 @@ public:
return vec;
}
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const = 0;
virtual void ptrcall(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return) const = 0;
static void bind_call(void *p_method_userdata, GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error);
static void bind_ptrcall(void *p_method_userdata, GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return);
@@ -190,8 +182,8 @@ public:
const MethodInfo &p_method_info,
bool p_return_nil_is_variant) :
method(p_method) {
_set_vararg(true);
_set_const(true);
set_vararg(true);
set_const(true);
set_argument_count(p_method_info.arguments.size());
if (p_method_info.arguments.size()) {
arguments = p_method_info.arguments;
@@ -204,8 +196,8 @@ public:
set_argument_names(names);
}
_generate_argument_types((int)p_method_info.arguments.size());
_set_returns(should_returns);
generate_argument_types((int)p_method_info.arguments.size());
set_return(should_returns);
}
~MethodBindVarArgBase() {}
@@ -342,7 +334,7 @@ public:
MethodBindT(void (MB_T::*p_method)(P...)) {
method = p_method;
_generate_argument_types(sizeof...(P));
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
}
};
@@ -418,9 +410,9 @@ public:
MethodBindTC(void (MB_T::*p_method)(P...) const) {
method = p_method;
_generate_argument_types(sizeof...(P));
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
_set_const(true);
set_const(true);
}
};
@@ -501,9 +493,9 @@ public:
MethodBindTR(R (MB_T::*p_method)(P...)) {
method = p_method;
_generate_argument_types(sizeof...(P));
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
_set_returns(true);
set_return(true);
}
};
@@ -584,10 +576,10 @@ public:
MethodBindTRC(R (MB_T::*p_method)(P...) const) {
method = p_method;
_generate_argument_types(sizeof...(P));
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
_set_returns(true);
_set_const(true);
set_return(true);
set_const(true);
}
};
@@ -656,9 +648,9 @@ public:
MethodBindTS(void (*p_function)(P...)) {
function = p_function;
_generate_argument_types(sizeof...(P));
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
_set_static(true);
set_static(true);
}
};
@@ -725,10 +717,10 @@ public:
MethodBindTRS(R (*p_function)(P...)) {
function = p_function;
_generate_argument_types(sizeof...(P));
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
_set_static(true);
_set_returns(true);
set_static(true);
set_return(true);
}
};

View File

@@ -122,9 +122,6 @@ MAKE_PTRARGCONV(uint16_t, int64_t);
MAKE_PTRARGCONV(int16_t, int64_t);
MAKE_PTRARGCONV(uint32_t, int64_t);
MAKE_PTRARGCONV(int32_t, int64_t);
MAKE_PTRARGCONV(char16_t, int64_t);
MAKE_PTRARGCONV(char32_t, int64_t);
MAKE_PTRARGCONV(wchar_t, int64_t);
MAKE_PTRARG(int64_t);
MAKE_PTRARG(uint64_t);
// Float types

View File

@@ -148,8 +148,8 @@ MAKE_TYPE_INFO_WITH_META(uint32_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_MET
MAKE_TYPE_INFO_WITH_META(int32_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT32)
MAKE_TYPE_INFO_WITH_META(uint64_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT64)
MAKE_TYPE_INFO_WITH_META(int64_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT64)
MAKE_TYPE_INFO(char16_t, GDEXTENSION_VARIANT_TYPE_INT)
MAKE_TYPE_INFO(char32_t, GDEXTENSION_VARIANT_TYPE_INT)
MAKE_TYPE_INFO_WITH_META(char16_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_CHAR16)
MAKE_TYPE_INFO_WITH_META(char32_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_CHAR32)
MAKE_TYPE_INFO_WITH_META(float, GDEXTENSION_VARIANT_TYPE_FLOAT, GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_FLOAT)
MAKE_TYPE_INFO_WITH_META(double, GDEXTENSION_VARIANT_TYPE_FLOAT, GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_DOUBLE)

View File

@@ -82,11 +82,13 @@ extern "C" GDExtensionInterfaceVariantGetType gdextension_interface_variant_get_
extern "C" GDExtensionInterfaceVariantHasMethod gdextension_interface_variant_has_method;
extern "C" GDExtensionInterfaceVariantHasMember gdextension_interface_variant_has_member;
extern "C" GDExtensionInterfaceVariantHasKey gdextension_interface_variant_has_key;
extern "C" GDExtensionInterfaceVariantGetObjectInstanceId gdextension_interface_variant_get_object_instance_id;
extern "C" GDExtensionInterfaceVariantGetTypeName gdextension_interface_variant_get_type_name;
extern "C" GDExtensionInterfaceVariantCanConvert gdextension_interface_variant_can_convert;
extern "C" GDExtensionInterfaceVariantCanConvertStrict gdextension_interface_variant_can_convert_strict;
extern "C" GDExtensionInterfaceGetVariantFromTypeConstructor gdextension_interface_get_variant_from_type_constructor;
extern "C" GDExtensionInterfaceGetVariantToTypeConstructor gdextension_interface_get_variant_to_type_constructor;
extern "C" GDExtensionInterfaceGetVariantGetInternalPtrFunc gdextension_interface_variant_get_ptr_internal_getter;
extern "C" GDExtensionInterfaceVariantGetPtrOperatorEvaluator gdextension_interface_variant_get_ptr_operator_evaluator;
extern "C" GDExtensionInterfaceVariantGetPtrBuiltinMethod gdextension_interface_variant_get_ptr_builtin_method;
extern "C" GDExtensionInterfaceVariantGetPtrConstructor gdextension_interface_variant_get_ptr_constructor;
@@ -158,6 +160,7 @@ extern "C" GDExtensionInterfaceArrayRef gdextension_interface_array_ref;
extern "C" GDExtensionInterfaceArraySetTyped gdextension_interface_array_set_typed;
extern "C" GDExtensionInterfaceDictionaryOperatorIndex gdextension_interface_dictionary_operator_index;
extern "C" GDExtensionInterfaceDictionaryOperatorIndexConst gdextension_interface_dictionary_operator_index_const;
extern "C" GDExtensionInterfaceDictionarySetTyped gdextension_interface_dictionary_set_typed;
extern "C" GDExtensionInterfaceObjectMethodBindCall gdextension_interface_object_method_bind_call;
extern "C" GDExtensionInterfaceObjectMethodBindPtrcall gdextension_interface_object_method_bind_ptrcall;
extern "C" GDExtensionInterfaceObjectDestroy gdextension_interface_object_destroy;
@@ -179,10 +182,10 @@ extern "C" GDExtensionInterfaceRefSetObject gdextension_interface_ref_set_object
extern "C" GDExtensionInterfaceScriptInstanceCreate3 gdextension_interface_script_instance_create3;
extern "C" GDExtensionInterfacePlaceHolderScriptInstanceCreate gdextension_interface_placeholder_script_instance_create;
extern "C" GDExtensionInterfacePlaceHolderScriptInstanceUpdate gdextension_interface_placeholder_script_instance_update;
extern "C" GDExtensionInterfaceClassdbConstructObject gdextension_interface_classdb_construct_object;
extern "C" GDExtensionInterfaceClassdbConstructObject2 gdextension_interface_classdb_construct_object2;
extern "C" GDExtensionInterfaceClassdbGetMethodBind gdextension_interface_classdb_get_method_bind;
extern "C" GDExtensionInterfaceClassdbGetClassTag gdextension_interface_classdb_get_class_tag;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClass3 gdextension_interface_classdb_register_extension_class3;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClass4 gdextension_interface_classdb_register_extension_class4;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassMethod gdextension_interface_classdb_register_extension_class_method;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassVirtualMethod gdextension_interface_classdb_register_extension_class_virtual_method;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant gdextension_interface_classdb_register_extension_class_integer_constant;

View File

@@ -153,7 +153,6 @@ struct [[nodiscard]] Projection {
Projection();
Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_z, const Vector4 &p_w);
Projection(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_xw, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_yw, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_zw, real_t p_wx, real_t p_wy, real_t p_wz, real_t p_ww);
Projection(const Transform3D &p_transform);
~Projection();
};

View File

@@ -0,0 +1,439 @@
/**************************************************************************/
/* typed_dictionary.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#ifndef GODOT_TYPED_DICTIONARY_HPP
#define GODOT_TYPED_DICTIONARY_HPP
#include <godot_cpp/core/type_info.hpp>
#include <godot_cpp/variant/dictionary.hpp>
#include <godot_cpp/variant/variant.hpp>
namespace godot {
template <typename K, typename V>
class TypedDictionary : public Dictionary {
public:
_FORCE_INLINE_ void operator=(const Dictionary &p_dictionary) {
ERR_FAIL_COND_MSG(!is_same_typed(p_dictionary), "Cannot assign a dictionary with a different element type.");
Dictionary::operator=(p_dictionary);
}
_FORCE_INLINE_ TypedDictionary(const Variant &p_variant) :
TypedDictionary(Dictionary(p_variant)) {
}
_FORCE_INLINE_ TypedDictionary(const Dictionary &p_dictionary) {
set_typed(Variant::OBJECT, K::get_class_static(), Variant(), Variant::OBJECT, V::get_class_static(), Variant());
if (is_same_typed(p_dictionary)) {
Dictionary::operator=(p_dictionary);
} else {
assign(p_dictionary);
}
}
_FORCE_INLINE_ TypedDictionary() {
set_typed(Variant::OBJECT, K::get_class_static(), Variant(), Variant::OBJECT, V::get_class_static(), Variant());
}
};
//specialization for the rest of variant types
#define MAKE_TYPED_DICTIONARY_WITH_OBJECT(m_type, m_variant_type) \
template <typename T> \
class TypedDictionary<T, m_type> : public Dictionary { \
public: \
_FORCE_INLINE_ void operator=(const Dictionary &p_dictionary) { \
ERR_FAIL_COND_MSG(!is_same_typed(p_dictionary), "Cannot assign an dictionary with a different element type."); \
Dictionary::operator=(p_dictionary); \
} \
_FORCE_INLINE_ TypedDictionary(const Variant &p_variant) : \
TypedDictionary(Dictionary(p_variant)) { \
} \
_FORCE_INLINE_ TypedDictionary(const Dictionary &p_dictionary) { \
set_typed(Variant::OBJECT, T::get_class_static(), Variant(), m_variant_type, StringName(), Variant()); \
if (is_same_typed(p_dictionary)) { \
Dictionary::operator=(p_dictionary); \
} else { \
assign(p_dictionary); \
} \
} \
_FORCE_INLINE_ TypedDictionary() { \
set_typed(Variant::OBJECT, T::get_class_static(), Variant(), m_variant_type, StringName(), Variant()); \
} \
}; \
template <typename T> \
class TypedDictionary<m_type, T> : public Dictionary { \
public: \
_FORCE_INLINE_ void operator=(const Dictionary &p_dictionary) { \
ERR_FAIL_COND_MSG(!is_same_typed(p_dictionary), "Cannot assign an dictionary with a different element type."); \
Dictionary::operator=(p_dictionary); \
} \
_FORCE_INLINE_ TypedDictionary(const Variant &p_variant) : \
TypedDictionary(Dictionary(p_variant)) { \
} \
_FORCE_INLINE_ TypedDictionary(const Dictionary &p_dictionary) { \
set_typed(m_variant_type, StringName(), Variant(), Variant::OBJECT, T::get_class_static(), Variant()); \
if (is_same_typed(p_dictionary)) { \
Dictionary::operator=(p_dictionary); \
} else { \
assign(p_dictionary); \
} \
} \
_FORCE_INLINE_ TypedDictionary() { \
set_typed(m_variant_type, StringName(), Variant(), Variant::OBJECT, T::get_class_static(), Variant()); \
} \
};
#define MAKE_TYPED_DICTIONARY_EXPANDED(m_type_key, m_variant_type_key, m_type_value, m_variant_type_value) \
template <> \
class TypedDictionary<m_type_key, m_type_value> : public Dictionary { \
public: \
_FORCE_INLINE_ void operator=(const Dictionary &p_dictionary) { \
ERR_FAIL_COND_MSG(!is_same_typed(p_dictionary), "Cannot assign an dictionary with a different element type."); \
Dictionary::operator=(p_dictionary); \
} \
_FORCE_INLINE_ TypedDictionary(const Variant &p_variant) : \
TypedDictionary(Dictionary(p_variant)) { \
} \
_FORCE_INLINE_ TypedDictionary(const Dictionary &p_dictionary) { \
set_typed(m_variant_type_key, StringName(), Variant(), m_variant_type_value, StringName(), Variant()); \
if (is_same_typed(p_dictionary)) { \
Dictionary::operator=(p_dictionary); \
} else { \
assign(p_dictionary); \
} \
} \
_FORCE_INLINE_ TypedDictionary() { \
set_typed(m_variant_type_key, StringName(), Variant(), m_variant_type_value, StringName(), Variant()); \
} \
};
#define MAKE_TYPED_DICTIONARY_NIL(m_type, m_variant_type) \
MAKE_TYPED_DICTIONARY_WITH_OBJECT(m_type, m_variant_type) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, bool, Variant::BOOL) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, uint8_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, int8_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, uint16_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, int16_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, uint32_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, int32_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, uint64_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, int64_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, float, Variant::FLOAT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, double, Variant::FLOAT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, String, Variant::STRING) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Vector2, Variant::VECTOR2) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Vector2i, Variant::VECTOR2I) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Rect2, Variant::RECT2) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Rect2i, Variant::RECT2I) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Vector3, Variant::VECTOR3) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Vector3i, Variant::VECTOR3I) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Transform2D, Variant::TRANSFORM2D) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Plane, Variant::PLANE) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Quaternion, Variant::QUATERNION) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, AABB, Variant::AABB) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Basis, Variant::BASIS) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Transform3D, Variant::TRANSFORM3D) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Color, Variant::COLOR) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, StringName, Variant::STRING_NAME) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, NodePath, Variant::NODE_PATH) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, RID, Variant::RID) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Callable, Variant::CALLABLE) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Signal, Variant::SIGNAL) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Dictionary, Variant::DICTIONARY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Array, Variant::ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedByteArray, Variant::PACKED_BYTE_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedInt32Array, Variant::PACKED_INT32_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedInt64Array, Variant::PACKED_INT64_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedStringArray, Variant::PACKED_STRING_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedColorArray, Variant::PACKED_COLOR_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY) \
/*MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, IPAddress, Variant::STRING)*/
#define MAKE_TYPED_DICTIONARY(m_type, m_variant_type) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Variant, Variant::NIL) \
MAKE_TYPED_DICTIONARY_NIL(m_type, m_variant_type)
MAKE_TYPED_DICTIONARY_NIL(Variant, Variant::NIL)
MAKE_TYPED_DICTIONARY(bool, Variant::BOOL)
MAKE_TYPED_DICTIONARY(uint8_t, Variant::INT)
MAKE_TYPED_DICTIONARY(int8_t, Variant::INT)
MAKE_TYPED_DICTIONARY(uint16_t, Variant::INT)
MAKE_TYPED_DICTIONARY(int16_t, Variant::INT)
MAKE_TYPED_DICTIONARY(uint32_t, Variant::INT)
MAKE_TYPED_DICTIONARY(int32_t, Variant::INT)
MAKE_TYPED_DICTIONARY(uint64_t, Variant::INT)
MAKE_TYPED_DICTIONARY(int64_t, Variant::INT)
MAKE_TYPED_DICTIONARY(float, Variant::FLOAT)
MAKE_TYPED_DICTIONARY(double, Variant::FLOAT)
MAKE_TYPED_DICTIONARY(String, Variant::STRING)
MAKE_TYPED_DICTIONARY(Vector2, Variant::VECTOR2)
MAKE_TYPED_DICTIONARY(Vector2i, Variant::VECTOR2I)
MAKE_TYPED_DICTIONARY(Rect2, Variant::RECT2)
MAKE_TYPED_DICTIONARY(Rect2i, Variant::RECT2I)
MAKE_TYPED_DICTIONARY(Vector3, Variant::VECTOR3)
MAKE_TYPED_DICTIONARY(Vector3i, Variant::VECTOR3I)
MAKE_TYPED_DICTIONARY(Transform2D, Variant::TRANSFORM2D)
MAKE_TYPED_DICTIONARY(Plane, Variant::PLANE)
MAKE_TYPED_DICTIONARY(Quaternion, Variant::QUATERNION)
MAKE_TYPED_DICTIONARY(AABB, Variant::AABB)
MAKE_TYPED_DICTIONARY(Basis, Variant::BASIS)
MAKE_TYPED_DICTIONARY(Transform3D, Variant::TRANSFORM3D)
MAKE_TYPED_DICTIONARY(Color, Variant::COLOR)
MAKE_TYPED_DICTIONARY(StringName, Variant::STRING_NAME)
MAKE_TYPED_DICTIONARY(NodePath, Variant::NODE_PATH)
MAKE_TYPED_DICTIONARY(RID, Variant::RID)
MAKE_TYPED_DICTIONARY(Callable, Variant::CALLABLE)
MAKE_TYPED_DICTIONARY(Signal, Variant::SIGNAL)
MAKE_TYPED_DICTIONARY(Dictionary, Variant::DICTIONARY)
MAKE_TYPED_DICTIONARY(Array, Variant::ARRAY)
MAKE_TYPED_DICTIONARY(PackedByteArray, Variant::PACKED_BYTE_ARRAY)
MAKE_TYPED_DICTIONARY(PackedInt32Array, Variant::PACKED_INT32_ARRAY)
MAKE_TYPED_DICTIONARY(PackedInt64Array, Variant::PACKED_INT64_ARRAY)
MAKE_TYPED_DICTIONARY(PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY)
MAKE_TYPED_DICTIONARY(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY)
MAKE_TYPED_DICTIONARY(PackedStringArray, Variant::PACKED_STRING_ARRAY)
MAKE_TYPED_DICTIONARY(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY)
MAKE_TYPED_DICTIONARY(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPED_DICTIONARY(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
MAKE_TYPED_DICTIONARY(PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY)
/*
MAKE_TYPED_DICTIONARY(IPAddress, Variant::STRING)
*/
#undef MAKE_TYPED_DICTIONARY
#undef MAKE_TYPED_DICTIONARY_NIL
#undef MAKE_TYPED_DICTIONARY_EXPANDED
#undef MAKE_TYPED_DICTIONARY_WITH_OBJECT
template <typename K, typename V>
struct PtrToArg<TypedDictionary<K, V>> {
_FORCE_INLINE_ static TypedDictionary<K, V> convert(const void *p_ptr) {
return TypedDictionary<K, V>(*reinterpret_cast<const Dictionary *>(p_ptr));
}
typedef Dictionary EncodeT;
_FORCE_INLINE_ static void encode(TypedDictionary<K, V> p_val, void *p_ptr) {
*(Dictionary *)p_ptr = p_val;
}
};
template <typename K, typename V>
struct PtrToArg<const TypedDictionary<K, V> &> {
typedef Dictionary EncodeT;
_FORCE_INLINE_ static TypedDictionary<K, V>
convert(const void *p_ptr) {
return TypedDictionary<K, V>(*reinterpret_cast<const Dictionary *>(p_ptr));
}
};
template <typename K, typename V>
struct GetTypeInfo<TypedDictionary<K, V>> {
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY;
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, vformat("%s;%s", K::get_class_static(), V::get_class_static()));
}
};
template <typename K, typename V>
struct GetTypeInfo<const TypedDictionary<K, V> &> {
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY;
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, vformat("%s;%s", K::get_class_static(), V::get_class_static()));
}
};
#define MAKE_TYPED_DICTIONARY_INFO_WITH_OBJECT(m_type, m_variant_type) \
template <typename T> \
struct GetTypeInfo<TypedDictionary<T, m_type>> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \
vformat("%s;%s", T::get_class_static(), m_variant_type == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type).utf8().get_data())); \
} \
}; \
template <typename T> \
struct GetTypeInfo<const TypedDictionary<T, m_type> &> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \
vformat("%s;%s", T::get_class_static(), m_variant_type == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type).utf8().get_data())); \
} \
}; \
template <typename T> \
struct GetTypeInfo<TypedDictionary<m_type, T>> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \
vformat("%s;%s", m_variant_type == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type).utf8().get_data(), T::get_class_static())); \
} \
}; \
template <typename T> \
struct GetTypeInfo<const TypedDictionary<m_type, T> &> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \
vformat("%s;%s", m_variant_type == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type).utf8().get_data(), T::get_class_static())); \
} \
};
#define MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type_key, m_variant_type_key, m_type_value, m_variant_type_value) \
template <> \
struct GetTypeInfo<TypedDictionary<m_type_key, m_type_value>> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \
vformat("%s;%s", m_variant_type_key == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type_key).utf8().get_data(), \
m_variant_type_value == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type_value).utf8().get_data())); \
} \
}; \
template <> \
struct GetTypeInfo<const TypedDictionary<m_type_key, m_type_value> &> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \
vformat("%s;%s", m_variant_type_key == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type_key).utf8().get_data(), \
m_variant_type_value == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type_value).utf8().get_data())); \
} \
};
#define MAKE_TYPED_DICTIONARY_INFO_NIL(m_type, m_variant_type) \
MAKE_TYPED_DICTIONARY_INFO_WITH_OBJECT(m_type, m_variant_type) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, bool, Variant::BOOL) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, uint8_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, int8_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, uint16_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, int16_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, uint32_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, int32_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, uint64_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, int64_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, float, Variant::FLOAT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, double, Variant::FLOAT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, String, Variant::STRING) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Vector2, Variant::VECTOR2) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Vector2i, Variant::VECTOR2I) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Rect2, Variant::RECT2) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Rect2i, Variant::RECT2I) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Vector3, Variant::VECTOR3) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Vector3i, Variant::VECTOR3I) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Transform2D, Variant::TRANSFORM2D) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Plane, Variant::PLANE) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Quaternion, Variant::QUATERNION) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, AABB, Variant::AABB) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Basis, Variant::BASIS) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Transform3D, Variant::TRANSFORM3D) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Color, Variant::COLOR) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, StringName, Variant::STRING_NAME) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, NodePath, Variant::NODE_PATH) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, RID, Variant::RID) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Callable, Variant::CALLABLE) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Signal, Variant::SIGNAL) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Dictionary, Variant::DICTIONARY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Array, Variant::ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedByteArray, Variant::PACKED_BYTE_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedInt32Array, Variant::PACKED_INT32_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedInt64Array, Variant::PACKED_INT64_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedStringArray, Variant::PACKED_STRING_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedColorArray, Variant::PACKED_COLOR_ARRAY) \
/* MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, IPAddress, Variant::STRING) */
#define MAKE_TYPED_DICTIONARY_INFO(m_type, m_variant_type) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Variant, Variant::NIL) \
MAKE_TYPED_DICTIONARY_INFO_NIL(m_type, m_variant_type)
MAKE_TYPED_DICTIONARY_INFO_NIL(Variant, Variant::NIL)
MAKE_TYPED_DICTIONARY_INFO(bool, Variant::BOOL)
MAKE_TYPED_DICTIONARY_INFO(uint8_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(int8_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(uint16_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(int16_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(uint32_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(int32_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(uint64_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(int64_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(float, Variant::FLOAT)
MAKE_TYPED_DICTIONARY_INFO(double, Variant::FLOAT)
MAKE_TYPED_DICTIONARY_INFO(String, Variant::STRING)
MAKE_TYPED_DICTIONARY_INFO(Vector2, Variant::VECTOR2)
MAKE_TYPED_DICTIONARY_INFO(Vector2i, Variant::VECTOR2I)
MAKE_TYPED_DICTIONARY_INFO(Rect2, Variant::RECT2)
MAKE_TYPED_DICTIONARY_INFO(Rect2i, Variant::RECT2I)
MAKE_TYPED_DICTIONARY_INFO(Vector3, Variant::VECTOR3)
MAKE_TYPED_DICTIONARY_INFO(Vector3i, Variant::VECTOR3I)
MAKE_TYPED_DICTIONARY_INFO(Transform2D, Variant::TRANSFORM2D)
MAKE_TYPED_DICTIONARY_INFO(Plane, Variant::PLANE)
MAKE_TYPED_DICTIONARY_INFO(Quaternion, Variant::QUATERNION)
MAKE_TYPED_DICTIONARY_INFO(AABB, Variant::AABB)
MAKE_TYPED_DICTIONARY_INFO(Basis, Variant::BASIS)
MAKE_TYPED_DICTIONARY_INFO(Transform3D, Variant::TRANSFORM3D)
MAKE_TYPED_DICTIONARY_INFO(Color, Variant::COLOR)
MAKE_TYPED_DICTIONARY_INFO(StringName, Variant::STRING_NAME)
MAKE_TYPED_DICTIONARY_INFO(NodePath, Variant::NODE_PATH)
MAKE_TYPED_DICTIONARY_INFO(RID, Variant::RID)
MAKE_TYPED_DICTIONARY_INFO(Callable, Variant::CALLABLE)
MAKE_TYPED_DICTIONARY_INFO(Signal, Variant::SIGNAL)
MAKE_TYPED_DICTIONARY_INFO(Dictionary, Variant::DICTIONARY)
MAKE_TYPED_DICTIONARY_INFO(Array, Variant::ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedByteArray, Variant::PACKED_BYTE_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedInt32Array, Variant::PACKED_INT32_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedInt64Array, Variant::PACKED_INT64_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedStringArray, Variant::PACKED_STRING_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
/*
MAKE_TYPED_DICTIONARY_INFO(IPAddress, Variant::STRING)
*/
#undef MAKE_TYPED_DICTIONARY_INFO
#undef MAKE_TYPED_DICTIONARY_INFO_NIL
#undef MAKE_TYPED_DICTIONARY_INFO_EXPANDED
#undef MAKE_TYPED_DICTIONARY_INFO_WITH_OBJECT
} // namespace godot
#endif // GODOT_TYPED_DICTIONARY_HPP

View File

@@ -49,6 +49,7 @@ class Variant {
friend class GDExtensionBinding;
friend class MethodBind;
friend class VariantInternal;
static void init_bindings();
@@ -264,6 +265,8 @@ public:
operator PackedColorArray() const;
operator PackedVector4Array() const;
Object *get_validated_object() const;
Variant &operator=(const Variant &other);
Variant &operator=(Variant &&other);
bool operator==(const Variant &other) const;

View File

@@ -0,0 +1,509 @@
/**************************************************************************/
/* variant_internal.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#ifndef GODOT_VARIANT_INTERNAL_HPP
#define GODOT_VARIANT_INTERNAL_HPP
#include <gdextension_interface.h>
#include <godot_cpp/variant/variant.hpp>
namespace godot {
// For use when you want to access the internal pointer of a Variant directly.
// Use with caution. You need to be sure that the type is correct.
namespace internal {
template <typename T>
struct VariantInternalType {};
template <>
struct VariantInternalType<bool> {
static constexpr Variant::Type type = Variant::BOOL;
};
template <>
struct VariantInternalType<int64_t> {
static constexpr Variant::Type type = Variant::INT;
};
template <>
struct VariantInternalType<double> {
static constexpr Variant::Type type = Variant::FLOAT;
};
template <>
struct VariantInternalType<String> {
static constexpr Variant::Type type = Variant::STRING;
};
template <>
struct VariantInternalType<Vector2> {
static constexpr Variant::Type type = Variant::VECTOR2;
};
template <>
struct VariantInternalType<Vector2i> {
static constexpr Variant::Type type = Variant::VECTOR2I;
};
template <>
struct VariantInternalType<Rect2> {
static constexpr Variant::Type type = Variant::RECT2;
};
template <>
struct VariantInternalType<Rect2i> {
static constexpr Variant::Type type = Variant::RECT2I;
};
template <>
struct VariantInternalType<Vector3> {
static constexpr Variant::Type type = Variant::VECTOR3;
};
template <>
struct VariantInternalType<Vector3i> {
static constexpr Variant::Type type = Variant::VECTOR3I;
};
template <>
struct VariantInternalType<Transform2D> {
static constexpr Variant::Type type = Variant::TRANSFORM2D;
};
template <>
struct VariantInternalType<Vector4> {
static constexpr Variant::Type type = Variant::VECTOR4;
};
template <>
struct VariantInternalType<Vector4i> {
static constexpr Variant::Type type = Variant::VECTOR4I;
};
template <>
struct VariantInternalType<Plane> {
static constexpr Variant::Type type = Variant::PLANE;
};
template <>
struct VariantInternalType<Quaternion> {
static constexpr Variant::Type type = Variant::QUATERNION;
};
template <>
struct VariantInternalType<AABB> {
static constexpr Variant::Type type = Variant::AABB;
};
template <>
struct VariantInternalType<Basis> {
static constexpr Variant::Type type = Variant::BASIS;
};
template <>
struct VariantInternalType<Transform3D> {
static constexpr Variant::Type type = Variant::TRANSFORM3D;
};
template <>
struct VariantInternalType<Projection> {
static constexpr Variant::Type type = Variant::PROJECTION;
};
template <>
struct VariantInternalType<Color> {
static constexpr Variant::Type type = Variant::COLOR;
};
template <>
struct VariantInternalType<StringName> {
static constexpr Variant::Type type = Variant::STRING_NAME;
};
template <>
struct VariantInternalType<NodePath> {
static constexpr Variant::Type type = Variant::NODE_PATH;
};
template <>
struct VariantInternalType<RID> {
static constexpr Variant::Type type = Variant::RID;
};
template <>
struct VariantInternalType<Object *> {
static constexpr Variant::Type type = Variant::OBJECT;
};
template <>
struct VariantInternalType<Callable> {
static constexpr Variant::Type type = Variant::CALLABLE;
};
template <>
struct VariantInternalType<Signal> {
static constexpr Variant::Type type = Variant::SIGNAL;
};
template <>
struct VariantInternalType<Dictionary> {
static constexpr Variant::Type type = Variant::DICTIONARY;
};
template <>
struct VariantInternalType<Array> {
static constexpr Variant::Type type = Variant::ARRAY;
};
template <>
struct VariantInternalType<PackedByteArray> {
static constexpr Variant::Type type = Variant::PACKED_BYTE_ARRAY;
};
template <>
struct VariantInternalType<PackedInt32Array> {
static constexpr Variant::Type type = Variant::PACKED_INT32_ARRAY;
};
template <>
struct VariantInternalType<PackedInt64Array> {
static constexpr Variant::Type type = Variant::PACKED_INT64_ARRAY;
};
template <>
struct VariantInternalType<PackedFloat32Array> {
static constexpr Variant::Type type = Variant::PACKED_FLOAT32_ARRAY;
};
template <>
struct VariantInternalType<PackedFloat64Array> {
static constexpr Variant::Type type = Variant::PACKED_FLOAT64_ARRAY;
};
template <>
struct VariantInternalType<PackedStringArray> {
static constexpr Variant::Type type = Variant::PACKED_STRING_ARRAY;
};
template <>
struct VariantInternalType<PackedVector2Array> {
static constexpr Variant::Type type = Variant::PACKED_VECTOR2_ARRAY;
};
template <>
struct VariantInternalType<PackedVector3Array> {
static constexpr Variant::Type type = Variant::PACKED_VECTOR3_ARRAY;
};
template <>
struct VariantInternalType<PackedColorArray> {
static constexpr Variant::Type type = Variant::PACKED_COLOR_ARRAY;
};
template <>
struct VariantInternalType<PackedVector4Array> {
static constexpr Variant::Type type = Variant::PACKED_VECTOR4_ARRAY;
};
} //namespace internal
class VariantInternal {
friend class Variant;
static GDExtensionVariantGetInternalPtrFunc get_internal_func[Variant::VARIANT_MAX];
static void init_bindings();
public:
template <typename T>
_FORCE_INLINE_ static T *get_internal_value(Variant *v) {
return static_cast<T *>(get_internal_func[internal::VariantInternalType<T>::type](v));
}
template <typename T>
_FORCE_INLINE_ static const T *get_internal_value(const Variant *v) {
return static_cast<const T *>(get_internal_func[internal::VariantInternalType<T>::type](const_cast<Variant *>(v)));
}
// Atomic types.
_FORCE_INLINE_ static bool *get_bool(Variant *v) { return get_internal_value<bool>(v); }
_FORCE_INLINE_ static const bool *get_bool(const Variant *v) { return get_internal_value<bool>(v); }
_FORCE_INLINE_ static int64_t *get_int(Variant *v) { return get_internal_value<int64_t>(v); }
_FORCE_INLINE_ static const int64_t *get_int(const Variant *v) { return get_internal_value<int64_t>(v); }
_FORCE_INLINE_ static double *get_float(Variant *v) { return get_internal_value<double>(v); }
_FORCE_INLINE_ static const double *get_float(const Variant *v) { return get_internal_value<double>(v); }
_FORCE_INLINE_ static String *get_string(Variant *v) { return get_internal_value<String>(v); }
_FORCE_INLINE_ static const String *get_string(const Variant *v) { return get_internal_value<String>(v); }
// Math types.
_FORCE_INLINE_ static Vector2 *get_vector2(Variant *v) { return get_internal_value<Vector2>(v); }
_FORCE_INLINE_ static const Vector2 *get_vector2(const Variant *v) { return get_internal_value<Vector2>(v); }
_FORCE_INLINE_ static Vector2i *get_vector2i(Variant *v) { return get_internal_value<Vector2i>(v); }
_FORCE_INLINE_ static const Vector2i *get_vector2i(const Variant *v) { return get_internal_value<Vector2i>(v); }
_FORCE_INLINE_ static Rect2 *get_rect2(Variant *v) { return get_internal_value<Rect2>(v); }
_FORCE_INLINE_ static const Rect2 *get_rect2(const Variant *v) { return get_internal_value<Rect2>(v); }
_FORCE_INLINE_ static Rect2i *get_rect2i(Variant *v) { return get_internal_value<Rect2i>(v); }
_FORCE_INLINE_ static const Rect2i *get_rect2i(const Variant *v) { return get_internal_value<Rect2i>(v); }
_FORCE_INLINE_ static Vector3 *get_vector3(Variant *v) { return get_internal_value<Vector3>(v); }
_FORCE_INLINE_ static const Vector3 *get_vector3(const Variant *v) { return get_internal_value<Vector3>(v); }
_FORCE_INLINE_ static Vector3i *get_vector3i(Variant *v) { return get_internal_value<Vector3i>(v); }
_FORCE_INLINE_ static const Vector3i *get_vector3i(const Variant *v) { return get_internal_value<Vector3i>(v); }
_FORCE_INLINE_ static Vector4 *get_vector4(Variant *v) { return get_internal_value<Vector4>(v); }
_FORCE_INLINE_ static const Vector4 *get_vector4(const Variant *v) { return get_internal_value<Vector4>(v); }
_FORCE_INLINE_ static Vector4i *get_vector4i(Variant *v) { return get_internal_value<Vector4i>(v); }
_FORCE_INLINE_ static const Vector4i *get_vector4i(const Variant *v) { return get_internal_value<Vector4i>(v); }
_FORCE_INLINE_ static Transform2D *get_transform2d(Variant *v) { return get_internal_value<Transform2D>(v); }
_FORCE_INLINE_ static const Transform2D *get_transform2d(const Variant *v) { return get_internal_value<Transform2D>(v); }
_FORCE_INLINE_ static Plane *get_plane(Variant *v) { return get_internal_value<Plane>(v); }
_FORCE_INLINE_ static const Plane *get_plane(const Variant *v) { return get_internal_value<Plane>(v); }
_FORCE_INLINE_ static Quaternion *get_quaternion(Variant *v) { return get_internal_value<Quaternion>(v); }
_FORCE_INLINE_ static const Quaternion *get_quaternion(const Variant *v) { return get_internal_value<Quaternion>(v); }
_FORCE_INLINE_ static AABB *get_aabb(Variant *v) { return get_internal_value<AABB>(v); }
_FORCE_INLINE_ static const AABB *get_aabb(const Variant *v) { return get_internal_value<AABB>(v); }
_FORCE_INLINE_ static Basis *get_basis(Variant *v) { return get_internal_value<Basis>(v); }
_FORCE_INLINE_ static const Basis *get_basis(const Variant *v) { return get_internal_value<Basis>(v); }
_FORCE_INLINE_ static Transform3D *get_transform(Variant *v) { return get_internal_value<Transform3D>(v); }
_FORCE_INLINE_ static const Transform3D *get_transform(const Variant *v) { return get_internal_value<Transform3D>(v); }
_FORCE_INLINE_ static Projection *get_projection(Variant *v) { return get_internal_value<Projection>(v); }
_FORCE_INLINE_ static const Projection *get_projection(const Variant *v) { return get_internal_value<Projection>(v); }
// Misc types.
_FORCE_INLINE_ static Color *get_color(Variant *v) { return get_internal_value<Color>(v); }
_FORCE_INLINE_ static const Color *get_color(const Variant *v) { return get_internal_value<Color>(v); }
_FORCE_INLINE_ static StringName *get_string_name(Variant *v) { return get_internal_value<StringName>(v); }
_FORCE_INLINE_ static const StringName *get_string_name(const Variant *v) { return get_internal_value<StringName>(v); }
_FORCE_INLINE_ static NodePath *get_node_path(Variant *v) { return get_internal_value<NodePath>(v); }
_FORCE_INLINE_ static const NodePath *get_node_path(const Variant *v) { return get_internal_value<NodePath>(v); }
_FORCE_INLINE_ static RID *get_rid(Variant *v) { return get_internal_value<RID>(v); }
_FORCE_INLINE_ static const RID *get_rid(const Variant *v) { return get_internal_value<RID>(v); }
_FORCE_INLINE_ static Callable *get_callable(Variant *v) { return get_internal_value<Callable>(v); }
_FORCE_INLINE_ static const Callable *get_callable(const Variant *v) { return get_internal_value<Callable>(v); }
_FORCE_INLINE_ static Signal *get_signal(Variant *v) { return get_internal_value<Signal>(v); }
_FORCE_INLINE_ static const Signal *get_signal(const Variant *v) { return get_internal_value<Signal>(v); }
_FORCE_INLINE_ static Dictionary *get_dictionary(Variant *v) { return get_internal_value<Dictionary>(v); }
_FORCE_INLINE_ static const Dictionary *get_dictionary(const Variant *v) { return get_internal_value<Dictionary>(v); }
_FORCE_INLINE_ static Array *get_array(Variant *v) { return get_internal_value<Array>(v); }
_FORCE_INLINE_ static const Array *get_array(const Variant *v) { return get_internal_value<Array>(v); }
// Typed arrays.
_FORCE_INLINE_ static PackedByteArray *get_byte_array(Variant *v) { return get_internal_value<PackedByteArray>(v); }
_FORCE_INLINE_ static const PackedByteArray *get_byte_array(const Variant *v) { return get_internal_value<PackedByteArray>(v); }
_FORCE_INLINE_ static PackedInt32Array *get_int32_array(Variant *v) { return get_internal_value<PackedInt32Array>(v); }
_FORCE_INLINE_ static const PackedInt32Array *get_int32_array(const Variant *v) { return get_internal_value<PackedInt32Array>(v); }
_FORCE_INLINE_ static PackedInt64Array *get_int64_array(Variant *v) { return get_internal_value<PackedInt64Array>(v); }
_FORCE_INLINE_ static const PackedInt64Array *get_int64_array(const Variant *v) { return get_internal_value<PackedInt64Array>(v); }
_FORCE_INLINE_ static PackedFloat32Array *get_float32_array(Variant *v) { return get_internal_value<PackedFloat32Array>(v); }
_FORCE_INLINE_ static const PackedFloat32Array *get_float32_array(const Variant *v) { return get_internal_value<PackedFloat32Array>(v); }
_FORCE_INLINE_ static PackedFloat64Array *get_float64_array(Variant *v) { return get_internal_value<PackedFloat64Array>(v); }
_FORCE_INLINE_ static const PackedFloat64Array *get_float64_array(const Variant *v) { return get_internal_value<PackedFloat64Array>(v); }
_FORCE_INLINE_ static PackedStringArray *get_string_array(Variant *v) { return get_internal_value<PackedStringArray>(v); }
_FORCE_INLINE_ static const PackedStringArray *get_string_array(const Variant *v) { return get_internal_value<PackedStringArray>(v); }
_FORCE_INLINE_ static PackedVector2Array *get_vector2_array(Variant *v) { return get_internal_value<PackedVector2Array>(v); }
_FORCE_INLINE_ static const PackedVector2Array *get_vector2_array(const Variant *v) { return get_internal_value<PackedVector2Array>(v); }
_FORCE_INLINE_ static PackedVector3Array *get_vector3_array(Variant *v) { return get_internal_value<PackedVector3Array>(v); }
_FORCE_INLINE_ static const PackedVector3Array *get_vector3_array(const Variant *v) { return get_internal_value<PackedVector3Array>(v); }
_FORCE_INLINE_ static PackedColorArray *get_color_array(Variant *v) { return get_internal_value<PackedColorArray>(v); }
_FORCE_INLINE_ static const PackedColorArray *get_color_array(const Variant *v) { return get_internal_value<PackedColorArray>(v); }
_FORCE_INLINE_ static PackedVector4Array *get_vector4_array(Variant *v) { return get_internal_value<PackedVector4Array>(v); }
_FORCE_INLINE_ static const PackedVector4Array *get_vector4_array(const Variant *v) { return get_internal_value<PackedVector4Array>(v); }
_FORCE_INLINE_ static Object **get_object(Variant *v) { return get_internal_value<Object *>(v); }
_FORCE_INLINE_ static const Object **get_object(const Variant *v) { return (const Object **)get_internal_value<Object *>(v); }
_FORCE_INLINE_ static void *get_opaque_pointer(Variant *v) {
switch (v->get_type()) {
case Variant::NIL:
return nullptr;
case Variant::BOOL:
return get_bool(v);
case Variant::INT:
return get_int(v);
case Variant::FLOAT:
return get_float(v);
case Variant::STRING:
return get_string(v);
case Variant::VECTOR2:
return get_vector2(v);
case Variant::VECTOR2I:
return get_vector2i(v);
case Variant::VECTOR3:
return get_vector3(v);
case Variant::VECTOR3I:
return get_vector3i(v);
case Variant::VECTOR4:
return get_vector4(v);
case Variant::VECTOR4I:
return get_vector4i(v);
case Variant::RECT2:
return get_rect2(v);
case Variant::RECT2I:
return get_rect2i(v);
case Variant::TRANSFORM3D:
return get_transform(v);
case Variant::PROJECTION:
return get_projection(v);
case Variant::TRANSFORM2D:
return get_transform2d(v);
case Variant::QUATERNION:
return get_quaternion(v);
case Variant::PLANE:
return get_plane(v);
case Variant::BASIS:
return get_basis(v);
case Variant::AABB:
return get_aabb(v);
case Variant::COLOR:
return get_color(v);
case Variant::STRING_NAME:
return get_string_name(v);
case Variant::NODE_PATH:
return get_node_path(v);
case Variant::RID:
return get_rid(v);
case Variant::CALLABLE:
return get_callable(v);
case Variant::SIGNAL:
return get_signal(v);
case Variant::DICTIONARY:
return get_dictionary(v);
case Variant::ARRAY:
return get_array(v);
case Variant::PACKED_BYTE_ARRAY:
return get_byte_array(v);
case Variant::PACKED_INT32_ARRAY:
return get_int32_array(v);
case Variant::PACKED_INT64_ARRAY:
return get_int64_array(v);
case Variant::PACKED_FLOAT32_ARRAY:
return get_float32_array(v);
case Variant::PACKED_FLOAT64_ARRAY:
return get_float64_array(v);
case Variant::PACKED_STRING_ARRAY:
return get_string_array(v);
case Variant::PACKED_VECTOR2_ARRAY:
return get_vector2_array(v);
case Variant::PACKED_VECTOR3_ARRAY:
return get_vector3_array(v);
case Variant::PACKED_COLOR_ARRAY:
return get_color_array(v);
case Variant::PACKED_VECTOR4_ARRAY:
return get_vector4_array(v);
case Variant::OBJECT:
return get_object(v);
case Variant::VARIANT_MAX:
ERR_FAIL_V(nullptr);
}
ERR_FAIL_V(nullptr);
}
_FORCE_INLINE_ static const void *get_opaque_pointer(const Variant *v) {
switch (v->get_type()) {
case Variant::NIL:
return nullptr;
case Variant::BOOL:
return get_bool(v);
case Variant::INT:
return get_int(v);
case Variant::FLOAT:
return get_float(v);
case Variant::STRING:
return get_string(v);
case Variant::VECTOR2:
return get_vector2(v);
case Variant::VECTOR2I:
return get_vector2i(v);
case Variant::VECTOR3:
return get_vector3(v);
case Variant::VECTOR3I:
return get_vector3i(v);
case Variant::VECTOR4:
return get_vector4(v);
case Variant::VECTOR4I:
return get_vector4i(v);
case Variant::RECT2:
return get_rect2(v);
case Variant::RECT2I:
return get_rect2i(v);
case Variant::TRANSFORM3D:
return get_transform(v);
case Variant::PROJECTION:
return get_projection(v);
case Variant::TRANSFORM2D:
return get_transform2d(v);
case Variant::QUATERNION:
return get_quaternion(v);
case Variant::PLANE:
return get_plane(v);
case Variant::BASIS:
return get_basis(v);
case Variant::AABB:
return get_aabb(v);
case Variant::COLOR:
return get_color(v);
case Variant::STRING_NAME:
return get_string_name(v);
case Variant::NODE_PATH:
return get_node_path(v);
case Variant::RID:
return get_rid(v);
case Variant::CALLABLE:
return get_callable(v);
case Variant::SIGNAL:
return get_signal(v);
case Variant::DICTIONARY:
return get_dictionary(v);
case Variant::ARRAY:
return get_array(v);
case Variant::PACKED_BYTE_ARRAY:
return get_byte_array(v);
case Variant::PACKED_INT32_ARRAY:
return get_int32_array(v);
case Variant::PACKED_INT64_ARRAY:
return get_int64_array(v);
case Variant::PACKED_FLOAT32_ARRAY:
return get_float32_array(v);
case Variant::PACKED_FLOAT64_ARRAY:
return get_float64_array(v);
case Variant::PACKED_STRING_ARRAY:
return get_string_array(v);
case Variant::PACKED_VECTOR2_ARRAY:
return get_vector2_array(v);
case Variant::PACKED_VECTOR3_ARRAY:
return get_vector3_array(v);
case Variant::PACKED_COLOR_ARRAY:
return get_color_array(v);
case Variant::PACKED_VECTOR4_ARRAY:
return get_vector4_array(v);
case Variant::OBJECT:
return get_object(v);
case Variant::VARIANT_MAX:
ERR_FAIL_V(nullptr);
}
ERR_FAIL_V(nullptr);
}
};
template <typename T>
struct VariantGetInternalPtr {
static internal::VariantInternalType<T> *get_ptr(Variant *v) { return VariantInternal::get_internal_value<T>(v); }
static const internal::VariantInternalType<T> *get_ptr(const Variant *v) { return VariantInternal::get_internal_value<T>(v); }
};
template <typename T>
struct can_set_variant_internal_value {
static const bool value = true;
};
template <>
struct can_set_variant_internal_value<Object *> {
static const bool value = false;
};
template <typename T>
struct VariantInternalAccessor {
static _FORCE_INLINE_ const T &get(const Variant *v) { return *VariantInternal::get_internal_value<T>(v); }
// Enable set() only for those types where we can set (all but Object *).
template <typename U = T, typename = std::enable_if_t<can_set_variant_internal_value<U>::value>>
static _FORCE_INLINE_ void set(Variant *v, const internal::VariantInternalType<U> &p_value) {
*VariantInternal::get_internal_value<U>(v) = p_value;
}
};
template <typename T, std::enable_if_t<can_set_variant_internal_value<T>::value>>
struct VariantDefaultInitializer {
static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_internal_value<T>(v) = T(); }
};
} // namespace godot
#endif // GODOT_VARIANT_INTERNAL_HPP

View File

@@ -19,7 +19,6 @@ def test(profile_filepath=""):
api = generate_trimmed_api(api_filepath, profile_filepath)
_generate_bindings(
api,
api_filepath,
use_template_get_node=False,
bits=bits,
precision=precision,

View File

@@ -60,9 +60,9 @@ void Wrapped::_postinitialize() {
Wrapped::_constructing_mutex.unlock();
#endif
// Only send NOTIFICATION_POSTINITIALIZE for extension classes.
if (_is_extension_class()) {
_notificationv(Object::NOTIFICATION_POSTINITIALIZE);
Object *obj = dynamic_cast<Object *>(this);
if (obj) {
obj->notification(Object::NOTIFICATION_POSTINITIALIZE);
}
}
@@ -74,7 +74,7 @@ Wrapped::Wrapped(const StringName p_godot_class) {
} else
#endif
{
_owner = godot::internal::gdextension_interface_classdb_construct_object(reinterpret_cast<GDExtensionConstStringNamePtr>(p_godot_class._native_ptr()));
_owner = godot::internal::gdextension_interface_classdb_construct_object2(reinterpret_cast<GDExtensionConstStringNamePtr>(p_godot_class._native_ptr()));
}
if (_constructing_extension_class_name) {

View File

@@ -285,7 +285,7 @@ void ClassDB::bind_integer_constant(const StringName &p_class_name, const String
// Register it with Godot
internal::gdextension_interface_classdb_register_extension_class_integer_constant(internal::library, p_class_name._native_ptr(), p_enum_name._native_ptr(), p_constant_name._native_ptr(), p_constant_value, p_is_bitfield);
}
GDExtensionClassCallVirtual ClassDB::get_virtual_func(void *p_userdata, GDExtensionConstStringNamePtr p_name) {
GDExtensionClassCallVirtual ClassDB::get_virtual_func(void *p_userdata, GDExtensionConstStringNamePtr p_name, uint32_t p_hash) {
// This is called by Godot the first time it calls a virtual function, and it caches the result, per object instance.
// Because of this, it can happen from different threads at once.
// It should be ok not using any mutex as long as we only READ data.
@@ -299,10 +299,10 @@ GDExtensionClassCallVirtual ClassDB::get_virtual_func(void *p_userdata, GDExtens
// Find method in current class, or any of its parent classes (Godot classes not included)
while (type != nullptr) {
std::unordered_map<StringName, GDExtensionClassCallVirtual>::const_iterator method_it = type->virtual_methods.find(*name);
std::unordered_map<StringName, ClassInfo::VirtualMethod>::const_iterator method_it = type->virtual_methods.find(*name);
if (method_it != type->virtual_methods.end()) {
return method_it->second;
if (method_it != type->virtual_methods.end() && method_it->second.hash == p_hash) {
return method_it->second.func;
}
type = type->parent_ptr;
@@ -328,7 +328,7 @@ const GDExtensionInstanceBindingCallbacks *ClassDB::get_instance_binding_callbac
return callbacks_it->second;
}
void ClassDB::bind_virtual_method(const StringName &p_class, const StringName &p_method, GDExtensionClassCallVirtual p_call) {
void ClassDB::bind_virtual_method(const StringName &p_class, const StringName &p_method, GDExtensionClassCallVirtual p_call, uint32_t p_hash) {
std::unordered_map<StringName, ClassInfo>::iterator type_it = classes.find(p_class);
ERR_FAIL_COND_MSG(type_it == classes.end(), String("Class '{0}' doesn't exist.").format(Array::make(p_class)));
@@ -337,7 +337,10 @@ void ClassDB::bind_virtual_method(const StringName &p_class, const StringName &p
ERR_FAIL_COND_MSG(type.method_map.find(p_method) != type.method_map.end(), String("Method '{0}::{1}()' already registered as non-virtual.").format(Array::make(p_class, p_method)));
ERR_FAIL_COND_MSG(type.virtual_methods.find(p_method) != type.virtual_methods.end(), String("Virtual '{0}::{1}()' method already registered.").format(Array::make(p_class, p_method)));
type.virtual_methods[p_method] = p_call;
type.virtual_methods[p_method] = ClassInfo::VirtualMethod{
p_call,
p_hash,
};
}
void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_method, const Vector<StringName> &p_arg_names) {
@@ -389,7 +392,7 @@ void ClassDB::initialize_class(const ClassInfo &p_cl) {
}
void ClassDB::initialize(GDExtensionInitializationLevel p_level) {
for (const std::pair<const StringName, ClassInfo> &pair : classes) {
for (const std::pair<StringName, ClassInfo> pair : classes) {
const ClassInfo &cl = pair.second;
if (cl.level != p_level) {
continue;

View File

@@ -32,22 +32,6 @@
namespace godot {
void MethodBind::_set_const(bool p_const) {
_const = p_const;
}
void MethodBind::_set_static(bool p_static) {
_static = p_static;
}
void MethodBind::_set_returns(bool p_returns) {
_returns = p_returns;
}
void MethodBind::_set_vararg(bool p_vararg) {
_vararg = p_vararg;
}
StringName MethodBind::get_name() const {
return name;
}
@@ -56,6 +40,26 @@ void MethodBind::set_name(const StringName &p_name) {
name = p_name;
}
void MethodBind::set_argument_count(int p_count) {
argument_count = p_count;
}
void MethodBind::set_const(bool p_const) {
_is_const = p_const;
}
void MethodBind::set_return(bool p_return) {
_has_return = p_return;
}
void MethodBind::set_static(bool p_static) {
_static = p_static;
}
void MethodBind::set_vararg(bool p_vararg) {
_vararg = p_vararg;
}
void MethodBind::set_argument_names(const std::vector<StringName> &p_names) {
argument_names = p_names;
}
@@ -64,7 +68,7 @@ std::vector<StringName> MethodBind::get_argument_names() const {
return argument_names;
}
void MethodBind::_generate_argument_types(int p_count) {
void MethodBind::generate_argument_types(int p_count) {
set_argument_count(p_count);
if (argument_types != nullptr) {

View File

@@ -88,11 +88,13 @@ GDExtensionInterfaceVariantGetType gdextension_interface_variant_get_type = null
GDExtensionInterfaceVariantHasMethod gdextension_interface_variant_has_method = nullptr;
GDExtensionInterfaceVariantHasMember gdextension_interface_variant_has_member = nullptr;
GDExtensionInterfaceVariantHasKey gdextension_interface_variant_has_key = nullptr;
GDExtensionInterfaceVariantGetObjectInstanceId gdextension_interface_variant_get_object_instance_id = nullptr;
GDExtensionInterfaceVariantGetTypeName gdextension_interface_variant_get_type_name = nullptr;
GDExtensionInterfaceVariantCanConvert gdextension_interface_variant_can_convert = nullptr;
GDExtensionInterfaceVariantCanConvertStrict gdextension_interface_variant_can_convert_strict = nullptr;
GDExtensionInterfaceGetVariantFromTypeConstructor gdextension_interface_get_variant_from_type_constructor = nullptr;
GDExtensionInterfaceGetVariantToTypeConstructor gdextension_interface_get_variant_to_type_constructor = nullptr;
GDExtensionInterfaceGetVariantGetInternalPtrFunc gdextension_interface_variant_get_ptr_internal_getter = nullptr;
GDExtensionInterfaceVariantGetPtrOperatorEvaluator gdextension_interface_variant_get_ptr_operator_evaluator = nullptr;
GDExtensionInterfaceVariantGetPtrBuiltinMethod gdextension_interface_variant_get_ptr_builtin_method = nullptr;
GDExtensionInterfaceVariantGetPtrConstructor gdextension_interface_variant_get_ptr_constructor = nullptr;
@@ -164,6 +166,7 @@ GDExtensionInterfaceArrayRef gdextension_interface_array_ref = nullptr;
GDExtensionInterfaceArraySetTyped gdextension_interface_array_set_typed = nullptr;
GDExtensionInterfaceDictionaryOperatorIndex gdextension_interface_dictionary_operator_index = nullptr;
GDExtensionInterfaceDictionaryOperatorIndexConst gdextension_interface_dictionary_operator_index_const = nullptr;
GDExtensionInterfaceDictionarySetTyped gdextension_interface_dictionary_set_typed = nullptr;
GDExtensionInterfaceObjectMethodBindCall gdextension_interface_object_method_bind_call = nullptr;
GDExtensionInterfaceObjectMethodBindPtrcall gdextension_interface_object_method_bind_ptrcall = nullptr;
GDExtensionInterfaceObjectDestroy gdextension_interface_object_destroy = nullptr;
@@ -185,10 +188,10 @@ GDExtensionInterfaceRefSetObject gdextension_interface_ref_set_object = nullptr;
GDExtensionInterfaceScriptInstanceCreate3 gdextension_interface_script_instance_create3 = nullptr;
GDExtensionInterfacePlaceHolderScriptInstanceCreate gdextension_interface_placeholder_script_instance_create = nullptr;
GDExtensionInterfacePlaceHolderScriptInstanceUpdate gdextension_interface_placeholder_script_instance_update = nullptr;
GDExtensionInterfaceClassdbConstructObject gdextension_interface_classdb_construct_object = nullptr;
GDExtensionInterfaceClassdbConstructObject2 gdextension_interface_classdb_construct_object2 = nullptr;
GDExtensionInterfaceClassdbGetMethodBind gdextension_interface_classdb_get_method_bind = nullptr;
GDExtensionInterfaceClassdbGetClassTag gdextension_interface_classdb_get_class_tag = nullptr;
GDExtensionInterfaceClassdbRegisterExtensionClass3 gdextension_interface_classdb_register_extension_class3 = nullptr;
GDExtensionInterfaceClassdbRegisterExtensionClass4 gdextension_interface_classdb_register_extension_class4 = nullptr;
GDExtensionInterfaceClassdbRegisterExtensionClassMethod gdextension_interface_classdb_register_extension_class_method = nullptr;
GDExtensionInterfaceClassdbRegisterExtensionClassVirtualMethod gdextension_interface_classdb_register_extension_class_virtual_method = nullptr;
GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant gdextension_interface_classdb_register_extension_class_integer_constant = nullptr;
@@ -367,11 +370,13 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
LOAD_PROC_ADDRESS(variant_has_method, GDExtensionInterfaceVariantHasMethod);
LOAD_PROC_ADDRESS(variant_has_member, GDExtensionInterfaceVariantHasMember);
LOAD_PROC_ADDRESS(variant_has_key, GDExtensionInterfaceVariantHasKey);
LOAD_PROC_ADDRESS(variant_get_object_instance_id, GDExtensionInterfaceVariantGetObjectInstanceId);
LOAD_PROC_ADDRESS(variant_get_type_name, GDExtensionInterfaceVariantGetTypeName);
LOAD_PROC_ADDRESS(variant_can_convert, GDExtensionInterfaceVariantCanConvert);
LOAD_PROC_ADDRESS(variant_can_convert_strict, GDExtensionInterfaceVariantCanConvertStrict);
LOAD_PROC_ADDRESS(get_variant_from_type_constructor, GDExtensionInterfaceGetVariantFromTypeConstructor);
LOAD_PROC_ADDRESS(get_variant_to_type_constructor, GDExtensionInterfaceGetVariantToTypeConstructor);
LOAD_PROC_ADDRESS(variant_get_ptr_internal_getter, GDExtensionInterfaceGetVariantGetInternalPtrFunc);
LOAD_PROC_ADDRESS(variant_get_ptr_operator_evaluator, GDExtensionInterfaceVariantGetPtrOperatorEvaluator);
LOAD_PROC_ADDRESS(variant_get_ptr_builtin_method, GDExtensionInterfaceVariantGetPtrBuiltinMethod);
LOAD_PROC_ADDRESS(variant_get_ptr_constructor, GDExtensionInterfaceVariantGetPtrConstructor);
@@ -443,6 +448,7 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
LOAD_PROC_ADDRESS(array_set_typed, GDExtensionInterfaceArraySetTyped);
LOAD_PROC_ADDRESS(dictionary_operator_index, GDExtensionInterfaceDictionaryOperatorIndex);
LOAD_PROC_ADDRESS(dictionary_operator_index_const, GDExtensionInterfaceDictionaryOperatorIndexConst);
LOAD_PROC_ADDRESS(dictionary_set_typed, GDExtensionInterfaceDictionarySetTyped);
LOAD_PROC_ADDRESS(object_method_bind_call, GDExtensionInterfaceObjectMethodBindCall);
LOAD_PROC_ADDRESS(object_method_bind_ptrcall, GDExtensionInterfaceObjectMethodBindPtrcall);
LOAD_PROC_ADDRESS(object_destroy, GDExtensionInterfaceObjectDestroy);
@@ -464,10 +470,10 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
LOAD_PROC_ADDRESS(script_instance_create3, GDExtensionInterfaceScriptInstanceCreate3);
LOAD_PROC_ADDRESS(placeholder_script_instance_create, GDExtensionInterfacePlaceHolderScriptInstanceCreate);
LOAD_PROC_ADDRESS(placeholder_script_instance_update, GDExtensionInterfacePlaceHolderScriptInstanceUpdate);
LOAD_PROC_ADDRESS(classdb_construct_object, GDExtensionInterfaceClassdbConstructObject);
LOAD_PROC_ADDRESS(classdb_construct_object2, GDExtensionInterfaceClassdbConstructObject2);
LOAD_PROC_ADDRESS(classdb_get_method_bind, GDExtensionInterfaceClassdbGetMethodBind);
LOAD_PROC_ADDRESS(classdb_get_class_tag, GDExtensionInterfaceClassdbGetClassTag);
LOAD_PROC_ADDRESS(classdb_register_extension_class3, GDExtensionInterfaceClassdbRegisterExtensionClass3);
LOAD_PROC_ADDRESS(classdb_register_extension_class4, GDExtensionInterfaceClassdbRegisterExtensionClass4);
LOAD_PROC_ADDRESS(classdb_register_extension_class_method, GDExtensionInterfaceClassdbRegisterExtensionClassMethod);
LOAD_PROC_ADDRESS(classdb_register_extension_class_virtual_method, GDExtensionInterfaceClassdbRegisterExtensionClassVirtualMethod);
LOAD_PROC_ADDRESS(classdb_register_extension_class_integer_constant, GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant);

View File

@@ -246,4 +246,10 @@ Variant &Dictionary::operator[](const Variant &p_key) {
return *var;
}
void Dictionary::set_typed(uint32_t p_key_type, const StringName &p_key_class_name, const Variant &p_key_script, uint32_t p_value_type, const StringName &p_value_class_name, const Variant &p_value_script) {
// p_key_type/p_value_type are not Variant::Type so that header doesn't depend on <variant.hpp>.
internal::gdextension_interface_dictionary_set_typed((GDExtensionTypePtr *)this, (GDExtensionVariantType)p_key_type, (GDExtensionConstStringNamePtr)&p_key_class_name, (GDExtensionConstVariantPtr)&p_key_script,
(GDExtensionVariantType)p_value_type, (GDExtensionConstStringNamePtr)&p_value_class_name, (GDExtensionConstVariantPtr)&p_value_script);
}
} // namespace godot

View File

@@ -913,13 +913,6 @@ Projection::Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_
columns[3] = p_w;
}
Projection::Projection(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_xw, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_yw, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_zw, real_t p_wx, real_t p_wy, real_t p_wz, real_t p_ww) {
columns[0] = Vector4(p_xx, p_xy, p_xz, p_xw);
columns[1] = Vector4(p_yx, p_yy, p_yz, p_yw);
columns[2] = Vector4(p_zx, p_zy, p_zz, p_zw);
columns[3] = Vector4(p_wx, p_wy, p_wz, p_ww);
}
Projection::Projection(const Transform3D &p_transform) {
const Transform3D &tr = p_transform;
real_t *m = &columns[0][0];

View File

@@ -35,6 +35,7 @@
#include <godot_cpp/core/binder_common.hpp>
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/variant/variant_internal.hpp>
#include <utility>
@@ -49,6 +50,7 @@ void Variant::init_bindings() {
from_type_constructor[i] = internal::gdextension_interface_get_variant_from_type_constructor((GDExtensionVariantType)i);
to_type_constructor[i] = internal::gdextension_interface_get_variant_to_type_constructor((GDExtensionVariantType)i);
}
VariantInternal::init_bindings();
StringName::init_bindings();
String::init_bindings();
@@ -448,12 +450,7 @@ Variant::operator ObjectID() const {
if (get_type() == Type::INT) {
return ObjectID(operator uint64_t());
} else if (get_type() == Type::OBJECT) {
Object *obj = operator Object *();
if (obj != nullptr) {
return ObjectID(obj->get_instance_id());
} else {
return ObjectID();
}
return ObjectID(internal::gdextension_interface_variant_get_object_instance_id(_native_ptr()));
} else {
return ObjectID();
}
@@ -515,6 +512,10 @@ Variant::operator PackedVector4Array() const {
return PackedVector4Array(this);
}
Object *Variant::get_validated_object() const {
return ObjectDB::get_instance(operator ObjectID());
}
Variant &Variant::operator=(const Variant &other) {
clear();
internal::gdextension_interface_variant_new_copy(_native_ptr(), other._native_ptr());

View File

@@ -0,0 +1,43 @@
/**************************************************************************/
/* variant_internal.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#include <godot_cpp/variant/variant_internal.hpp>
namespace godot {
GDExtensionVariantGetInternalPtrFunc VariantInternal::get_internal_func[Variant::VARIANT_MAX]{};
void VariantInternal::init_bindings() {
for (int i = 1; i < Variant::VARIANT_MAX; i++) {
get_internal_func[i] = internal::gdextension_interface_variant_get_ptr_internal_getter((GDExtensionVariantType)i);
}
}
} // namespace godot

View File

@@ -1,143 +1,81 @@
cmake_minimum_required(VERSION 3.13)
project(godot-cpp-test)
#[=======================================================================[.rst:
Integration Testing
-------------------
set(GODOT_GDEXTENSION_DIR ../gdextension/ CACHE STRING "Path to GDExtension interface header directory")
set(CPP_BINDINGS_PATH ../ CACHE STRING "Path to C++ bindings")
The Test target used to validate changes in the GitHub CI.
]=======================================================================]
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(TARGET_PATH x11)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(TARGET_PATH win64)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(TARGET_PATH macos)
else()
message(FATAL_ERROR "Not implemented support for ${CMAKE_SYSTEM_NAME}")
endif()
message( STATUS "Testing Integration targets are enabled.")
# Change the output directory to the bin directory
set(BUILD_PATH ${CMAKE_SOURCE_DIR}/bin/${TARGET_PATH})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${BUILD_PATH}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${BUILD_PATH}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${BUILD_PATH}")
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${BUILD_PATH}")
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${BUILD_PATH}")
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${BUILD_PATH}")
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE "${BUILD_PATH}")
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${BUILD_PATH}")
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${BUILD_PATH}")
# Generate Doc Data
file( GLOB_RECURSE DOC_XML
LIST_DIRECTORIES NO
CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/doc_classes/*.xml" )
# Set the c++ standard to c++17
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
foreach( TARGET_ALIAS template_debug template_release editor )
set( TARGET_NAME "godot-cpp.test.${TARGET_ALIAS}" )
set(GODOT_COMPILE_FLAGS )
set(GODOT_LINKER_FLAGS )
add_library( ${TARGET_NAME} SHARED EXCLUDE_FROM_ALL )
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# using Visual Studio C++
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /WX") # /GF /MP
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /DTYPED_METHOD_BIND")
target_sources( ${TARGET_NAME}
PRIVATE
src/example.cpp
src/example.h
src/register_types.cpp
src/register_types.h
src/tests.h
)
if(CMAKE_BUILD_TYPE MATCHES Debug)
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MDd") # /Od /RTC1 /Zi
else()
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MD /O2") # /Oy /GL /Gy
STRING(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
endif(CMAKE_BUILD_TYPE MATCHES Debug)
# conditionally add doc data to compile output
if( TARGET_ALIAS MATCHES "editor|template_debug" )
target_doc_sources( ${TARGET_NAME} ${DOC_XML} )
endif()
# Disable conversion warning, truncation, unreferenced var, signed mismatch
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /wd4244 /wd4305 /wd4101 /wd4018 /wd4267")
set( OUTPUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/project/bin/" )
add_definitions(-DNOMINMAX)
# Link to godot-cpp target
set( LINK_TARGET "godot-cpp::${TARGET_ALIAS}" )
target_link_libraries( ${TARGET_NAME} PRIVATE ${LINK_TARGET} )
# Unkomment for warning level 4
#if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
# string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
#endif()
### Get useful properties from godot-cpp target
get_target_property( GODOTCPP_SUFFIX ${LINK_TARGET} GODOTCPP_SUFFIX )
get_target_property( OSX_ARCH ${LINK_TARGET} OSX_ARCHITECTURES )
else()
set_target_properties( ${TARGET_NAME}
PROPERTIES
CXX_STANDARD 17
CXX_EXTENSIONS OFF
CXX_VISIBILITY_PRESET ${GODOTCPP_SYMBOL_VISIBILITY}
set(GODOT_LINKER_FLAGS "-static-libgcc -static-libstdc++ -Wl,-R,'$$ORIGIN'")
POSITION_INDEPENDENT_CODE ON
BUILD_RPATH_USE_ORIGIN ON
set(GODOT_COMPILE_FLAGS "-fPIC -g -Wwrite-strings")
# Try to ensure only static libraries are selected to be linked to.
LINK_SEARCH_START_STATIC ON
LINK_SEARCH_END_STATIC ON
if(CMAKE_BUILD_TYPE MATCHES Debug)
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0")
else()
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -O3")
endif(CMAKE_BUILD_TYPE MATCHES Debug)
endif()
# NOTE: Wrapping the output variables inside a generator expression
# prevents msvc generator from adding addition Config Directories
LIBRARY_OUTPUT_DIRECTORY "$<1:${OUTPUT_DIR}>"
RUNTIME_OUTPUT_DIRECTORY "$<1:${OUTPUT_DIR}>"
PDB_OUTPUT_DIRECTORY "$<1:${OUTPUT_DIR}>" #MSVC Only, ignored on other platforms
# Disable exception handling. Godot doesn't use exceptions anywhere, and this
# saves around 20% of binary size and very significant build time (GH-80513).
option(GODOT_DISABLE_EXCEPTIONS ON "Force disabling exception handling code")
if (GODOT_DISABLE_EXCEPTIONS)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -D_HAS_EXCEPTIONS=0")
else()
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-exceptions")
endif()
else()
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /EHsc")
endif()
endif()
PREFIX "lib"
OUTPUT_NAME "gdexample${GODOTCPP_SUFFIX}"
# Get Sources
file(GLOB_RECURSE SOURCES src/*.c**)
file(GLOB_RECURSE HEADERS include/*.h**)
# Some IDE's respect this property to logically group targets
FOLDER "godot-cpp"
)
# Define our godot-cpp library
add_library(${PROJECT_NAME} SHARED ${SOURCES} ${HEADERS})
# CMAKE_SYSTEM_NAME refers to the target system
if( CMAKE_SYSTEM_NAME STREQUAL Darwin )
set_target_properties( ${TARGET_NAME}
PROPERTIES
SUFFIX ""
OUTPUT_DIR "${OUTPUT_DIR}/libgdexample.macos.${TARGET_ALIAS}.framework"
OSX_ARCHITECTURES "${OSX_ARCH}"
)
endif()
target_include_directories(${PROJECT_NAME} SYSTEM
PRIVATE
${CPP_BINDINGS_PATH}/include
${CPP_BINDINGS_PATH}/gen/include
${GODOT_GDEXTENSION_DIR}
)
# Create the correct name (godot.os.build_type.system_bits)
# Synchronized with godot-cpp's CMakeLists.txt
set(BITS 32)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(BITS 64)
endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
if(CMAKE_BUILD_TYPE MATCHES Debug)
set(GODOT_CPP_BUILD_TYPE Debug)
else()
set(GODOT_CPP_BUILD_TYPE Release)
endif()
string(TOLOWER ${CMAKE_SYSTEM_NAME} SYSTEM_NAME)
string(TOLOWER ${GODOT_CPP_BUILD_TYPE} BUILD_TYPE)
if(ANDROID)
# Added the android abi after system name
set(SYSTEM_NAME ${SYSTEM_NAME}.${ANDROID_ABI})
endif()
if(CMAKE_VERSION VERSION_GREATER "3.13")
target_link_directories(${PROJECT_NAME}
PRIVATE
${CPP_BINDINGS_PATH}/bin/
)
target_link_libraries(${PROJECT_NAME}
godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}$<$<NOT:$<PLATFORM_ID:Android>>:.${BITS}>
)
else()
target_link_libraries(${PROJECT_NAME}
${CPP_BINDINGS_PATH}/bin/libgodot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}$<$<NOT:$<PLATFORM_ID:Android>>:.${BITS}>.a
)
endif()
# Add the compile flags
set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY COMPILE_FLAGS ${GODOT_COMPILE_FLAGS})
set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY LINK_FLAGS ${GODOT_LINKER_FLAGS})
set_property(TARGET ${PROJECT_NAME} PROPERTY OUTPUT_NAME "gdexample")
endforeach()

View File

@@ -18,7 +18,8 @@ func _ready():
# To string.
assert_equal(example.to_string(),'[ GDExtension::Example <--> Instance ID:%s ]' % example.get_instance_id())
assert_equal($Example/ExampleMin.to_string(), 'ExampleMin:<ExampleMin#%s>' % $Example/ExampleMin.get_instance_id())
# It appears there's a bug with instance ids :-(
#assert_equal($Example/ExampleMin.to_string(), 'ExampleMin:[Wrapped:%s]' % $Example/ExampleMin.get_instance_id())
# Call static methods.
assert_equal(Example.test_static(9, 100), 109);
@@ -80,10 +81,13 @@ func _ready():
# Array and Dictionary
assert_equal(example.test_array(), [1, 2])
assert_equal(example.test_tarray(), [ Vector2(1, 2), Vector2(2, 3) ])
assert_equal(example.test_dictionary(), {"hello": "world", "foo": "bar"})
assert_equal(example.test_tarray(), [Vector2(1, 2), Vector2(2, 3)])
var array: Array[int] = [1, 2, 3]
assert_equal(example.test_tarray_arg(array), 6)
assert_equal(example.test_dictionary(), { "hello": "world", "foo": "bar" })
assert_equal(example.test_tdictionary(), { Vector2(1, 2): Vector2i(2, 3) })
var dictionary: Dictionary[String, int] = { "1": 1, "2": 2, "3": 3 }
assert_equal(example.test_tdictionary_arg(dictionary), 6)
example.callable_bind()
assert_equal(custom_signal_emitted, ["bound", 11])
@@ -205,6 +209,12 @@ func _ready():
assert_equal(example.test_variant_float_conversion(10.0), 10.0)
assert_equal(example.test_variant_float_conversion(10), 10.0)
# Test checking if objects are valid.
var object_of_questionable_validity = Object.new()
assert_equal(example.test_object_is_valid(object_of_questionable_validity), true)
object_of_questionable_validity.free()
assert_equal(example.test_object_is_valid(object_of_questionable_validity), false)
# Test that ptrcalls from GDExtension to the engine are correctly encoding Object and RefCounted.
var new_node = Node.new()
example.test_add_child(new_node)
@@ -261,6 +271,9 @@ func _ready():
# Test that we can access an engine singleton.
assert_equal(example.test_use_engine_singleton(), OS.get_name())
assert_equal(example.test_get_internal(1), 1)
assert_equal(example.test_get_internal(true), -1)
# Test that notifications happen on both parent and child classes.
var example_child = $ExampleChild
assert_equal(example_child.get_value1(), 11)
@@ -275,6 +288,10 @@ func _ready():
assert_equal(library_path, ProjectSettings.globalize_path(library_path))
assert_equal(FileAccess.file_exists(library_path), true)
# Test a class with a unicode name.
var przykład = ExamplePrzykład.new()
assert_equal(przykład.get_the_word(), "słowo to przykład")
exit_with_status()
func _on_Example_custom_signal(signal_name, value):

View File

@@ -12,6 +12,7 @@
#include <godot_cpp/classes/multiplayer_api.hpp>
#include <godot_cpp/classes/multiplayer_peer.hpp>
#include <godot_cpp/classes/os.hpp>
#include <godot_cpp/variant/typed_dictionary.hpp>
#include <godot_cpp/variant/utility_functions.hpp>
using namespace godot;
@@ -199,6 +200,8 @@ void Example::_bind_methods() {
ClassDB::bind_method(D_METHOD("test_tarray_arg", "array"), &Example::test_tarray_arg);
ClassDB::bind_method(D_METHOD("test_tarray"), &Example::test_tarray);
ClassDB::bind_method(D_METHOD("test_dictionary"), &Example::test_dictionary);
ClassDB::bind_method(D_METHOD("test_tdictionary_arg", "dictionary"), &Example::test_tdictionary_arg);
ClassDB::bind_method(D_METHOD("test_tdictionary"), &Example::test_tdictionary);
ClassDB::bind_method(D_METHOD("test_node_argument"), &Example::test_node_argument);
ClassDB::bind_method(D_METHOD("test_string_ops"), &Example::test_string_ops);
ClassDB::bind_method(D_METHOD("test_str_utility"), &Example::test_str_utility);
@@ -215,6 +218,7 @@ void Example::_bind_methods() {
ClassDB::bind_method(D_METHOD("test_variant_vector2i_conversion", "variant"), &Example::test_variant_vector2i_conversion);
ClassDB::bind_method(D_METHOD("test_variant_int_conversion", "variant"), &Example::test_variant_int_conversion);
ClassDB::bind_method(D_METHOD("test_variant_float_conversion", "variant"), &Example::test_variant_float_conversion);
ClassDB::bind_method(D_METHOD("test_object_is_valid", "variant"), &Example::test_object_is_valid);
ClassDB::bind_method(D_METHOD("test_add_child", "node"), &Example::test_add_child);
ClassDB::bind_method(D_METHOD("test_set_tileset", "tilemap", "tileset"), &Example::test_set_tileset);
@@ -240,6 +244,8 @@ void Example::_bind_methods() {
ClassDB::bind_method(D_METHOD("callable_bind"), &Example::callable_bind);
ClassDB::bind_method(D_METHOD("test_post_initialize"), &Example::test_post_initialize);
ClassDB::bind_method(D_METHOD("test_get_internal", "a"), &Example::test_get_internal);
GDVIRTUAL_BIND(_do_something_virtual, "name", "value");
ClassDB::bind_method(D_METHOD("test_virtual_implemented_in_script"), &Example::test_virtual_implemented_in_script);
GDVIRTUAL_BIND(_do_something_virtual_with_control, "control");
@@ -551,6 +557,23 @@ Dictionary Example::test_dictionary() const {
return dict;
}
int Example::test_tdictionary_arg(const TypedDictionary<String, int64_t> &p_dictionary) {
int sum = 0;
TypedArray<int64_t> values = p_dictionary.values();
for (int i = 0; i < p_dictionary.size(); i++) {
sum += (int)values[i];
}
return sum;
}
TypedDictionary<Vector2, Vector2i> Example::test_tdictionary() const {
TypedDictionary<Vector2, Vector2i> dict;
dict[Vector2(1, 2)] = Vector2i(2, 3);
return dict;
}
Example *Example::test_node_argument(Example *p_node) const {
return p_node;
}
@@ -579,6 +602,10 @@ float Example::test_variant_float_conversion(const Variant &p_variant) const {
return p_variant;
}
bool Example::test_object_is_valid(const Variant &p_variant) const {
return static_cast<bool>(p_variant.get_validated_object());
}
void Example::test_add_child(Node *p_node) {
add_child(p_node);
}
@@ -717,6 +744,14 @@ String Example::test_library_path() {
return library_path;
}
int64_t Example::test_get_internal(const Variant &p_input) const {
if (p_input.get_type() != Variant::INT) {
return -1;
}
return *VariantInternal::get_int(&p_input);
}
void ExampleRuntime::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_prop_value", "value"), &ExampleRuntime::set_prop_value);
ClassDB::bind_method(D_METHOD("get_prop_value"), &ExampleRuntime::get_prop_value);
@@ -736,3 +771,11 @@ ExampleRuntime::ExampleRuntime() {
ExampleRuntime::~ExampleRuntime() {
}
void ExamplePrzykład::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_the_word"), &ExamplePrzykład::get_the_word);
}
String ExamplePrzykład::get_the_word() const {
return U"słowo to przykład";
}

View File

@@ -21,7 +21,9 @@
#include <godot_cpp/classes/tile_map.hpp>
#include <godot_cpp/classes/tile_set.hpp>
#include <godot_cpp/classes/viewport.hpp>
#include <godot_cpp/variant/typed_dictionary.hpp>
#include <godot_cpp/variant/variant.hpp>
#include <godot_cpp/variant/variant_internal.hpp>
#include <godot_cpp/core/binder_common.hpp>
#include <godot_cpp/core/gdvirtual.gen.inc>
@@ -129,6 +131,8 @@ public:
int test_tarray_arg(const TypedArray<int64_t> &p_array);
TypedArray<Vector2> test_tarray() const;
Dictionary test_dictionary() const;
int test_tdictionary_arg(const TypedDictionary<String, int64_t> &p_dictionary);
TypedDictionary<Vector2, Vector2i> test_tdictionary() const;
Example *test_node_argument(Example *p_node) const;
String test_string_ops() const;
String test_str_utility() const;
@@ -145,6 +149,7 @@ public:
Vector2i test_variant_vector2i_conversion(const Variant &p_variant) const;
int test_variant_int_conversion(const Variant &p_variant) const;
float test_variant_float_conversion(const Variant &p_variant) const;
bool test_object_is_valid(const Variant &p_variant) const;
void test_add_child(Node *p_node);
void test_set_tileset(TileMap *p_tilemap, const Ref<TileSet> &p_tileset) const;
@@ -182,6 +187,8 @@ public:
bool test_post_initialize() const;
int64_t test_get_internal(const Variant &p_input) const;
// Static method.
static int test_static(int p_a, int p_b);
static void test_static2();
@@ -273,4 +280,14 @@ public:
~ExampleRuntime();
};
class ExamplePrzykład : public RefCounted {
GDCLASS(ExamplePrzykład, RefCounted);
protected:
static void _bind_methods();
public:
String get_the_word() const;
};
#endif // EXAMPLE_CLASS_H

View File

@@ -30,6 +30,7 @@ void initialize_example_module(ModuleInitializationLevel p_level) {
GDREGISTER_CLASS(ExampleBase);
GDREGISTER_CLASS(ExampleChild);
GDREGISTER_RUNTIME_CLASS(ExampleRuntime);
GDREGISTER_CLASS(ExamplePrzykład);
}
void uninitialize_example_module(ModuleInitializationLevel p_level) {

View File

@@ -11,11 +11,6 @@ def options(opts):
"Target Android API level",
"21",
)
opts.Add(
"ndk_version",
"Fully qualified version of ndk to use for compilation.",
"23.2.8568313",
)
opts.Add(
"ANDROID_HOME",
"Path to your Android SDK installation. By default, uses ANDROID_HOME from your defined environment variables.",
@@ -27,9 +22,14 @@ def exists(env):
return get_android_ndk_root(env) is not None
# This must be kept in sync with the value in https://github.com/godotengine/godot/blob/master/platform/android/detect.py#L58.
def get_ndk_version():
return "23.2.8568313"
def get_android_ndk_root(env):
if env["ANDROID_HOME"]:
return env["ANDROID_HOME"] + "/ndk/" + env["ndk_version"]
return env["ANDROID_HOME"] + "/ndk/" + get_ndk_version()
else:
return os.environ.get("ANDROID_NDK_ROOT")
@@ -68,7 +68,7 @@ def generate(env):
if not os.path.exists(toolchain):
print("ERROR: Could not find NDK toolchain at " + toolchain + ".")
print("Make sure NDK version " + env["ndk_version"] + " is installed.")
print("Make sure NDK version " + get_ndk_version() + " is installed.")
env.Exit(1)
env.PrependENVPath("PATH", toolchain + "/bin") # This does nothing half of the time, but we'll put it here anyways

View File

@@ -2,7 +2,6 @@ import os
import platform
import sys
from SCons import __version__ as scons_raw_version
from SCons.Action import Action
from SCons.Builder import Builder
from SCons.Errors import UserError
@@ -13,6 +12,7 @@ from SCons.Variables.BoolVariable import _text2bool
from binding_generator import _generate_bindings, _get_file_list, get_file_list
from build_profile import generate_trimmed_api
from doc_source_generator import scons_generate_doc_source
def add_sources(sources, dir, extension):
@@ -154,7 +154,6 @@ def scons_generate_bindings(target, source, env):
_generate_bindings(
api,
str(source[0]),
env["generate_template_get_node"],
"32" if "32" in env["arch"] else "64",
env["precision"],
@@ -379,54 +378,7 @@ def options(opts, env):
tool.options(opts)
def make_doc_source(target, source, env):
import zlib
dst = str(target[0])
g = open(dst, "w", encoding="utf-8")
buf = ""
docbegin = ""
docend = ""
for src in source:
src_path = str(src)
if not src_path.endswith(".xml"):
continue
with open(src_path, "r", encoding="utf-8") as f:
content = f.read()
buf += content
buf = (docbegin + buf + docend).encode("utf-8")
decomp_size = len(buf)
# Use maximum zlib compression level to further reduce file size
# (at the cost of initial build times).
buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION)
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
g.write("\n")
g.write("#include <godot_cpp/godot.hpp>\n")
g.write("\n")
g.write('static const char *_doc_data_hash = "' + str(hash(buf)) + '";\n')
g.write("static const int _doc_data_uncompressed_size = " + str(decomp_size) + ";\n")
g.write("static const int _doc_data_compressed_size = " + str(len(buf)) + ";\n")
g.write("static const unsigned char _doc_data_compressed[] = {\n")
for i in range(len(buf)):
g.write("\t" + str(buf[i]) + ",\n")
g.write("};\n")
g.write("\n")
g.write(
"static godot::internal::DocDataRegistration _doc_data_registration(_doc_data_hash, _doc_data_uncompressed_size, _doc_data_compressed_size, _doc_data_compressed);\n"
)
g.write("\n")
g.close()
def generate(env):
env.scons_version = env._get_major_minor_revision(scons_raw_version)
# Default num_jobs to local cpu count if not user specified.
# SCons has a peculiarity where user-specified options won't be overridden
# by SetOption, so we can rely on this to know if we should use our default.
@@ -484,17 +436,6 @@ def generate(env):
else: # Release
opt_level = "speed"
# Allow marking includes as external/system to avoid raising warnings.
if env.scons_version < (4, 2):
env["_CPPEXTINCFLAGS"] = "${_concat(EXTINCPREFIX, CPPEXTPATH, EXTINCSUFFIX, __env__, RDirs, TARGET, SOURCE)}"
else:
env["_CPPEXTINCFLAGS"] = (
"${_concat(EXTINCPREFIX, CPPEXTPATH, EXTINCSUFFIX, __env__, RDirs, TARGET, SOURCE, affect_signature=False)}"
)
env["CPPEXTPATH"] = []
env["EXTINCPREFIX"] = "-isystem "
env["EXTINCSUFFIX"] = ""
env["optimize"] = ARGUMENTS.get("optimize", opt_level)
env["debug_symbols"] = get_cmdline_bool("debug_symbols", env.dev_build)
@@ -569,7 +510,7 @@ def generate(env):
env.Append(
BUILDERS={
"GodotCPPBindings": Builder(action=Action(scons_generate_bindings, "$GENCOMSTR"), emitter=scons_emit_files),
"GodotCPPDocData": Builder(action=make_doc_source),
"GodotCPPDocData": Builder(action=scons_generate_doc_source),
}
)
env.AddMethod(_godot_cpp, "GodotCPP")

View File

@@ -36,11 +36,9 @@ def generate(env):
if env["ios_simulator"]:
sdk_name = "iphonesimulator"
env.Append(CCFLAGS=["-mios-simulator-version-min=" + env["ios_min_version"]])
env.Append(LINKFLAGS=["-mios-simulator-version-min=" + env["ios_min_version"]])
else:
sdk_name = "iphoneos"
env.Append(CCFLAGS=["-miphoneos-version-min=" + env["ios_min_version"]])
env.Append(LINKFLAGS=["-miphoneos-version-min=" + env["ios_min_version"]])
if sys.platform == "darwin":
if env["IOS_SDK_PATH"] == "":

View File

@@ -78,6 +78,7 @@ def options(opts):
opts.Add(BoolVariable("use_mingw", "Use the MinGW compiler instead of MSVC - only effective on Windows", False))
opts.Add(BoolVariable("use_static_cpp", "Link MinGW/MSVC C++ runtime libraries statically", True))
opts.Add(BoolVariable("silence_msvc", "Silence MSVC's cl/link stdout bloat, redirecting errors to stderr.", True))
opts.Add(BoolVariable("debug_crt", "Compile with MSVC's debug CRT (/MDd)", False))
opts.Add(BoolVariable("use_llvm", "Use the LLVM compiler (MVSC or MinGW depending on the use_mingw flag)", False))
opts.Add("mingw_prefix", "MinGW prefix", mingw)
@@ -117,19 +118,18 @@ def generate(env):
env["CC"] = "clang-cl"
env["CXX"] = "clang-cl"
if env["use_static_cpp"]:
env.Append(CCFLAGS=["/MT"])
if env["debug_crt"]:
# Always use dynamic runtime, static debug CRT breaks thread_local.
env.AppendUnique(CCFLAGS=["/MDd"])
else:
env.Append(CCFLAGS=["/MD"])
if env["use_static_cpp"]:
env.AppendUnique(CCFLAGS=["/MT"])
else:
env.AppendUnique(CCFLAGS=["/MD"])
if env["silence_msvc"] and not env.GetOption("clean"):
silence_msvc(env)
if not env["use_llvm"]:
env.AppendUnique(CCFLAGS=["/experimental:external", "/external:anglebrackets"])
env.AppendUnique(CCFLAGS=["/external:W0"])
env["EXTINCPREFIX"] = "/external:I"
elif (sys.platform == "win32" or sys.platform == "msys") and not env["mingw_prefix"]:
env["use_mingw"] = True
mingw.generate(env)