Compare commits

...

645 Commits

Author SHA1 Message Date
David Snopek
b0e3b1e4b7 Merge pull request #1890 from dsnopek/4.4-cherrypicks-5
Cherry-picks for the godot-cpp 4.4 branch - 5th batch
2025-12-01 05:23:45 -06:00
Guillaume Riou
ac235d7a5e make -fno-exceptions private
(cherry picked from commit 7d114d8d28)
2025-11-30 06:31:28 -06:00
janos-ijgyarto
211ecf768c Added missing namespace prefixes to GDVIRTUAL macros
(cherry picked from commit 8c5e038744)
2025-11-30 06:31:18 -06:00
Lukas Tenbrink
2c24570997 Make ClassDB::classes pointer-stable again by changing it to HashMap (from AHashMap).
(cherry picked from commit 788edc6bfe)
2025-11-30 06:31:08 -06:00
Samuel Nicholas
2680f4600c CMake: Fix missing -sUSE_PTHREADS=1 in web build
- add -sUSE_PTHREADS=1 to link flags
- add =1 to sSIDE_MODULE=1 in compile flags to match scons.

(cherry picked from commit 42b03da2b1)
2025-11-30 06:30:55 -06:00
David Snopek
a64f264337 On Linux default use_static_cpp to disabled
(cherry picked from commit d033e8abea)
2025-11-30 06:30:40 -06:00
David Snopek
cc8ad37ee0 Merge pull request #1871 from dsnopek/4.4-cherrypicks-4
Cherry-picks for the godot-cpp 4.4 branch - 4th batch
2025-10-21 09:51:09 -05:00
Aaron Franke
33ecd5bf8a Add header builders script for env.GLSL_HEADER and SVG icons
(cherry picked from commit 51008e1556)
2025-10-20 13:30:20 -05:00
Lukas Tenbrink
c1b2eb0d5a Migrate cmake docs to the godot docs.
(cherry picked from commit c7873e1355)
2025-10-20 13:30:07 -05:00
David Snopek
8ef809b9b6 Specifically handle each "meta" value, so new ones don't break code generation
(cherry picked from commit a9773579cb)
2025-10-20 13:29:00 -05:00
dementive
d3adff0063 Update missing hashfuncs
(cherry picked from commit fc70347ef7)
2025-10-20 13:28:49 -05:00
dementive
dae8fbdebc Replace unordered_map with AHashMap
(cherry picked from commit 2fd41b7e16)
2025-10-20 13:28:37 -05:00
=
0d658486dc Silenced compiler warning in godot::call_with_variant_args_ret_helper
(cherry picked from commit 3eb3069e09)
2025-10-20 13:26:03 -05:00
Thomas Staudinger
895b66453c README: Add link to 4.5 branch and fix link to Godot compile docs
Signed-off-by: Thomas Staudinger <Staudi.Kaos@gmail.com>
(cherry picked from commit ef63d2e657)
2025-10-20 13:25:49 -05:00
dementive
fec8bd56db Use LocalVector instead of std::vector
(cherry picked from commit 0b8e76817b)
2025-10-20 13:25:39 -05:00
Lukas Tenbrink
50eabd9359 Update contributing section in README.md
(cherry picked from commit c58dfa4d99)
2025-10-20 13:25:26 -05:00
dementive
1518bd17dc Remove <string> includes in headers
(cherry picked from commit e36e81ac86)
2025-10-20 13:25:12 -05:00
David Snopek
269c925c29 Merge pull request #1836 from dsnopek/4.4-cherrypicks-3
Cherry-picks for the godot-cpp 4.4 branch - 3rd batch
2025-09-11 10:08:06 -05:00
Samuel Nicholas
ad484bcdbb CMake: Add GODOTCPP_SUFFIX_GENEX variable
This is the same as GODOTCPP_SUFFIX but without the leading '.'
GODOTCPP_SUFFIX is  then based on the above.

(cherry picked from commit b64b941adf)
2025-08-21 08:49:36 -05:00
David Snopek
b842dc9696 Take reference in Wrapped(const StringName &)
(cherry picked from commit b192b880d3)
2025-08-21 08:49:28 -05:00
Ben Lubar
cf79eb39da Only check for Godot 4.0 if the pointer is aligned how it would be for the legacy interface.
(cherry picked from commit 05d2ce3006)
2025-08-21 08:49:18 -05:00
Ben Lubar
0eeb43c4be Fix debug symbols logic on platform=web to match Godot core.
(cherry picked from commit 9ea9b4797c)
2025-08-21 08:49:09 -05:00
Klaim (Joël Lamotte)
9d8c520bb9 fix: missing type_traits include
Usage of `std::is_trivially_constructible` in `defs.hpp` requires including `type_traits`. This missing include leads to errors about that type not being found when building with clang++-22 with libc++-22.

(cherry picked from commit fbe5262d7b)
2025-08-21 08:48:56 -05:00
Chris Cranford
a8faa36fd2 Reintroduce Math_INF and Math_NAN defines
(cherry picked from commit 6a21f76c4d)
2025-08-21 08:48:46 -05:00
David Snopek
d7bdc62a91 Fix custom_api_file with SCons 4.0.1
(cherry picked from commit 8e7dfbc71a)
2025-08-21 08:48:33 -05:00
Cedric Shock
9b6a44cb04 Add SCons variant_dir support, which allows specifying a target build directory.
(cherry picked from commit 1345c46650)
2025-08-21 08:48:19 -05:00
David Snopek
58c3594cd7 Files generated by SCons should depend on the build_profile (if given)
(cherry picked from commit 646ccdf470)
2025-08-21 08:48:04 -05:00
David Snopek
d502d8e8aa Merge pull request #1805 from dsnopek/4.4-cherrypicks-2a
Cherry-picks for the godot-cpp 4.4 branch - 2nd batch
2025-07-03 08:53:10 -05:00
David Snopek
2f0dbc7bba Update CI to use windows-2022
(cherry picked from commit 8938e7e4e3)
2025-06-24 17:31:47 -05:00
David Snopek
022ce432b8 Disable double precisions builds in CI
(cherry picked from commit b46c31a50e)
2025-06-24 15:40:57 -05:00
Samuel Nicholas
6371691009 added missing include .hpp and .inc detection
removed redundant .py detection.

(cherry picked from commit 6d11a780bf)
2025-06-24 15:40:44 -05:00
Pāvels Nadtočajevs
4f2f319fb2 Fix binding generation for TypedArray/TypedDictionary with refcounted elements.
(cherry picked from commit ed53a70e71)
2025-06-24 15:40:34 -05:00
Tom
da3b350e85 Cleaned up the MethodBind class
(cherry picked from commit ca5af3c861)
2025-06-24 15:40:24 -05:00
marcin.mirski
bda8a0fbd6 Improve CMAKE_BUILD_PARALLEL_LEVEL message
(cherry picked from commit 0c2e66e414)
2025-06-24 15:39:54 -05:00
marcin.mirski
eaeafdf596 Fix: Add STATUS to CMake message commands missing them
(cherry picked from commit 8eac097c37)
2025-06-24 15:39:48 -05:00
MJacred
980edc22a7 Fix URL to gdextension cpp example in the official docs
(cherry picked from commit f25c4df5c4)
2025-06-24 15:39:24 -05:00
Lukas Tenbrink
0be68c870f Make ndk version configurable as a command-like argument.
(cherry picked from commit 16e47d7ae5)
2025-06-24 15:39:06 -05:00
Tom
ac2263f126 Fixed a crash with an Array constructor
(cherry picked from commit ddd4f2513c)
2025-06-24 15:38:55 -05:00
Dyllan Cole
2eb13f8971 Fix incorrect binding_generator_generate_bindings variable names
(cherry picked from commit 4824aa41e8)
2025-06-24 15:38:41 -05:00
Thaddeus Crews
2bd3d5314e CI: Ensure utf-8 support on Windows GHA
(cherry picked from commit 42f6dc6d49)
2025-06-24 15:38:32 -05:00
Thaddeus Crews
08f893f1ea CI: Various version bumps; sync with main repo
(cherry picked from commit 64cdf089d9)
2025-06-24 15:37:21 -05:00
Fabio Alessandrelli
532a028e17 fix: Add iOS min SDK version link flags
This is required when publishing to the App Store, and consistent with
what we already do for the macOS deployment target.

(cherry picked from commit 4879eb7bd0)
2025-06-24 15:37:09 -05:00
David Snopek
90260ea659 Stop referring to GDExtension as experimental in the README
(cherry picked from commit 7660dd28b3)
2025-06-24 15:36:53 -05:00
Ben Lubar
b41801b6a8 fix iterators making unintended copies
(cherry picked from commit 7fd0999b3c)
2025-06-24 15:36:35 -05:00
David Snopek
f4c1de582c Fix classes without _to_string() always returning "[Wrapped:0]"
(cherry picked from commit f38c056b67)
2025-06-24 15:35:46 -05:00
Samuel Nicholas
947d357252 Match #1758 build option changes
d634a5f8c4 (diff-e2225522e55739f1533a3ce9eee58324ac9c192c8ba30065067964347d22fdacL471)
(cherry picked from commit b195a51c6c)
2025-06-24 15:35:33 -05:00
Thaddeus Crews
b905a87ebe SCons: Add CPPEXTPATH for external includes
(cherry picked from commit 30bfa6f215)
2025-06-24 15:35:19 -05:00
Marc Gilleron
6182a2728b Use Math::abs to avoid ambiguity with integer abs
(cherry picked from commit 7670de814f)
2025-06-24 15:35:09 -05:00
Samuel Nicholas
5dae002a5d version bump of mozilla-sccache action to 0.0.9
https://github.blog/changelog/2025-03-20-notification-of-upcoming-breaking-changes-in-github-actions/#decommissioned-cache-service-brownouts
(cherry picked from commit bbbcc6adc7)
2025-06-24 15:35:00 -05:00
Grublady
b0399d9782 Fix TypedDictionary binding generation
(cherry picked from commit 26201dd27a)
2025-06-24 15:34:29 -05:00
Tom
b139e2fb76 Synced defs.hpp with godot's typedefs.h
(cherry picked from commit d634a5f8c4)
2025-06-24 15:34:18 -05:00
Marc Gilleron
bdeb1987f6 Use Math::abs to avoid ambiguity with integer abs
(cherry picked from commit 7e6c9c9370)
2025-06-24 15:34:04 -05:00
Samuel Nicholas
2b4512414b Fix compatibility break for CI
(cherry picked from commit 38e517b98b)
2025-06-24 15:33:53 -05:00
Hugo Locurcio
483499c14c Update test project to Godot 4.4
(cherry picked from commit 552a74c96e)
2025-06-24 15:33:43 -05:00
Tom
466a743112 Added initialiser list support to TypedDictionary
(cherry picked from commit 335b490061)
2025-06-24 15:33:33 -05:00
Samuel Nicholas
3963054a14 CMake: Update CI
- Duplicated the ci.yml into ci-scons.yml and ci-cmake.yml
- Replaced some manual shell commands to detect changes with  tj-actions/changed-files@v45
- Conditionally run the CI depending on what files change.
- Add ios toolchain from leetal/ios-cmake
- Added a cmake-minimum of 3.10 to silence errors from ios toolchain

(cherry picked from commit b6c0251296)
2025-06-24 15:33:21 -05:00
Tom
6e6a1ea451 .
(cherry picked from commit 946a693859)
2025-06-24 15:33:04 -05:00
Tom
c435258dde Made the Array's ptr and ptrw methods private
(cherry picked from commit a2c37f8a16)
2025-06-24 15:32:54 -05:00
unvermuthet
863f94de77 Implement use_static_cpp flag for Linux
(cherry picked from commit b0f41909e0)
2025-06-24 15:32:45 -05:00
Aaron Franke
e299bc623d Add missing Projection constructor with 16 real_t values
(cherry picked from commit aa03c32b3e)
2025-06-24 15:32:33 -05:00
Tom
37febead2b Add method_ptrcall header include to type_info to fix compiler errors
(cherry picked from commit 7ffaecce8c)
2025-06-24 15:32:23 -05:00
David Snopek
940fdea07f Fix stack smashing when Godot methods return char32_t, char16_t or wchar_t
(cherry picked from commit 035add9d4f)
2025-06-24 15:32:14 -05:00
Pāvels Nadtočajevs
6917c1ea17 [macOS] Remove unnecessary Cocoa reference.
(cherry picked from commit d239da3221)
2025-06-24 15:32:03 -05:00
David Snopek
0a39efe3d3 Synchronize most shared template code with Godot 4.4
(cherry picked from commit 1edfca295b)
2025-06-24 15:31:53 -05:00
David Snopek
67f6f96a9b Synchronize most shared variant code with Godot 4.4
(cherry picked from commit 075b517d96)
2025-06-24 15:31:38 -05:00
Thaddeus Crews
749d68037e Ignore #pragma once commit
(cherry picked from commit c963321cdd)
2025-06-24 15:31:24 -05:00
Thaddeus Crews
f166d4ed8c Style: Replace header guards with #pragma once
(cherry picked from commit 7056c996dd)
2025-06-24 15:31:15 -05:00
Thaddeus Crews
6fcc184587 Style: Integrate #pragma once in builders/checks
(cherry picked from commit 107cb1da5e)
2025-06-24 15:31:06 -05:00
David Snopek
e4b7c25e72 gdextension: Sync with upstream commit 49a5bc7b616bd04689a2c89e89bda41f50241464 (4.4.1-stable) 2025-03-27 07:31:44 -05:00
David Snopek
6388e26dd8 Merge pull request #1745 from dsnopek/4.4-cherrypicks-1
Cherry-picks for the godot-cpp 4.4 branch - 1st batch
2025-03-18 08:08:53 -05:00
Samuel Nicholas
e9a6dbd697 CMake: public/private flags
Made all warnings private.
Warning as error private
Consistency in  generator expressions

(cherry picked from commit 5eb16d0c5b)
2025-03-17 11:27:37 -05:00
zhmt
6b0d2e502c binding_generator.py: Don't error if directory already exists
It should be ok when folders exist. Exception shouldn't be thrown.

Update binding_generator.py

It should be ok when folds exist. It will fail to build without this patch,  in vs code on windows with compiler ( visual studio community 2022 amd 64) .

Co-Authored-By: Chris Cranford <ccranfor@redhat.com>
(cherry picked from commit d79959c79e)
2025-03-17 11:27:27 -05:00
Samuel Nicholas
21fba890d6 CMake: XCode dependency chain fixes - remastered
When attempting to generate XCode projects it would fail due to the target dependency chain not meeting expectations.

This PR, adds the required dependency infomation so that the XCode generator works.

(cherry picked from commit f83f364144)
2025-03-17 11:27:17 -05:00
David Snopek
2d45d08722 Check that precision of extension_api.json matches build options
(cherry picked from commit 0a73df5f53)
2025-03-17 11:27:06 -05:00
Samuel Nicholas
368ec63a24 CMake: Target as configuration option
Add GODOTCPP_TARGET configuration option
Remove loop to generate the godot-cpp.<target> CMake Targets

Rename test bindings target
Update documentation

(cherry picked from commit 89abe15268)
2025-03-17 11:26:56 -05:00
ytnuf
1f477a780e Remove unnecessary forced -fno-exceptions for web builds
The SCons build doesn't do this, so neither should CMake
Excpetions are already handled by DISABLE_EXCEPTIONS option

(cherry picked from commit 43690cb60b)
2025-03-17 11:26:44 -05:00
Samuel Nicholas
5ba2d9c9f6 CMake: default target when godot-cpp is top level
People seem to want to build godot-cpp without any arguments, not even specifying a target.

We have to detect if we are top level though because it conflicts with being consumed.

(cherry picked from commit 8b33e73353)
2025-03-17 11:26:33 -05:00
Samuel Nicholas
4b5d800596 Updating commenting to be consistent
(cherry picked from commit 671e309cfa)
2025-03-17 11:26:21 -05:00
Samuel Nicholas
8bdf9b82a2 add gersemi to pre-commit hooks for CMake formatting like black
(cherry picked from commit 2f6d7f2dad)
2025-03-17 11:26:12 -05:00
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
David Snopek
fbbf9ec4ef Merge pull request #1550 from Naros/sync-4.3-stable
gdextension: Sync with upstream commit 77dcf97d82cbfe4e4615475fa52ca03da645dbd8 (4.3-stable)
2024-08-15 06:27:31 -05:00
Chris Cranford
2e4c350b83 gdextension: Sync with upstream commit 77dcf97d82cbfe4e4615475fa52ca03da645dbd8 (4.3-stable) 2024-08-15 05:53:22 -04:00
bruvzg
f2353da5a3 Add support for LLVM/MinGW and ARM64 Windows builds. 2024-08-12 08:53:40 +03:00
David Snopek
9b98377a62 Merge pull request #1546 from aaronfranke/fix-vec4arr
Fix missing type info for PackedVector4Array
2024-08-11 06:19:28 -05:00
Aaron Franke
92e6ea7303 Fix missing type info for PackedVector4Array 2024-08-10 21:21:13 -07:00
David Snopek
11773e52b0 gdextension: Sync with upstream commit 03afb92efa18874da19f7fc185a32c005d20aa1d (4.3-rc3) 2024-08-09 08:44:03 -05:00
David Snopek
937b1d809a Merge pull request #1545 from Klaim/warnings_gdclass
Removes warnings generated by GDCLASS usage
2024-08-08 09:13:51 -05:00
Klaim (Joël Lamotte)
738859f49b removes warnings generated by GDCLASS usage
This change removes the warnings (unused parameters) coming from code injected by the GDCLASS macro.
Contrary to warnings coming from the normal source code which can be suppressed with most compiles by specifying the include directories of this library as external or system,
when the code is injected through a macro it is considered in the context of the user, which is the source code of user of the library.
That forces the users to modify their code to hide the warnings coming from the mandatory `GDCLASS` here.
That's why it's important to remove these warning from that specific macro and ideally any other macro that the user must use.
2024-08-08 02:46:28 +02:00
David Snopek
9da1e0cee1 Merge pull request #1543 from Calinou/readme-use-github-admonition-syntax
Use GitHub admonition syntax for the warning in README
2024-08-07 15:54:36 -05:00
David Snopek
3f4590f8e1 Merge pull request #1539 from Naros/dispatch-get-set-up-hierarchy
Make sure `_get` and `_set` dispatch up the class hierarchy
2024-08-07 15:53:54 -05:00
David Snopek
e3e8101e8c Merge pull request #1330 from pimms/cmake-hot-reload
Add hot reload support to CMakeLists.txt
2024-08-07 15:53:35 -05:00
Hugo Locurcio
26459dc47b Use GitHub admonition syntax for the warning in README 2024-08-05 19:31:32 +02:00
David Snopek
daf6ad3649 gdextension: Sync with upstream commit 3978628c6cc1227250fc6ed45c8d854d24c30c30 (4.3-rc2) 2024-08-02 09:39:49 -05:00
Chris Cranford
c77d44f3f6 Make sure _get and _set dispatch up the class hierarchy 2024-08-01 12:03:27 -04:00
David Snopek
f2b521f55a Merge pull request #1530 from akien-mga/py-two-old
SCons: Remove old Python 2 compat code
2024-07-24 09:06:01 -05:00
David Snopek
628606b28b Merge pull request #1519 from AThousandShips/cache_improve
[CI] Upload build cache before running tests
2024-07-24 09:05:48 -05:00
Rémi Verschelde
958776dfc3 SCons: Remove old Python 2 compat code 2024-07-18 10:37:47 +02:00
A Thousand Ships
f131efb791 Make generated code mostly style compliant 2024-07-17 17:29:31 +02:00
David Snopek
0a1e31fa45 Merge pull request #1513 from dsnopek/unexpose-is-instance-valid
Unexpose `UtilityFunctions::is_instance_valid()`
2024-07-15 12:16:21 -05:00
David Snopek
8012716ee3 Merge pull request #1510 from dsnopek/memnew-better-crash-message
Remind developers about `memnew()` in crash message when missing binding callbacks
2024-07-15 12:15:53 -05:00
A Thousand Ships
76b38de01a [CI] Upload build cache before running tests 2024-07-13 16:25:12 +02:00
David Snopek
6d939e6878 Merge pull request #1509 from YuriSizov/method-bind-is-off-by-one
Fix argument metadata when binding methods
2024-07-06 11:42:45 -05:00
David Snopek
56cd3fd99e Unexpose UtilityFunctions::is_instance_valid() 2024-07-01 12:29:28 -05:00
David Snopek
99926d8e20 Merge pull request #1483 from AThousandShips/arr_typed_fix
Fix sharing of typed arrays from constructor
2024-06-28 07:26:44 -05:00
David Snopek
e65ec904b8 Remind developers about memnew() in crash message when missing binding callbacks 2024-06-27 13:09:24 -05:00
Yuri Sizov
2b34bd0d8b Fix argument metadata when binding methods
While there doesn't seem to be any runtime issues,
this triggers the address sanitizer in a few ways,
depending on what kind of method you're
binding.
2024-06-27 18:40:29 +02:00
David Snopek
53b546e1df Merge pull request #1507 from Repiteo/silence-msvc
SCons: Add `silence_msvc` option for Windows
2024-06-25 17:45:33 -05:00
David Snopek
7abe4ca9e4 Merge pull request #1506 from Repiteo/editorconfig
Add `.editorconfig`, consolidate `.gitattributes`
2024-06-25 09:43:36 -05:00
David Snopek
316dde80ba Merge pull request #1505 from Repiteo/include-formatting
Fix `#include` formatting
2024-06-25 09:43:17 -05:00
David Snopek
7d7799b56e Merge pull request #1504 from Repiteo/pre-commit-hooks
Replace legacy hooks with `pre-commit` Python tool
2024-06-25 09:42:55 -05:00
David Snopek
90c6ea2a12 Merge pull request #1497 from Naros/fix-variant-hpp-packed-vector4-array
Add missing enum & ctor for PackedVector4Array implementation
2024-06-25 09:42:41 -05:00
Thaddeus Crews
1989b1bf57 SCons: Add silence_msvc option 2024-06-25 09:38:00 -05:00
Thaddeus Crews
7a96d0314e Add .editorconfig, consolidate .gitattributes 2024-06-25 08:46:06 -05:00
Thaddeus Crews
999018e7d1 Fix #include formatting 2024-06-25 08:28:04 -05:00
Thaddeus Crews
e0d363aad8 Integrate .pre-commit-config.yaml 2024-06-24 15:43:55 -05:00
David Snopek
c414c2b37d gdextension: Sync with upstream commit b75f0485ba15951b87f1d9a2d8dd0fcd55e178e4 (4.3-beta2) 2024-06-20 08:55:38 -05:00
Chris Cranford
78b63203d4 Add missing enum & ctor for PackedVector4Array implementation 2024-06-19 11:21:11 -04:00
David Snopek
0efc6cddbc Merge pull request #1423 from AThousandShips/style_fix
Fix some style details in generation
2024-06-18 11:24:11 -05:00
A Thousand Ships
e7a13e3bf4 Fix some style details in generation 2024-06-18 17:46:54 +02:00
David Snopek
ed1e963a31 Merge pull request #1490 from AThousandShips/arg_name_fix
Enforce `p_` prefixes for arguments in binds
2024-06-18 10:43:27 -05:00
David Snopek
068e930c6a Merge pull request #1496 from Faless/ci/fix-macos
[CI] Update macOS workers to macos-latest
2024-06-18 10:13:21 -05:00
Fabio Alessandrelli
2dd8917508 [CI] Update macOS workers to macos-latest
GitHub actions no longer allow `macos-11` runners
2024-06-18 16:52:42 +02:00
David Snopek
89831ff333 Merge pull request #1489 from Faless/web/longjmp
[Web] Force emcc to use "wasm" longjmp mode
2024-06-17 11:53:05 -05:00
David Snopek
f2ac49aea5 Merge pull request #1167 from Faless/build/build_profile
Add support for build profiles.
2024-06-17 11:52:20 -05:00
Fabio Alessandrelli
1186c488bd Add support for build profiles.
Allow enabling or disabling specific classes (which will not be built).
2024-06-15 16:19:41 +02:00
David Snopek
8cdd56e149 Merge pull request #1493 from dsnopek/ci-godot-test-version
Allow selecting Godot version to run the tests with
2024-06-14 12:43:48 -05:00
David Snopek
f1b7ba3e06 Allow selecting Godot version to run the tests with 2024-06-14 11:20:50 -05:00
David Snopek
5d8f80bc55 Merge pull request #1446 from Daylily-Zeleen/daylily-zeleen/set_instance_and_instance_biding_in_Wrapped_constructor
Set instance and instance binding in `Wrapped` constructor.
2024-06-14 09:39:46 -05:00
A Thousand Ships
9e2771f918 Enforce p_ prefixes for arguments in binds 2024-06-14 16:05:03 +02:00
David Snopek
ee9acbcf10 Merge pull request #1488 from AThousandShips/default_node_path
Add default argument processing for `NodePath`
2024-06-14 08:15:04 -05:00
David Snopek
64f1bc847a Merge pull request #1485 from dsnopek/classdb-call-static-method
Fix vararg methods forwarded to the `ClassDB` singleton
2024-06-14 08:14:42 -05:00
Fabio Alessandrelli
1bb543b6f4 [Web] Force emcc to use "wasm" longjmp mode
SUPPORT_LONGJMP have changed since emscripten 3.1.32 to default to
"wasm" mode when exceptions are enabled, and "emscripten" mode when
disabled.

While we generally doesn't use exception in core, linked libraries may
need them, and emscripten don't plan to support WASM EH + Emscripten
SjLj in the long term.
2024-06-14 01:46:04 +02:00
A Thousand Ships
37e7a6da05 Add default argument processing for NodePath 2024-06-13 20:53:01 +02:00
David Snopek
6c4064125b Merge pull request #1487 from AThousandShips/arg_default_fix
Fix generating default values for `StringName`
2024-06-13 13:49:54 -05:00
David Snopek
9f6fe36633 Merge pull request #1479 from bruvzg/ts_gde_sync_cpp
[TextServer, GDExtension] Fix building text servers as GDExtension, expose new/changed low-level methods to GDExtension API.
2024-06-13 13:49:25 -05:00
bruvzg
2360f84513 [TextServer, GDExtension] Fix building text servers as GDExtension, expose new/changed low-level methods to GDExtension API. 2024-06-13 18:57:24 +03:00
A Thousand Ships
6cd6c8923a Fix generating default values for StringName
Cases other than `&""` were not processed correctly
2024-06-13 16:57:23 +02:00
David Snopek
e04a26b2bc Fix vararg methods forwarded to the ClassDB singleton 2024-06-12 10:32:38 -05:00
David Snopek
c5986e666f Merge pull request #1486 from dsnopek/fix-to-string-test
Fix tests after upstream change to `Node::to_string()`
2024-06-12 10:31:38 -05:00
David Snopek
7d4758eace Merge pull request #1478 from richardhozak/fix-warnings
Fix warnings emitted with -Wall
2024-06-12 10:01:59 -05:00
David Snopek
4f7439d4cf Fix tests after upstream change to Node::to_string() 2024-06-12 09:22:14 -05:00
David Snopek
fe0647202b Merge pull request #1484 from dsnopek/virtual-node-pointer
Fix undefined symbol error on Linux with virtual methods that take `Node *` arguments
2024-06-11 09:38:08 -05:00
David Snopek
7f74fe7bb2 Fix undefined symbol error on Linux with virtual methods that take Node * arguments 2024-06-10 10:55:24 -05:00
A Thousand Ships
41aa71f8c3 Fix sharing of typed arrays from constructor 2024-06-06 16:40:10 +02:00
Richard Hozák
8c6cc1ec15 Fix warnings emitted with -Wall 2024-06-02 21:48:50 +02:00
David Snopek
21d526e5e5 Merge pull request #1477 from dsnopek/macros-godot-namespace
Explicitly refer to `godot` namespace in `GDREGISTER_*_CLASS()` macros
2024-06-01 13:29:25 -05:00
David Snopek
246a803954 Explicitly refer to godot namespace in GDREGISTER_*_CLASS() macros 2024-06-01 08:46:26 -05:00
David Snopek
45be6d0bd4 gdextension: Sync with upstream commit a4f2ea91a1bd18f70a43ff4c1377db49b56bc3f0 (4.3-beta1) 2024-05-31 09:36:08 -05:00
David Snopek
21b86b6770 Merge pull request #1473 from dsnopek/gdextension-interface-catch-up
Catch up with minor changes to `gdextension_interface.h`
2024-05-29 08:09:55 -05:00
Daylily-Zeleen
76cbc66785 Set instance and instance binding in Wrapped constructor. 2024-05-28 22:59:37 +08:00
David Snopek
3e9afccae8 Catch up with minor changes to gdextension_interface.h 2024-05-28 09:26:13 -05:00
David Snopek
b697ba8896 Merge pull request #1447 from dsnopek/avoid-double-postinitialize
Fix NOTIFICATION_POSTINITIALIZE sent twice to native parent classes
2024-05-17 11:56:09 -05:00
David Snopek
e4a4d76cb3 Merge pull request #1463 from Daylily-Zeleen/daylily-zeleen/const_get_class_static
Mark return value of `get_class_static` and `get_parent_class_static` as const.
2024-05-17 11:55:45 -05:00
Daylily-Zeleen
3db8549e19 mark return value of get_class_static and get_parent_class_static as const 2024-05-17 02:06:59 +08:00
David Snopek
340dde31a2 Merge pull request #1451 from Faless/build/to_threads_or_not_to_threads
[SCons] Add option to build without threads
2024-05-16 10:39:57 -05:00
David Snopek
6b39ed0732 Merge pull request #1457 from AThousandShips/foreach_list
[Core] Reduce and prevent unnecessary random-access to `List`
2024-05-16 08:46:39 -05:00
David Snopek
16cad7ba24 Merge pull request #1462 from aarjaneiro/toc-examples-and-templates
Fix README Examples and Templates TOC Entry
2024-05-13 08:43:35 -05:00
David Snopek
798fbab653 Merge pull request #1458 from dsnopek/free-callback-crash
Clean up instance bindings for engine singletons to prevent crash
2024-05-12 08:04:57 -05:00
David Snopek
88df025aa0 Clean up instance bindings for engine singletons to prevent crash 2024-05-10 19:51:31 -05:00
David Snopek
85172dad1b Merge pull request #1461 from dsnopek/fix-ci-2
Attempt to fix recent CI failures on `master` branch
2024-05-10 17:59:35 -05:00
Aaron Janeiro Stone
996d229b26 Fix README table of contents 2024-05-09 17:40:44 -04:00
David Snopek
5bad5d6958 Attempt to fix recent CI failures on master branch 2024-05-09 11:21:45 -05:00
David Snopek
e3f3cb58b7 Merge pull request #1450 from dsnopek/free-property-list-count
Update `free_property_list` callback to take count
2024-05-08 04:40:52 -05:00
Rémi Verschelde
17a82e7f94 Merge pull request #1374 from dsnopek/gdext-docs
Allow submitting documentation to the Godot editor
2024-05-08 00:48:02 +02:00
David Snopek
f5c2b38724 Merge pull request #1456 from dsnopek/packedvector4array
Add support for `PackedVector4Array`
2024-05-07 12:56:11 -05:00
David Snopek
3d0d9cd0e2 Merge pull request #1455 from AThousandShips/localvector_has
[Core] Add `LocalVector::has` for convenience
2024-05-07 12:55:59 -05:00
David Snopek
43be24f34c Merge pull request #1437 from AThousandShips/vec_elem_scalar
Add scalar versions of `Vector*` `min/max/clamp/snap(ped)`
2024-05-07 12:55:23 -05:00
David Snopek
a434850069 Allow submitting documentation to the Godot editor 2024-05-07 11:08:18 -05:00
A Thousand Ships
d0bdd6096c Optionaly add compatibility operators 2024-05-07 11:01:37 +02:00
A Thousand Ships
12a1283663 [Core] Reduce and prevent unnecessary random-access to List
Random-access access to `List` when iterating is `O(n^2)` (`O(n)` when accessing a single element)

* Removed subscript operator, in favor of a more explicit `get`
* Added conversion from `Iterator` to `ConstIterator`
2024-05-07 11:00:56 +02:00
David Snopek
23178e81ff Add support for PackedVector4Array 2024-05-06 14:30:04 -05:00
A Thousand Ships
505076c9a9 [Core] Add LocalVector::has for convenience 2024-05-06 17:47:21 +02:00
Fabio Alessandrelli
b0296bb562 [SCons] Add option to build without threads
This is relevant for the Web platform, where builds with and without
threads are incompatible.
2024-04-30 19:19:36 +02:00
David Snopek
54fe2f9891 Merge pull request #1445 from dsnopek/classdb-enum-issue
Allow forwarding from `ClassDB` to `ClassDBSingleton` to support enumerations
2024-04-30 09:30:01 -05:00
David Snopek
8cc78cfea9 Update free_property_list callback to take count 2024-04-30 08:48:53 -05:00
David Snopek
2cd3d39108 Merge pull request #1405 from dsnopek/fix-null-object-arguments
Correctly handle `Object *` arguments that were encoded as `nullptr`
2024-04-29 16:46:46 -05:00
David Snopek
1d829f2e4a Merge pull request #1448 from dsnopek/require-bind-methods
Give compile-time error if registering a class without its own `_bind_methods()` function
2024-04-26 14:51:37 -05:00
David Snopek
ca46ef4d25 Give compile-time error if registering a class without its own _bind_methods() function 2024-04-24 14:49:26 -05:00
David Snopek
e23b117ac3 Merge pull request #1431 from pupil1337/fix-create-instance-func
Fix create instance func
2024-04-24 14:44:29 -05:00
David Snopek
d304f12dcd Merge pull request #1443 from Naros/property-method-dict-helpers
Implement to/from dict helpers for PropertyInfo/MethodInfo
2024-04-24 14:43:53 -05:00
David Snopek
61450b3e1b Merge pull request #1436 from AThousandShips/math_update
[Math] Add `is_finite` methods
2024-04-24 14:43:36 -05:00
David Snopek
06373ce1cf Fix NOTIFICATION_POSTINITIALIZE sent twice to native parent class 2024-04-24 13:22:19 -05:00
David Snopek
e1b3b32db5 Allow forwarding from ClassDB to ClassDBSingleton to support enumerations 2024-04-23 13:47:36 -05:00
Chris Cranford
2a041b5240 Implement to/from dict helpers for PropertyInfo/MethodInfo 2024-04-20 18:50:34 -04:00
David Snopek
ad307e4b9c Merge pull request #1440 from Naros/propertyinfo-wrong-usage-init-value
Fix PropertyInfo to use hint/usage default constants
2024-04-17 10:46:35 -05:00
David Snopek
6873658d26 Merge pull request #1438 from thimenesup/patch-1
Fix Projection create_orthogonal being incorrect
2024-04-17 10:44:17 -05:00
David Snopek
9ff49b7b1b Merge pull request #1364 from Repiteo/non-verbose
Implement `verbose` toggle from godot repo
2024-04-17 10:42:40 -05:00
David Snopek
048f49af39 Merge pull request #1371 from godotengine/dependabot/github_actions/mymindstorm/setup-emsdk-14
Bump mymindstorm/setup-emsdk from 13 to 14
2024-04-17 10:42:11 -05:00
Chris Cranford
e160966163 Fix PropertyInfo to use hint/usage default constants 2024-04-16 07:24:48 -04:00
thimenesup
e4ae69f607 Fix Projection create_orthogonal being incorrect
Title
2024-04-14 20:27:53 +02:00
David Snopek
4b7661a60a Merge pull request #1435 from Repiteo/example-use-defines
Use `GDREGISTER` defines in example
2024-04-11 13:38:29 -05:00
A Thousand Ships
d389171905 [Math] Add is_finite methods 2024-04-11 13:30:28 +02:00
A Thousand Ships
b65970860e Add scalar versions of Vector* min/max/clamp/snap(ped)
Also added `snapped` to the integer vectors for completeness
2024-04-11 10:42:29 +02:00
pupil1337
1fa7a9cb19 Add static_assert() for register_class 2024-04-11 10:48:13 +08:00
Thaddeus Crews
a537b4af4d Use GDREGISTER defines in example 2024-04-10 14:15:28 -05:00
Thaddeus Crews
b05c21bb1d Implement verbose toggle from godot repo 2024-04-09 21:13:02 -05:00
David Snopek
37542dc2ec Correctly handle Object * arguments that were encoded as nullptr 2024-04-08 11:12:40 -05:00
David Snopek
b02124595f Merge pull request #1422 from AThousandShips/utility_fix
Fix incorrect utility call signature
2024-04-03 08:56:20 -05:00
A Thousand Ships
d055b575fb Fix incorrect utility call signature 2024-04-02 21:44:40 +02:00
David Snopek
7d4a24caab Merge pull request #1417 from ytnuf/cmake-fix
Change cmake required to v3.13
2024-04-02 14:30:26 -05:00
David Snopek
3715bfe253 Merge pull request #1413 from AThousandShips/the_angry_count_extended_cpp
Add extension support for argument count to `ScriptInstance`
2024-04-02 14:30:13 -05:00
David Snopek
44d78ec881 Merge pull request #1409 from Repiteo/class-to-typename
Enforce template syntax  `typename` over `class`
2024-04-02 14:30:01 -05:00
ytnuf
5c12bd2287 Change cmake_minimum_required to match actual requirements
This is because target_link_options was added in v3.13
So this wouldn't build with cmake v3.12

Likewise in CMAKE_CXX_STANDARD only supports value of 17 starting with
cmake v3.9
So the test wouldn't build properly with cmake v3.6
2024-03-22 13:55:34 +00:00
A Thousand Ships
87ecf17242 Add extension support for argument count to ScriptInstance 2024-03-14 17:45:56 +01:00
David Snopek
a62f633ceb Merge pull request #1379 from dsnopek/uninitialized-value-mk2
Avoid creating most objects that Godot is going to use placement new to initialize
2024-03-14 11:06:59 -05:00
David Snopek
ec166295ba Merge pull request #1397 from dsnopek/script-free-lists
Load new `script_instance_create3` GDExtension interface function
2024-03-14 10:02:21 -05:00
David Snopek
916b4ff2d5 Merge pull request #1375 from AThousandShips/the_angry_count_cpp
Add support for getting argument count from `Callable`s
2024-03-14 09:13:12 -05:00
A Thousand Ships
fb79d5ff98 Add support for getting argument count from Callables 2024-03-14 10:27:39 +01:00
David Snopek
e6b6df5893 Merge pull request #1399 from bruvzg/init_list
[Packed*Array] Add support for initializer lists.
2024-03-12 14:30:38 -05:00
David Snopek
d78fe9853f Merge pull request #1412 from dsnopek/gdextension-register-virtual-method-namespace
Use explicit `::godot` namespace in gdvirtual.gen.inc
2024-03-12 14:27:56 -05:00
David Snopek
12ebe4b180 Use explicit ::godot namespace in gdvirtual.gen.inc 2024-03-12 13:06:57 -05:00
David Snopek
efb46f7f82 Merge pull request #1407 from AThousandShips/flag_fix
Fix invalid `void` return in `BitField`
2024-03-11 12:43:12 -05:00
David Snopek
7cff8ca896 Merge pull request #1408 from Zylann/fix_explicit_namespace_in_macros
Fix explicit namespaces in macros
2024-03-11 12:43:00 -05:00
Thaddeus Crews
87f5fb0691 Enforce template syntax typename over class 2024-03-10 16:02:43 -05:00
Marc Gilleron
e607790647 Fix explicit namespaces in macros 2024-03-08 19:42:07 +00:00
A Thousand Ships
7ed8ef7221 Fix invalid void return in BitField 2024-03-08 13:32:28 +01:00
David Snopek
cc1217a43c Merge pull request #1381 from dsnopek/notification-hierarchy
Fix `_notification()` with parent and child classes
2024-03-05 11:50:13 -06:00
David Snopek
f444616553 Merge pull request #1404 from AThousandShips/virt_fix
Fix crash on virtual method calls
2024-03-05 11:50:02 -06:00
A Thousand Ships
fc986c2d12 Fix crash on virtual method calls 2024-03-05 15:30:59 +01:00
bruvzg
8c98a90f32 [Packed*Array] Add support for initializer lists. 2024-03-03 12:50:53 +02:00
David Snopek
8b92368165 Load new script_instance_create3 GDExtension interface function 2024-03-01 10:50:02 -06:00
David Snopek
e55b792fea Merge pull request #1383 from bruvzg/memalign
[Core] Improve `CowData` and `Memory` metadata alignment.
2024-02-26 12:54:17 -06:00
David Snopek
c4fde852e6 Avoid creating most objects that Godot is going to use placement new to initialize 2024-02-26 10:36:16 -06:00
David Snopek
23c010900c Fix _notification with parent and child classes 2024-02-22 14:39:50 -06:00
David Snopek
f90085917b Merge pull request #1256 from dsnopek/placeholders
Allow registering "runtime classes"
2024-02-21 07:51:52 -06:00
David Snopek
a6d9393341 Merge pull request #1392 from Faless/build/targets_no_more
[SCons] Split `targets.py`, apply flags from tools
2024-02-16 17:13:48 -06:00
Fabio Alessandrelli
16df4bff30 [SCons] Split targets.py, apply flags from tools
Split `targets` tool logic, moving all the compiler-specific flags to a
new `common_compiler_flags.py` file, and everything else (CPPDEFINES,
optimize option logic, dev build logic, etc) to the `godotcpp` tool.

The default tools now apply the common compiler flags by importing the
file and explicitly calling `configure`.
2024-02-16 23:08:06 +01:00
David Snopek
620104e700 Merge pull request #1367 from AThousandShips/issue_version
Use latest doc version in issue template
2024-02-16 09:06:30 -06:00
David Snopek
349b081b18 Merge pull request #1391 from Faless/build/custom_tools
[SCons] Add support for custom build tools and platforms
2024-02-15 09:37:06 -06:00
Fabio Alessandrelli
baaad7ada2 [SCons] Add support for custom build tools and platforms
Use with:

`scons platform=os2 custom_tools=/path/to/tools`

(assuming you have an `os2.py` inside `/path/to/tools/`)
2024-02-14 21:20:38 +01:00
David Snopek
fb884573ea Allow registering "runtime classes" 2024-02-13 08:55:25 -06:00
David Snopek
5fcc43e54d Merge pull request #1377 from dsnopek/gdextension-register-virtual-method
Allow GDExtensions to register virtual methods and call them on scripts (godot-cpp support)
2024-02-12 18:43:12 -06:00
David Snopek
9a13efa0e3 Merge pull request #1363 from Daylily-Zeleen/daylily-zeleen/fix_object_return_value_of_builtin_types_methods
Fix object return value of builtin types' methods.
2024-02-12 14:33:20 -06:00
David Snopek
8fbb7cf795 Allow GDExtensions to register virtual methods and call them on scripts 2024-02-12 13:30:07 -06:00
DaylilyZeleen
6a3753c076 Fix object return value of builtin types' methods. 2024-02-13 03:20:02 +08:00
David Snopek
7c547c6c6b Merge pull request #1384 from allenwp/godot-87991-typed-array-additions
Added newer Variant types to `typed_array.hpp`
2024-02-12 10:07:32 -06:00
Allen Pestaluky
349b5a3146 Added newer Variant types to typed_array.hpp
This is a companion commit to the godot PR https://github.com/godotengine/godot/pull/87992 which fixes https://github.com/godotengine/godot/issues/87991
Also undefines typed array templates after use to match Godot's typed_array.h
2024-02-06 13:53:38 -05:00
bruvzg
b173a4d935 [Core] Improve CowData and Memory metadata alignment. 2024-02-05 19:26:45 +02:00
dependabot[bot]
32ca574f49 Bump mymindstorm/setup-emsdk from 13 to 14
Bumps [mymindstorm/setup-emsdk](https://github.com/mymindstorm/setup-emsdk) from 13 to 14.
- [Release notes](https://github.com/mymindstorm/setup-emsdk/releases)
- [Commits](https://github.com/mymindstorm/setup-emsdk/compare/v13...v14)

---
updated-dependencies:
- dependency-name: mymindstorm/setup-emsdk
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-22 19:23:26 +00:00
David Snopek
36847f6af0 Merge pull request #1370 from MJacred/patch-1
Update README: fix godot-cpp issue tracker url
2024-01-22 08:57:08 -06:00
MJacred
8a535d0ecc Update README: fix godot-cpp issue tracker url 2024-01-22 10:50:27 +01:00
A Thousand Ships
cd5673bf2e Use latest doc version in issue template 2024-01-20 14:28:40 +01:00
David Snopek
0145e900f3 Merge pull request #1357 from bruvzg/cpp_64
Switch to 64-bit ints.
2024-01-19 12:15:55 -06:00
David Snopek
6c04514039 Merge pull request #1359 from Naros/GH-1287
Rework GDCLASS macro to allow abstract classes
2024-01-19 07:27:06 -06:00
David Snopek
480a0f8c06 Merge pull request #1360 from AThousandShips/aabb_fix
Fix `AABB.encloses` failing on shared upper bound
2024-01-19 07:26:45 -06:00
Chris Cranford
5f350e2572 Rework GDCLASS macro to allow pure virtual functions 2024-01-18 20:14:13 -05:00
A Thousand Ships
3943e41d2f Fix AABB.encloses failing on shared upper bound 2024-01-12 18:08:40 +01:00
Rémi Verschelde
0ddef6ed96 Merge pull request #1354 from nightblade9/patch-1
Update README.md with basic pre-requisites
2024-01-11 13:11:30 +01:00
Rémi Verschelde
64529361b4 Merge pull request #1351 from Daylily-Zeleen/daylily-zeleen/remove_namespace_in_global_constants_binding
Remove "godot" namespace when binding global constants.
2024-01-11 13:10:51 +01:00
Rémi Verschelde
edf1637c2c Merge pull request #1349 from AThousandShips/op_fix
Add missing `OP_POWER` operator to `Variant`
2024-01-11 13:10:07 +01:00
nightblade9
ee169b201b Update README.md with basic pre-requisites 2024-01-10 15:29:23 -05:00
bruvzg
59a5a8b104 Switch to 64-bit ints. 2024-01-10 15:36:36 +02:00
Daylily-Zeleen
bd40a94424 Remove "godot" namespace when binding global constants. 2024-01-07 15:24:02 +08:00
A Thousand Ships
f037a697eb Add missing OP_POWER operator to Variant 2024-01-06 21:12:52 +01:00
David Snopek
dd62b9685f Merge pull request #1347 from Chubercik/vector_method_parity
Add `Vector2i/3i/4i` methods: `distance_to` and `distance_squared_to`
2024-01-04 08:36:30 -06:00
David Snopek
8d13acca91 Merge pull request #1346 from AThousandShips/arg_fix
Fix expected argument count for call errors
2024-01-04 08:35:46 -06:00
David Snopek
b1769a70f0 Merge pull request #1344 from ArchLinus/ndk-error
Add an error message if android NDK is not installed
2024-01-04 08:35:18 -06:00
Jakub Mateusz Marcowski
b733102f4a Add Vector2i/3i/4i methods: distance_to and distance_squared_to 2024-01-03 11:45:05 +01:00
ArchLinus
718d0baea3 Add an error message if android NDK is not installed 2023-12-30 13:56:46 -05:00
A Thousand Ships
b77cb648c3 Fix expected argument count for call errors 2023-12-30 13:23:36 +01:00
David Snopek
3f44e9b404 Merge pull request #1339 from aaronfranke/detect-gdext
Allow detecting when building as a GDExtension
2023-12-29 14:14:35 -06:00
David Snopek
1c19d627aa Merge pull request #1340 from aaronfranke/really-packed
Add PackedRealArray as an alias for PackedFloat(32/64)Array
2023-12-20 08:25:42 -06:00
Aaron Franke
646c71c277 Add PackedRealArray as an alias for PackedFloat(32/64)Array 2023-12-19 04:44:05 -06:00
Aaron Franke
e17c7bf530 Allow detecting when building as a GDExtension 2023-12-18 09:13:20 -06: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
Joakim Stien
0a078d9ec9 PR comments — added doc, default 'ON' in Debug, 'OFF' in Release 2023-12-10 11:25:38 +01:00
Joakim Stien
31179ee47c Added hot reload support to CMakeLists.txt 2023-12-09 15:14:44 +01:00
Rémi Verschelde
48afa82f29 Merge pull request #1329 from godotengine/dependabot/github_actions/actions/setup-python-5
Bump actions/setup-python from 4 to 5
2023-12-07 08:58:31 +01:00
Rémi Verschelde
39ca745d0d Merge pull request #1324 from akien-mga/cmake-remove-hardcoded-warnings
CMake: Remove hardcoded warnings list and forcing -Werror on library builds
2023-12-07 08:57:52 +01:00
dependabot[bot]
a7becb43e6 Bump actions/setup-python from 4 to 5
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4 to 5.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v4...v5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-06 19:33:16 +00:00
Rémi Verschelde
41517eacb1 CMake: Remove hardcoded warnings list and forcing -Werror on library builds
The CMake buildsystem should be completely reviewed to properly match
what is done by SCons, instead of making its own arbitrary decisions on
how godot-cpp should be compiled.

Currently the SCons setup doesn't include warning options, so CMake
shouldn't either. Options similar to upstream Godot's SCons setup could
be added, and then replicated for CMake.
2023-12-01 10:45:07 +01:00
Rémi Verschelde
17137b2e2e Merge pull request #1323 from dsnopek/gcc-type-limits-error
Prevent `-Wtype-limits` warning on GCC 11 due to unsigned comparison
2023-12-01 10:36:59 +01:00
David Snopek
cad5be53b1 Avoid error from -Werror=type-limits on GCC 11 2023-11-30 17:52:33 -06:00
Rémi Verschelde
54136ee835 Add 4.2 branch to README 2023-11-30 10:02:53 +01:00
Rémi Verschelde
0f78fc45bd gdextension: Sync with upstream commit 46dc277917a93cbf601bbcf0d27d00f6feeec0d5 (4.2-stable) 2023-11-30 10:01:44 +01:00
Rémi Verschelde
11b2700b23 Merge pull request #1321 from dsnopek/postinitialize
Send NOTIFICATION_POSTINITIALIZE to extension classes
2023-11-30 09:55:30 +01:00
David Snopek
20c4e843b0 Send NOTIFICATION_POSTINITIALIZE to extension classes 2023-11-29 12:00:43 -06:00
Rémi Verschelde
f3143c7a9c Merge pull request #1320 from mihe/bit-field-size
Change bit field enums to use `uint64_t` as underlying type
2023-11-28 15:05:41 +01:00
Mikael Hermansson
943d1c8cdf Change bit field enums to use uint64_t as underlying type 2023-11-28 01:03:41 +01:00
David Snopek
588d869a3b Merge pull request #1313 from DmitriySalnikov/visibility_hidden
[Scons] Added the ability to change the visibility of symbols
2023-11-24 07:15:52 -06:00
Rémi Verschelde
5be275d73b gdextension: Sync with upstream commit d6a1db2b07595f80c0f19ab01c6b4d0b66002b18 (4.2-rc2) 2023-11-24 12:36:26 +01:00
Rémi Verschelde
4fed88afcf Merge pull request #1307 from LAK132/master
Fix file list issues when trying to build with meson via cmake
2023-11-24 12:35:29 +01:00
Rémi Verschelde
7fb8acaa53 Merge pull request #1288 from bytzo/cmake-fix-persistent-debug-symbols
Make CMake only include debug symbols when appropriate
2023-11-24 12:35:22 +01:00
Rémi Verschelde
2f16eddf15 Merge pull request #1316 from bruvzg/static_multiple_init
[iOS] Fix initialisation/termination of multiple statically linked extensions.
2023-11-24 09:23:42 +01:00
bruvzg
adc9def046 [iOS] Fix initialisation/termination of multiple statically linked extensions. 2023-11-23 13:38:20 +02:00
Rémi Verschelde
32409472b7 Merge pull request #1318 from DmitriySalnikov/android_api_version
[Scons] Set the minimum Android API level to 21
2023-11-22 22:56:44 +01:00
DmitriySalnikov
79d2a9c456 [Scons] Set the minimum Android API level to 21 2023-11-23 00:28:03 +03:00
Rémi Verschelde
d0fdc3adf3 Merge pull request #1317 from godotengine/dependabot/github_actions/mymindstorm/setup-emsdk-13
Bump mymindstorm/setup-emsdk from 12 to 13
2023-11-22 22:16:15 +01:00
dependabot[bot]
78bf5a42ed Bump mymindstorm/setup-emsdk from 12 to 13
Bumps [mymindstorm/setup-emsdk](https://github.com/mymindstorm/setup-emsdk) from 12 to 13.
- [Release notes](https://github.com/mymindstorm/setup-emsdk/releases)
- [Commits](https://github.com/mymindstorm/setup-emsdk/compare/v12...v13)

---
updated-dependencies:
- dependency-name: mymindstorm/setup-emsdk
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-22 19:10:15 +00:00
DmitriySalnikov
f5e4f95cde [Scons] Added the ability to change the visibility of symbols 2023-11-21 18:55:02 +03:00
Rémi Verschelde
6fd4e151b8 Merge pull request #1315 from bruvzg/ios_bump_version
[iOS] Bump default version to 12 to match engine.
2023-11-21 10:37:36 +01:00
bruvzg
e854e0b592 [iOS] Bump default version to 12 to match engine. 2023-11-21 09:39:53 +02:00
Rémi Verschelde
fa10d1a303 Merge pull request #1314 from akien-mga/ci-android-ndk-r23c
CI: Install Android NDK r23c explicitly
2023-11-21 00:00:26 +01:00
Rémi Verschelde
eea33b4133 CI: Install Android NDK r23c explicitly
It has just been removed from the Ubuntu 20.04 default install,
breaking our CI setup.

Also, sets Emscripten version to 3.1.39, as done upstream.
Newer versions actually break dynamic library support.
2023-11-20 23:43:58 +01:00
Rémi Verschelde
7cd79e4cc6 gdextension: Sync with upstream commit ad72de508363ca8d10c6b148be44a02cdf12be13 (4.2-rc1) 2023-11-20 14:42:29 +01:00
David Snopek
8d17966e81 Merge pull request #1294 from dsnopek/is-connected
Fix comparison of `Callable`s from `callable_mp()` of the same method
2023-11-17 13:18:19 -06:00
David Snopek
f426b12b5b Fix comparison of Callables from callable_mp() of the same method 2023-11-17 12:49:53 -06:00
David Snopek
4439a4a569 Merge pull request #1280 from dsnopek/callable-custom
Add `CallableCustom` that devs can use in their GDExtensions
2023-11-17 12:48:39 -06:00
David Snopek
c4b7b08c91 Merge pull request #1298 from Repiteo/int-to-variant-fix
Add missing int→Variant conversions
2023-11-15 09:07:48 -06:00
Rémi Verschelde
9d528c30ee gdextension: Sync with upstream commit 64150060f89677eaf11229813ae6c5cf8a873802 (4.2-beta6) 2023-11-13 20:32:11 +01:00
Rémi Verschelde
3d22ab88a3 gdextension: Sync with upstream commit 4c96e9676b66d0cc9a25022b019b78f4c20ddc60 (4.2-beta5) 2023-11-13 20:31:34 +01:00
Rémi Verschelde
5deb29b283 gdextension: Sync with upstream commit 93cdacbb0a30f12b2f3f5e8e06b90149deeb554b (4.2-beta4) 2023-11-13 20:30:59 +01:00
Rémi Verschelde
c51c5425ba Merge pull request #1308 from akien-mga/ci-tests-timeout-import
CI: Workaround upstream issue with .NET editor build not exiting
2023-11-13 19:13:54 +01:00
Rémi Verschelde
306774b5a4 CI: Workaround upstream issue with .NET editor build not exiting
We force closing the process after 10 s, which should be ample time to generate
the .godot folder.
2023-11-13 18:51:47 +01:00
LAK132
39c139c814 Fix file list issues when trying to build with meson via cmake 2023-11-11 23:29:33 +10:30
Rémi Verschelde
73757e3a9f Merge pull request #1304 from dsnopek/revert-fix-tests-hack
Revert "Hack adding `--quit-after 100` to ensure extension_list.cfg gets generated"
2023-11-10 11:38:44 +01:00
Rémi Verschelde
adb0cfc59c Merge pull request #1302 from bruvzg/ios_static
[iOS] Fix building as static library or xcframework, add iOS config and xcframework build script to the test project.
2023-11-10 11:38:21 +01:00
bruvzg
29b34d92bb [iOS] Fix building as static library or xcframework, add iOS config and xcframework build script to the test project. 2023-11-09 20:01:59 +02:00
Rémi Verschelde
cc89bd2132 Merge pull request #1301 from brno32/master
ignoring venv in .gitignore
2023-11-09 12:42:16 +01:00
Rémi Verschelde
4af46132c2 Merge pull request #1303 from Repiteo/is_msvc-and-use_hot_reload-fix
Fix `is_msvc` and `use_hot_reload` variables
2023-11-09 12:36:11 +01:00
Thaddeus Crews
bcac96c8c2 Add missing int→Variant conversions 2023-11-08 09:45:53 -06:00
David Snopek
d239312e7b Merge pull request #1292 from Repiteo/GDCLASS-style-sync
`GDCLASS` synced by ending with "private:"
2023-11-08 16:22:46 +01:00
David Snopek
59392bc1fa Revert "Hack adding --quit-after 100 to ensure extension_list.cfg gets generated"
This reverts commit 93260e1700.
2023-11-07 15:48:25 -06:00
Alex Drozd
92dd34ae96 ignoring venv in .gitignore 2023-11-06 22:32:52 +01:00
Thaddeus Crews
648b8c4489 fix is_msvc and use_hot_reload variables 2023-11-06 10:50:19 -06:00
David Snopek
d33bd47219 Add CallableCustom that devs can use in their GDExtensions 2023-11-06 00:09:06 -06:00
David Snopek
2dfe7929de Merge pull request #1299 from dsnopek/fix-tests
Hack adding `--quit-after 100` to ensure `extension_list.cfg` gets generated
2023-11-06 07:05:58 +01:00
David Snopek
93260e1700 Hack adding --quit-after 100 to ensure extension_list.cfg gets generated 2023-11-04 17:24:36 -05:00
David Snopek
e4eee8b12d Merge pull request #1291 from m4gr3d/update_android_logic_to_retrieve_ndk_toolchain
Update the environment variables used to access the Android NDK toolchain
2023-11-03 18:31:25 -05:00
Fredia Huya-Kouadio
86dbd5fa0d Update the environment variables used to access the Android NDK toolchain 2023-11-01 12:14:55 -07:00
Thaddeus Crews
6eb5d450bd GDCLASS synced by ending with "private:"
• Matches implementation used by modules and godot itself
• Apply same to GDEXTENSION_CLASS, setup with same diff-friendly spacers as GDCLASS
2023-11-01 12:44:14 -05:00
Bytzo
db884e9b1d Prevent CMake from always including debug symbols 2023-10-25 23:57:13 -07:00
David Snopek
c1196a1ab0 Merge pull request #1286 from dsnopek/callable-custom-object-id
Switch to using `ObjectID` in custom callables
2023-10-25 15:13:22 -05:00
David Snopek
4b76485a4e Switch to using ObjectID in custom callables 2023-10-25 13:05:32 -05:00
Rémi Verschelde
f79bd795d5 gdextension: Sync with upstream commit e8d57afaeccf0d9f9726746f49936eb93aa0039b (4.2-beta3) 2023-10-24 22:58:57 +02:00
Rémi Verschelde
1ab94699c5 Merge pull request #1277 from dsnopek/variant-iter-tests
Add an automated test using a Variant iterator
2023-10-24 22:30:42 +02:00
David Snopek
c82f2a3714 Merge pull request #1279 from dsnopek/gdclass-protections
Add protections against registering classes that didn't use `GDCLASS()`
2023-10-22 10:07:41 -05:00
David Snopek
edb52293d9 Merge pull request #1278 from dsnopek/gdextension-callable-bind-test
Add test for `Callable.bind()`
2023-10-22 10:07:09 -05:00
David Snopek
379ce2b5e5 Merge pull request #1216 from akien-mga/scons-disable-exception-handling
SCons: Disable C++ exception handling by default
2023-10-22 10:06:34 -05:00
David Snopek
a61cdc8860 Add protections against registering classes that didn't use GDCLASS() 2023-10-22 08:44:09 -05:00
Rémi Verschelde
bf1c03ab5f SCons: Disable C++ exception handling by default
Counterpart to https://github.com/godotengine/godot/pull/80612.
2023-10-22 12:45:46 +02:00
David Snopek
421c61e730 Add test for Callable.bind() 2023-10-21 17:42:10 -05:00
David Snopek
d733663e8b Add an automated test using a Variant iterator 2023-10-20 12:58:00 -05:00
David Snopek
0a6a19e33b Merge pull request #1253 from gilzoide/fix-variant-iteration-valid-flag
Fix return value and `r_valid` value in `Variant::iter_init` and `Variant::iter_next`
2023-10-20 10:39:05 -05:00
Rémi Verschelde
5182624141 gdextension: Sync with upstream commit f8818f85e6c43cdf1277e8ae85eba19ca0a003b0 (4.2-beta2) 2023-10-20 08:40:49 +02:00
David Snopek
7a260f5e93 Merge pull request #1230 from adamscott/compiledb-alias
Refactor compiledb implementation
2023-10-19 14:34:17 -05:00
Adam Scott
2d5024ac8e Refactor compiledb implementation
This comment enables the possibility to build the "compile_commands.json"
file by only using `scons -Q compiledb`. No need to use the argument
`compiledb=yes`.

And when using the `compiledb=yes`, it will create a
"compiled_commands.json" automatically.
2023-10-19 10:51:31 -04:00
David Snopek
7a3cfe8089 Merge pull request #1275 from capnm/fix-clang-virt_destructor-warning
clang: Add CallableCustomMethodPointerBase virtual destructor
2023-10-19 09:06:45 -05:00
David Snopek
5c4a7dc7b2 Merge pull request #1258 from Repiteo/standalone-gdextension_dir
Let `gdextension_dir` function as standalone argument
2023-10-19 09:06:12 -05:00
Martin Capitanio
a926b96103 clang: Add CallableCustomMethodPointerBase virtual destructor
Fixes #1272
+ clang++ (debian v16/v17) warning:
	destructor called on
	'godot::CallableCustomMethodPointerBase' that is abstract but has non-virtual destructor
	[-Wdelete-abstract-non-virtual-dtor]
2023-10-19 09:37:11 +02:00
Thaddeus Crews
7a5cbcac21 Let gdextension_dir function as only argument 2023-10-18 11:32:51 -05:00
David Snopek
64eac01d04 Merge pull request #1266 from dsnopek/automatic-engine-class-registration
Automatically register only engine classes whose header has been included
2023-10-16 10:47:06 -05:00
David Snopek
b507b3e591 Automatically register only engine classes whose header has been included 2023-10-16 10:19:11 -05:00
David Snopek
4320c62c76 Merge pull request #1270 from Faless/build/web_rename
[SCons] Rename javascript tool to web
2023-10-15 09:49:53 -05:00
Fabio Alessandrelli
18bfa133ab [SCons] Rename javascript tool to web
And clean it up a bit.
2023-10-15 13:12:49 +02:00
Rémi Verschelde
c4d3f019da gdextension: Sync with upstream commit b1371806ad3907c009458ea939bd4b810f9deb21 (4.2-beta1) 2023-10-12 18:10:11 +02:00
Rémi Verschelde
4f0eb2f520 Merge pull request #1263 from dsnopek/string-name-new
Use the new `string_name_new_with_latin1_chars` function to improve StringName construction performance
2023-10-12 18:08:09 +02:00
David Snopek
292a50dd08 Merge pull request #1265 from mihe/char-string-specializations
Declare explicit specializations for `CharStringT`
2023-10-12 10:47:06 -05:00
Mikael Hermansson
6e05b978b8 Declare explicit specializations for CharStringT 2023-10-12 16:00:48 +02:00
Rémi Verschelde
55618ebf58 Merge pull request #1264 from dsnopek/misc-gdextension-interface-changes
Miscellaneous updates to gdextension_interface.h
2023-10-12 09:19:23 +02:00
David Snopek
29248c31ae Miscellaneous updates to gdextension_interface.h 2023-10-11 21:42:05 -05:00
David Snopek
3d814f9e4a Use the new string_name_new_with_latin1_chars function to improve StringName construction performance 2023-10-09 16:59:29 -05:00
David Snopek
ef2f63a00c Merge pull request #1260 from Klaim/master
Fixes crash in ClassDB::deinitialize due to usage of invalid iterator.
2023-10-05 11:07:11 -05:00
Joël Lamotte (Klaim)
5134c82573 Fixes crash in ClassDB::deinitialize due to usage of invalid iterator.
After the removed call to `std::vector::erase` all iterators,
`i` included, are invalidated and therefore this code has undefined
behavior (which can or not lead to a crash).
This change delays the removal of class names from
`class_register_order` to after having gone through it's content,
removing the undefined behavior.
2023-10-05 16:58:49 +02:00
David Snopek
cd61a9bbe8 Merge pull request #1257 from dsnopek/script-class-category
Update for `get_class_category` added to `GDExtensionScriptInstanceInfo2`
2023-10-04 11:17:41 -05:00
David Snopek
96bec613a0 Merge pull request #1247 from nicholas-maltbie/nickmaltbie/javascript-wasm-fix
Javascript Web WASM Fix
2023-10-04 09:58:01 -05:00
David Snopek
6ad187cc7e Update for get_class_category added to GDExtensionScriptInstanceInfo2 2023-10-04 09:19:45 -05:00
Rémi Verschelde
98737b2678 Merge pull request #1259 from akien-mga/ci-fix-mingw-install-error
CI: Fix MinGW install error by pinning to earlier version
2023-10-04 15:20:37 +02:00
Rémi Verschelde
0369f6fea0 CI: Fix MinGW install error by pinning to earlier version
Works around https://github.com/egor-tensin/setup-mingw/issues/14.
2023-10-04 13:42:49 +02:00
Nick Maltbie
2b4bcbb0ce Added fix for javascript build for godot 4.x
Added changes to tools/javascript.py to add PFlags to fix SharedArrayBuffer memory error.
Corrected some small errors in tools/javascript.py to support new target names.
Also updated ci to include validation for web build.
2023-10-01 13:43:19 -07:00
David Snopek
bf2f9e2f55 Merge pull request #1200 from dsnopek/hot-reload
Changes necessary for hot reload to work
2023-09-26 08:38:12 -05:00
David Snopek
df849651d9 Changes necessary for hot reload to work 2023-09-25 22:13:33 -05:00
gilzoide
60dfa3445a Fix return value and r_valid value in Variant::iter_init and iter_next 2023-09-24 17:10:29 -03:00
David Snopek
c44c3d5ebf Merge pull request #1155 from dsnopek/callable-mp
Implement `callable_mp()` and `callable_mp_static()`
2023-09-21 16:20:21 -05:00
David Snopek
c18c1916c3 Implement callable_mp() and callable_mp_static() 2023-09-21 15:17:50 -05:00
David Snopek
4314f91b7d Merge pull request #1238 from dsnopek/variant-call-callp
Fix variant call compiler error (alternate)
2023-09-21 15:07:05 -05:00
David Snopek
db15731e4d Merge pull request #1165 from dsnopek/missing-classes
Handle missing instance binding callbacks by finding the closest parent
2023-09-21 15:06:51 -05:00
David Snopek
381df0081a Merge pull request #1220 from adamscott/add-local-custom-support-redux
Add support to import custom variables from parent SConstruct (redux)
2023-09-21 15:06:30 -05:00
David Snopek
a963b8b7c7 Merge pull request #1246 from dsnopek/virtual-call-data
Update for addition of `get_virtual_call_data_func` and `call_virtual_func` to `GDExtensionClassCreationInfo2`
2023-09-20 14:16:43 -05:00
David Snopek
3a02feddc3 Update for addition of get_virtual_call_data_func and call_virtual_func to GDExtensionClassCreationInfo2 2023-09-20 12:15:31 -05:00
David Snopek
a3dfbbde85 Merge pull request #1245 from AThousandShips/alloc_fix
Fix allocation size overflow check in `CowData`
2023-09-20 07:39:27 -05:00
David Snopek
b1fd1b65fd Merge pull request #1242 from AThousandShips/null_check
Replace `ERR_FAIL_COND` with `ERR_FAIL_NULL` where applicable
2023-09-20 07:32:14 -05:00
David Snopek
52ca3ef547 Handle missing instance binding callbacks by finding the closest parent 2023-09-19 10:54:07 -05:00
David Snopek
0d6de7a80e Merge pull request #1164 from dsnopek/classdb-singleton-alternate
Add static methods to `ClassDB` for the methods bound to the `ClassDB` singleton
2023-09-19 10:33:15 -05:00
A Thousand Ships
06ffc7e952 Fix allocation size overflow check in CowData 2023-09-19 16:14:00 +02:00
David Snopek
73500966ae Merge pull request #1243 from dsnopek/load-print-error-with-message
Load 'print_error_with_message' function
2023-09-15 15:29:33 -05:00
David Snopek
634ed09ec0 Load 'print_error_with_message' function 2023-09-15 14:08:27 -05:00
A Thousand Ships
1e5767693e Replace ERR_FAIL_COND with ERR_FAIL_NULL where applicable 2023-09-13 14:34:04 +02:00
Rémi Verschelde
6caf4909d4 Merge pull request #1239 from dsnopek/gdextension-validate-property-object
Support `_validate_property()`
2023-09-13 13:44:22 +02:00
David Snopek
aa6867e6c9 Support _validate_property() 2023-09-12 13:21:16 -05:00
David Snopek
16ffb2795a Merge pull request #970 from Daylily-Zeleen/daylily-zeleen/register_unexposed_class
Implement register unexposed classes
2023-09-11 09:35:32 -05:00
Matthew Murphy
ca3e25de04 Fix variant call compiler error
Co-authored-by: David Snopek <dsnopek@gmail.com>
2023-09-09 11:30:29 -05:00
David Snopek
b488f009bd Merge pull request #1208 from dsnopek/check-godot-version
Check that GDExtension is opened by compatible Godot version
2023-09-09 09:30:36 -05:00
David Snopek
80f98de905 Merge pull request #1237 from DmitriySalnikov/fix-scons-crashes
[SCons] Fixed crashes in several scripts
2023-09-09 09:19:38 -05:00
DmitriySalnikov
0e5975dd26 [SCons] Fixed crashes in several scripts 2023-09-09 12:44:14 +03:00
David Snopek
5cdc2fc099 Merge pull request #1214 from dsnopek/ptrtoarg-native-struct
Ensure that PtrToArg specializations for native structs are used
2023-09-08 10:12:23 -05:00
David Snopek
adcc95534b Merge pull request #1231 from godotengine/dependabot/github_actions/actions/checkout-4
Bump actions/checkout from 3 to 4
2023-09-07 17:46:16 -05:00
David Snopek
82e960a810 Merge pull request #1233 from AThousandShips/wrapper_fix
Ensure `const` correctness for wrappers
2023-09-07 08:27:38 -05:00
A Thousand Ships
f651df5e7a Ensure const correctness for wrappers 2023-09-06 19:33:03 +02:00
dependabot[bot]
5d4ff63930 Bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-04 19:13:12 +00:00
Adam Scott
982e01ec7f Add support to import custom variables from parent SConstruct (redux) 2023-09-04 15:05:52 -04:00
Daylily-Zeleen
2d1f852baf Implement register unexposed class. 2023-09-04 00:59:10 +08:00
David Snopek
0db95a92a6 Merge pull request #1228 from Bromeon/bugfix/yet-another-bool
GDExtension: fix `bool` unknown in C
2023-09-02 16:13:51 -05:00
David Snopek
8990d5a40e Merge pull request #1091 from Daylily-Zeleen/daylily-zeleen/implement_builtin_classes_vararg_methods
Implement vararg methods of builtin classes.
2023-09-02 08:04:29 -05:00
Jan Haller
54092861f1 GDExtension: fix bool unknown in C 2023-09-02 13:19:14 +02:00
David Snopek
9ada7065d6 Merge pull request #1226 from AThousandShips/version_str
Fix formatting of `compatibility_minimum` examples
2023-08-31 08:17:51 -05:00
A Thousand Ships
b3596a18e1 Fix formatting of compatibility_minimum examples
Without quotes the values is parsed as a float, breaking in various
cases.
2023-08-31 12:45:11 +02:00
David Snopek
9a6c741d5d Merge pull request #1151 from Sauermann/fix-notification-order
Fix `Object::notification` order (cpp-bindings)
2023-08-30 14:19:51 -05:00
Markus Sauermann
c2d99fd519 Fix Object::notification order
For the notification-order to work correctly, it is necessary to
allow the `p_reversed` argument to be used within cpp.
This PR changes the necessary bindings.
2023-08-30 00:07:28 +02:00
David Snopek
dd9586b841 Merge pull request #1190 from Faless/build/godotcpp_tool
[SCons] Move the GodotCPP build to its own tool.
2023-08-29 13:07:38 -05:00
Fabio Alessandrelli
f8b4f60cb9 [SCons] Move the GodotCPP build to its own tool. 2023-08-29 18:14:42 +02:00
David Snopek
6d9416eb17 Merge pull request #1225 from dsnopek/placeholder-script-instance
Add support for placeholder_script_instance_create/update
2023-08-29 09:39:05 -05:00
David Snopek
f0405f18a3 Add support for placeholder_script_instance_create/update 2023-08-28 17:02:13 -05:00
Rémi Verschelde
c370f0f24a Merge pull request #1221 from dsnopek/readme-improvements
Clarify versions and examples in the README
2023-08-17 17:14:07 +02:00
David Snopek
1588dc8437 Clarify versions and examples in the README 2023-08-17 09:39:13 -05:00
David Snopek
a7d3f00b26 Merge pull request #1218 from AThousandShips/readme_fix
Fix link to test project in readme
2023-08-17 06:27:11 -05:00
A Thousand Ships
e586e11637 Fix link to test project in readme
Also updated format for library paths
2023-08-17 10:51:12 +02:00
David Snopek
7ed7a84782 Merge pull request #1197 from AThousandShips/vec_elem
Add remaining component-wise `min/max` functions to `Vector*`
2023-08-16 16:45:33 -05:00
David Snopek
112e41bd8f Merge pull request #1204 from akien-mga/scons-targets-sync-with-godot
SCons: Sync `targets.py` fully with upstream Godot
2023-08-16 10:02:54 -05:00
A Thousand Ships
52eb77efd4 Add remaining component-wise min/max functions to Vector* 2023-08-16 13:52:51 +02:00
Rémi Verschelde
74b352e979 Merge pull request #1215 from adamscott/fix-deprecated-builtins-clang-2
Fix forgotten not operator
2023-08-16 12:29:56 +02:00
Adam Scott
f5c8e5190f Fix forgotten not operator 2023-08-16 05:30:40 -04:00
Rémi Verschelde
524bbd3ee9 Merge pull request #1211 from adamscott/fix-deprecated-builtins-clang
Fix Clang deprecated builtins
2023-08-16 09:12:41 +02:00
David Snopek
3cd3f24150 Ensure that PtrToArg specializations for native structs are used 2023-08-15 17:54:11 -05:00
Adam Scott
5c262844ad Fix Clang deprecated builtins
It seems that Clang and GCC have different interpretations of certain
builtins. So this PR uses std <type_traits> functions just as cowdata.h
does in the godot project.
2023-08-15 18:50:47 -04:00
Rémi Verschelde
df5500565a Merge pull request #1209 from dsnopek/missing-tests
Add automated tests to verify some previous fixes
2023-08-15 09:30:21 +02:00
David Snopek
d5fab0b9f8 Add automated tests to verify some previous fixes 2023-08-14 20:48:51 -05:00
David Snopek
fecb2959b4 Check that GDExtension is opened by compatible Godot version 2023-08-14 17:01:12 -05:00
David Snopek
5eebc6b20c Merge pull request #1193 from Zylann/version_header
Added generated version header
2023-08-11 10:33:49 -05:00
Rémi Verschelde
600e749d9b SCons: Sync targets.py fully with upstream Godot
- Reorders existing code to match Godot.
- Adds `NDEBUG` for non-dev builds.
- Adds `-gdwarf-4` for Clang debug symbols.
- Adds strip link flag for GCC/Clang builds without debug symbols.
2023-08-10 09:23:32 +02:00
David Snopek
c47bd60c73 Merge pull request #1203 from dsnopek/1082-update
Statically link mingw/msvc runtime libraries on Windows
2023-08-09 18:53:16 -05:00
Feiyun Wang
a745c2ac47 Statically link mingw/msvc runtime libraries on Windows
Co-authored-by: David Snopek <dsnopek@gmail.com>
2023-08-09 13:38:38 -05:00
David Snopek
5834e16a22 Merge pull request #1166 from dsnopek/string-resize
Implement `String::resize()` in godot-cpp
2023-07-31 18:31:24 -05:00
David Snopek
6f913563d8 Add static methods to ClassDB for the methods bound to the ClassDB singleton 2023-07-31 16:04:27 -05:00
David Snopek
845226d66a Merge pull request #1191 from Faless/build/unify_osxcross
[SCons] Merge OSXCross tools into platform ones
2023-07-31 15:40:27 -05:00
David Snopek
d168dd021e Merge pull request #1189 from Faless/build/compiledb
[SCons] Add option to generate a compilation database.
2023-07-31 15:39:07 -05:00
David Snopek
494b51698d Merge pull request #1188 from adamscott/add-platform-macros
Add platform macros
2023-07-31 15:38:47 -05:00
David Snopek
8bc1c1dbeb Implement String::resize() 2023-07-31 15:14:10 -05:00
David Snopek
c5d8447861 Merge pull request #1181 from Zylann/fix_singleton_caching
Don't cache `null` forever if a singleton isn't available yet
2023-07-26 21:09:10 -05:00
Marc Gilleron
c6b2c82570 Added generated version header 2023-07-26 23:23:56 +01:00
David Snopek
1d49bef096 Merge pull request #1184 from Zylann/fix_get_property_list_calling_parent
Don't call parent _get_property_list when a class doesn't define it (for internal binding).
2023-07-26 15:31:15 -05:00
David Snopek
d15550fdee Merge pull request #1186 from mihe/indexed-properties
Add support for indexed properties
2023-07-26 14:22:34 -05:00
Marc Gilleron
baf0b9e0f7 Don't call parent _get_property_list when a class doesn't define it.
Godot is already supposed to call _get_property_list of parent classes,
so this binding function must really only return procedural properties of
the class it belongs to, and not parent or child classes.
2023-07-26 20:12:25 +01:00
Mikael Hermansson
7d8cb7c155 Add support for indexed properties 2023-07-26 00:31:53 +02:00
Adam Scott
9d9f4279ed Add platform macros 2023-07-23 19:23:01 -04:00
Fabio Alessandrelli
6d195137fe [SCons] Merge OSXCross tools into platofrm ones 2023-07-23 22:54:07 +02:00
Fabio Alessandrelli
2586ad016e [SCons] Add option to generate a compilation database. 2023-07-22 20:04:30 +02:00
Marc Gilleron
548c758677 Don't cache null forever if a singleton isn't available yet
# Conflicts:
#	binding_generator.py
2023-07-22 16:31:28 +01:00
David Snopek
3162be28e5 Merge pull request #1150 from dsnopek/charstring-full
Attempt to fully implement CharString
2023-07-22 09:04:27 -05:00
David Snopek
ef5a185dc4 Merge pull request #1176 from dsnopek/string-name-allocate-once
In generated methods, only allocate the method StringName the first time
2023-07-22 09:04:13 -05:00
Yuri Sizov
1009da4d7e gdextension: Sync with upstream commit bd6af8e0ea69167dd0627f3bd54f9105bda0f8b5 (4.1.1-stable) 2023-07-17 20:10:45 +02:00
David Snopek
749b0b9ae0 Merge pull request #1172 from adamscott/add-cache-dir-gitignore
Add lower-case "*.cache" in ".gitignore"
2023-07-14 11:41:03 -05:00
David Snopek
67bd2eac44 Merge pull request #1170 from adamscott/import-env-if-exists
Import `env` if possible
2023-07-14 11:40:52 -05:00
David Snopek
a9209ce881 Merge pull request #1175 from bruvzg/msvc_force_utf8
[MSVC] Force UTF-8 encoding.
2023-07-14 06:49:42 -05:00
David Snopek
efc16b49d9 In generated methods, only construct the method StringName the first time 2023-07-13 13:05:41 -05:00
bruvzg
d1aeba771a [MSVC] Force UTF-8 encoding. 2023-07-11 16:11:51 +03:00
Adam Scott
8155f35b29 Import env if possible
This PR make it possible to import `env` and use it instead of creating
one from scratch every time.

Handy because we encourage users to use the godot-cpp SConstruct file as
a base to their projects (see the test project). So, if a project want
to override specific settings, (eg. make a path local to their SConstruct
file, not local to the godot-cpp/SConstruct file), it can do so.
2023-07-11 04:41:55 -04:00
Adam Scott
67501f1ee2 Add lower-case "*.cache" in ".gitignore" 2023-07-09 12:13:34 -04:00
Rémi Verschelde
d627942b64 gdextension: Sync with upstream commit 970459615f6b2b4151742ec6d7ef8559f87fd5c5 (4.1-stable) 2023-07-05 16:31:31 +02:00
Rémi Verschelde
d2b8ff4e9c gdextension: Sync with upstream commit cdd2313ba27d0a2600a18e849b4c5d1fd6a6e351 (4.1-rc3) 2023-07-04 13:42:41 +02:00
Daylily-Zeleen
3536803e9e Implement vararg methods of builtin classes. 2023-07-03 17:30:42 +08:00
Rémi Verschelde
ff6f5792d2 Merge pull request #1159 from mihe/unused-exports
Remove unused free-standing `initialize_level` and `deinitialize_level`
2023-07-01 00:33:09 +02:00
Mikael Hermansson
4b1072e4da Remove unused free-standing initialize_level and deinitialize_level 2023-06-30 19:36:46 +02:00
Rémi Verschelde
3e44ad1867 Merge pull request #1157 from Faless/feat/rpc_test
Add RPC tests.
2023-06-30 15:50:03 +02:00
Fabio Alessandrelli
155f2e2a62 Add RPC tests. 2023-06-30 15:07:42 +02:00
Rémi Verschelde
80986f8497 gdextension: Sync with upstream commit 46424488edc341b65467ee7fd3ac423e4d49ad34 (4.1-rc2) 2023-06-30 10:02:54 +02:00
Rémi Verschelde
a4784e12b9 gdextension: Sync with upstream commit ada712e06a471da2a2f4646237830bbd7980c114 (4.1-rc1) 2023-06-29 09:51:49 +02:00
David Snopek
4df112cd95 Attempt to fully implement CharString 2023-06-22 21:03:30 -05:00
Rémi Verschelde
bfc9e0bd93 gdextension: Sync with upstream commit ada712e06a471da2a2f4646237830bbd7980c114 (4.1-beta3) 2023-06-21 15:58:41 +02:00
David Snopek
2377f7ec75 Merge pull request #1047 from Kehom/master
Unregister custom classes in reverse registration order
2023-06-20 08:24:56 -05:00
Kehom
20be441026 Unregister custom classes in reverse registration order 2023-06-19 11:04:11 -03:00
Rémi Verschelde
82edc89cfa Merge pull request #1148 from Bromeon/bugfix/uninit-ptr-signature
GDExtension: `Uninitialized*Ptr` for constructors/converters using placement new
2023-06-19 10:43:58 +02:00
Rémi Verschelde
130644c061 Merge pull request #1138 from dsnopek/editor-plugins-deinitialize
Automatically remove editor plugins when deinitializing GDExtension
2023-06-19 10:43:34 +02:00
Rémi Verschelde
ca78bcf558 Merge pull request #1086 from lucasrafael98/fixes/missing-include-audio-frame
Fix: Include method_ptrcall.hpp on simple structs.
2023-06-19 10:43:10 +02:00
Jan Haller
2d4ec829a0 GDExtension: Uninitialized*Ptr for constructors/converters using placement new
These methods construct their destination in-place, but the parameters are not declared using the `Uninitialized*Ptr` pointer types.
2023-06-18 23:11:12 +02:00
Rémi Verschelde
f56f45156b Merge pull request #1143 from bruvzg/py_utf8
Force UTF-8 encoding in the binding generator script.
2023-06-16 10:30:08 +02:00
Rémi Verschelde
f0065bd801 Merge pull request #1048 from asmaloney/reserved_identifiers
Identifiers containing double underscore are reserved according to the C++ standard
2023-06-16 10:29:45 +02:00
bruvzg
f1ad719ffc Force UTF-8 encoding in the binding generator script. 2023-06-16 10:41:23 +03:00
Andy Maloney
db2394dbe7 Identifiers containing double underscore are reserved according to the C++ standard
Rename __* to _gde_*

https://timsong-cpp.github.io/cppwp/n3337/global.names

https://en.cppreference.com/w/cpp/language/identifiers

Identifiers appearing as a token or preprocessing token (i.e., not in user-defined-string-literal like operator ""id) (since C++11) of one of the following forms are reserved:
 - identifiers with a double underscore anywhere;
 - identifiers that begin with an underscore followed by an uppercase letter;
 - in the global namespace, identifiers that begin with an underscore.
2023-06-15 20:45:01 -04:00
Rémi Verschelde
1bc9ca7b57 Merge pull request #1139 from Trey2k/master
Prepend PATH to scons env to allow use of buildroot
2023-06-15 10:58:13 +02:00
Trey Moller
6f7e80bbb6 Prepend PATH to scons env 2023-06-14 10:30:24 -05:00
Rémi Verschelde
be25a50617 gdextension: Sync with upstream commit a2575cba48121a9e31c3a550ebd29398a7facf3f (4.1-beta2) 2023-06-14 10:05:18 +02:00
David Snopek
d28a3cbbd5 Automatically remove editor plugins when deinitializing GDExtension 2023-06-13 14:24:33 -05:00
Rémi Verschelde
d12cf071bb Merge pull request #1128 from Mathis-Z/master
Fixing #1127 by making return types of auto-generated functions dynamic
2023-06-08 22:31:51 +02:00
Mathis-Z
ac98dd2752 Fixing #1127 by making return types of auto-generated functions dynamic 2023-06-08 20:35:29 +02:00
David Snopek
ee5cf3a11d Merge pull request #1137 from dsnopek/no-more-legacy-mode
Clarify error message because there isn't a legacy Godot 4.0 mode anymore
2023-06-08 10:11:29 -05:00
David Snopek
3074d22815 Clarify error message because there isn't a legacy Godot 4.0 mode anymore 2023-06-08 09:42:03 -05:00
Rémi Verschelde
92a139d31e Merge pull request #1129 from dsnopek/interface-print-error
Correctly load gdextension_interface_print_error
2023-06-08 16:01:40 +02:00
Rémi Verschelde
b5a3aeb8ee Merge pull request #1123 from dsnopek/revert-pr-1044-1045
Revert the changes from PR #1044 and #1045 and standardize on `Object **` encoding in ptrcall
2023-06-07 17:30:44 +02:00
David Snopek
ad726015e7 Revert the changes from PR #1044 and #1045 and standardize on Object ** encoding in ptrcall 2023-06-07 08:30:33 -05:00
Rémi Verschelde
c669f0b78a gdextension: Sync with upstream commit 828ec2c5d005b6499c7c4c88beaf81767d05614b (4.1-beta1) 2023-06-07 13:23:12 +02:00
David Snopek
59bffc94a8 Correctly load gdextension_interface_print_error 2023-05-31 01:32:44 -05:00
David Snopek
aef9ea7387 Merge pull request #1113 from Calinou/add-issue-template
Add issue template based on the main Godot repository
2023-05-26 17:00:25 -05:00
David Snopek
0c466ddb67 Merge pull request #1117 from dsnopek/sync-gdextension-interface
Synchronize gdextension_interface.h with Godot
2023-05-26 17:00:13 -05:00
David Snopek
6347ce2550 Synchronize gdextension_interface.h with Godot 2023-05-26 15:43:50 -05:00
Rémi Verschelde
2078c00bab Merge pull request #1114 from dsnopek/editor-plugins
Add support for adding/removing editor plugins
2023-05-26 11:04:35 +02:00
Hugo Locurcio
e7c57a39db Add issue template based on the main Godot repository 2023-05-25 15:59:33 +02:00
David Snopek
2e45bd8373 Merge pull request #1101 from dsnopek/better-tests
Add automated tests that run a GDExtension (rather than just building it)
2023-05-24 21:18:12 -05:00
David Snopek
0d0d5a670b Merge pull request #1116 from saki7/Ref-allow-non-const-access
Change Ref<T> to allow non const access to ptr
2023-05-24 21:17:25 -05:00
David Snopek
8052f818b4 Merge pull request #1050 from dsnopek/object-correct-class
Ensure GDExtension class is the correct type for the Godot engine class
2023-05-24 21:17:12 -05:00
David Snopek
08bc2ef680 Merge pull request #1115 from dgcole/master
Update Getting Started section of README.md
2023-05-24 21:16:28 -05:00
dgcole
6f0649a86d Update getting started section of README.md 2023-05-24 21:49:55 -04:00
David Snopek
1fd3f82d3a Add automated tests that run a GDExtension (rather than just building it) 2023-05-17 14:08:12 -05:00
Nana Sakisaka
48635729b9 Change Ref<T> to allow non const access to ptr 2023-05-17 19:24:09 +09:00
David Snopek
e75ebffb70 Add support for adding/removing editor plugins 2023-05-16 22:02:35 -05:00
David Snopek
431e30bc32 Ensure GDExtension class is the correct type for the Godot engine class 2023-05-16 15:18:48 -05:00
Rémi Verschelde
1c18413de0 Merge pull request #1095 from dsnopek/gdextension-interface
Update to load function pointers for GDExtension interface
2023-05-16 17:26:31 +02:00
Hugo Locurcio
813827c26a Merge pull request #1108 from sasichkamega/master 2023-05-12 19:58:34 +02:00
David Snopek
a5c6ca5920 Update to load function pointers for GDExtension interface 2023-05-09 21:45:48 -05:00
Alex
7f94f90b01 Update CMakeLists.txt 2023-05-06 09:55:41 +03:00
Lucas Rafael
cb0b105402 Fix: Include method_ptrcall.hpp on simple structs. 2023-04-07 18:53:07 +01:00
Rémi Verschelde
feaba551b5 Merge pull request #1045 from zhehangd/fix_ref_crash
Fix crash using Ref<T> as parameter
2023-04-04 11:30:08 +02:00
Rémi Verschelde
e9942db502 Merge pull request #1044 from zhehangd/fix_obj_ptr_crash
Fix crash using Object* as parameter
2023-04-01 11:36:17 +02:00
Zhehang Ding
093f0673f5 Fix PtrToArg<Object*> crash 2023-03-30 19:38:12 -07:00
Zhehang Ding
517db6686a Fix PtrToArg<Ref<T>> crash 2023-02-15 22:36:29 -08:00
198 changed files with 82702 additions and 10426 deletions

View File

@@ -1,80 +1,105 @@
# Commented out parameters are those with the same value as base LLVM style.
# We can uncomment them if we want to change their value, or enforce the
# chosen value in case the base style changes (last sync: Clang 14.0).
---
### General config, applies to all languages ###
BasedOnStyle: LLVM
# chosen value in case the base style changes (last sync: Clang 17.0.6).
BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: DontAlign
# AlignArrayOfStructures: None
# AlignConsecutiveMacros: None
# AlignConsecutiveAssignments: None
# AlignConsecutiveBitFields: None
# AlignConsecutiveDeclarations: None
# AlignConsecutiveAssignments:
# Enabled: false
# AcrossEmptyLines: false
# AcrossComments: false
# AlignCompound: false
# PadOperators: true
# AlignConsecutiveBitFields:
# Enabled: false
# AcrossEmptyLines: false
# AcrossComments: false
# AlignCompound: false
# PadOperators: false
# AlignConsecutiveDeclarations:
# Enabled: false
# AcrossEmptyLines: false
# AcrossComments: false
# AlignCompound: false
# PadOperators: false
# AlignConsecutiveMacros:
# Enabled: false
# AcrossEmptyLines: false
# AcrossComments: false
# AlignCompound: false
# PadOperators: false
# AlignConsecutiveShortCaseStatements:
# Enabled: false
# AcrossEmptyLines: false
# AcrossComments: false
# AlignCaseColons: false
# AlignEscapedNewlines: Right
AlignOperands: DontAlign
AlignTrailingComments: false
AlignOperands: DontAlign
AlignTrailingComments:
Kind: Never
OverEmptyLines: 0
# AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
# AllowShortEnumsOnASingleLine: true
# AllowShortBlocksOnASingleLine: Never
# AllowShortCaseLabelsOnASingleLine: false
# AllowShortFunctionsOnASingleLine: All
# AllowShortLambdasOnASingleLine: All
# AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: Inline
# AllowShortIfStatementsOnASingleLine: Never
# AllowShortLambdasOnASingleLine: All
# AllowShortLoopsOnASingleLine: false
# AlwaysBreakAfterDefinitionReturnType: None
# AlwaysBreakAfterReturnType: None
# AlwaysBreakBeforeMultilineStrings: false
# AlwaysBreakTemplateDeclarations: MultiLine
# AttributeMacros:
# - __capability
AttributeMacros:
- _ALWAYS_INLINE_
- _FORCE_INLINE_
- _NO_INLINE_
# BinPackArguments: true
# BinPackParameters: true
# BitFieldColonSpacing: Both
# BraceWrapping:
# AfterCaseLabel: false
# AfterClass: false
# AfterCaseLabel: false
# AfterClass: false
# AfterControlStatement: Never
# AfterEnum: false
# AfterFunction: false
# AfterNamespace: false
# AfterEnum: false
# AfterFunction: false
# AfterNamespace: false
# AfterObjCDeclaration: false
# AfterStruct: false
# AfterUnion: false
# AfterStruct: false
# AfterUnion: false
# AfterExternBlock: false
# BeforeCatch: false
# BeforeElse: false
# BeforeCatch: false
# BeforeElse: false
# BeforeLambdaBody: false
# BeforeWhile: false
# IndentBraces: false
# BeforeWhile: false
# IndentBraces: false
# SplitEmptyFunction: true
# SplitEmptyRecord: true
# SplitEmptyNamespace: true
# BreakAfterAttributes: Never
# BreakAfterJavaFieldAnnotations: false
# BreakArrays: true
# BreakBeforeBinaryOperators: None
# BreakBeforeConceptDeclarations: true
# BreakBeforeBraces: Attach
# BreakBeforeInheritanceComma: false
# BreakInheritanceList: BeforeColon
# BreakBeforeConceptDeclarations: Always
# BreakBeforeInlineASMColon: OnlyMultiline
# BreakBeforeTernaryOperators: true
# BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: AfterColon
# BreakInheritanceList: BeforeColon
# BreakStringLiterals: true
ColumnLimit: 0
# CommentPragmas: '^ IWYU pragma:'
# QualifierAlignment: Leave
ColumnLimit: 0
# CommentPragmas: "^ IWYU pragma:"
# CompactNamespaces: false
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
# DeriveLineEnding: true
# DerivePointerAlignment: false
# DisableFormat: false
# DisableFormat: false
# EmptyLineAfterAccessModifier: Never
# EmptyLineBeforeAccessModifier: LogicalBlock
# ExperimentalAutoDetectBinPacking: false
# PackConstructorInitializers: BinPack
ConstructorInitializerAllOnOneLineOrOnePerLine: true
# AllowAllConstructorInitializersOnNextLine: true
# FixNamespaceComments: true
# ForEachMacros:
# - foreach
@@ -82,34 +107,61 @@ ConstructorInitializerAllOnOneLineOrOnePerLine: true
# - BOOST_FOREACH
# IfMacros:
# - KJ_IF_MAYBE
# IncludeBlocks: Preserve
# IncludeBlocks: Preserve
IncludeCategories:
- Regex: '".*"'
Priority: 1
- Regex: '^<.*\.h>'
Priority: 2
- Regex: '^<.*'
Priority: 3
# IncludeIsMainRegex: '(Test)?$'
# IncludeIsMainSourceRegex: ''
- Regex: ^".*"$
Priority: 1
- Regex: ^<.*\.h>$
Priority: 2
- Regex: ^<.*>$
Priority: 3
# IncludeIsMainRegex: (Test)?$
# IncludeIsMainSourceRegex: ""
# IndentAccessModifiers: false
IndentCaseLabels: true
# IndentCaseBlocks: false
IndentCaseLabels: true
# IndentExternBlock: AfterExternBlock
# IndentGotoLabels: true
# IndentPPDirectives: None
# IndentExternBlock: AfterExternBlock
# IndentRequires: false
IndentWidth: 4
# IndentRequiresClause: true
IndentWidth: 4
# IndentWrappedFunctionNames: false
InsertBraces: true
# InsertNewlineAtEOF: false
# InsertTrailingCommas: None
# IntegerLiteralSeparator:
# Binary: 0
# BinaryMinDigits: 0
# Decimal: 0
# DecimalMinDigits: 0
# Hex: 0
# HexMinDigits: 0
JavaImportGroups:
- org.godotengine
- android
- androidx
- com.android
- com.google
- java
- javax
# JavaScriptQuotes: Leave
# JavaScriptWrapImports: true
# KeepEmptyLinesAtEOF: false
KeepEmptyLinesAtTheStartOfBlocks: false
# LambdaBodyIndentation: Signature
# MacroBlockBegin: ''
# MacroBlockEnd: ''
# Language: Cpp
# LineEnding: DeriveLF
# MacroBlockBegin: ""
# MacroBlockEnd: ""
# MaxEmptyLinesToKeep: 1
# NamespaceIndentation: None
# ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 4
# ObjCBreakBeforeNestedBlockParam: true
# ObjCSpaceAfterProperty: false
# ObjCSpaceBeforeProtocolList: true
# PPIndentWidth: -1
PackConstructorInitializers: NextLine
# PenaltyBreakAssignment: 2
# PenaltyBreakBeforeFirstCallParameter: 19
# PenaltyBreakComment: 300
@@ -118,82 +170,71 @@ KeepEmptyLinesAtTheStartOfBlocks: false
# PenaltyBreakString: 1000
# PenaltyBreakTemplateDeclaration: 10
# PenaltyExcessCharacter: 1000000
# PenaltyReturnTypeOnItsOwnLine: 60
# PenaltyIndentedWhitespace: 0
# PenaltyReturnTypeOnItsOwnLine: 60
# PointerAlignment: Right
# PPIndentWidth: -1
# QualifierAlignment: Leave
# ReferenceAlignment: Pointer
# ReflowComments: true
# ReflowComments: true
# RemoveBracesLLVM: false
# RemoveParentheses: Leave
RemoveSemicolon: true
# RequiresClausePosition: OwnLine
# RequiresExpressionIndentation: OuterScope
# SeparateDefinitionBlocks: Leave
# ShortNamespaceLines: 1
# SortIncludes: CaseSensitive
# SortIncludes: CaseSensitive
# SortJavaStaticImport: Before
# SortUsingDeclarations: true
# SortUsingDeclarations: LexicographicNumeric
# SpaceAfterCStyleCast: false
# SpaceAfterLogicalNot: false
# SpaceAfterTemplateKeyword: true
# SpaceAroundPointerQualifiers: Default
# SpaceBeforeAssignmentOperators: true
# SpaceBeforeCaseColon: false
# SpaceBeforeCpp11BracedList: false
# SpaceBeforeCtorInitializerColon: true
# SpaceBeforeInheritanceColon: true
# SpaceBeforeJsonColon: false
# SpaceBeforeParens: ControlStatements
# SpaceBeforeParensOptions:
# AfterControlStatements: true
# AfterForeachMacros: true
# AfterFunctionDefinitionName: false
# AfterFunctionDeclarationName: false
# AfterIfMacros: true
# AfterFunctionDefinitionName: false
# AfterIfMacros: true
# AfterOverloadedOperator: false
# AfterRequiresInClause: false
# AfterRequiresInExpression: false
# BeforeNonEmptyParentheses: false
# SpaceAroundPointerQualifiers: Default
# SpaceBeforeRangeBasedForLoopColon: true
# SpaceInEmptyBlock: false
# SpaceInEmptyParentheses: false
# SpacesBeforeTrailingComments: 1
# SpacesInAngles: Never
# SpacesInConditionalStatement: false
# SpacesInContainerLiterals: true
# SpacesInCStyleCastParentheses: false
## Godot TODO: We'll want to use a min of 1, but we need to see how to fix
## our comment capitalization at the same time.
SpacesInLineCommentPrefix:
Minimum: 0
Maximum: -1
# SpacesInParentheses: false
# SpacesInSquareBrackets: false
# SpaceBeforeSquareBrackets: false
# BitFieldColonSpacing: Both
# SpaceInEmptyBlock: false
# SpacesBeforeTrailingComments: 1
# SpacesInAngles: Never
# SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 0 # We want a minimum of 1 for comments, but allow 0 for disabled code.
Maximum: -1
# SpacesInParens: Never
# SpacesInParensOptions:
# InConditionalStatements: false
# InCStyleCasts: false
# InEmptyParentheses: false
# Other: false
# SpacesInSquareBrackets: false
Standard: c++20
# StatementAttributeLikeMacros:
# - Q_EMIT
# StatementMacros:
# - Q_UNUSED
# - QT_REQUIRE_VERSION
TabWidth: 4
# UseCRLF: false
UseTab: Always
TabWidth: 4
UseTab: Always
# VerilogBreakBetweenInstancePorts: true
# WhitespaceSensitiveMacros:
# - STRINGIZE
# - PP_STRINGIZE
# - BOOST_PP_STRINGIZE
# - NS_SWIFT_NAME
# - CF_SWIFT_NAME
---
### C++ specific config ###
Language: Cpp
Standard: c++17
---
### ObjC specific config ###
Language: ObjC
# ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 4
# ObjCBreakBeforeNestedBlockParam: true
# ObjCSpaceAfterProperty: false
# ObjCSpaceBeforeProtocolList: true
---
### Java specific config ###
Language: Java
# BreakAfterJavaFieldAnnotations: false
JavaImportGroups: ['org.godotengine', 'android', 'androidx', 'com.android', 'com.google', 'java', 'javax']
...
# - NS_SWIFT_NAME
# - PP_STRINGIZE
# - STRINGIZE

17
.editorconfig Normal file
View File

@@ -0,0 +1,17 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = tab
insert_final_newline = true
max_line_length = 120
trim_trailing_whitespace = true
[{*.py,SConstruct}]
indent_style = space
[{*.{yml,yaml},.clang-format}]
indent_size = 2
indent_style = space

11
.git-blame-ignore-revs Normal file
View File

@@ -0,0 +1,11 @@
# This file contains a list of Git commit hashes that should be hidden from the
# regular Git history. Typically, this includes commits involving mass auto-formatting
# or other normalizations. Commit hashes *must* use the full 40-character notation.
# To apply the ignore list in your local Git client, you must run:
#
# git config blame.ignoreRevsFile .git-blame-ignore-revs
#
# This file is automatically used by GitHub.com's blame view.
# Style: Replace header guards with `#pragma once`
7056c996dd43ae1aa466c94d95cc2fe63853d8a9

8
.gitattributes vendored
View File

@@ -1,6 +1,2 @@
*.c eol=lf
*.cpp eol=lf
*.gd eol=lf
*.tscn eol=lf
*.cfg eol=lf
*.godot eol=lf
# Normalize EOL for all files that Git considers text files
* text=auto eol=lf

71
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,71 @@
name: Bug report
description: Report a bug in the godot-cpp GDExtension/GDNative integration
body:
- type: markdown
attributes:
value: |
- When reporting bugs, you'll make our life simpler (and the fix will come sooner) if you follow the guidelines in this template.
- Write a descriptive issue title above.
- The golden rule is to **always open *one* issue for *one* bug**. If you notice several bugs and want to report them, make sure to create one new issue for each of them.
- Search [open](https://github.com/godotengine/godot-cpp/issues) and [closed](https://github.com/godotengine/godot-cpp/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported. If you don't find a relevant match or if you're unsure, don't hesitate to **open a new issue**. The bugsquad will handle it from there if it's a duplicate.
- Verify that you are using a [supported Godot version](https://docs.godotengine.org/en/latest/about/release_policy.html).
- type: input
attributes:
label: Godot version
description: >
Specify the Git commit hash if using a development or non-official build.
If you use a custom build, please test if your issue is reproducible in official builds too.
placeholder: 3.3.stable, 4.0.dev (3041becc6)
validations:
required: true
- type: input
attributes:
label: godot-cpp version
description: >
Specify the Git commit hash if using a development build.
placeholder: 3.3.stable, 4.0.dev (3041becc6)
validations:
required: true
- type: input
attributes:
label: System information
description: |
- Specify the OS version, and when relevant hardware information.
- For issues that are likely OS-specific and/or graphics-related, please specify the CPU model and architecture.
- **Bug reports not including the required information may be closed at the maintainers' discretion.** If in doubt, always include all the requested information; it's better to include too much information than not enough information.
placeholder: Windows 10, Intel Core i5-7200U
validations:
required: true
- type: textarea
attributes:
label: Issue description
description: |
Describe your issue briefly. What doesn't work, and how do you expect it to work instead?
You can include images or videos with drag and drop, and format code blocks or logs with <code>```</code> tags.
validations:
required: true
- type: textarea
attributes:
label: Steps to reproduce
description: |
List of steps or sample code that reproduces the issue. Having reproducible issues is a prerequisite for contributors to be able to solve them.
If you include a minimal reproduction project below, you can detail how to use it here.
validations:
required: true
- type: textarea
attributes:
label: Minimal reproduction project
description: |
- A small Godot project which reproduces the issue, with no unnecessary files included. Be sure to not include the `.godot` folder in the archive (but keep `project.godot`).
- Required, unless the reproduction steps are trivial and don't require any project files to be followed. In this case, write "N/A" in the field.
- Drag and drop a ZIP archive to upload it. **Do not select another field until the project is done uploading.**
- **If you've been asked by a maintainer to upload a minimal reproduction project, you *must* do so within 7 days.** Otherwise, your bug report will be closed as it'll be considered too difficult to diagnose.
validations:
required: true

14
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,14 @@
blank_issues_enabled: false
contact_links:
- name: Godot proposals
url: https://github.com/godotengine/godot-proposals
about: Please submit feature proposals on the Godot proposals repository, not here.
- name: Godot documentation repository
url: https://github.com/godotengine/godot-docs
about: Please report issues with documentation on the Godot documentation repository, not here.
- name: Godot community channels
url: https://godotengine.org/community
about: Please ask for technical support on one of the other community channels, not here.

View File

@@ -0,0 +1,24 @@
name: Restore Godot build cache
description: Restore Godot build cache.
inputs:
cache-name:
description: The cache base name (job name by default).
default: ${{ github.job }}
scons-cache:
description: The SCons cache path.
default: ${{ github.workspace }}/.scons-cache/
runs:
using: composite
steps:
- name: Restore SCons cache directory
uses: actions/cache/restore@v4
with:
path: ${{ inputs.scons-cache }}
key: ${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}-${{ github.sha }}
restore-keys: |
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}-${{ github.sha }}
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-refs/heads/${{ env.GODOT_BASE_BRANCH }}
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}

View File

@@ -0,0 +1,18 @@
name: Save Godot build cache
description: Save Godot build cache.
inputs:
cache-name:
description: The cache base name (job name by default).
default: ${{ github.job }}
scons-cache:
description: The SCons cache path.
default: ${{ github.workspace }}/.scons-cache/
runs:
using: composite
steps:
- name: Save SCons cache directory
uses: actions/cache/save@v4
with:
path: ${{ inputs.scons-cache }}
key: ${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}-${{ github.sha }}

View File

@@ -1,22 +0,0 @@
name: Setup Godot build cache
description: Setup Godot build cache.
inputs:
cache-name:
description: The cache base name (job name by default).
default: "${{github.job}}"
scons-cache:
description: The scons cache path.
default: "${{github.workspace}}/.scons-cache/"
runs:
using: "composite"
steps:
# Upload cache on completion and check it out now
- name: Load .scons_cache directory
uses: actions/cache@v3
with:
path: ${{inputs.scons-cache}}
key: ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
restore-keys: |
${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}
${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}

View File

@@ -0,0 +1,71 @@
name: Setup godot-cpp
description: Setup build dependencies for godot-cpp.
inputs:
platform:
required: true
description: Target platform.
em-version:
default: 3.1.62
description: Emscripten version.
windows-compiler:
required: true
description: The compiler toolchain to use on Windows ('mingw' or 'msvc').
type: choice
options:
- mingw
- msvc
default: mingw
mingw-version:
default: 12.2.0
description: MinGW version.
ndk-version:
default: r23c
description: Android NDK version.
buildtool:
default: scons
description: scons or cmake
scons-version:
default: 4.4.0
description: SCons version.
runs:
using: composite
steps:
- name: Setup Python (for SCons)
uses: actions/setup-python@v5
with:
python-version: 3.x
- name: Setup Android dependencies
if: inputs.platform == 'android'
uses: nttld/setup-ndk@v1
with:
ndk-version: ${{ inputs.ndk-version }}
link-to-sdk: true
- name: Setup Web dependencies
if: inputs.platform == 'web'
uses: mymindstorm/setup-emsdk@v14
with:
version: ${{ inputs.em-version }}
no-cache: true
- name: Setup MinGW for Windows/MinGW build
if: inputs.platform == 'windows' && inputs.windows-compiler == 'mingw'
uses: egor-tensin/setup-mingw@v2
with:
version: ${{ inputs.mingw-version }}
- name: Setup SCons
if: ${{ inputs.buildtool == 'scons' }}
shell: bash
run: |
python -c "import sys; print(sys.version)"
python -m pip install scons==${{ inputs.scons-version }}
scons --version
- name: Install Ninja
if: ${{ inputs.buildtool == 'cmake' }}
uses: ashutoshvarma/setup-ninja@master

186
.github/workflows/ci-cmake.yml vendored Normal file
View File

@@ -0,0 +1,186 @@
name: Continuous integration
on:
workflow_call:
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: master
# Use UTF-8 on Linux.
LANG: en_US.UTF-8
LC_ALL: en_US.UTF-8
concurrency:
group: ci-cmake-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build-cmake:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
env:
EM_VERSION: 3.1.39
config-flags:
-DCMAKE_C_COMPILER_LAUNCHER=sccache
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache
-DGODOTCPP_ENABLE_TESTING=ON
-DGODOTCPP_BUILD_PROFILE="test/build_profile.json"
SCCACHE_GHA_ENABLED: "true"
strategy:
fail-fast: false
matrix:
include:
- name: 🐧 Linux (GCC, Makefiles)
os: ubuntu-22.04
platform: linux
config-flags: -DCMAKE_BUILD_TYPE=Release
artifact-name: godot-cpp-linux-glibc2.27-x86_64-release.cmake
artifact-path: cmake-build/bin/libgodot-cpp.linux.template_release.x86_64.a
run-tests: true
- name: 🏁 Windows (x86_64, MSVC)
os: windows-2022
platform: windows
compiler: msvc
build-flags: --config Release
artifact-name: godot-cpp-windows-msvc2019-x86_64-release.cmake
artifact-path: cmake-build/bin/libgodot-cpp.windows.template_release.x86_64.lib
run-tests: false
- name: 🏁 Windows (x86_64, MinGW, Ninja)
os: windows-2022
platform: windows
compiler: mingw
config-flags:
-GNinja -DCMAKE_BUILD_TYPE=Release
-DCMAKE_CXX_COMPILER=cc -DCMAKE_CXX_COMPILER=c++
artifact-name: godot-cpp-linux-mingw-x86_64-release.cmake
artifact-path: cmake-build/bin/libgodot-cpp.windows.template_release.x86_64.a
run-tests: false
- name: 🍎 macOS (universal, Makefiles)
os: macos-latest
platform: macos
config-flags: -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64"
artifact-name: godot-cpp-macos-universal-release.cmake
artifact-path: cmake-build/bin/libgodot-cpp.macos.template_release.universal.a
run-tests: false
- name: 🤖 Android (arm64, Ninja)
os: ubuntu-22.04
platform: android
config-flags:
-G Ninja -DCMAKE_BUILD_TYPE=Release
--toolchain ${ANDROID_HOME}/ndk/23.2.8568313/build/cmake/android.toolchain.cmake
-DANDROID_PLATFORM=21 -DANDROID_ABI=arm64-v8a
artifact-name: godot-cpp-android-arm64-release.cmake
artifact-path: cmake-build/bin/libgodot-cpp.android.template_release.arm64.a
flags: arch=arm64
run-tests: false
- name: 🍏 iOS (arm64, XCode)
os: macos-latest
platform: ios
config-flags:
-G Xcode
--toolchain cmake/ios.toolchain.cmake
-DPLATFORM=OS64
build-flags: --config Release
artifact-name: godot-cpp-ios-arm64-release.cmake
artifact-path: cmake-build/bin/libgodot-cpp.ios.template_release.arm64.a
flags: arch=arm64
run-tests: false
- name: 🌐 Web (wasm32, Ninja)
os: ubuntu-22.04
platform: web
config-flags:
-G Ninja -DCMAKE_BUILD_TYPE=Release
--toolchain ${EMSDK}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake
artifact-name: godot-cpp-web-wasm32-release.cmake
artifact-path: cmake-build/bin/libgodot-cpp.web.template_release.wasm32.a
run-tests: false
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Run sccache-cache
uses: mozilla-actions/sccache-action@v0.0.9
- name: Setup godot-cpp
uses: ./.github/actions/setup-godot-cpp
with:
platform: ${{ matrix.platform }}
windows-compiler: ${{ matrix.compiler }}
buildtool: cmake
- name: Configure godot-cpp-test with template_debug
run: >
cmake --log-level=VERBOSE -S . -B cmake-build ${{ env.config-flags }} ${{ matrix.config-flags }}
- name: Build godot-cpp-test (template_debug)
run: >
cmake --build cmake-build --verbose --target godot-cpp-test ${{ matrix.build-flags }}
- name: Configure godot-cpp-test with template_release
run: >
cmake --fresh --log-level=VERBOSE -S . -B cmake-build
-DGODOTCPP_TARGET=template_release ${{ env.config-flags }} ${{ matrix.config-flags }}
- name: Build godot-cpp-test (template_release)
run: >
cmake --build cmake-build --verbose --target godot-cpp-test ${{ matrix.build-flags }}
- name: Run sccache stat for check
shell: bash
run: ${SCCACHE_PATH} --show-stats
- name: Download latest Godot artifacts
uses: dsnopek/action-download-artifact@1322f74e2dac9feed2ee76a32d9ae1ca3b4cf4e9
if: matrix.run-tests && env.GODOT_TEST_VERSION == 'master'
with:
repo: godotengine/godot
branch: master
event: push
workflow: linux_builds.yml
workflow_conclusion: success
name: linux-editor-mono
search_artifacts: true
check_artifacts: true
ensure_latest: true
path: godot-artifacts
- name: Prepare Godot artifacts for testing
if: matrix.run-tests && env.GODOT_TEST_VERSION == 'master'
run: |
chmod +x ./godot-artifacts/godot.linuxbsd.editor.x86_64.mono
echo "GODOT=$(pwd)/godot-artifacts/godot.linuxbsd.editor.x86_64.mono" >> $GITHUB_ENV
- name: Download requested Godot version for testing
if: matrix.run-tests && env.GODOT_TEST_VERSION != 'master'
run: |
wget "https://github.com/godotengine/godot-builds/releases/download/${GODOT_TEST_VERSION}/Godot_v${GODOT_TEST_VERSION}_linux.x86_64.zip" -O Godot.zip
unzip -a Godot.zip
chmod +x "Godot_v${GODOT_TEST_VERSION}_linux.x86_64"
echo "GODOT=$(pwd)/Godot_v${GODOT_TEST_VERSION}_linux.x86_64" >> $GITHUB_ENV
- name: Run tests
if: matrix.run-tests
run: |
$GODOT --headless --version
cd test
# Need to run the editor so .godot is generated... but it crashes! Ignore that :-)
(cd project && (timeout 30 $GODOT --import --headless >/dev/null 2>&1 || true))
./run-tests.sh
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.artifact-name }}
path: ${{ matrix.artifact-path }}
if-no-files-found: error

179
.github/workflows/ci-scons.yml vendored Normal file
View File

@@ -0,0 +1,179 @@
name: Continuous integration
on:
workflow_call:
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: master
# Use UTF-8 on Linux.
LANG: en_US.UTF-8
LC_ALL: en_US.UTF-8
# Use UTF-8 on Windows.
PYTHONIOENCODING: utf8
concurrency:
group: ci-scons-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build-scons:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- name: 🐧 Linux (GCC)
os: ubuntu-22.04
platform: linux
artifact-name: godot-cpp-linux-glibc2.27-x86_64-release
artifact-path: bin/libgodot-cpp.linux.template_release.x86_64.a
run-tests: true
cache-name: linux-x86_64
- name: 🏁 Windows (x86_64, MSVC)
os: windows-2022
platform: windows
artifact-name: godot-cpp-windows-msvc2019-x86_64-release
artifact-path: bin/libgodot-cpp.windows.template_release.x86_64.lib
run-tests: false
cache-name: windows-x86_64-msvc
- name: 🏁 Windows (x86_64, MinGW)
os: windows-2022
platform: windows
artifact-name: godot-cpp-linux-mingw-x86_64-release
artifact-path: bin/libgodot-cpp.windows.template_release.x86_64.a
flags: use_mingw=yes
run-tests: false
cache-name: windows-x86_64-mingw
- name: 🍎 macOS (universal)
os: macos-latest
platform: macos
artifact-name: godot-cpp-macos-universal-release
artifact-path: bin/libgodot-cpp.macos.template_release.universal.a
flags: arch=universal
run-tests: false
cache-name: macos-universal
- name: 🤖 Android (arm64)
os: ubuntu-22.04
platform: android
artifact-name: godot-cpp-android-arm64-release
artifact-path: bin/libgodot-cpp.android.template_release.arm64.a
flags: arch=arm64
run-tests: false
cache-name: android-arm64
- name: 🍏 iOS (arm64)
os: macos-latest
platform: ios
artifact-name: godot-cpp-ios-arm64-release
artifact-path: bin/libgodot-cpp.ios.template_release.arm64.a
flags: arch=arm64
run-tests: false
cache-name: ios-arm64
- name: 🌐 Web (wasm32)
os: ubuntu-22.04
platform: web
artifact-name: godot-cpp-web-wasm32-release
artifact-path: bin/libgodot-cpp.web.template_release.wasm32.a
run-tests: false
cache-name: web-wasm32
env:
SCONS_CACHE: ${{ github.workspace }}/.scons-cache/
EM_VERSION: 3.1.39
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Restore Godot build cache
uses: ./.github/actions/godot-cache-restore
with:
cache-name: ${{ matrix.cache-name }}
continue-on-error: true
- name: Setup godot-cpp
uses: ./.github/actions/setup-godot-cpp
with:
platform: ${{ matrix.platform }}
windows-compiler: ${{ contains(matrix.flags, 'use_mingw=yes') && 'mingw' || 'msvc' }}
buildtool: scons
- name: Generate godot-cpp sources only
run: |
scons platform=${{ matrix.platform }} verbose=yes build_library=no ${{ matrix.flags }}
scons -c
- name: Build godot-cpp (debug)
run: |
scons platform=${{ matrix.platform }} verbose=yes target=template_debug ${{ matrix.flags }}
- name: Build test without rebuilding godot-cpp (debug)
run: |
cd test
scons platform=${{ matrix.platform }} verbose=yes target=template_debug ${{ matrix.flags }} build_library=no
- name: Build test and godot-cpp (release)
run: |
cd test
scons platform=${{ matrix.platform }} verbose=yes target=template_release ${{ matrix.flags }}
- name: Save Godot build cache
uses: ./.github/actions/godot-cache-save
with:
cache-name: ${{ matrix.cache-name }}
continue-on-error: true
- name: Download latest Godot artifacts
uses: dsnopek/action-download-artifact@1322f74e2dac9feed2ee76a32d9ae1ca3b4cf4e9
if: matrix.run-tests && env.GODOT_TEST_VERSION == 'master'
with:
repo: godotengine/godot
branch: master
event: push
workflow: linux_builds.yml
workflow_conclusion: success
name: linux-editor-mono
search_artifacts: true
check_artifacts: true
ensure_latest: true
path: godot-artifacts
- name: Prepare Godot artifacts for testing
if: matrix.run-tests && env.GODOT_TEST_VERSION == 'master'
run: |
chmod +x ./godot-artifacts/godot.linuxbsd.editor.x86_64.mono
echo "GODOT=$(pwd)/godot-artifacts/godot.linuxbsd.editor.x86_64.mono" >> $GITHUB_ENV
- name: Download requested Godot version for testing
if: matrix.run-tests && env.GODOT_TEST_VERSION != 'master'
run: |
wget "https://github.com/godotengine/godot-builds/releases/download/${GODOT_TEST_VERSION}/Godot_v${GODOT_TEST_VERSION}_linux.x86_64.zip" -O Godot.zip
unzip -a Godot.zip
chmod +x "Godot_v${GODOT_TEST_VERSION}_linux.x86_64"
echo "GODOT=$(pwd)/Godot_v${GODOT_TEST_VERSION}_linux.x86_64" >> $GITHUB_ENV
- name: Run tests
if: matrix.run-tests
run: |
$GODOT --headless --version
cd test
# Need to run the editor so .godot is generated... but it crashes! Ignore that :-)
(cd project && (timeout 30 $GODOT --import --headless >/dev/null 2>&1 || true))
./run-tests.sh
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.artifact-name }}
path: ${{ matrix.artifact-path }}
if-no-files-found: error

View File

@@ -1,199 +0,0 @@
name: Continuous integration
on: [push, pull_request]
env:
# Only used for the cache key. Increment version to force clean build.
GODOT_BASE_BRANCH: master
concurrency:
group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}
cancel-in-progress: true
jobs:
build:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- name: 🐧 Linux (GCC)
os: ubuntu-20.04
platform: linux
artifact-name: godot-cpp-linux-glibc2.27-x86_64-release
artifact-path: bin/libgodot-cpp.linux.template_release.x86_64.a
cache-name: linux-x86_64
- name: 🐧 Linux (GCC, Double Precision)
os: ubuntu-20.04
platform: linux
artifact-name: godot-cpp-linux-glibc2.27-x86_64-double-release
artifact-path: bin/libgodot-cpp.linux.template_release.double.x86_64.a
flags: precision=double
cache-name: linux-x86_64-f64
- name: 🏁 Windows (x86_64, MSVC)
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
cache-name: windows-x86_64-msvc
- name: 🏁 Windows (x86_64, MinGW)
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
flags: use_mingw=yes
cache-name: windows-x86_64-mingw
- name: 🍎 macOS (universal)
os: macos-11
platform: macos
artifact-name: godot-cpp-macos-universal-release
artifact-path: bin/libgodot-cpp.macos.template_release.universal.a
flags: arch=universal
cache-name: macos-universal
- name: 🤖 Android (arm64)
os: ubuntu-20.04
platform: android
artifact-name: godot-cpp-android-arm64-release
artifact-path: bin/libgodot-cpp.android.template_release.arm64.a
flags: ANDROID_NDK_ROOT=$ANDROID_NDK_LATEST_HOME arch=arm64
cache-name: android-arm64
- name: 🍏 iOS (arm64)
os: macos-11
platform: ios
artifact-name: godot-cpp-ios-arm64-release
artifact-path: bin/libgodot-cpp.ios.template_release.arm64.a
flags: arch=arm64
cache-name: ios-arm64
env:
SCONS_CACHE: ${{ github.workspace }}/.scons-cache/
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: recursive
- name: Setup Godot build cache
uses: ./.github/actions/godot-cache
with:
cache-name: ${{ matrix.cache-name }}
continue-on-error: true
- name: Set up Python (for SCons)
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Linux dependencies
if: ${{ matrix.platform == 'linux' }}
run: |
sudo apt-get update -qq
sudo apt-get install -qqq build-essential pkg-config
- name: Install scons
run: |
python -m pip install scons==4.0.0
- name: Setup MinGW for Windows/MinGW build
if: ${{ matrix.platform == 'windows' && matrix.flags == 'use_mingw=yes' }}
uses: egor-tensin/setup-mingw@v2
- name: Generate godot-cpp sources only
run: |
scons platform=${{ matrix.platform }} build_library=no ${{ matrix.flags }}
scons -c
- name: Build godot-cpp (debug)
run: |
scons platform=${{ matrix.platform }} target=template_debug ${{ matrix.flags }}
- name: Build test without rebuilding godot-cpp (debug)
run: |
cd test
scons platform=${{ matrix.platform }} target=template_debug ${{ matrix.flags }} build_library=no
- name: Build test and godot-cpp (release)
run: |
cd test
scons platform=${{ matrix.platform }} target=template_release ${{ matrix.flags }}
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.artifact-name }}
path: ${{ matrix.artifact-path }}
if-no-files-found: error
linux-cmake:
name: 🐧 Build (Linux, GCC, CMake)
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v3
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-20.04
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: recursive
- name: Install dependencies
run: |
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
windows-msvc-cmake:
name: 🏁 Build (Windows, MSVC, CMake)
runs-on: windows-2019
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: recursive
- name: Build godot-cpp
run: |
cmake -DCMAKE_BUILD_TYPE=Release -G"Visual Studio 16 2019" .
cmake --build . --verbose
- name: Build test GDExtension library
run: |
cd test && cmake -DCMAKE_BUILD_TYPE=Release -DGODOT_HEADERS_PATH="../godot-headers" -DCPP_BINDINGS_PATH=".." -G"Visual Studio 16 2019" .
cmake --build . --verbose

66
.github/workflows/runner.yml vendored Normal file
View File

@@ -0,0 +1,66 @@
name: 🔗 GHA
on: [push, pull_request, merge_group]
concurrency:
group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-runner
cancel-in-progress: true
jobs:
# First stage: Only static checks, fast and prevent expensive builds from running.
static-checks:
name: 📊 Static Checks
if: '!vars.DISABLE_GODOT_CI'
uses: ./.github/workflows/static_checks.yml
# Second stage: Review code changes
changes:
name: Analyze Changes
needs: static-checks
runs-on: ubuntu-latest
outputs:
sources: ${{ steps.filter.outputs.sources_any_changed }}
scons: ${{ steps.filter.outputs.scons_any_changed }}
cmake: ${{ steps.filter.outputs.cmake_any_changed }}
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: tj-actions/changed-files@v45
id: filter
with:
files_yaml: |
sources:
- '.github/workflows/*.yml'
- '**/*.py'
- '**/*.cpp'
- '**/*.hpp'
- '**/*.h'
- '**/*.inc'
- 'test/build_profile.json'
- 'gdextension/extension_api.json'
scons:
- '**/SConstruct'
- '**/SCsub'
cmake:
- '**/CMakeLists.txt'
- '**/*.cmake'
- name: echo sources changed
run: |
echo sources ${{ steps.filter.outputs.sources_any_modified }}
echo scons ${{ steps.filter.outputs.scons_any_modified }}
echo cmake ${{ steps.filter.outputs.cmake_any_modified }}
# Third stage: Run all the builds and some of the tests.
ci-scons:
name: 🛠️ SCons CI
needs: changes
if: ${{ needs.changes.outputs.scons == 'true' || needs.changes.outputs.sources == 'true' }}
uses: ./.github/workflows/ci-scons.yml
ci-cmake:
name: 🛠️ CMake CI
needs: changes
if: ${{ needs.changes.outputs.cmake == 'true' || needs.changes.outputs.sources == 'true' }}
uses: ./.github/workflows/ci-cmake.yml

View File

@@ -1,54 +1,30 @@
name: 📊 Static Checks
on: [push, pull_request]
on:
workflow_call:
concurrency:
group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-static
group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-static
cancel-in-progress: true
jobs:
static-checks:
name: Format (clang-format, black format, file format)
runs-on: ubuntu-20.04
name: Format (clang-format, ruff format, file format)
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 2
# Azure repositories are not reliable, we need to prevent Azure giving us packages.
- name: Make apt sources.list use the default Ubuntu repositories
run: |
sudo rm -f /etc/apt/sources.list.d/*
sudo cp -f misc/ci/sources.list /etc/apt/sources.list
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-15 main"
sudo apt-get update
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v45
- name: Install dependencies
run: |
sudo apt-get install -qq dos2unix recode clang-format-15 libxml2-utils python3-pip moreutils
sudo update-alternatives --remove-all clang-format || true
sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-15 100
sudo pip3 install black==22.3.0 pygments pytest==7.1.2 mypy==0.971
- name: Style checks via pre-commit
uses: pre-commit/action@v3.0.1
with:
extra_args: --verbose --hook-stage manual --files ${{ steps.changed-files.outputs.all_changed_files }}
- name: File formatting checks (file_format.sh)
run: |
bash ./misc/scripts/file_format.sh
- name: Header guards formatting checks (header_guards.sh)
run: |
bash ./misc/scripts/header_guards.sh
- name: Python style checks via black (black_format.sh)
run: |
bash ./misc/scripts/black_format.sh
- name: Python scripts static analysis (mypy_check.sh)
run: |
bash ./misc/scripts/mypy_check.sh
- name: Bindings generation checks (ensures get_file_list returns all generated files)
run: |
python ./misc/scripts/check_get_file_list.py
- name: Style checks via clang-format (clang_format.sh)
run: |
bash ./misc/scripts/clang_format.sh
- name: Check generated files consistency
run:
python misc/scripts/check_get_file_list.py

15
.gitignore vendored
View File

@@ -8,7 +8,7 @@
include/gen
src/gen
# Build configuarion.
# Build configuration.
/custom.py
# Misc
@@ -100,7 +100,7 @@ AppPackages/
# Others
sql/
*.Cache
*.[Cc]ache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
@@ -191,3 +191,14 @@ godot.creator.*
# compile commands (https://clang.llvm.org/docs/JSONCompilationDatabase.html)
compile_commands.json
# Python development
.venv
venv
# Clion Configuration
.idea/
cmake-build*/
# CMake related
CMakeUserPresets.json

74
.pre-commit-config.yaml Normal file
View File

@@ -0,0 +1,74 @@
default_language_version:
python: python3
exclude: |
(?x)^(
gdextension/extension_api\.json|
gdextension/gdextension_interface\.h
)$
repos:
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v20.1.0
hooks:
- id: clang-format
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.4
hooks:
- id: ruff
args: [--fix]
files: (\.py|SConstruct)$
types_or: [text]
- id: ruff-format
files: (\.py|SConstruct)$
types_or: [text]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.14.1 # Latest version that supports Python 3.8
hooks:
- id: mypy
files: \.py$
types_or: [text]
- repo: https://github.com/codespell-project/codespell
rev: v2.4.1
hooks:
- id: codespell
additional_dependencies: [tomli]
- repo: https://github.com/BlankSpruce/gersemi
rev: 0.19.2
hooks:
- id: gersemi
args: ["-i", "--no-warn-about-unknown-commands", "-l", "120"]
- repo: local
hooks:
- id: copyright-headers
name: copyright-headers
language: python
entry: python misc/scripts/copyright_headers.py
files: \.(c|h)pp$
exclude: ^test/
- id: header-guards
name: header-guards
language: python
entry: python misc/scripts/header_guards.py
files: \.hpp$
exclude: ^test/
- id: file-format
name: file-format
language: python
entry: python misc/scripts/file_format.py
types_or: [text]
- id: check-get-file-list
name: check-get-file-list
language: python
entry: python misc/scripts/check_get_file_list.py
pass_filenames: false
always_run: true
stages: [manual]

View File

@@ -1,212 +1,75 @@
# 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_CPP_SYSTEM_HEADERS Mark the header files as SYSTEM. This may be useful to supress warnings in projects including this one.
# GODOT_CPP_WARNING_AS_ERROR Treat any warnings as errors
# GODOT_CUSTOM_API_FILE: Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`)
# FLOAT_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
#
# Builds a debug version:
# cmake .
# cmake --build .
#
# Builds a release version with clang
# 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:
# 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:
# mkdir build && cd build && cmake -G "Unix Makefiles" .. && cmake --build .
#
# Todo
# Test build for Windows, Mac and mingw.
cmake_minimum_required(VERSION 3.10...3.17)
project(godot-cpp LANGUAGES CXX)
cmake_minimum_required(VERSION 3.12)
#[=======================================================================[.rst:
option(GENERATE_TEMPLATE_GET_NODE "Generate a template version of the Node class's get_node." ON)
option(GODOT_CPP_SYSTEM_HEADERS "Expose headers as SYSTEM." ON)
option(GODOT_CPP_WARNING_AS_ERROR "Treat warnings as errors" OFF)
CMake Version requirements
--------------------------
# Add path to modules
list( APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" )
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
# Check if we are building ourself or being included
if(${PROJECT_NAME} STREQUAL ${CMAKE_PROJECT_NAME})
set(GODOT_CPP_BUILDING_SELF ON)
For more information check cmake/emsdkHack.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.
Where they are not, we will attempt to document common difference in
the docs (https://docs.godotengine.org/en/latest/tutorials/scripting/cpp/build_system/cmake.html)
and platform specific differences in their respective
cmake/<platform>.cmake file.
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 matched by the cmake/godotcpp.cmake file
.. highlight:: python
cpp_tool = Tool("godotcpp", toolpath=["tools"])
cpp_tool.options(opts, env)
The CMake equivalent is below.
]=======================================================================]
include(cmake/godotcpp.cmake)
godotcpp_options()
#[[ People are compiling godot by itself and expecting template_debug
Replace this with PROJECT_IS_TOP_LEVEL, <PROJECT-NAME>_IS_TOP_LEVEL when minimum reaches 3.21
]]
if(NOT PROJECT_NAME)
set(GODOTCPP_IS_TOP_LEVEL ON)
endif()
# 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>" )
# Default build type is Debug in the SConstruct
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
set(CMAKE_BUILD_TYPE Debug)
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()
# Input from user for GDExtension interface header and the API JSON file
set(GODOT_GDEXTENSION_DIR "gdextension" CACHE STRING "")
set(GODOT_CUSTOM_API_FILE "" CACHE STRING "")
set(FLOAT_PRECISION "single" CACHE STRING "")
if ("${FLOAT_PRECISION}" STREQUAL "double")
add_definitions(-DREAL_T_IS_DOUBLE)
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()
set(GODOT_COMPILE_FLAGS )
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# using Visual Studio C++
set(GODOT_COMPILE_FLAGS "/EHsc") # /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
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)
add_definitions(-DNOMINMAX)
else() # GCC/Clang
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -g")
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()
# Generate source from the bindings file
find_package(Python3 3.4 REQUIRED) # pathlib should be present
if(GENERATE_TEMPLATE_GET_NODE)
set(GENERATE_BINDING_PARAMETERS "True")
else()
set(GENERATE_BINDING_PARAMETERS "False")
endif()
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
# 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
)
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}\", \"${FLOAT_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"
)
compiler_detection()
godotcpp_generate()
# Get Sources
file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS src/*.c**)
file(GLOB_RECURSE HEADERS CONFIGURE_DEPENDS include/*.h**)
# Define our godot-cpp library
add_library(${PROJECT_NAME} STATIC
${SOURCES}
${HEADERS}
${GENERATED_FILES_LIST}
)
add_library(godot::cpp ALIAS ${PROJECT_NAME})
include(GodotCompilerWarnings)
# Treat warnings as errors if we are building ourself
if(GODOT_CPP_BUILDING_SELF)
unset( GODOT_CPP_WARNING_AS_ERROR CACHE )
set_warning_as_error()
# Conditionally enable the godot-cpp.test.<target> integration testing targets
if(GODOTCPP_ENABLE_TESTING)
add_subdirectory(test)
endif()
target_compile_features(${PROJECT_NAME}
PRIVATE
cxx_std_17
)
target_compile_definitions(${PROJECT_NAME} PUBLIC
$<$<CONFIG:Debug>:
DEBUG_ENABLED
DEBUG_METHODS_ENABLED
>
$<${compiler_is_msvc}:
TYPED_METHOD_BIND
>
)
target_link_options(${PROJECT_NAME} PRIVATE
$<$<NOT:${compiler_is_msvc}>:
-static-libgcc
-static-libstdc++
-Wl,-R,'$$ORIGIN'
>
)
# Optionally mark headers as SYSTEM
set(GODOT_CPP_SYSTEM_HEADERS_ATTRIBUTE "")
if (GODOT_CPP_SYSTEM_HEADERS)
set(GODOT_CPP_SYSTEM_HEADERS_ATTRIBUTE SYSTEM)
endif ()
target_include_directories(${PROJECT_NAME} ${GODOT_CPP_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC
include
${CMAKE_CURRENT_BINARY_DIR}/gen/include
${GODOT_GDEXTENSION_DIR}
)
# Add the compile flags
set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY COMPILE_FLAGS ${GODOT_COMPILE_FLAGS})
# Create the correct name (godot.os.build_type.system_bits)
string(TOLOWER "${CMAKE_SYSTEM_NAME}" SYSTEM_NAME)
string(TOLOWER "${CMAKE_BUILD_TYPE}" BUILD_TYPE)
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}")
endif()
set_target_properties(${PROJECT_NAME}
PROPERTIES
CXX_EXTENSIONS OFF
POSITION_INDEPENDENT_CODE ON
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}"
)
#[[ If this is the top level CMakeLists.txt, Generators which honor the
USE_FOLDERS flag will organize godot-cpp targets under a subfolder named
'godot-cpp'. This is enable by default from CMake version 3.26 ]]
set_property(GLOBAL PROPERTY USE_FOLDERS ON)

View File

@@ -1,9 +1,20 @@
# godot-cpp
> **Warning**
> [!WARNING]
>
> This repository's `master` branch is only usable with Godot's ([GDExtension](https://godotengine.org/article/introducing-gd-extensions))
> API (Godot 4.0 and later).
> This repository's `master` branch is only usable with
> [GDExtension](https://godotengine.org/article/introducing-gd-extensions)
> from Godot's `master` branch.
>
> For users of stable branches, switch to the branch matching your target Godot version:
> - [`4.5`](https://github.com/godotengine/godot-cpp/tree/4.5)
> - [`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)
>
> Or check out the Git tag matching your Godot version (e.g. `godot-4.1.1-stable`).
>
> For GDNative users (Godot 3.x), switch to the [`3.x`](https://github.com/godotengine/godot-cpp/tree/3.x)
> or the [`3.5`](https://github.com/godotengine/godot-cpp/tree/3.5) branch.
@@ -14,7 +25,7 @@ This repository contains the *C++ bindings* for the [**Godot Engine**](https://
- [**Compatibility**](#compatibility)
- [**Contributing**](#contributing)
- [**Getting started**](#getting-started)
- [**Included example**](#included-example)
- [**Examples and templates**](#examples-and-templates)
## Versioning
@@ -41,31 +52,25 @@ Godot version.**
## Compatibility
**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.
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.
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
[issue tracker](https://github.com/godotengine/godot/issues) for a list of known
issues, and be sure to provide feedback on issues and PRs which affect your use
of this extension.
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).
## Contributing
We greatly appreciate help in maintaining and extending this project. If you
wish to help out, ensure you have an account on GitHub and create a "fork" of
this repository. See [Pull request workflow](https://docs.godotengine.org/en/stable/community/contributing/pr_workflow.html)
for instructions.
Please install clang-format and copy the files in `misc/hooks` into `.git/hooks`
so formatting is done before your changes are submitted.
wish to help out, please visit the [godot-cpp section of the Contributing docs](https://contributing.godotengine.org/en/latest/other/godot-cpp.html).
## Getting started
It's a bit similar to what it was for 3.x but also a bit different.
You need the same C++ pre-requisites installed that are required for the `godot` repository. Follow the [official build instructions for your target platform](https://docs.godotengine.org/en/latest/engine_details/development/compiling/index.html).
Getting started with GDExtensions is a bit similar to what it was for 3.x but also a bit different.
This new approach is much more akin to how core Godot modules are structured.
Compiling this repository generates a static library to be linked with your shared lib,
@@ -73,21 +78,22 @@ just like before.
To use the shared lib in your Godot project you'll need a `.gdextension`
file, which replaces what was the `.gdnlib` before.
Follow [the example](test/demo/example.gdextension):
See [example.gdextension](test/project/example.gdextension) used in the test project:
```ini
[configuration]
entry_symbol = "example_library_init"
compatibility_minimum = "4.1"
[libraries]
macos.debug = "bin/libgdexample.macos.debug.framework"
macos.release = "bin/libgdexample.macos.release.framework"
windows.debug.x86_64 = "bin/libgdexample.windows.debug.x86_64.dll"
windows.release.x86_64 = "bin/libgdexample.windows.release.x86_64.dll"
linux.debug.x86_64 = "bin/libgdexample.linux.debug.x86_64.so"
linux.release.x86_64 = "bin/libgdexample.linux.release.x86_64.so"
macos.debug = "res://bin/libgdexample.macos.debug.framework"
macos.release = "res://bin/libgdexample.macos.release.framework"
windows.debug.x86_64 = "res://bin/libgdexample.windows.debug.x86_64.dll"
windows.release.x86_64 = "res://bin/libgdexample.windows.release.x86_64.dll"
linux.debug.x86_64 = "res://bin/libgdexample.linux.debug.x86_64.so"
linux.release.x86_64 = "res://bin/libgdexample.linux.release.x86_64.so"
# Repeat for other architectures to support arm64, rv64, etc.
```
@@ -99,8 +105,8 @@ extern "C" {
// Initialization.
GDExtensionBool GDE_EXPORT example_library_init(const GDExtensionInterface *p_interface, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
godot::GDExtensionBinding::InitObject init_obj(p_interface, p_library, r_initialization);
GDExtensionBool GDE_EXPORT example_library_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
godot::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization);
init_obj.register_initializer(initialize_example_module);
init_obj.register_terminator(uninitialize_example_module);
@@ -119,12 +125,16 @@ void initialize_example_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
ClassDB::register_class<Example>();
GDREGISTER_CLASS(Example);
}
```
Any node and resource you register will be available in the corresponding `Create...` dialog. Any class will be available to scripting as well.
## Included example
## Examples and templates
Check the project in the `test` folder for an example on how to use and register different things.
See the [godot-cpp-template](https://github.com/godotengine/godot-cpp-template) project for a
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).

View File

@@ -1,80 +1,30 @@
#!/usr/bin/env python
import os
import platform
import sys
import subprocess
from binding_generator import scons_generate_bindings, scons_emit_files
from SCons.Errors import UserError
# Add godot-cpp folder to sys.path, so that we can import local modules.
sys.path.append(Dir(".").srcnode().abspath)
EnsureSConsVersion(4, 0)
EnsurePythonVersion(3, 8)
try:
Import("env")
except Exception:
# Default tools with no platform defaults to gnu toolchain.
# We apply platform specific toolchains via our custom tools.
env = Environment(tools=["default"], PLATFORM="")
def add_sources(sources, dir, extension):
for f in os.listdir(dir):
if f.endswith("." + extension):
sources.append(dir + "/" + f)
def normalize_path(val):
return val if os.path.isabs(val) else os.path.join(env.Dir("#").abspath, val)
def validate_api_file(key, val, env):
if not os.path.isfile(normalize_path(val)):
raise UserError("GDExtension API file ('%s') does not exist: %s" % (key, val))
def validate_gdextension_dir(key, val, env):
if not os.path.isdir(normalize_path(val)):
raise UserError("GDExtension directory ('%s') does not exist: %s" % (key, val))
def get_gdextension_dir(env):
return normalize_path(env.get("gdextension_dir", env.Dir("gdextension").abspath))
def get_api_file(env):
return normalize_path(env.get("custom_api_file", os.path.join(get_gdextension_dir(env), "extension_api.json")))
# Try to detect the host platform automatically.
# This is used if no `platform` argument is passed
if sys.platform.startswith("linux"):
default_platform = "linux"
elif sys.platform == "darwin":
default_platform = "macos"
elif sys.platform == "win32" or sys.platform == "msys":
default_platform = "windows"
elif ARGUMENTS.get("platform", ""):
default_platform = ARGUMENTS.get("platform")
else:
raise ValueError("Could not detect platform automatically, please specify with platform=<platform>")
# Default tools with no platform defaults to gnu toolchain.
# We apply platform specific toolchains via our custom tools.
env = Environment(tools=["default"], PLATFORM="")
# 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.
initial_num_jobs = env.GetOption("num_jobs")
altered_num_jobs = initial_num_jobs + 1
env.SetOption("num_jobs", altered_num_jobs)
if env.GetOption("num_jobs") == altered_num_jobs:
cpu_count = os.cpu_count()
if cpu_count is None:
print("Couldn't auto-detect CPU count to configure build parallelism. Specify it with the -j argument.")
else:
safer_cpu_count = cpu_count if cpu_count <= 4 else cpu_count - 1
print(
"Auto-detected %d CPU cores available for build parallelism. Using %d cores by default. You can override it with the -j argument."
% (cpu_count, safer_cpu_count)
)
env.SetOption("num_jobs", safer_cpu_count)
env.PrependENVPath("PATH", os.getenv("PATH"))
# Custom options and profile flags.
customs = ["custom.py"]
try:
customs += Import("customs")
except Exception:
pass
profile = ARGUMENTS.get("profile", "")
if profile:
if os.path.isfile(profile):
@@ -82,113 +32,12 @@ if profile:
elif os.path.isfile(profile + ".py"):
customs.append(profile + ".py")
opts = Variables(customs, ARGUMENTS)
platforms = ("linux", "macos", "windows", "android", "ios", "javascript")
opts.Add(
EnumVariable(
"platform",
"Target platform",
default_platform,
allowed_values=platforms,
ignorecase=2,
)
)
# Editor and template_debug are compatible (i.e. you can use the same binary for Godot editor builds and Godot debug templates).
# Godot release templates are only compatible with "template_release" builds.
# For this reason, we default to template_debug builds, unlike Godot which defaults to editor builds.
opts.Add(
EnumVariable("target", "Compilation target", "template_debug", ("editor", "template_release", "template_debug"))
)
opts.Add(
PathVariable(
"gdextension_dir",
"Path to a custom directory containing GDExtension interface header and API JSON file",
None,
validate_gdextension_dir,
)
)
opts.Add(
PathVariable(
"custom_api_file",
"Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`)",
None,
validate_api_file,
)
)
opts.Add(
BoolVariable("generate_bindings", "Force GDExtension API bindings generation. Auto-detected by default.", False)
)
opts.Add(BoolVariable("generate_template_get_node", "Generate a template version of the Node class's get_node.", True))
opts.Add(BoolVariable("build_library", "Build the godot-cpp library.", True))
opts.Add(EnumVariable("precision", "Set the floating-point precision level", "single", ("single", "double")))
# Add platform options
tools = {}
for pl in platforms:
tool = Tool(pl, toolpath=["tools"])
if hasattr(tool, "options"):
tool.options(opts)
tools[pl] = tool
# CPU architecture options.
architecture_array = ["", "universal", "x86_32", "x86_64", "arm32", "arm64", "rv64", "ppc32", "ppc64", "wasm32"]
architecture_aliases = {
"x64": "x86_64",
"amd64": "x86_64",
"armv7": "arm32",
"armv8": "arm64",
"arm64v8": "arm64",
"aarch64": "arm64",
"rv": "rv64",
"riscv": "rv64",
"riscv64": "rv64",
"ppcle": "ppc32",
"ppc": "ppc32",
"ppc64le": "ppc64",
}
opts.Add(EnumVariable("arch", "CPU architecture", "", architecture_array, architecture_aliases))
# Targets flags tool (optimizations, debug symbols)
target_tool = Tool("targets", toolpath=["tools"])
target_tool.options(opts)
cpp_tool = Tool("godotcpp", toolpath=[Dir("tools").srcnode().abspath])
cpp_tool.options(opts, env)
opts.Update(env)
Help(opts.GenerateHelpText(env))
# Process CPU architecture argument.
if env["arch"] == "":
# No architecture specified. Default to arm64 if building for Android,
# universal if building for macOS or iOS, wasm32 if building for web,
# otherwise default to the host architecture.
if env["platform"] in ["macos", "ios"]:
env["arch"] = "universal"
elif env["platform"] == "android":
env["arch"] = "arm64"
elif env["platform"] == "javascript":
env["arch"] = "wasm32"
else:
host_machine = platform.machine().lower()
if host_machine in architecture_array:
env["arch"] = host_machine
elif host_machine in architecture_aliases.keys():
env["arch"] = architecture_aliases[host_machine]
elif "86" in host_machine:
# Catches x86, i386, i486, i586, i686, etc.
env["arch"] = "x86_32"
else:
print("Unsupported CPU architecture: " + host_machine)
Exit()
tool = Tool(env["platform"], toolpath=["tools"])
if tool is None or not tool.exists(env):
raise ValueError("Required toolchain not found for platform " + env["platform"])
tool.generate(env)
target_tool.generate(env)
# Detect and print a warning listing unknown SCons variables to ease troubleshooting.
unknown = opts.UnknownVariables()
if unknown:
@@ -196,66 +45,12 @@ if unknown:
for item in unknown.items():
print(" " + item[0] + "=" + item[1])
print("Building for architecture " + env["arch"] + " on platform " + env["platform"])
# Require C++17
if env.get("is_msvc", False):
env.Append(CXXFLAGS=["/std:c++17"])
else:
env.Append(CXXFLAGS=["-std=c++17"])
if env["precision"] == "double":
env.Append(CPPDEFINES=["REAL_T_IS_DOUBLE"])
# Generate bindings
env.Append(BUILDERS={"GenerateBindings": Builder(action=scons_generate_bindings, emitter=scons_emit_files)})
bindings = env.GenerateBindings(
env.Dir("."),
[get_api_file(env), os.path.join(get_gdextension_dir(env), "gdextension_interface.h"), "binding_generator.py"],
)
scons_cache_path = os.environ.get("SCONS_CACHE")
if scons_cache_path is not None:
CacheDir(scons_cache_path)
Decider("MD5")
# Forces bindings regeneration.
if env["generate_bindings"]:
AlwaysBuild(bindings)
NoCache(bindings)
cpp_tool.generate(env)
library = env.GodotCPP()
# Includes
env.Append(CPPPATH=[[env.Dir(d) for d in [get_gdextension_dir(env), "include", os.path.join("gen", "include")]]])
# Sources to compile
sources = []
add_sources(sources, "src", "cpp")
add_sources(sources, "src/classes", "cpp")
add_sources(sources, "src/core", "cpp")
add_sources(sources, "src/variant", "cpp")
sources.extend([f for f in bindings if str(f).endswith(".cpp")])
suffix = ".{}.{}".format(env["platform"], env["target"])
if env.dev_build:
suffix += ".dev"
if env["precision"] == "double":
suffix += ".double"
suffix += "." + env["arch"]
if env["ios_simulator"]:
suffix += ".simulator"
# Expose it when included from another project
env["suffix"] = suffix
library = None
env["OBJSUFFIX"] = suffix + env["OBJSUFFIX"]
library_name = "libgodot-cpp{}{}".format(suffix, env["LIBSUFFIX"])
if env["build_library"]:
library = env.StaticLibrary(target=env.File("bin/%s" % library_name), source=sources)
Default(library)
env.Append(LIBPATH=[env.Dir("bin")])
env.Append(LIBS=library_name)
Return("env")

File diff suppressed because it is too large Load Diff

183
build_profile.py Normal file
View File

@@ -0,0 +1,183 @@
import json
import sys
def parse_build_profile(profile_filepath, api):
if profile_filepath == "":
return {}
with open(profile_filepath, encoding="utf-8") as profile_file:
profile = json.load(profile_file)
api_dict = {}
parents = {}
children = {}
for engine_class in api["classes"]:
api_dict[engine_class["name"]] = engine_class
parent = engine_class.get("inherits", "")
child = engine_class["name"]
parents[child] = parent
if parent == "":
continue
children[parent] = children.get(parent, [])
children[parent].append(child)
included = []
front = list(profile.get("enabled_classes", []))
if front:
# These must always be included
front.append("WorkerThreadPool")
front.append("ClassDB")
front.append("ClassDBSingleton")
# In src/classes/low_level.cpp
front.append("FileAccess")
front.append("Image")
front.append("XMLParser")
# In include/godot_cpp/templates/thread_work_pool.hpp
front.append("Semaphore")
while front:
cls = front.pop()
if cls in included:
continue
included.append(cls)
parent = parents.get(cls, "")
if parent:
front.append(parent)
excluded = []
front = list(profile.get("disabled_classes", []))
while front:
cls = front.pop()
if cls in excluded:
continue
excluded.append(cls)
front += children.get(cls, [])
if included and excluded:
print(
"WARNING: Cannot specify both 'enabled_classes' and 'disabled_classes' in build profile. 'disabled_classes' will be ignored."
)
return {
"enabled_classes": included,
"disabled_classes": excluded,
}
def generate_trimmed_api(source_api_filepath, profile_filepath):
with open(source_api_filepath, encoding="utf-8") as api_file:
api = json.load(api_file)
if profile_filepath == "":
return api
build_profile = parse_build_profile(profile_filepath, api)
engine_classes = {}
for class_api in api["classes"]:
engine_classes[class_api["name"]] = class_api["is_refcounted"]
for native_struct in api["native_structures"]:
if native_struct["name"] == "ObjectID":
continue
engine_classes[native_struct["name"]] = False
classes = []
for class_api in api["classes"]:
if not is_class_included(class_api["name"], build_profile):
continue
if "methods" in class_api:
methods = []
for method in class_api["methods"]:
if not is_method_included(method, build_profile, engine_classes):
continue
methods.append(method)
class_api["methods"] = methods
classes.append(class_api)
api["classes"] = classes
return api
def is_class_included(class_name, build_profile):
"""
Check if an engine class should be included.
This removes classes according to a build profile of enabled or disabled classes.
"""
included = build_profile.get("enabled_classes", [])
excluded = build_profile.get("disabled_classes", [])
if included:
return class_name in included
if excluded:
return class_name not in excluded
return True
def is_method_included(method, build_profile, engine_classes):
"""
Check if an engine class method should be included.
This removes methods according to a build profile of enabled or disabled classes.
"""
included = build_profile.get("enabled_classes", [])
excluded = build_profile.get("disabled_classes", [])
ref_cls = set()
rtype = get_base_type(method.get("return_value", {}).get("type", ""))
args = [get_base_type(a["type"]) for a in method.get("arguments", [])]
if rtype in engine_classes:
ref_cls.add(rtype)
elif is_enum(rtype) and get_enum_class(rtype) in engine_classes:
ref_cls.add(get_enum_class(rtype))
for arg in args:
if arg in engine_classes:
ref_cls.add(arg)
elif is_enum(arg) and get_enum_class(arg) in engine_classes:
ref_cls.add(get_enum_class(arg))
for acls in ref_cls:
if len(included) > 0 and acls not in included:
return False
elif len(excluded) > 0 and acls in excluded:
return False
return True
def is_enum(type_name):
return type_name.startswith("enum::") or type_name.startswith("bitfield::")
def get_enum_class(enum_name: str):
if "." in enum_name:
if is_bitfield(enum_name):
return enum_name.replace("bitfield::", "").split(".")[0]
else:
return enum_name.replace("enum::", "").split(".")[0]
else:
return "GlobalConstants"
def get_base_type(type_name):
if type_name.startswith("const "):
type_name = type_name[6:]
if type_name.endswith("*"):
type_name = type_name[:-1]
if type_name.startswith("typedarray::"):
type_name = type_name.replace("typedarray::", "")
return type_name
def is_bitfield(type_name):
return type_name.startswith("bitfield::")
if __name__ == "__main__":
if len(sys.argv) < 3 or len(sys.argv) > 4:
print("Usage: %s BUILD_PROFILE INPUT_JSON [OUTPUT_JSON]" % (sys.argv[0]))
sys.exit(1)
profile = sys.argv[1]
infile = sys.argv[2]
outfile = sys.argv[3] if len(sys.argv) > 3 else ""
api = generate_trimmed_api(infile, profile)
if outfile:
with open(outfile, "w", encoding="utf-8") as f:
json.dump(api, f)
else:
json.dump(api, sys.stdout)

176
cmake/GodotCPPModule.cmake Normal file
View File

@@ -0,0 +1,176 @@
#[=======================================================================[.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"
)
add_custom_target(generate_bindings DEPENDS ${GENERATED_FILES_LIST})
set_target_properties(generate_bindings PROPERTIES FOLDER "godot-cpp")
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}"
)
add_custom_target(generate_doc_source DEPENDS "${OUTPUT_PATH}")
set_target_properties(generate_doc_source PROPERTIES FOLDER "godot-cpp")
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.]]
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}")
# Without adding this dependency to the doc_source_generator, XCode will complain.
add_dependencies(${TARGET} generate_doc_source)
endfunction()

View File

@@ -1,94 +0,0 @@
# 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>" )
# These compiler options reflect what is in godot/SConstruct.
target_compile_options( ${PROJECT_NAME} PRIVATE
# MSVC only
$<${compiler_is_msvc}:
/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)
>
# 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
>
# Clang only
$<${compiler_is_clang}:
-Wimplicit-fallthrough
-Wno-ordered-compare-function-pointers
>
# 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
>
)
# 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_CPP_WARNING_AS_ERROR )
set_warning_as_error()
endif()

49
cmake/android.cmake Normal file
View File

@@ -0,0 +1,49 @@
#[=======================================================================[.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 docs: https://docs.godotengine.org/en/latest/tutorials/scripting/cpp/build_system/cmake.html
]=======================================================================]
#[============================[ Android Options ]============================]
function(android_options)
#[[ Options from SCons
The options below are managed by CMake toolchain files, the docs have more information:
https://docs.godotengine.org/en/latest/tutorials/scripting/cpp/build_system/cmake.html
android_api_level : Target Android API level.
Default = 21
ANDROID_HOME : Path to your Android SDK installation.
Default = os.environ.get("ANDROID_HOME", os.environ.get("ANDROID_SDK_ROOT")
]]
endfunction()
#[===========================[ Target Generation ]===========================]
function(android_generate)
target_compile_definitions(godot-cpp PUBLIC ANDROID_ENABLED UNIX_ENABLED)
common_compiler_flags()
endfunction()

View File

@@ -0,0 +1,192 @@
#[=======================================================================[.rst:
Common Compiler Flags
---------------------
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.
The default compile and link options CMake adds can be found in the
platform modules_. When a project is created it initializes its variables from
the ``CMAKE_*`` values. The cleanest way I have found to alter these defaults
is the use of the ``CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`` as demonstrated by
the emsdkHack.cmake to overcome the limitation on shared library creation.
So far the emsdkHack is the only modification to the defaults we have made.
.. _modules: https://github.com/Kitware/CMake/blob/master/Modules/Platform/
]=======================================================================]
#[[ Compiler Configuration, not to be confused with build targets ]]
set(DEBUG_SYMBOLS "$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>")
#[[ 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>>")
set(LT_V8 "$<VERSION_LESS:$<CXX_COMPILER_VERSION>,8>")
set(GE_V9 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,9>")
set(GT_V11 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,11>")
set(LT_V11 "$<VERSION_LESS:$<CXX_COMPILER_VERSION>,11>")
set(GE_V12 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,12>")
#[===========================[ compiler_detection ]===========================]
#[[ 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(STATUS "Using clang-cl")
set(IS_CLANG "0" PARENT_SCOPE)
set(IS_MSVC "1" PARENT_SCOPE)
set(NOT_MSVC "0" PARENT_SCOPE)
endif()
endif()
endfunction()
#[=========================[ common_compiler_flags ]=========================]
#[[ This function assumes it is being called from within one of the platform
generate functions, with all the variables from lower scopes defined. ]]
function(common_compiler_flags)
# gersemi: off
# These compiler options reflect what is in godot/SConstruct.
target_compile_options(
godot-cpp
# The public flag tells CMake that the following options are transient,
# and will propagate to consumers.
PUBLIC
# 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}>
# Interpret source files as utf-8
/utf-8
>
# Warnings below, these do not need to propagate to consumers.
PRIVATE
# 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>>
$<${IS_MSVC}:
/W4 # Warning level 4 (informational) warnings that aren't off by default.
# 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:${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+.
$<${LT_V8}:-Wno-strict-overflow>
$<${GE_V9}:-Wattribute-alias=2>
# Broke on MethodBind templates before GCC 11.
$<${GT_V11}:-Wlogical-op>
# Regression in GCC 9/10, spams so much in our variadic templates that we need to outright disable it.
$<${LT_V11}:-Wno-type-limits>
# False positives in our error macros, see GH-58747.
$<${GE_V12}:-Wno-return-type>
>
)
target_compile_definitions(
godot-cpp
PUBLIC
GDEXTENSION
# features
$<${DEBUG_FEATURES}:DEBUG_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(
godot-cpp
PUBLIC
$<${DEBUG_SYMBOLS}:$<${IS_MSVC}:/DEBUG:FULL>>
$<$<NOT:${DEBUG_SYMBOLS}>:
$<${IS_GNU}:-s>
$<${IS_CLANG}:-s>
$<${IS_APPLECLANG}:-Wl,-S -Wl,-x -Wl,-dead_strip>
>
PRIVATE
$<${IS_MSVC}:
/WX # treat link warnings as errors.
/MANIFEST:NO # We dont need a manifest
>
)
# gersemi: on
endfunction()

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 copies that to CMAKE_SYSTEM_PROCESSOR. We 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()

399
cmake/godotcpp.cmake Normal file
View File

@@ -0,0 +1,399 @@
#[=======================================================================[.rst:
godotcpp.cmake
--------------
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()
#[[ 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(STATUS "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
)
#[=============================[ godot_arch_name ]=============================]
#[[ Function to map CMAKE_SYSTEM_PROCESSOR names to godot arch equivalents ]]
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.
# To create a universal build for macos, set CMAKE_OSX_ARCHITECTURES
set(GODOTCPP_TARGET
"template_debug"
CACHE STRING
"Which target to generate. valid values are: template_debug, template_release, and editor"
)
set_property(CACHE GODOTCPP_TARGET PROPERTY STRINGS "template_debug;template_release;editor")
# Input from user for GDExtension interface header and the API JSON file
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(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(GODOTCPP_GENERATE_TEMPLATE_GET_NODE "Generate a template version of the Node class's get_node. (ON|OFF)" ON)
#TODO build_library
set(GODOTCPP_PRECISION "single" CACHE STRING "Set the floating-point precision level (single|double)")
set(GODOTCPP_THREADS ON CACHE BOOL "Enable threading support")
#TODO compiledb
#TODO compiledb_file
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)")
# 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(GODOTCPP_DISABLE_EXCEPTIONS "Force disabling exception handling code (ON|OFF)" ON)
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")
#TODO optimize
option(GODOTCPP_DEV_BUILD "Developer build with dev-only debugging code (DEV_ENABLED)" OFF)
#[[ debug_symbols
Debug symbols are enabled by using the Debug or RelWithDebInfo build configurations.
Single Config Generator is set at configure time
cmake ../ -DCMAKE_BUILD_TYPE=Debug
Multi-Config Generator is set at build time
cmake --build . --config Debug
]]
# 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)
# Enable Testing
option(GODOTCPP_ENABLE_TESTING "Enable the godot-cpp.test.<target> integration testing targets" OFF)
#[[ Target Platform Options ]]
android_options()
ios_options()
linux_options()
macos_options()
web_options()
windows_options()
endfunction()
#[===========================[ Target Generation ]===========================]
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(STATUS "Using ${PROC_N} cores for multi-threaded compilation.")
# TODO You can override it at configure time with ...." )
else()
if(CMAKE_BUILD_PARALLEL_LEVEL)
set(_cores "${CMAKE_BUILD_PARALLEL_LEVEL}")
else()
set(_cores "all")
endif()
message(
STATUS
"Using ${_cores} cores. You can override"
" this at configure time by using -j <n> or --parallel <n> in the build"
" command."
)
message(STATUS " eg. cmake --build . -j 7 ...")
endif()
#[[ 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.
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()
# Setup variable to optionally mark headers as SYSTEM
set(GODOTCPP_SYSTEM_HEADERS_ATTRIBUTE "")
if(GODOTCPP_SYSTEM_HEADERS)
set(GODOTCPP_SYSTEM_HEADERS_ATTRIBUTE SYSTEM)
endif()
#[[ 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()
# 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(STATUS "\tBUILD_PROFILE = '${GODOTCPP_BUILD_PROFILE}'")
message(STATUS "\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}"
)
### Platform is derived from the toolchain target
# See GeneratorExpressions PLATFORM_ID and CMAKE_SYSTEM_NAME
string(
CONCAT
SYSTEM_NAME
"$<$<PLATFORM_ID:Android>:android>"
"$<$<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
# Generator Expressions that rely on the target
set(DEBUG_FEATURES "$<NOT:$<STREQUAL:${GODOTCPP_TARGET},template_release>>")
set(HOT_RELOAD "$<IF:${HOT_RELOAD-UNSET},${DEBUG_FEATURES},$<BOOL:${GODOTCPP_USE_HOT_RELOAD}>>")
# Suffix Generator Expression
string(
CONCAT
GODOTCPP_SUFFIX_GENEX
"$<1:${SYSTEM_NAME}>"
"$<1:.${GODOTCPP_TARGET}>"
"$<${IS_DEV_BUILD}:.dev>"
"$<$<STREQUAL:${GODOTCPP_PRECISION},double>:.double>"
"$<1:.${ARCH_NAME}>"
# TODO IOS_SIMULATOR
"$<$<NOT:${THREADS_ENABLED}>:.nothreads>"
)
# The same as above, but with a leading '.' to maintain backwards compatibility.
set(GODOTCPP_SUFFIX ".${GODOTCPP_SUFFIX_GENEX}")
# the godot-cpp.* library targets
add_library(godot-cpp STATIC)
# Without adding this dependency to the binding generator, XCode will complain.
add_dependencies(godot-cpp generate_bindings)
# 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)
file(GLOB_RECURSE GODOTCPP_SOURCES LIST_DIRECTORIES NO CONFIGURE_DEPENDS src/*.cpp)
target_sources(godot-cpp PRIVATE ${GODOTCPP_SOURCES} ${GENERATED_FILES_LIST})
target_include_directories(
godot-cpp
${GODOTCPP_SYSTEM_HEADERS_ATTRIBUTE}
PUBLIC include ${CMAKE_CURRENT_BINARY_DIR}/gen/include ${GODOTCPP_GDEXTENSION_DIR}
)
# gersemi: off
set_target_properties(
godot-cpp
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 "${GODOTCPP_TARGET}"
GODOTCPP_ARCH "${ARCH_NAME}"
GODOTCPP_PRECISION "${GODOTCPP_PRECISION}"
GODOTCPP_SUFFIX "${GODOTCPP_SUFFIX}"
GODOTCPP_SUFFIX_GENEX "${GODOTCPP_SUFFIX_GENEX}"
# Some IDE's respect this property to logically group targets
FOLDER "godot-cpp"
)
# gersemi: on
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()
endfunction()

36
cmake/ios.cmake Normal file
View File

@@ -0,0 +1,36 @@
#[=======================================================================[.rst:
iOS
---
This file contains functions for options and configuration for targeting the
iOS platform
]=======================================================================]
#[==============================[ iOS Options ]==============================]
function(ios_options)
#[[ Options from SCons
TODO ios_simulator: Target iOS Simulator
Default: False
TODO ios_min_version: Target minimum iphoneos/iphonesimulator version
Default: 12.0
TODO IOS_TOOLCHAIN_PATH: Path to iOS toolchain
Default: "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain",
TODO IOS_SDK_PATH: Path to the iOS SDK
Default: ''
TODO ios_triple: Triple for ios toolchain
Default: if has_ios_osxcross(): 'ios_triple' else ''
]]
endfunction()
#[===========================[ Target Generation ]===========================]
function(ios_generate)
target_compile_definitions(godot-cpp PUBLIC IOS_ENABLED UNIX_ENABLED)
common_compiler_flags()
endfunction()

1147
cmake/ios.toolchain.cmake Normal file

File diff suppressed because it is too large Load Diff

39
cmake/linux.cmake Normal file
View File

@@ -0,0 +1,39 @@
#[=======================================================================[.rst:
Linux
-----
This file contains functions for options and configuration for targeting the
Linux platform
]=======================================================================]
#[=============================[ Linux Options ]=============================]
function(linux_options)
#[[ Options from SCons
use_llvm : Use the LLVM compiler
Not implemented as compiler selection is managed by CMake. Look to
the docs (https://docs.godotengine.org/en/latest/tutorials/scripting/cpp/build_system/cmake.html)
for examples.
]]
option(GODOTCPP_USE_STATIC_CPP "Link libgcc and libstdc++ statically for better portability" OFF)
endfunction()
#[===========================[ Target Generation ]===========================]
function(linux_generate)
set(STATIC_CPP "$<BOOL:${GODOTCPP_USE_STATIC_CPP}>")
target_compile_definitions(godot-cpp PUBLIC LINUX_ENABLED UNIX_ENABLED)
# gersemi: off
target_link_options(
godot-cpp
PUBLIC
$<${STATIC_CPP}:
-static-libgcc
-static-libstdc++
>
)
# gersemi: on
common_compiler_flags()
endfunction()

41
cmake/macos.cmake Normal file
View File

@@ -0,0 +1,41 @@
#[=======================================================================[.rst:
MacOS
-----
This file contains functions for options and configuration for targeting the
MacOS platform
Universal Builds
----------------
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})
endif(APPLE)
#[=============================[ MacOS Options ]=============================]
function(macos_options)
#[[ Options from SCons
TODO macos_deployment_target: macOS deployment target
Default: 'default'
TODO macos_sdk_path: macOS SDK path
Default: ''
TODO osxcross_sdk: OSXCross SDK version
Default: if has_osxcross(): "darwin16" else None
]]
endfunction()
#[===========================[ Target Generation ]===========================]
function(macos_generate)
target_compile_definitions(godot-cpp PUBLIC MACOS_ENABLED UNIX_ENABLED)
common_compiler_flags()
endfunction()

40
cmake/web.cmake Normal file
View File

@@ -0,0 +1,40 @@
#[=======================================================================[.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)
#[==============================[ Web Options ]==============================]
function(web_options)
endfunction()
#[===========================[ Target Generation ]===========================]
function(web_generate)
target_compile_definitions(godot-cpp PUBLIC WEB_ENABLED UNIX_ENABLED)
target_compile_options(
godot-cpp
PUBLIC #
-sSIDE_MODULE=1
-sSUPPORT_LONGJMP=wasm
$<${THREADS_ENABLED}:-sUSE_PTHREADS=1>
)
target_link_options(
godot-cpp
INTERFACE #
-sWASM_BIGINT
-sSUPPORT_LONGJMP=wasm
-fvisibility=hidden
-shared
$<${THREADS_ENABLED}:-sUSE_PTHREADS=1>
)
common_compiler_flags()
endfunction()

118
cmake/windows.cmake Normal file
View File

@@ -0,0 +1,118 @@
#[=======================================================================[.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
]=======================================================================]
#[============================[ Windows Options ]============================]
function(windows_options)
#[[ Options from SCons
TODO silence_msvc: Silence MSVC's cl/link stdout bloat, redirecting errors to stderr
Default: True
These three options will not implemented as compiler selection is managed
by CMake toolchain files. Look to the docs
(https://docs.godotengine.org/en/latest/tutorials/scripting/cpp/build_system/cmake.html)
for examples.
use_mingw: Use the MinGW compiler instead of MSVC - only effective on Windows
use_llvm: Use the LLVM compiler (MVSC or MinGW depending on the use_mingw flag
mingw_prefix: MinGW prefix
]]
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(godot-cpp PROPERTIES PDB_OUTPUT_DIRECTORY "$<1:${CMAKE_SOURCE_DIR}/bin>")
target_compile_definitions(
godot-cpp
PUBLIC WINDOWS_ENABLED $<${IS_MSVC}: TYPED_METHOD_BIND NOMINMAX >
)
# gersemi: off
target_link_options(
godot-cpp
PUBLIC
$<${NOT_MSVC}:
-Wl,--no-undefined
$<${STATIC_CPP}:
-static
-static-libgcc
-static-libstdc++
>
>
$<${IS_CLANG}:-lstdc++>
)
# gersemi: on
common_compiler_flags()
endfunction()

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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
/**************************************************************************/
/* editor_plugin_registration.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. */
/**************************************************************************/
#pragma once
#include <godot_cpp/templates/vector.hpp>
namespace godot {
class EditorPlugin;
class StringName;
class EditorPlugins {
private:
static Vector<StringName> plugin_classes;
public:
static void add_plugin_class(const StringName &p_class_name);
static void remove_plugin_class(const StringName &p_class_name);
static void deinitialize(GDExtensionInitializationLevel p_level);
template <typename T>
static void add_by_type() {
add_plugin_class(T::get_class_static());
}
template <typename T>
static void remove_by_type() {
remove_plugin_class(T::get_class_static());
}
};
} // namespace godot

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_REF_HPP
#define GODOT_REF_HPP
#pragma once
#include <godot_cpp/core/defs.hpp>
@@ -45,7 +44,7 @@ namespace godot {
class RefCounted;
template <class T>
template <typename T>
class Ref {
T *reference = nullptr;
@@ -63,7 +62,7 @@ class Ref {
}
void ref_pointer(T *p_ref) {
ERR_FAIL_COND(!p_ref);
ERR_FAIL_NULL(p_ref);
if (p_ref->init_ref()) {
reference = p_ref;
@@ -71,6 +70,10 @@ class Ref {
}
public:
static _FORCE_INLINE_ String get_class_static() {
return T::get_class_static();
}
_FORCE_INLINE_ bool operator==(const T *p_ptr) const {
return reference == p_ptr;
}
@@ -88,26 +91,15 @@ public:
return reference != p_r.reference;
}
_FORCE_INLINE_ T *operator->() {
_FORCE_INLINE_ T *operator*() const {
return reference;
}
_FORCE_INLINE_ T *operator*() {
_FORCE_INLINE_ T *operator->() const {
return reference;
}
_FORCE_INLINE_ const T *operator->() const {
return reference;
}
_FORCE_INLINE_ const T *ptr() const {
return reference;
}
_FORCE_INLINE_ T *ptr() {
return reference;
}
_FORCE_INLINE_ const T *operator*() const {
_FORCE_INLINE_ T *ptr() const {
return reference;
}
@@ -119,7 +111,7 @@ public:
ref(p_from);
}
template <class T_Other>
template <typename T_Other>
void operator=(const Ref<T_Other> &p_from) {
RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr()));
if (!refb) {
@@ -155,7 +147,7 @@ public:
}
}
template <class T_Other>
template <typename T_Other>
void reference_ptr(T_Other *p_ptr) {
if (reference == p_ptr) {
return;
@@ -172,7 +164,7 @@ public:
ref(p_from);
}
template <class T_Other>
template <typename T_Other>
Ref(const Ref<T_Other> &p_from) {
RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr()));
if (!refb) {
@@ -230,21 +222,21 @@ public:
// Used exclusively in the bindings to recreate the Ref Godot encapsulates in return values,
// without adding to the refcount.
inline static Ref<T> ___internal_constructor(Object *obj) {
inline static Ref<T> _gde_internal_constructor(Object *obj) {
Ref<T> r;
r.reference = (T *)obj;
return r;
}
};
template <class T>
template <typename T>
struct PtrToArg<Ref<T>> {
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
GDExtensionRefPtr ref = (GDExtensionRefPtr)p_ptr;
ERR_FAIL_NULL_V(ref, Ref<T>());
T *obj = reinterpret_cast<T *>(godot::internal::gde_interface->object_get_instance_binding(godot::internal::gde_interface->ref_get_object(ref), godot::internal::token, &T::___binding_callbacks));
return Ref<T>(obj);
if (unlikely(!p_ptr)) {
return Ref<T>();
}
return Ref<T>(reinterpret_cast<T *>(godot::internal::get_object_instance_binding(godot::internal::gdextension_interface_ref_get_object(ref))));
}
typedef Ref<T> EncodeT;
@@ -256,34 +248,38 @@ struct PtrToArg<Ref<T>> {
// This code assumes that p_ptr points to an unset Ref<T> variable on the Godot side
// so we only set it if we have an object to set.
if (p_val.is_valid()) {
godot::internal::gde_interface->ref_set_object(ref, p_val->_owner);
godot::internal::gdextension_interface_ref_set_object(ref, p_val->_owner);
}
}
};
template <class T>
template <typename T>
struct PtrToArg<const Ref<T> &> {
typedef Ref<T> EncodeT;
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
return Ref<T>(reinterpret_cast<T *>(godot::internal::gde_interface->object_get_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr)), godot::internal::token, &T::___binding_callbacks)));
GDExtensionRefPtr ref = const_cast<GDExtensionRefPtr>(p_ptr);
if (unlikely(!p_ptr)) {
return Ref<T>();
}
return Ref<T>(reinterpret_cast<T *>(godot::internal::get_object_instance_binding(godot::internal::gdextension_interface_ref_get_object(ref))));
}
};
template <class T>
template <typename T>
struct GetTypeInfo<Ref<T>, typename EnableIf<TypeInherits<RefCounted, T>::value>::type> {
static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
}
};
template <class T>
template <typename T>
struct GetTypeInfo<const Ref<T> &, typename EnableIf<TypeInherits<RefCounted, T>::value>::type> {
static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
@@ -291,5 +287,3 @@ struct GetTypeInfo<const Ref<T> &, typename EnableIf<TypeInherits<RefCounted, T>
};
} // namespace godot
#endif // GODOT_REF_HPP

View File

@@ -28,31 +28,63 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_WRAPPED_HPP
#define GODOT_WRAPPED_HPP
#pragma once
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/core/property_info.hpp>
#include <godot_cpp/templates/list.hpp>
#include <godot_cpp/templates/vector.hpp>
#include <godot_cpp/godot.hpp>
#if defined(MACOS_ENABLED) && defined(HOT_RELOAD_ENABLED)
#include <mutex>
#define _GODOT_CPP_AVOID_THREAD_LOCAL
#define _GODOT_CPP_THREAD_LOCAL
#else
#define _GODOT_CPP_THREAD_LOCAL thread_local
#endif
namespace godot {
class ClassDB;
typedef void GodotObject;
template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool> = true>
_ALWAYS_INLINE_ void _pre_initialize();
// Base for all engine classes, to contain the pointer to the engine instance.
class Wrapped {
friend class GDExtensionBinding;
friend class ClassDB;
friend void postinitialize_handler(Wrapped *);
template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool>>
friend _ALWAYS_INLINE_ void _pre_initialize();
#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
static std::recursive_mutex _constructing_mutex;
#endif
_GODOT_CPP_THREAD_LOCAL static const StringName *_constructing_extension_class_name;
_GODOT_CPP_THREAD_LOCAL static const GDExtensionInstanceBindingCallbacks *_constructing_class_binding_callbacks;
#ifdef HOT_RELOAD_ENABLED
_GODOT_CPP_THREAD_LOCAL static GDExtensionObjectPtr _constructing_recreate_owner;
#endif
template <typename T>
_ALWAYS_INLINE_ static void _set_construct_info() {
_constructing_extension_class_name = T::_get_extension_class_name();
_constructing_class_binding_callbacks = &T::_gde_binding_callbacks;
}
protected:
virtual const StringName *_get_extension_class_name() const; // This is needed to retrieve the class name before the godot object has its _extension and _extension_instance members assigned.
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const = 0;
virtual bool _is_extension_class() const { return false; }
static const StringName *_get_extension_class_name(); // This is needed to retrieve the class name before the godot object has its _extension and _extension_instance members assigned.
void _notification(int p_what) {}
bool _set(const StringName &p_name, const Variant &p_property) { return false; }
@@ -60,56 +92,109 @@ protected:
void _get_property_list(List<PropertyInfo> *p_list) const {}
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; }
String _to_string() const { return "[" + String(get_class_static()) + ":" + itos(get_instance_id()) + "]"; }
void _validate_property(PropertyInfo &p_property) const {}
String _to_string() const { return "<Wrapped#0>"; }
static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what) {}
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; }
static GDExtensionBool get_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { return false; }
static const GDExtensionPropertyInfo *get_property_list_bind(GDExtensionClassInstancePtr p_instance, uint32_t *r_count) { return nullptr; }
static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list) {}
static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list, uint32_t p_count) {}
static GDExtensionBool property_can_revert_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name) { return false; }
static GDExtensionBool property_get_revert_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { return false; }
static GDExtensionBool validate_property_bind(GDExtensionClassInstancePtr p_instance, GDExtensionPropertyInfo *p_property) { return false; }
static void to_string_bind(GDExtensionClassInstancePtr p_instance, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out) {}
// The only reason this has to be held here, is when we return results of `_get_property_list` to Godot, we pass
// pointers to strings in this list. They have to remain valid to pass the bridge, until the list is freed by Godot...
::godot::List<::godot::PropertyInfo> plist_owned;
GDExtensionPropertyInfo *plist = nullptr;
uint32_t plist_size = 0;
void _postinitialize();
Wrapped(const StringName p_godot_class);
Wrapped(const StringName &p_godot_class);
Wrapped(GodotObject *p_godot_object);
virtual ~Wrapped() {}
public:
static StringName &get_class_static() {
static StringName string_name = StringName("Wrapped");
static const StringName &get_class_static() {
static const StringName string_name = StringName("Wrapped");
return string_name;
}
uint64_t get_instance_id() const {
return 0;
}
// Must be public but you should not touch this.
GodotObject *_owner = nullptr;
};
template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool>>
_ALWAYS_INLINE_ void _pre_initialize() {
#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
Wrapped::_constructing_mutex.lock();
#endif
Wrapped::_set_construct_info<T>();
}
_FORCE_INLINE_ void snarray_add_str(Vector<StringName> &arr) {
}
_FORCE_INLINE_ void snarray_add_str(Vector<StringName> &arr, const StringName &p_str) {
arr.push_back(p_str);
}
template <typename... P>
_FORCE_INLINE_ void snarray_add_str(Vector<StringName> &arr, const StringName &p_str, P... p_args) {
arr.push_back(p_str);
snarray_add_str(arr, p_args...);
}
template <typename... P>
_FORCE_INLINE_ Vector<StringName> snarray(P... p_args) {
Vector<StringName> arr;
snarray_add_str(arr, p_args...);
return arr;
}
namespace internal {
GDExtensionPropertyInfo *create_c_property_list(const ::godot::List<::godot::PropertyInfo> &plist_cpp, uint32_t *r_size);
void free_c_property_list(GDExtensionPropertyInfo *plist);
typedef void (*EngineClassRegistrationCallback)();
void add_engine_class_registration_callback(EngineClassRegistrationCallback p_callback);
void register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks);
void register_engine_classes();
template <typename T>
struct EngineClassRegistration {
EngineClassRegistration() {
add_engine_class_registration_callback(&EngineClassRegistration<T>::callback);
}
static void callback() {
register_engine_class(T::get_class_static(), &T::_gde_binding_callbacks);
}
};
} // namespace internal
} // namespace godot
#define GDCLASS(m_class, m_inherits) \
// Use this on top of your own classes.
// Note: the trail of `***` is to keep sane diffs in PRs, because clang-format otherwise moves every `\` which makes
// every line of the macro different
#define GDCLASS(m_class, m_inherits) /***********************************************************************************************************************************************/ \
private: \
void operator=(const m_class &p_rval) {} \
void operator=(const m_class & /*p_rval*/) {} \
friend class ::godot::ClassDB; \
friend class ::godot::Wrapped; \
\
protected: \
virtual const ::godot::StringName *_get_extension_class_name() const override { \
static ::godot::StringName string_name = get_class_static(); \
return &string_name; \
virtual bool _is_extension_class() const override { \
return true; \
} \
\
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const override { \
return &___binding_callbacks; \
static const ::godot::StringName *_get_extension_class_name() { \
const ::godot::StringName &string_name = get_class_static(); \
return &string_name; \
} \
\
static void (*_get_bind_methods())() { \
@@ -117,39 +202,46 @@ protected:
} \
\
static void (::godot::Wrapped::*_get_notification())(int) { \
return (void(::godot::Wrapped::*)(int)) & m_class::_notification; \
return (void (::godot::Wrapped::*)(int)) & m_class::_notification; \
} \
\
static bool (::godot::Wrapped::*_get_set())(const ::godot::StringName &p_name, const ::godot::Variant &p_property) { \
return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name, const ::godot::Variant &p_property)) & m_class::_set; \
return (bool (::godot::Wrapped::*)(const ::godot::StringName &p_name, const ::godot::Variant &p_property)) & m_class::_set; \
} \
\
static bool (::godot::Wrapped::*_get_get())(const ::godot::StringName &p_name, ::godot::Variant &r_ret) const { \
return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name, ::godot::Variant &r_ret) const) & m_class::_get; \
return (bool (::godot::Wrapped::*)(const ::godot::StringName &p_name, ::godot::Variant &r_ret) const) & m_class::_get; \
} \
\
static void (::godot::Wrapped::*_get_get_property_list())(::godot::List<::godot::PropertyInfo> * p_list) const { \
return (void(::godot::Wrapped::*)(::godot::List<::godot::PropertyInfo> * p_list) const) & m_class::_get_property_list; \
return (void (::godot::Wrapped::*)(::godot::List<::godot::PropertyInfo> * p_list) const) & m_class::_get_property_list; \
} \
\
static bool (::godot::Wrapped::*_get_property_can_revert())(const ::godot::StringName &p_name) { \
return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name)) & m_class::_property_can_revert; \
static bool (::godot::Wrapped::*_get_property_can_revert())(const ::godot::StringName &p_name) const { \
return (bool (::godot::Wrapped::*)(const ::godot::StringName &p_name) const) & m_class::_property_can_revert; \
} \
\
static bool (::godot::Wrapped::*_get_property_get_revert())(const ::godot::StringName &p_name, ::godot::Variant &) { \
return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name, ::godot::Variant &)) & m_class::_property_get_revert; \
static bool (::godot::Wrapped::*_get_property_get_revert())(const ::godot::StringName &p_name, ::godot::Variant &) const { \
return (bool (::godot::Wrapped::*)(const ::godot::StringName &p_name, ::godot::Variant &) const) & m_class::_property_get_revert; \
} \
\
static ::godot::String (::godot::Wrapped::*_get_to_string())() { \
return (::godot::String(::godot::Wrapped::*)()) & m_class::_to_string; \
static void (::godot::Wrapped::*_get_validate_property())(::godot::PropertyInfo & p_property) const { \
return (void (::godot::Wrapped::*)(::godot::PropertyInfo & p_property) const) & m_class::_validate_property; \
} \
\
template <class T, class B> \
static ::godot::String (::godot::Wrapped::*_get_to_string())() const { \
return (::godot::String (::godot::Wrapped::*)() const) & m_class::_to_string; \
} \
\
template <typename T, typename B> \
static void register_virtuals() { \
m_inherits::register_virtuals<T, B>(); \
} \
\
public: \
typedef m_class self_type; \
typedef m_inherits parent_type; \
\
static void initialize_class() { \
static bool initialized = false; \
if (initialized) { \
@@ -163,86 +255,78 @@ public:
initialized = true; \
} \
\
static ::godot::StringName &get_class_static() { \
static ::godot::StringName string_name = ::godot::StringName(#m_class); \
static const ::godot::StringName &get_class_static() { \
static const ::godot::StringName string_name = ::godot::StringName(U## #m_class); \
return string_name; \
} \
\
static ::godot::StringName &get_parent_class_static() { \
static const ::godot::StringName &get_parent_class_static() { \
return m_inherits::get_class_static(); \
} \
\
static GDExtensionObjectPtr create(void *data) { \
m_class *new_object = memnew(m_class); \
return new_object->_owner; \
} \
\
static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what) { \
static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what, GDExtensionBool p_reversed) { \
if (p_instance && m_class::_get_notification()) { \
if (!p_reversed) { \
m_inherits::notification_bind(p_instance, p_what, p_reversed); \
} \
if (m_class::_get_notification() != m_inherits::_get_notification()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
return cls->_notification(p_what); \
cls->_notification(p_what); \
} \
if (p_reversed) { \
m_inherits::notification_bind(p_instance, p_what, p_reversed); \
} \
m_inherits::notification_bind(p_instance, p_what); \
} \
} \
\
static GDExtensionBool set_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionConstVariantPtr p_value) { \
if (p_instance && m_class::_get_set()) { \
if (p_instance) { \
if (m_inherits::set_bind(p_instance, p_name, p_value)) { \
return true; \
} \
if (m_class::_get_set() != m_inherits::_get_set()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
return cls->_set(*reinterpret_cast<const ::godot::StringName *>(p_name), *reinterpret_cast<const ::godot::Variant *>(p_value)); \
} \
return m_inherits::set_bind(p_instance, p_name, p_value); \
} \
return false; \
} \
\
static GDExtensionBool get_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { \
if (p_instance && m_class::_get_get()) { \
if (p_instance) { \
if (m_inherits::get_bind(p_instance, p_name, r_ret)) { \
return true; \
} \
if (m_class::_get_get() != m_inherits::_get_get()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
return cls->_get(*reinterpret_cast<const ::godot::StringName *>(p_name), *reinterpret_cast<::godot::Variant *>(r_ret)); \
} \
return m_inherits::get_bind(p_instance, p_name, r_ret); \
} \
return false; \
} \
\
static const GDExtensionPropertyInfo *get_property_list_bind(GDExtensionClassInstancePtr p_instance, uint32_t *r_count) { \
if (p_instance && m_class::_get_get_property_list()) { \
if (m_class::_get_get_property_list() != m_inherits::_get_get_property_list()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
ERR_FAIL_COND_V_MSG(!cls->plist_owned.is_empty() || cls->plist != nullptr || cls->plist_size != 0, nullptr, "Internal error, property list was not freed by engine!"); \
cls->_get_property_list(&cls->plist_owned); \
cls->plist = reinterpret_cast<GDExtensionPropertyInfo *>(memalloc(sizeof(GDExtensionPropertyInfo) * cls->plist_owned.size())); \
cls->plist_size = 0; \
for (const ::godot::PropertyInfo &E : cls->plist_owned) { \
cls->plist[cls->plist_size].type = static_cast<GDExtensionVariantType>(E.type); \
cls->plist[cls->plist_size].name = E.name._native_ptr(); \
cls->plist[cls->plist_size].hint = E.hint; \
cls->plist[cls->plist_size].hint_string = E.hint_string._native_ptr(); \
cls->plist[cls->plist_size].class_name = E.class_name._native_ptr(); \
cls->plist[cls->plist_size].usage = E.usage; \
cls->plist_size++; \
} \
if (r_count) \
*r_count = cls->plist_size; \
return cls->plist; \
} \
return m_inherits::get_property_list_bind(p_instance, r_count); \
} \
return nullptr; \
static inline bool has_get_property_list() { \
return m_class::_get_get_property_list() && m_class::_get_get_property_list() != m_inherits::_get_get_property_list(); \
} \
\
static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list) { \
static const GDExtensionPropertyInfo *get_property_list_bind(GDExtensionClassInstancePtr p_instance, uint32_t *r_count) { \
if (!p_instance) { \
if (r_count) \
*r_count = 0; \
return nullptr; \
} \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
::godot::List<::godot::PropertyInfo> &plist_cpp = cls->plist_owned; \
ERR_FAIL_COND_V_MSG(!plist_cpp.is_empty(), nullptr, "Internal error, property list was not freed by engine!"); \
cls->_get_property_list(&plist_cpp); \
return ::godot::internal::create_c_property_list(plist_cpp, r_count); \
} \
\
static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list, uint32_t /*p_count*/) { \
if (p_instance) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
ERR_FAIL_COND_MSG(cls->plist == nullptr, "Internal error, property list double free!"); \
memfree(cls->plist); \
cls->plist = nullptr; \
cls->plist_size = 0; \
cls->plist_owned.clear(); \
::godot::internal::free_c_property_list(const_cast<GDExtensionPropertyInfo *>(p_list)); \
} \
} \
\
@@ -268,6 +352,21 @@ public:
return false; \
} \
\
static GDExtensionBool validate_property_bind(GDExtensionClassInstancePtr p_instance, GDExtensionPropertyInfo *p_property) { \
bool ret = false; \
if (p_instance && m_class::_get_validate_property()) { \
ret = m_inherits::validate_property_bind(p_instance, p_property); \
if (m_class::_get_validate_property() != m_inherits::_get_validate_property()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
::godot::PropertyInfo info(p_property); \
cls->_validate_property(info); \
info._update(p_property); \
return true; \
} \
} \
return ret; \
} \
\
static void to_string_bind(GDExtensionClassInstancePtr p_instance, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out) { \
if (p_instance && m_class::_get_to_string()) { \
if (m_class::_get_to_string() != m_inherits::_get_to_string()) { \
@@ -280,7 +379,7 @@ public:
} \
} \
\
static void free(void *data, GDExtensionClassInstancePtr ptr) { \
static void free(void * /*data*/, GDExtensionClassInstancePtr ptr) { \
if (ptr) { \
m_class *cls = reinterpret_cast<m_class *>(ptr); \
cls->~m_class(); \
@@ -288,97 +387,124 @@ public:
} \
} \
\
static void *___binding_create_callback(void *p_token, void *p_instance) { \
static void *_gde_binding_create_callback(void * /*p_token*/, void * /*p_instance*/) { \
return nullptr; \
} \
\
static void ___binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \
static void _gde_binding_free_callback(void * /*p_token*/, void * /*p_instance*/, void * /*p_binding*/) { \
} \
\
static GDExtensionBool ___binding_reference_callback(void *p_token, void *p_instance, GDExtensionBool p_reference) { \
static GDExtensionBool _gde_binding_reference_callback(void * /*p_token*/, void * /*p_instance*/, GDExtensionBool /*p_reference*/) { \
return true; \
} \
\
static constexpr GDExtensionInstanceBindingCallbacks ___binding_callbacks = { \
___binding_create_callback, \
___binding_free_callback, \
___binding_reference_callback, \
};
static constexpr GDExtensionInstanceBindingCallbacks _gde_binding_callbacks = { \
_gde_binding_create_callback, \
_gde_binding_free_callback, \
_gde_binding_reference_callback, \
}; \
\
private:
// Don't use this for your classes, use GDCLASS() instead.
#define GDEXTENSION_CLASS(m_class, m_inherits) \
private: \
void operator=(const m_class &p_rval) {} \
\
protected: \
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const override { \
return &___binding_callbacks; \
} \
\
m_class(const char *p_godot_class) : m_inherits(p_godot_class) {} \
m_class(GodotObject *p_godot_object) : m_inherits(p_godot_object) {} \
\
static void (*_get_bind_methods())() { \
return nullptr; \
} \
\
static void (Wrapped::*_get_notification())(int) { \
return nullptr; \
} \
\
static bool (Wrapped::*_get_set())(const ::godot::StringName &p_name, const Variant &p_property) { \
return nullptr; \
} \
\
static bool (Wrapped::*_get_get())(const ::godot::StringName &p_name, Variant &r_ret) const { \
return nullptr; \
} \
\
static void (Wrapped::*_get_get_property_list())(List<PropertyInfo> * p_list) const { \
return nullptr; \
} \
\
static bool (Wrapped::*_get_property_can_revert())(const ::godot::StringName &p_name) { \
return nullptr; \
} \
\
static bool (Wrapped::*_get_property_get_revert())(const ::godot::StringName &p_name, Variant &) { \
return nullptr; \
} \
\
static String (Wrapped::*_get_to_string())() { \
return nullptr; \
} \
\
public: \
static void initialize_class() {} \
\
static ::godot::StringName &get_class_static() { \
static ::godot::StringName string_name = ::godot::StringName(#m_class); \
return string_name; \
} \
\
static ::godot::StringName &get_parent_class_static() { \
return m_inherits::get_class_static(); \
} \
\
static void *___binding_create_callback(void *p_token, void *p_instance) { \
/* Do not call memnew here, we don't want the postinitializer to be called */ \
return new ("") m_class((GodotObject *)p_instance); \
} \
static void ___binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \
/* Explicitly call the deconstructor to ensure proper lifecycle for non-trivial members */ \
reinterpret_cast<m_class *>(p_binding)->~m_class(); \
Memory::free_static(reinterpret_cast<m_class *>(p_binding)); \
} \
static GDExtensionBool ___binding_reference_callback(void *p_token, void *p_instance, GDExtensionBool p_reference) { \
return true; \
} \
static constexpr GDExtensionInstanceBindingCallbacks ___binding_callbacks = { \
___binding_create_callback, \
___binding_free_callback, \
___binding_reference_callback, \
}; \
m_class() : m_class(#m_class) {}
#define GDEXTENSION_CLASS_ALIAS(m_class, m_alias_for, m_inherits) /******************************************************************************************************************/ \
private: \
inline static ::godot::internal::EngineClassRegistration<m_class> _gde_engine_class_registration_helper; \
void operator=(const m_class &p_rval) {} \
friend class ::godot::ClassDB; \
friend class ::godot::Wrapped; \
\
protected: \
m_class(const char *p_godot_class) : m_inherits(p_godot_class) {} \
m_class(GodotObject *p_godot_object) : m_inherits(p_godot_object) {} \
\
static void _bind_methods() {} \
\
static void (*_get_bind_methods())() { \
return nullptr; \
} \
\
static void (Wrapped::*_get_notification())(int) { \
return nullptr; \
} \
\
static bool (Wrapped::*_get_set())(const ::godot::StringName &p_name, const Variant &p_property) { \
return nullptr; \
} \
\
static bool (Wrapped::*_get_get())(const ::godot::StringName &p_name, Variant &r_ret) const { \
return nullptr; \
} \
\
static inline bool has_get_property_list() { \
return false; \
} \
\
static void (Wrapped::*_get_get_property_list())(List<PropertyInfo> * p_list) const { \
return nullptr; \
} \
\
static bool (Wrapped::*_get_property_can_revert())(const ::godot::StringName &p_name) const { \
return nullptr; \
} \
\
static bool (Wrapped::*_get_property_get_revert())(const ::godot::StringName &p_name, Variant &) const { \
return nullptr; \
} \
\
static void (Wrapped::*_get_validate_property())(::godot::PropertyInfo & p_property) const { \
return nullptr; \
} \
\
static String (Wrapped::*_get_to_string())() const { \
return nullptr; \
} \
\
public: \
typedef m_class self_type; \
typedef m_inherits parent_type; \
\
static void initialize_class() {} \
\
static const ::godot::StringName &get_class_static() { \
static const ::godot::StringName string_name = ::godot::StringName(#m_alias_for); \
return string_name; \
} \
\
static const ::godot::StringName &get_parent_class_static() { \
return m_inherits::get_class_static(); \
} \
\
static void free(void *data, GDExtensionClassInstancePtr ptr) { \
} \
\
static void *_gde_binding_create_callback(void *p_token, void *p_instance) { \
/* Do not call memnew here, we don't want the post-initializer to be called */ \
return new ("", "") m_class((GodotObject *)p_instance); \
} \
static void _gde_binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \
/* Explicitly call the deconstructor to ensure proper lifecycle for non-trivial members */ \
reinterpret_cast<m_class *>(p_binding)->~m_class(); \
Memory::free_static(reinterpret_cast<m_class *>(p_binding)); \
} \
static GDExtensionBool _gde_binding_reference_callback(void *p_token, void *p_instance, GDExtensionBool p_reference) { \
return true; \
} \
static constexpr GDExtensionInstanceBindingCallbacks _gde_binding_callbacks = { \
_gde_binding_create_callback, \
_gde_binding_free_callback, \
_gde_binding_reference_callback, \
}; \
m_class() : m_class(#m_alias_for) {} \
\
private:
#endif // GODOT_WRAPPED_HPP
// 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(__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()
#define GDVIRTUAL_IS_OVERRIDDEN_PTR(m_obj, m_name) m_obj->_gdvirtual_##m_name##_overridden()

View File

@@ -28,16 +28,15 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_BINDER_COMMON_HPP
#define GODOT_BINDER_COMMON_HPP
#pragma once
#include <gdextension_interface.h>
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/core/method_ptrcall.hpp>
#include <godot_cpp/core/type_info.hpp>
#include <array>
#include <vector>
namespace godot {
@@ -83,7 +82,7 @@ namespace godot {
}; \
}
template <class T>
template <typename T>
struct VariantCaster {
static _FORCE_INLINE_ T cast(const Variant &p_variant) {
using TStripped = std::remove_pointer_t<T>;
@@ -95,7 +94,7 @@ struct VariantCaster {
}
};
template <class T>
template <typename T>
struct VariantCaster<T &> {
static _FORCE_INLINE_ T cast(const Variant &p_variant) {
using TStripped = std::remove_pointer_t<T>;
@@ -107,7 +106,7 @@ struct VariantCaster<T &> {
}
};
template <class T>
template <typename T>
struct VariantCaster<const T &> {
static _FORCE_INLINE_ T cast(const Variant &p_variant) {
using TStripped = std::remove_pointer_t<T>;
@@ -144,11 +143,11 @@ struct VariantObjectClassChecker<const Ref<T> &> {
}
};
template <class T>
template <typename T>
struct VariantCasterAndValidate {
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) {
GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE);
if (!internal::gde_interface->variant_can_convert_strict(static_cast<GDExtensionVariantType>(p_args[p_arg_idx]->get_type()), argtype) ||
if (!internal::gdextension_interface_variant_can_convert_strict(static_cast<GDExtensionVariantType>(p_args[p_arg_idx]->get_type()), argtype) ||
!VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
r_error.error = GDEXTENSION_CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = p_arg_idx;
@@ -159,11 +158,11 @@ struct VariantCasterAndValidate {
}
};
template <class T>
template <typename T>
struct VariantCasterAndValidate<T &> {
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) {
GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE);
if (!internal::gde_interface->variant_can_convert_strict(static_cast<GDExtensionVariantType>(p_args[p_arg_idx]->get_type()), argtype) ||
if (!internal::gdextension_interface_variant_can_convert_strict(static_cast<GDExtensionVariantType>(p_args[p_arg_idx]->get_type()), argtype) ||
!VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
r_error.error = GDEXTENSION_CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = p_arg_idx;
@@ -174,11 +173,11 @@ struct VariantCasterAndValidate<T &> {
}
};
template <class T>
template <typename T>
struct VariantCasterAndValidate<const T &> {
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) {
GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE);
if (!internal::gde_interface->variant_can_convert_strict(static_cast<GDExtensionVariantType>(p_args[p_arg_idx]->get_type()), argtype) ||
if (!internal::gdextension_interface_variant_can_convert_strict(static_cast<GDExtensionVariantType>(p_args[p_arg_idx]->get_type()), argtype) ||
!VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
r_error.error = GDEXTENSION_CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = p_arg_idx;
@@ -189,47 +188,47 @@ struct VariantCasterAndValidate<const T &> {
}
};
template <class T, class... P, size_t... Is>
template <typename T, typename... P, size_t... Is>
void call_with_ptr_args_helper(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) {
(p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...);
}
template <class T, class... P, size_t... Is>
template <typename T, typename... P, size_t... Is>
void call_with_ptr_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) {
(p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...);
}
template <class T, class R, class... P, size_t... Is>
template <typename T, typename R, typename... P, size_t... Is>
void call_with_ptr_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence<Is...>) {
PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
}
template <class T, class R, class... P, size_t... Is>
template <typename T, typename R, typename... P, size_t... Is>
void call_with_ptr_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence<Is...>) {
PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
}
template <class T, class... P>
template <typename T, typename... P>
void call_with_ptr_args(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void * /*ret*/) {
call_with_ptr_args_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}
template <class T, class... P>
template <typename T, typename... P>
void call_with_ptr_args(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void * /*ret*/) {
call_with_ptr_argsc_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}
template <class T, class R, class... P>
template <typename T, typename R, typename... P>
void call_with_ptr_args(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret) {
call_with_ptr_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
template <class T, class R, class... P>
template <typename T, typename R, typename... P>
void call_with_ptr_args(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void *r_ret) {
call_with_ptr_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
template <class T, class... P, size_t... Is>
template <typename T, typename... P, size_t... Is>
void call_with_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK;
@@ -241,7 +240,7 @@ void call_with_variant_args_helper(T *p_instance, void (T::*p_method)(P...), con
(void)(p_args); // Avoid warning.
}
template <class T, class... P, size_t... Is>
template <typename T, typename... P, size_t... Is>
void call_with_variant_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK;
@@ -253,7 +252,7 @@ void call_with_variant_argsc_helper(T *p_instance, void (T::*p_method)(P...) con
(void)(p_args); // Avoid warning.
}
template <class T, class R, class... P, size_t... Is>
template <typename T, typename R, typename... P, size_t... Is>
void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK;
@@ -262,9 +261,10 @@ void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), co
#else
r_ret = (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
#endif
(void)p_args; // Avoid warning.
}
template <class T, class R, class... P, size_t... Is>
template <typename T, typename R, typename... P, size_t... Is>
void call_with_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK;
@@ -273,15 +273,69 @@ void call_with_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) co
#else
r_ret = (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
#endif
(void)p_args;
(void)p_args; // Avoid warning.
}
template <class T, class... P>
void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
template <typename T, typename... P>
void call_with_variant_args(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, int p_argcount, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
r_error.expected = (int32_t)sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
call_with_variant_args_helper<T, P...>(p_instance, p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <typename T, typename R, typename... P>
void call_with_variant_args_ret(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
call_with_variant_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <typename T, typename R, typename... P>
void call_with_variant_args_retc(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
call_with_variant_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <typename T, typename... P>
void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const LocalVector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
@@ -292,7 +346,7 @@ void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const G
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
@@ -311,12 +365,12 @@ void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const G
call_with_variant_args_helper(p_instance, p_method, argsp.data(), r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <class T, class... P>
void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
template <typename T, typename... P>
void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const LocalVector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
@@ -327,7 +381,7 @@ void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const,
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
@@ -346,12 +400,12 @@ void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const,
call_with_variant_argsc_helper(p_instance, p_method, argsp.data(), r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <class T, class R, class... P>
void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
template <typename T, typename R, typename... P>
void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const LocalVector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
@@ -362,7 +416,7 @@ void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
@@ -381,12 +435,12 @@ void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const
call_with_variant_args_ret_helper(p_instance, p_method, argsp.data(), r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <class T, class R, class... P>
void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
template <typename T, typename R, typename... P>
void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const LocalVector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
@@ -397,7 +451,7 @@ void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const,
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
@@ -423,7 +477,7 @@ void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const,
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#endif
template <class Q>
template <typename Q>
void call_get_argument_type_helper(int p_arg, int &index, GDExtensionVariantType &type) {
if (p_arg == index) {
type = GDExtensionVariantType(GetTypeInfo<Q>::VARIANT_TYPE);
@@ -431,7 +485,7 @@ void call_get_argument_type_helper(int p_arg, int &index, GDExtensionVariantType
index++;
}
template <class... P>
template <typename... P>
GDExtensionVariantType call_get_argument_type(int p_arg) {
GDExtensionVariantType type = GDEXTENSION_VARIANT_TYPE_NIL;
int index = 0;
@@ -443,7 +497,7 @@ GDExtensionVariantType call_get_argument_type(int p_arg) {
return type;
}
template <class Q>
template <typename Q>
void call_get_argument_type_info_helper(int p_arg, int &index, PropertyInfo &info) {
if (p_arg == index) {
info = GetTypeInfo<Q>::get_class_info();
@@ -451,7 +505,7 @@ void call_get_argument_type_info_helper(int p_arg, int &index, PropertyInfo &inf
index++;
}
template <class... P>
template <typename... P>
void call_get_argument_type_info(int p_arg, PropertyInfo &info) {
int index = 0;
// I think rocket science is simpler than modern C++.
@@ -461,7 +515,7 @@ void call_get_argument_type_info(int p_arg, PropertyInfo &info) {
(void)index; // Suppress GCC warning.
}
template <class Q>
template <typename Q>
void call_get_argument_metadata_helper(int p_arg, int &index, GDExtensionClassMethodArgumentMetadata &md) {
if (p_arg == index) {
md = GetTypeInfo<Q>::METADATA;
@@ -469,7 +523,7 @@ void call_get_argument_metadata_helper(int p_arg, int &index, GDExtensionClassMe
index++;
}
template <class... P>
template <typename... P>
GDExtensionClassMethodArgumentMetadata call_get_argument_metadata(int p_arg) {
GDExtensionClassMethodArgumentMetadata md = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
@@ -482,7 +536,7 @@ GDExtensionClassMethodArgumentMetadata call_get_argument_metadata(int p_arg) {
return md;
}
template <class... P, size_t... Is>
template <typename... P, size_t... Is>
void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_args, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK;
@@ -493,12 +547,12 @@ void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_arg
#endif
}
template <class... P>
void call_with_variant_args_static_dv(void (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
template <typename... P>
void call_with_variant_args_static_dv(void (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const LocalVector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument = sizeof...(P);
r_error.expected = sizeof...(P);
return;
}
#endif
@@ -509,7 +563,7 @@ void call_with_variant_args_static_dv(void (*p_method)(P...), const GDExtensionC
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = sizeof...(P);
r_error.expected = sizeof...(P);
return;
}
#endif
@@ -528,17 +582,53 @@ void call_with_variant_args_static_dv(void (*p_method)(P...), const GDExtensionC
call_with_variant_args_static(p_method, argsp.data(), r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <class... P, size_t... Is>
template <typename... P, size_t... Is>
void call_with_ptr_args_static_method_helper(void (*p_method)(P...), const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) {
p_method(PtrToArg<P>::convert(p_args[Is])...);
}
template <class... P>
template <typename... P>
void call_with_ptr_args_static_method(void (*p_method)(P...), const GDExtensionConstTypePtr *p_args) {
call_with_ptr_args_static_method_helper<P...>(p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}
template <class R, class... P, size_t... Is>
template <typename R, typename... P>
void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
call_with_variant_args_static_ret<R, P...>(p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <typename... P>
void call_with_variant_args_static_ret(void (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
call_with_variant_args_static<P...>(p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <typename R, typename... P, size_t... Is>
void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK;
@@ -549,12 +639,12 @@ void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_ar
#endif
}
template <class R, class... P>
void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
template <typename R, typename... P>
void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const LocalVector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument = sizeof...(P);
r_error.expected = sizeof...(P);
return;
}
#endif
@@ -565,7 +655,7 @@ void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const GDExtension
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = sizeof...(P);
r_error.expected = sizeof...(P);
return;
}
#endif
@@ -584,12 +674,12 @@ void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const GDExtension
call_with_variant_args_static_ret(p_method, argsp.data(), r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <class R, class... P, size_t... Is>
template <typename R, typename... P, size_t... Is>
void call_with_ptr_args_static_method_ret_helper(R (*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence<Is...>) {
PtrToArg<R>::encode(p_method(PtrToArg<P>::convert(p_args[Is])...), r_ret);
}
template <class R, class... P>
template <typename R, typename... P>
void call_with_ptr_args_static_method_ret(R (*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret) {
call_with_ptr_args_static_method_ret_helper<R, P...>(p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
@@ -602,5 +692,3 @@ void call_with_ptr_args_static_method_ret(R (*p_method)(P...), const GDExtension
#include <godot_cpp/classes/global_constants_binds.hpp>
#include <godot_cpp/variant/builtin_binds.hpp>
#endif // GODOT_BINDER_COMMON_HPP

View File

@@ -28,10 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_BUILTIN_PTRCALL_HPP
#define GODOT_BUILTIN_PTRCALL_HPP
#pragma once
#include <gdextension_interface.h>
#include <godot_cpp/core/object.hpp>
#include <array>
@@ -39,13 +39,24 @@ namespace godot {
namespace internal {
template <class... Args>
template <typename O, typename... Args>
O *_call_builtin_method_ptr_ret_obj(const GDExtensionPtrBuiltInMethod method, GDExtensionTypePtr base, const Args &...args) {
GodotObject *ret = nullptr;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } };
method(base, call_args.data(), &ret, sizeof...(Args));
if (ret == nullptr) {
return nullptr;
}
return reinterpret_cast<O *>(internal::get_object_instance_binding(ret));
}
template <typename... Args>
void _call_builtin_constructor(const GDExtensionPtrConstructor constructor, GDExtensionTypePtr base, Args... args) {
std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } };
constructor(base, call_args.data());
}
template <class T, class... Args>
template <typename T, typename... Args>
T _call_builtin_method_ptr_ret(const GDExtensionPtrBuiltInMethod method, GDExtensionTypePtr base, Args... args) {
T ret;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } };
@@ -53,20 +64,20 @@ T _call_builtin_method_ptr_ret(const GDExtensionPtrBuiltInMethod method, GDExten
return ret;
}
template <class... Args>
template <typename... Args>
void _call_builtin_method_ptr_no_ret(const GDExtensionPtrBuiltInMethod method, GDExtensionTypePtr base, Args... args) {
std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } };
method(base, call_args.data(), nullptr, sizeof...(Args));
}
template <class T>
template <typename T>
T _call_builtin_operator_ptr(const GDExtensionPtrOperatorEvaluator op, GDExtensionConstTypePtr left, GDExtensionConstTypePtr right) {
T ret;
op(left, right, &ret);
return ret;
}
template <class T>
template <typename T>
T _call_builtin_ptr_getter(const GDExtensionPtrGetter getter, GDExtensionConstTypePtr base) {
T ret;
getter(base, &ret);
@@ -76,5 +87,3 @@ T _call_builtin_ptr_getter(const GDExtensionPtrGetter getter, GDExtensionConstTy
} // namespace internal
} // namespace godot
#endif // GODOT_BUILTIN_PTRCALL_HPP

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_CLASS_DB_HPP
#define GODOT_CLASS_DB_HPP
#pragma once
#include <gdextension_interface.h>
@@ -37,20 +36,18 @@
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/method_bind.hpp>
#include <godot_cpp/core/object.hpp>
#include <godot_cpp/core/print_string.hpp>
#include <godot_cpp/classes/class_db_singleton.hpp>
// Makes callable_mp readily available in all classes connecting signals.
// Needs to come after method_bind and object have been included.
#include <godot_cpp/variant/callable_method_pointer.hpp>
#include <godot_cpp/templates/a_hash_map.hpp>
#include <list>
#include <mutex>
#include <set>
#include <string>
#include <unordered_map>
#include <vector>
// Needed to use StringName as key in `std::unordered_map`
template <>
struct std::hash<godot::StringName> {
std::size_t operator()(godot::StringName const &s) const noexcept {
return s.hash();
}
};
namespace godot {
@@ -79,22 +76,18 @@ class ClassDB {
friend class godot::GDExtensionBinding;
public:
struct PropertySetGet {
int index;
StringName setter;
StringName getter;
MethodBind *_setptr;
MethodBind *_getptr;
Variant::Type type;
};
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;
AHashMap<StringName, MethodBind *> method_map;
std::set<StringName> signal_names;
std::unordered_map<StringName, GDExtensionClassCallVirtual> virtual_methods;
AHashMap<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.
@@ -103,98 +96,177 @@ public:
private:
// This may only contain custom classes, not Godot classes
static std::unordered_map<StringName, ClassInfo> classes;
static HashMap<StringName, ClassInfo> classes;
static AHashMap<StringName, const GDExtensionInstanceBindingCallbacks *> instance_binding_callbacks;
// Used to remember the custom class registration order.
static LocalVector<StringName> class_register_order;
static AHashMap<StringName, Object *> engine_singletons;
static std::mutex engine_singletons_mutex;
static MethodBind *bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const void **p_defs, int p_defcount);
static void initialize_class(const ClassInfo &cl);
static void bind_method_godot(const StringName &p_class_name, MethodBind *p_method);
template <class T, bool is_abstract>
static void _register_class(bool p_virtual = false);
template <typename T, bool is_abstract>
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, GDExtensionBool p_notify_postinitialize) {
if constexpr (!std::is_abstract_v<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;
}
}
template <typename T>
static GDExtensionClassInstancePtr _recreate_instance_func(void *data, GDExtensionObjectPtr obj) {
if constexpr (!std::is_abstract_v<T>) {
#ifdef HOT_RELOAD_ENABLED
#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
std::lock_guard<std::recursive_mutex> lk(Wrapped::_constructing_mutex);
#endif
Wrapped::_constructing_recreate_owner = obj;
T *new_instance = (T *)memalloc(sizeof(T));
memnew_placement(new_instance, T);
return new_instance;
#else
return nullptr;
#endif
} else {
return nullptr;
}
}
public:
template <class T>
template <typename T>
static void register_class(bool p_virtual = false);
template <class T>
template <typename T>
static void register_abstract_class();
template <typename T>
static void register_internal_class();
template <typename T>
static void register_runtime_class();
template <class N, class M, typename... VarArgs>
_FORCE_INLINE_ static void _register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
instance_binding_callbacks[p_name] = p_callbacks;
}
static void _register_engine_singleton(const StringName &p_class_name, Object *p_singleton) {
std::lock_guard<std::mutex> lock(engine_singletons_mutex);
AHashMap<StringName, Object *>::ConstIterator i = engine_singletons.find(p_class_name);
if (i != engine_singletons.end()) {
ERR_FAIL_COND((*i).value != p_singleton);
return;
}
engine_singletons[p_class_name] = p_singleton;
}
static void _unregister_engine_singleton(const StringName &p_class_name) {
std::lock_guard<std::mutex> lock(engine_singletons_mutex);
engine_singletons.erase(p_class_name);
}
template <typename N, typename M, typename... VarArgs>
static MethodBind *bind_method(N p_method_name, M p_method, VarArgs... p_args);
template <class N, class M, typename... VarArgs>
template <typename N, typename M, typename... VarArgs>
static MethodBind *bind_static_method(StringName p_class, N p_method_name, M p_method, VarArgs... p_args);
template <class M>
static MethodBind *bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const std::vector<Variant> &p_default_args = std::vector<Variant>{}, bool p_return_nil_is_variant = true);
template <typename M>
static MethodBind *bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const LocalVector<Variant> &p_default_args = LocalVector<Variant>{}, bool p_return_nil_is_variant = true);
static void add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix);
static void add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix);
static void add_property(const StringName &p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index = -1);
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);
static void bind_virtual_method(const StringName &p_class, const StringName &p_method, GDExtensionClassCallVirtual p_call);
// 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, 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);
static void deinitialize(GDExtensionInitializationLevel p_level);
CLASSDB_SINGLETON_FORWARD_METHODS;
};
#define BIND_CONSTANT(m_constant) \
godot::ClassDB::bind_integer_constant(get_class_static(), "", #m_constant, m_constant);
::godot::ClassDB::bind_integer_constant(get_class_static(), "", #m_constant, m_constant);
#define BIND_ENUM_CONSTANT(m_constant) \
godot::ClassDB::bind_integer_constant(get_class_static(), godot::__constant_get_enum_name(m_constant, #m_constant), #m_constant, m_constant);
::godot::ClassDB::bind_integer_constant(get_class_static(), ::godot::_gde_constant_get_enum_name(m_constant, #m_constant), #m_constant, m_constant);
#define BIND_BITFIELD_FLAG(m_constant) \
godot::ClassDB::bind_integer_constant(get_class_static(), godot::__constant_get_bitfield_name(m_constant, #m_constant), #m_constant, m_constant, true);
::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) \
{ \
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); \
#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, m_hash); \
}
template <class T, bool is_abstract>
void ClassDB::_register_class(bool p_virtual) {
template <typename T, bool is_abstract>
void ClassDB::_register_class(bool p_virtual, bool p_exposed, bool p_runtime) {
static_assert(TypesAreSame<typename T::self_type, T>::value, "Class not declared properly, please use GDCLASS.");
static_assert(!FunctionsAreSame<T::self_type::_bind_methods, T::parent_type::_bind_methods>::value, "Class must declare 'static void _bind_methods'.");
static_assert(!std::is_abstract_v<T> || is_abstract, "Class is abstract, please use GDREGISTER_ABSTRACT_CLASS.");
instance_binding_callbacks[T::get_class_static()] = &T::_gde_binding_callbacks;
// Register this class within our plugin
ClassInfo cl;
cl.name = T::get_class_static();
cl.parent_name = T::get_parent_class_static();
cl.level = current_level;
std::unordered_map<StringName, ClassInfo>::iterator parent_it = classes.find(cl.parent_name);
HashMap<StringName, ClassInfo>::Iterator parent_it = classes.find(cl.parent_name);
if (parent_it != classes.end()) {
// Assign parent if it is also a custom class
cl.parent_ptr = &parent_it->second;
cl.parent_ptr = &parent_it->value;
}
classes[cl.name] = cl;
class_register_order.push_back(cl.name);
// Register this class with Godot
GDExtensionClassCreationInfo 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::get_property_list_bind, // GDExtensionClassGetPropertyList get_property_list_func;
T::free_property_list_bind, // GDExtensionClassFreePropertyList free_property_list_func;
T::has_get_property_list() ? T::get_property_list_bind : nullptr, // GDExtensionClassGetPropertyList get_property_list_func;
T::free_property_list_bind, // GDExtensionClassFreePropertyList2 free_property_list_func;
T::property_can_revert_bind, // GDExtensionClassPropertyCanRevert property_can_revert_func;
T::property_get_revert_bind, // GDExtensionClassPropertyGetRevert property_get_revert_func;
T::notification_bind, // GDExtensionClassNotification notification_func;
T::validate_property_bind, // GDExtensionClassValidateProperty validate_property_func;
T::notification_bind, // GDExtensionClassNotification2 notification_func;
T::to_string_bind, // GDExtensionClassToString to_string_func;
nullptr, // GDExtensionClassReference reference_func;
nullptr, // GDExtensionClassUnreference unreference_func;
T::create, // GDExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
&_create_instance_func<T>, // GDExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
T::free, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
&_recreate_instance_func<T>, // GDExtensionClassRecreateInstance recreate_instance_func;
&ClassDB::get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
nullptr, // GDExtensionClassGetRID get_rid;
nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
nullptr, // GDExtensionClassCallVirtualWithData call_virtual_func;
(void *)&T::get_class_static(), // void *class_userdata;
};
internal::gde_interface->classdb_register_extension_class(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();
@@ -203,17 +275,27 @@ void ClassDB::_register_class(bool p_virtual) {
initialize_class(classes[cl.name]);
}
template <class T>
template <typename T>
void ClassDB::register_class(bool p_virtual) {
ClassDB::_register_class<T, false>(p_virtual);
}
template <class T>
template <typename T>
void ClassDB::register_abstract_class() {
ClassDB::_register_class<T, true>();
}
template <class N, class M, typename... VarArgs>
template <typename T>
void ClassDB::register_internal_class() {
ClassDB::_register_class<T, false>(false, false);
}
template <typename T>
void ClassDB::register_runtime_class() {
ClassDB::_register_class<T, false>(false, true, true);
}
template <typename N, typename M, typename... VarArgs>
MethodBind *ClassDB::bind_method(N p_method_name, M p_method, VarArgs... p_args) {
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
const Variant *argptrs[sizeof...(p_args) + 1];
@@ -224,7 +306,7 @@ MethodBind *ClassDB::bind_method(N p_method_name, M p_method, VarArgs... p_args)
return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const void **)argptrs, sizeof...(p_args));
}
template <class N, class M, typename... VarArgs>
template <typename N, typename M, typename... VarArgs>
MethodBind *ClassDB::bind_static_method(StringName p_class, N p_method_name, M p_method, VarArgs... p_args) {
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
const Variant *argptrs[sizeof...(p_args) + 1];
@@ -236,23 +318,23 @@ MethodBind *ClassDB::bind_static_method(StringName p_class, N p_method_name, M p
return bind_methodfi(0, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const void **)argptrs, sizeof...(p_args));
}
template <class M>
MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info, const std::vector<Variant> &p_default_args, bool p_return_nil_is_variant) {
template <typename M>
MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info, const LocalVector<Variant> &p_default_args, bool p_return_nil_is_variant) {
MethodBind *bind = create_vararg_method_bind(p_method, p_info, p_return_nil_is_variant);
ERR_FAIL_COND_V(!bind, nullptr);
ERR_FAIL_NULL_V(bind, nullptr);
bind->set_name(p_name);
bind->set_default_arguments(p_default_args);
StringName instance_type = bind->get_instance_class();
std::unordered_map<StringName, ClassInfo>::iterator type_it = classes.find(instance_type);
HashMap<StringName, ClassInfo>::Iterator type_it = classes.find(instance_type);
if (type_it == classes.end()) {
memdelete(bind);
ERR_FAIL_V_MSG(nullptr, String("Class '{0}' doesn't exist.").format(Array::make(instance_type)));
}
ClassInfo &type = type_it->second;
ClassInfo &type = type_it->value;
if (type.method_map.find(p_name) != type.method_map.end()) {
memdelete(bind);
@@ -268,10 +350,12 @@ MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p
return bind;
}
#define GDREGISTER_CLASS(m_class) ClassDB::register_class<m_class>();
#define GDREGISTER_VIRTUAL_CLASS(m_class) ClassDB::register_class<m_class>(true);
#define GDREGISTER_ABSTRACT_CLASS(m_class) ClassDB::register_abstract_class<m_class>();
#define GDREGISTER_CLASS(m_class) ::godot::ClassDB::register_class<m_class>();
#define GDREGISTER_VIRTUAL_CLASS(m_class) ::godot::ClassDB::register_class<m_class>(true);
#define GDREGISTER_ABSTRACT_CLASS(m_class) ::godot::ClassDB::register_abstract_class<m_class>();
#define GDREGISTER_INTERNAL_CLASS(m_class) ::godot::ClassDB::register_internal_class<m_class>();
#define GDREGISTER_RUNTIME_CLASS(m_class) ::godot::ClassDB::register_runtime_class<m_class>();
} // namespace godot
#endif // GODOT_CLASS_DB_HPP
CLASSDB_SINGLETON_VARIANT_CAST;

View File

@@ -28,12 +28,14 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_DEFS_HPP
#define GODOT_DEFS_HPP
#pragma once
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <type_traits>
#include <utility>
namespace godot {
#if !defined(GDE_EXPORT)
#if defined(_WIN32)
@@ -63,17 +65,31 @@
#endif
#endif
// Should always inline, except in debug builds because it makes debugging harder.
// Should always inline, except in dev builds because it makes debugging harder,
// or `size_enabled` builds where inlining is actively avoided.
#ifndef _FORCE_INLINE_
#ifdef DISABLE_FORCED_INLINE
#if defined(DEV_ENABLED) || defined(SIZE_EXTRA)
#define _FORCE_INLINE_ inline
#else
#define _FORCE_INLINE_ _ALWAYS_INLINE_
#endif
#endif
#ifndef _NO_DISCARD_
#define _NO_DISCARD_ [[nodiscard]]
// Should never inline.
#ifndef _NO_INLINE_
#if defined(__GNUC__)
#define _NO_INLINE_ __attribute__((noinline))
#elif defined(_MSC_VER)
#define _NO_INLINE_ __declspec(noinline)
#else
#define _NO_INLINE_
#endif
#endif
// In some cases [[nodiscard]] will get false positives,
// we can prevent the warning in specific cases by preceding the call with a cast.
#ifndef _ALLOW_DISCARD_
#define _ALLOW_DISCARD_ (void)
#endif
// Windows badly defines a lot of stuff we'll never use. Undefine it.
@@ -83,14 +99,182 @@
#undef ERROR // override (really stupid) wingdi.h standard definition
#undef DELETE // override (another really stupid) winnt.h standard definition
#undef MessageBox // override winuser.h standard definition
#undef MIN // override standard definition
#undef MAX // override standard definition
#undef CLAMP // override standard definition
#undef Error
#undef OK
#undef CONNECT_DEFERRED // override from Windows SDK, clashes with Object enum
#undef MemoryBarrier
#undef MONO_FONT
#endif
// Make room for our constexpr's below by overriding potential system-specific macros.
#undef SIGN
#undef MIN
#undef MAX
#undef CLAMP
template <typename T>
constexpr const T SIGN(const T m_v) {
return m_v > 0 ? +1.0f : (m_v < 0 ? -1.0f : 0.0f);
}
template <typename T, typename T2>
constexpr auto MIN(const T m_a, const T2 m_b) {
return m_a < m_b ? m_a : m_b;
}
template <typename T, typename T2>
constexpr auto MAX(const T m_a, const T2 m_b) {
return m_a > m_b ? m_a : m_b;
}
template <typename T, typename T2, typename T3>
constexpr auto CLAMP(const T m_a, const T2 m_min, const T3 m_max) {
return m_a < m_min ? m_min : (m_a > m_max ? m_max : m_a);
}
// Generic swap template.
#ifndef SWAP
#define SWAP(m_x, m_y) std::swap((m_x), (m_y))
#endif // SWAP
/* Functions to handle powers of 2 and shifting. */
// Returns `true` if a positive integer is a power of 2, `false` otherwise.
template <typename T>
inline bool is_power_of_2(const T x) {
return x && ((x & (x - 1)) == 0);
}
// Function to find the next power of 2 to an integer.
static _FORCE_INLINE_ unsigned int next_power_of_2(unsigned int x) {
if (x == 0) {
return 0;
}
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return ++x;
}
// Function to find the previous power of 2 to an integer.
static _FORCE_INLINE_ unsigned int previous_power_of_2(unsigned int x) {
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return x - (x >> 1);
}
// Function to find the closest power of 2 to an integer.
static _FORCE_INLINE_ unsigned int closest_power_of_2(unsigned int x) {
unsigned int nx = next_power_of_2(x);
unsigned int px = previous_power_of_2(x);
return (nx - x) > (x - px) ? px : nx;
}
// Get a shift value from a power of 2.
static inline int get_shift_from_power_of_2(unsigned int p_bits) {
for (unsigned int i = 0; i < 32; i++) {
if (p_bits == (unsigned int)(1 << i)) {
return i;
}
}
return -1;
}
template <typename T>
static _FORCE_INLINE_ T nearest_power_of_2_templated(T x) {
--x;
// The number of operations on x is the base two logarithm
// of the number of bits in the type. Add three to account
// for sizeof(T) being in bytes.
size_t num = get_shift_from_power_of_2(sizeof(T)) + 3;
// If the compiler is smart, it unrolls this loop.
// If it's dumb, this is a bit slow.
for (size_t i = 0; i < num; i++) {
x |= x >> (1 << i);
}
return ++x;
}
// Function to find the nearest (bigger) power of 2 to an integer.
static inline unsigned int nearest_shift(unsigned int p_number) {
for (int i = 30; i >= 0; i--) {
if (p_number & (1 << i)) {
return i + 1;
}
}
return 0;
}
// constexpr function to find the floored log2 of a number
template <typename T>
constexpr T floor_log2(T x) {
return x < 2 ? x : 1 + floor_log2(x >> 1);
}
// Get the number of bits needed to represent the number.
// IE, if you pass in 8, you will get 4.
// If you want to know how many bits are needed to store 8 values however, pass in (8 - 1).
template <typename T>
constexpr T get_num_bits(T x) {
return floor_log2(x);
}
// Swap 16, 32 and 64 bits value for endianness.
#if defined(__GNUC__)
#define BSWAP16(x) __builtin_bswap16(x)
#define BSWAP32(x) __builtin_bswap32(x)
#define BSWAP64(x) __builtin_bswap64(x)
#elif defined(_MSC_VER)
#define BSWAP16(x) _byteswap_ushort(x)
#define BSWAP32(x) _byteswap_ulong(x)
#define BSWAP64(x) _byteswap_uint64(x)
#else
static inline uint16_t BSWAP16(uint16_t x) {
return (x >> 8) | (x << 8);
}
static inline uint32_t BSWAP32(uint32_t x) {
return ((x << 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x >> 24));
}
static inline uint64_t BSWAP64(uint64_t x) {
x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32;
x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8;
return x;
}
#endif
// Generic comparator used in Map, List, etc.
template <typename T>
struct Comparator {
_ALWAYS_INLINE_ bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); }
};
// Global lock macro, relies on the static Mutex::_global_mutex.
void _global_lock();
void _global_unlock();
struct _GlobalLock {
_GlobalLock() { _global_lock(); }
~_GlobalLock() { _global_unlock(); }
};
#define GLOBAL_LOCK_FUNCTION _GlobalLock _global_lock_;
#if defined(__GNUC__)
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
@@ -99,22 +283,17 @@
#define unlikely(x) x
#endif
#ifdef REAL_T_IS_DOUBLE
typedef double real_t;
#if defined(__GNUC__)
#define _PRINTF_FORMAT_ATTRIBUTE_2_0 __attribute__((format(printf, 2, 0)))
#define _PRINTF_FORMAT_ATTRIBUTE_2_3 __attribute__((format(printf, 2, 3)))
#else
typedef float real_t;
#define _PRINTF_FORMAT_ATTRIBUTE_2_0
#define _PRINTF_FORMAT_ATTRIBUTE_2_3
#endif
// Generic swap template.
#ifndef SWAP
#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y))
template <class T>
inline void __swap_tmpl(T &x, T &y) {
T aux = x;
x = y;
y = aux;
}
#endif // SWAP
// This is needed due to a strange OpenGL API that expects a pointer
// type for an argument that is actually an offset.
#define CAST_INT_TO_UCHAR_PTR(ptr) ((uint8_t *)(uintptr_t)(ptr))
// Home-made index sequence trick, so it can be used everywhere without the costly include of std::tuple.
// https://stackoverflow.com/questions/15014096/c-index-of-type-during-variadic-template-expansion
@@ -127,4 +306,36 @@ struct BuildIndexSequence : BuildIndexSequence<N - 1, N - 1, Is...> {};
template <size_t... Is>
struct BuildIndexSequence<0, Is...> : IndexSequence<Is...> {};
#endif // GODOT_DEFS_HPP
// Limit the depth of recursive algorithms when dealing with Array/Dictionary
#define MAX_RECURSION 100
#ifdef DEBUG_ENABLED
#define DEBUG_METHODS_ENABLED
#endif
// Macro GD_IS_DEFINED() allows to check if a macro is defined. It needs to be defined to anything (say 1) to work.
#define __GDARG_PLACEHOLDER_1 false,
#define __gd_take_second_arg(__ignored, val, ...) val
#define ____gd_is_defined(arg1_or_junk) __gd_take_second_arg(arg1_or_junk true, false)
#define ___gd_is_defined(val) ____gd_is_defined(__GDARG_PLACEHOLDER_##val)
#define GD_IS_DEFINED(x) ___gd_is_defined(x)
// Whether the default value of a type is just all-0 bytes.
// This can most commonly be exploited by using memset for these types instead of loop-construct.
// Trivially constructible types are also zero-constructible.
template <typename T>
struct is_zero_constructible : std::is_trivially_constructible<T> {};
template <typename T>
struct is_zero_constructible<const T> : is_zero_constructible<T> {};
template <typename T>
struct is_zero_constructible<volatile T> : is_zero_constructible<T> {};
template <typename T>
struct is_zero_constructible<const volatile T> : is_zero_constructible<T> {};
template <typename T>
inline constexpr bool is_zero_constructible_v = is_zero_constructible<T>::value;
} //namespace godot

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_ENGINE_PTRCALL_HPP
#define GODOT_ENGINE_PTRCALL_HPP
#pragma once
#include <gdextension_interface.h>
@@ -43,48 +42,48 @@ namespace godot {
namespace internal {
template <class O, class... Args>
template <typename O, typename... Args>
O *_call_native_mb_ret_obj(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) {
GodotObject *ret = nullptr;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
internal::gde_interface->object_method_bind_ptrcall(mb, instance, mb_args.data(), &ret);
internal::gdextension_interface_object_method_bind_ptrcall(mb, instance, mb_args.data(), &ret);
if (ret == nullptr) {
return nullptr;
}
return reinterpret_cast<O *>(internal::gde_interface->object_get_instance_binding(ret, internal::token, &O::___binding_callbacks));
return reinterpret_cast<O *>(internal::get_object_instance_binding(ret));
}
template <class R, class... Args>
template <typename R, typename... Args>
R _call_native_mb_ret(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) {
R ret;
typename PtrToArg<R>::EncodeT ret;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
internal::gde_interface->object_method_bind_ptrcall(mb, instance, mb_args.data(), &ret);
return ret;
internal::gdextension_interface_object_method_bind_ptrcall(mb, instance, mb_args.data(), &ret);
return static_cast<R>(ret);
}
template <class... Args>
template <typename... Args>
void _call_native_mb_no_ret(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) {
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
internal::gde_interface->object_method_bind_ptrcall(mb, instance, mb_args.data(), nullptr);
internal::gdextension_interface_object_method_bind_ptrcall(mb, instance, mb_args.data(), nullptr);
}
template <class R, class... Args>
template <typename R, typename... Args>
R _call_utility_ret(GDExtensionPtrUtilityFunction func, const Args &...args) {
R ret;
typename PtrToArg<R>::EncodeT ret;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
func(&ret, mb_args.data(), mb_args.size());
return ret;
return static_cast<R>(ret);
}
template <class... Args>
Object *_call_utility_ret_obj(const GDExtensionPtrUtilityFunction func, void *instance, const Args &...args) {
template <typename... Args>
Object *_call_utility_ret_obj(const GDExtensionPtrUtilityFunction func, const Args &...args) {
GodotObject *ret = nullptr;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
func(&ret, mb_args.data(), mb_args.size());
return (Object *)internal::gde_interface->object_get_instance_binding(ret, internal::token, &Object::___binding_callbacks);
return (Object *)internal::get_object_instance_binding(ret);
}
template <class... Args>
template <typename... Args>
void _call_utility_no_ret(const GDExtensionPtrUtilityFunction func, const Args &...args) {
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
func(nullptr, mb_args.data(), mb_args.size());
@@ -93,5 +92,3 @@ void _call_utility_no_ret(const GDExtensionPtrUtilityFunction func, const Args &
} // namespace internal
} // namespace godot
#endif // GODOT_ENGINE_PTRCALL_HPP

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_ERROR_MACROS_HPP
#define GODOT_ERROR_MACROS_HPP
#pragma once
#include <godot_cpp/core/defs.hpp>
@@ -802,5 +801,3 @@ void _err_flush_stdout();
#define CHECK_METHOD_BIND_RET(m_mb, m_ret)
#define CHECK_METHOD_BIND(m_mb)
#endif
#endif // GODOT_ERROR_MACROS_HPP

View File

@@ -0,0 +1,51 @@
/**************************************************************************/
/* math.compat.inc */
/**************************************************************************/
/* 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 DISABLE_DEPRECATED
namespace godot {
#undef ABS
// Generic ABS function, for math uses please use Math::abs.
template <typename T>
[[deprecated("Use Math::abs instead")]]
constexpr T ABS(T m_v) {
return m_v < 0 ? -m_v : m_v;
}
}
// To maintain compatibility an alias is defined outside the namespace.
// Consider it deprecated.
using real_t = godot::real_t;
#endif

View File

@@ -28,10 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_MATH_HPP
#define GODOT_MATH_HPP
#pragma once
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/core/math_defs.hpp>
#include <gdextension_interface.h>
@@ -39,185 +39,8 @@
namespace godot {
#define Math_SQRT12 0.7071067811865475244008443621048490
#define Math_SQRT2 1.4142135623730950488016887242
#define Math_LN2 0.6931471805599453094172321215
#define Math_PI 3.1415926535897932384626433833
#define Math_TAU 6.2831853071795864769252867666
#define Math_E 2.7182818284590452353602874714
#define Math_INF INFINITY
#define Math_NAN NAN
// Make room for our constexpr's below by overriding potential system-specific macros.
#undef ABS
#undef SIGN
#undef MIN
#undef MAX
#undef CLAMP
// Generic ABS function, for math uses please use Math::abs.
template <typename T>
constexpr T ABS(T m_v) {
return m_v < 0 ? -m_v : m_v;
}
template <typename T>
constexpr const T SIGN(const T m_v) {
return m_v == 0 ? 0.0f : (m_v < 0 ? -1.0f : +1.0f);
}
template <typename T, typename T2>
constexpr auto MIN(const T m_a, const T2 m_b) {
return m_a < m_b ? m_a : m_b;
}
template <typename T, typename T2>
constexpr auto MAX(const T m_a, const T2 m_b) {
return m_a > m_b ? m_a : m_b;
}
template <typename T, typename T2, typename T3>
constexpr auto CLAMP(const T m_a, const T2 m_min, const T3 m_max) {
return m_a < m_min ? m_min : (m_a > m_max ? m_max : m_a);
}
// Generic swap template.
#ifndef SWAP
#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y))
template <class T>
inline void __swap_tmpl(T &x, T &y) {
T aux = x;
x = y;
y = aux;
}
#endif // SWAP
/* Functions to handle powers of 2 and shifting. */
// Function to find the next power of 2 to an integer.
static _FORCE_INLINE_ unsigned int next_power_of_2(unsigned int x) {
if (x == 0) {
return 0;
}
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return ++x;
}
// Function to find the previous power of 2 to an integer.
static _FORCE_INLINE_ unsigned int previous_power_of_2(unsigned int x) {
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return x - (x >> 1);
}
// Function to find the closest power of 2 to an integer.
static _FORCE_INLINE_ unsigned int closest_power_of_2(unsigned int x) {
unsigned int nx = next_power_of_2(x);
unsigned int px = previous_power_of_2(x);
return (nx - x) > (x - px) ? px : nx;
}
// Get a shift value from a power of 2.
static inline int get_shift_from_power_of_2(unsigned int p_bits) {
for (unsigned int i = 0; i < 32; i++) {
if (p_bits == (unsigned int)(1 << i)) {
return i;
}
}
return -1;
}
template <class T>
static _FORCE_INLINE_ T nearest_power_of_2_templated(T x) {
--x;
// The number of operations on x is the base two logarithm
// of the number of bits in the type. Add three to account
// for sizeof(T) being in bytes.
size_t num = get_shift_from_power_of_2(sizeof(T)) + 3;
// If the compiler is smart, it unrolls this loop.
// If it's dumb, this is a bit slow.
for (size_t i = 0; i < num; i++) {
x |= x >> (1 << i);
}
return ++x;
}
// Function to find the nearest (bigger) power of 2 to an integer.
static inline unsigned int nearest_shift(unsigned int p_number) {
for (int i = 30; i >= 0; i--) {
if (p_number & (1 << i)) {
return i + 1;
}
}
return 0;
}
// constexpr function to find the floored log2 of a number
template <typename T>
constexpr T floor_log2(T x) {
return x < 2 ? x : 1 + floor_log2(x >> 1);
}
// Get the number of bits needed to represent the number.
// IE, if you pass in 8, you will get 4.
// If you want to know how many bits are needed to store 8 values however, pass in (8 - 1).
template <typename T>
constexpr T get_num_bits(T x) {
return floor_log2(x);
}
// Swap 16, 32 and 64 bits value for endianness.
#if defined(__GNUC__)
#define BSWAP16(x) __builtin_bswap16(x)
#define BSWAP32(x) __builtin_bswap32(x)
#define BSWAP64(x) __builtin_bswap64(x)
#else
static inline uint16_t BSWAP16(uint16_t x) {
return (x >> 8) | (x << 8);
}
static inline uint32_t BSWAP32(uint32_t x) {
return ((x << 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x >> 24));
}
static inline uint64_t BSWAP64(uint64_t x) {
x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32;
x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8;
return x;
}
#endif
namespace Math {
// This epsilon should match the one used by Godot for consistency.
// Using `f` when `real_t` is float.
#define CMP_EPSILON 0.00001f
#define CMP_EPSILON2 (CMP_EPSILON * CMP_EPSILON)
// This epsilon is for values related to a unit size (scalar or vector len).
#ifdef PRECISE_MATH_CHECKS
#define UNIT_EPSILON 0.00001
#else
// Tolerate some more floating point error normally.
#define UNIT_EPSILON 0.001
#endif
// Functions reproduced as in Godot's source code `math_funcs.h`.
// Some are overloads to automatically support changing real_t into either double or float in the way Godot does.
@@ -538,6 +361,26 @@ inline float bezier_interpolate(float p_start, float p_control_1, float p_contro
return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0f + p_control_2 * omt * t2 * 3.0f + p_end * t3;
}
inline double bezier_derivative(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) {
/* Formula from Wikipedia article on Bezier curves. */
double omt = (1.0 - p_t);
double omt2 = omt * omt;
double t2 = p_t * p_t;
double d = (p_control_1 - p_start) * 3.0 * omt2 + (p_control_2 - p_control_1) * 6.0 * omt * p_t + (p_end - p_control_2) * 3.0 * t2;
return d;
}
inline float bezier_derivative(float p_start, float p_control_1, float p_control_2, float p_end, float p_t) {
/* Formula from Wikipedia article on Bezier curves. */
float omt = (1.0f - p_t);
float omt2 = omt * omt;
float t2 = p_t * p_t;
float d = (p_control_1 - p_start) * 3.0f * omt2 + (p_control_2 - p_control_1) * 6.0f * omt * p_t + (p_end - p_control_2) * 3.0f * t2;
return d;
}
template <typename T>
inline T clamp(T x, T minv, T maxv) {
if (x < minv) {
@@ -613,6 +456,14 @@ inline bool is_inf(double p_val) {
return std::isinf(p_val);
}
inline bool is_finite(float p_val) {
return std::isfinite(p_val);
}
inline bool is_finite(double p_val) {
return std::isfinite(p_val);
}
inline bool is_equal_approx(float a, float b) {
// Check for exact equality first, required to handle "infinity" values.
if (a == b) {
@@ -808,4 +659,4 @@ inline float snap_scalar_separation(float p_offset, float p_step, float p_target
} // namespace Math
} // namespace godot
#endif // GODOT_MATH_HPP
#include "math.compat.inc"

View File

@@ -0,0 +1,74 @@
/**************************************************************************/
/* math_defs.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. */
/**************************************************************************/
#pragma once
namespace godot {
#define CMP_EPSILON 0.00001
#define CMP_EPSILON2 (CMP_EPSILON * CMP_EPSILON)
#define CMP_NORMALIZE_TOLERANCE 0.000001
#define CMP_POINT_IN_PLANE_EPSILON 0.00001
#define Math_SQRT12 0.7071067811865475244008443621048490
#define Math_SQRT2 1.4142135623730950488016887242
#define Math_LN2 0.6931471805599453094172321215
#define Math_TAU 6.2831853071795864769252867666
#define Math_PI 3.1415926535897932384626433833
#define Math_E 2.7182818284590452353602874714
#define Math_INF INFINITY
#define Math_NAN NAN
#ifdef DEBUG_ENABLED
#define MATH_CHECKS
#endif
//this epsilon is for values related to a unit size (scalar or vector len)
#ifdef PRECISE_MATH_CHECKS
#define UNIT_EPSILON 0.00001
#else
//tolerate some more floating point error normally
#define UNIT_EPSILON 0.001
#endif
#define USEC_TO_SEC(m_usec) ((m_usec) / 1000000.0)
/**
* The "Real" type is an abstract type used for real numbers, such as 1.5,
* in contrast to integer numbers. Precision can be controlled with the
* presence or absence of the REAL_T_IS_DOUBLE define.
*/
#ifdef REAL_T_IS_DOUBLE
typedef double real_t;
#else
typedef float real_t;
#endif
} // namespace godot

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_MEMORY_HPP
#define GODOT_MEMORY_HPP
#pragma once
#include <cstddef>
#include <cstdint>
@@ -40,24 +39,21 @@
#include <type_traits>
#ifndef PAD_ALIGN
#define PAD_ALIGN 16 //must always be greater than this at much
#endif
// p_dummy argument is added to avoid conflicts with the engine functions when both engine and GDExtension are built as a static library on iOS.
void *operator new(size_t p_size, const char *p_dummy, const char *p_description); ///< operator new that takes a description and uses MemoryStaticPool
void *operator new(size_t p_size, const char *p_dummy, void *(*p_allocfunc)(size_t p_size)); ///< operator new that takes a description and uses MemoryStaticPool
void *operator new(size_t p_size, const char *p_dummy, void *p_pointer, size_t check, const char *p_description); ///< operator new that takes a description and uses a pointer to the preallocated memory
void *operator new(size_t p_size, const char *p_description); ///< operator new that takes a description and uses MemoryStaticPool
void *operator new(size_t p_size, void *(*p_allocfunc)(size_t p_size)); ///< operator new that takes a description and uses MemoryStaticPool
void *operator new(size_t p_size, void *p_pointer, size_t check, const char *p_description); ///< operator new that takes a description and uses a pointer to the preallocated memory
_ALWAYS_INLINE_ void *operator new(size_t p_size, void *p_pointer, size_t check, const char *p_description) {
_ALWAYS_INLINE_ void *operator new(size_t p_size, const char *p_dummy, void *p_pointer, size_t check, const char *p_description) {
return p_pointer;
}
#ifdef _MSC_VER
// When compiling with VC++ 2017, the above declarations of placement new generate many irrelevant warnings (C4291).
// The purpose of the following definitions is to muffle these warnings, not to provide a usable implementation of placement delete.
void operator delete(void *p_mem, const char *p_description);
void operator delete(void *p_mem, void *(*p_allocfunc)(size_t p_size));
void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_description);
void operator delete(void *p_mem, const char *p_dummy, const char *p_description);
void operator delete(void *p_mem, const char *p_dummy, void *(*p_allocfunc)(size_t p_size));
void operator delete(void *p_mem, const char *p_dummy, void *p_pointer, size_t check, const char *p_description);
#endif
namespace godot {
@@ -68,14 +64,29 @@ class Memory {
Memory();
public:
// Alignment: ↓ max_align_t ↓ uint64_t ↓ max_align_t
// ┌─────────────────┬──┬────────────────┬──┬───────────...
// │ uint64_t │░░│ uint64_t │░░│ T[]
// │ alloc size │░░│ element count │░░│ data
// └─────────────────┴──┴────────────────┴──┴───────────...
// Offset: ↑ SIZE_OFFSET ↑ ELEMENT_OFFSET ↑ DATA_OFFSET
// Note: "alloc size" is used and set by the engine and is never accessed or changed for the extension.
static constexpr size_t SIZE_OFFSET = 0;
static constexpr size_t ELEMENT_OFFSET = ((SIZE_OFFSET + sizeof(uint64_t)) % alignof(uint64_t) == 0) ? (SIZE_OFFSET + sizeof(uint64_t)) : ((SIZE_OFFSET + sizeof(uint64_t)) + alignof(uint64_t) - ((SIZE_OFFSET + sizeof(uint64_t)) % alignof(uint64_t)));
static constexpr size_t DATA_OFFSET = ((ELEMENT_OFFSET + sizeof(uint64_t)) % alignof(max_align_t) == 0) ? (ELEMENT_OFFSET + sizeof(uint64_t)) : ((ELEMENT_OFFSET + sizeof(uint64_t)) + alignof(max_align_t) - ((ELEMENT_OFFSET + sizeof(uint64_t)) % alignof(max_align_t)));
static void *alloc_static(size_t p_bytes, bool p_pad_align = false);
static void *realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align = false);
static void free_static(void *p_ptr, bool p_pad_align = false);
};
template <typename T, std::enable_if_t<!std::is_base_of<::godot::Wrapped, T>::value, bool> = true>
_ALWAYS_INLINE_ void _pre_initialize() {}
_ALWAYS_INLINE_ void postinitialize_handler(void *) {}
template <class T>
template <typename T>
_ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
postinitialize_handler(p_obj);
return p_obj;
@@ -85,34 +96,28 @@ _ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
#define memrealloc(m_mem, m_size) ::godot::Memory::realloc_static(m_mem, m_size)
#define memfree(m_mem) ::godot::Memory::free_static(m_mem)
#define memnew(m_class) ::godot::_post_initialize(new ("") m_class)
#define memnew(m_class) (::godot::_pre_initialize<std::remove_pointer_t<decltype(new ("", "") m_class)>>(), ::godot::_post_initialize(new ("", "") m_class))
#define memnew_allocator(m_class, m_allocator) ::godot::_post_initialize(new (m_allocator::alloc) m_class)
#define memnew_placement(m_placement, m_class) ::godot::_post_initialize(new (m_placement, sizeof(m_class), "") m_class)
#define memnew_allocator(m_class, m_allocator) (::godot::_pre_initialize<std::remove_pointer_t<decltype(new ("", "") m_class)>>(), ::godot::_post_initialize(new ("", m_allocator::alloc) m_class))
#define memnew_placement(m_placement, m_class) (::godot::_pre_initialize<std::remove_pointer_t<decltype(new ("", "") m_class)>>(), ::godot::_post_initialize(new ("", m_placement, sizeof(m_class), "") m_class))
// Generic comparator used in Map, List, etc.
template <class T>
struct Comparator {
_ALWAYS_INLINE_ bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); }
};
template <class T>
template <typename T>
void memdelete(T *p_class, typename std::enable_if<!std::is_base_of_v<godot::Wrapped, T>>::type * = nullptr) {
if (!std::is_trivially_destructible<T>::value) {
if constexpr (!std::is_trivially_destructible_v<T>) {
p_class->~T();
}
Memory::free_static(p_class);
}
template <class T, std::enable_if_t<std::is_base_of_v<godot::Wrapped, T>, bool> = true>
template <typename T, std::enable_if_t<std::is_base_of_v<godot::Wrapped, T>, bool> = true>
void memdelete(T *p_class) {
godot::internal::gde_interface->object_destroy(p_class->_owner);
godot::internal::gdextension_interface_object_destroy(p_class->_owner);
}
template <class T, class A>
template <typename T, typename A>
void memdelete_allocator(T *p_class) {
if (!std::is_trivially_destructible<T>::value) {
if constexpr (!std::is_trivially_destructible_v<T>) {
p_class->~T();
}
@@ -125,16 +130,20 @@ public:
_ALWAYS_INLINE_ static void free(void *p_ptr) { Memory::free_static(p_ptr); }
};
template <class T>
template <typename T>
class DefaultTypedAllocator {
public:
template <class... Args>
template <typename... Args>
_ALWAYS_INLINE_ T *new_allocation(const Args &&...p_args) { return memnew(T(p_args...)); }
_ALWAYS_INLINE_ void delete_allocation(T *p_allocation) { memdelete(p_allocation); }
};
#define memnew_arr(m_class, m_count) memnew_arr_template<m_class>(m_count)
_FORCE_INLINE_ uint64_t *_get_element_count_ptr(uint8_t *p_ptr) {
return (uint64_t *)(p_ptr - Memory::DATA_OFFSET + Memory::ELEMENT_OFFSET);
}
template <typename T>
T *memnew_arr_template(size_t p_elements, const char *p_descr = "") {
if (p_elements == 0) {
@@ -144,17 +153,19 @@ T *memnew_arr_template(size_t p_elements, const char *p_descr = "") {
same strategy used by std::vector, and the Vector class, so it should be safe.*/
size_t len = sizeof(T) * p_elements;
uint64_t *mem = (uint64_t *)Memory::alloc_static(len, true);
uint8_t *mem = (uint8_t *)Memory::alloc_static(len, true);
T *failptr = nullptr; // Get rid of a warning.
ERR_FAIL_COND_V(!mem, failptr);
*(mem - 1) = p_elements;
ERR_FAIL_NULL_V(mem, failptr);
if (!std::is_trivially_destructible<T>::value) {
uint64_t *_elem_count_ptr = _get_element_count_ptr(mem);
*(_elem_count_ptr) = p_elements;
if constexpr (!std::is_trivially_destructible_v<T>) {
T *elems = (T *)mem;
/* call operator new */
for (size_t i = 0; i < p_elements; i++) {
new (&elems[i], sizeof(T), p_descr) T;
new ("", &elems[i], sizeof(T), p_descr) T;
}
}
@@ -162,11 +173,19 @@ T *memnew_arr_template(size_t p_elements, const char *p_descr = "") {
}
template <typename T>
void memdelete_arr(T *p_class) {
uint64_t *ptr = (uint64_t *)p_class;
size_t memarr_len(const T *p_class) {
uint8_t *ptr = (uint8_t *)p_class;
uint64_t *_elem_count_ptr = _get_element_count_ptr(ptr);
return *(_elem_count_ptr);
}
if (!std::is_trivially_destructible<T>::value) {
uint64_t elem_count = *(ptr - 1);
template <typename T>
void memdelete_arr(T *p_class) {
uint8_t *ptr = (uint8_t *)p_class;
if constexpr (!std::is_trivially_destructible_v<T>) {
uint64_t *_elem_count_ptr = _get_element_count_ptr(ptr);
uint64_t elem_count = *(_elem_count_ptr);
for (uint64_t i = 0; i < elem_count; i++) {
p_class[i].~T();
@@ -190,5 +209,3 @@ struct _GlobalNilClass {
};
} // namespace godot
#endif // GODOT_MEMORY_HPP

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_METHOD_BIND_HPP
#define GODOT_METHOD_BIND_HPP
#pragma once
#include <godot_cpp/core/binder_common.hpp>
#include <godot_cpp/core/type_info.hpp>
@@ -39,44 +38,40 @@
#include <gdextension_interface.h>
#include <godot_cpp/classes/global_constants.hpp>
#include <string>
#include <vector>
#include <iostream>
#include <godot_cpp/templates/local_vector.hpp>
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 _is_const = false;
bool _has_return = false;
bool _const = false;
bool _returns = false;
bool _vararg = false;
std::vector<StringName> argument_names;
LocalVector<StringName> argument_names;
GDExtensionVariantType *argument_types = nullptr;
std::vector<Variant> default_arguments;
LocalVector<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_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);
void _generate_argument_types(int p_count);
void set_argument_count(int p_count) { argument_count = p_count; }
public:
StringName get_name() const;
void set_name(const StringName &p_name);
_FORCE_INLINE_ const LocalVector<Variant> &get_default_arguments() const { return default_arguments; }
_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,19 +92,6 @@ 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);
@@ -117,10 +99,9 @@ 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;
LocalVector<PropertyInfo> get_arguments_info_list() const {
LocalVector<PropertyInfo> vec;
// First element is return value
vec.reserve(argument_count + 1);
for (int i = 0; i < argument_count + 1; i++) {
@@ -128,31 +109,52 @@ public:
}
return vec;
}
std::vector<GDExtensionClassMethodArgumentMetadata> get_arguments_metadata_list() const {
std::vector<GDExtensionClassMethodArgumentMetadata> vec;
void set_argument_names(const LocalVector<StringName> &p_names);
LocalVector<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 LocalVector<Variant> &p_default_arguments) { default_arguments = p_default_arguments; }
LocalVector<GDExtensionClassMethodArgumentMetadata> get_arguments_metadata_list() const {
LocalVector<GDExtensionClassMethodArgumentMetadata> vec;
// First element is return value
vec.reserve(argument_count + 1);
for (int i = 0; i < argument_count; i++) {
for (int i = 0; i < argument_count + 1; i++) {
vec.push_back(get_argument_metadata(i - 1));
}
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);
virtual ~MethodBind();
};
template <class Derived, class T, class R, bool should_returns>
template <typename Derived, typename T, typename R, bool should_returns>
class MethodBindVarArgBase : public MethodBind {
protected:
R(T::*method)
(const Variant **, GDExtensionInt, GDExtensionCallError &);
std::vector<PropertyInfo> arguments;
R (T::*method)(const Variant **, GDExtensionInt, GDExtensionCallError &);
LocalVector<PropertyInfo> arguments;
public:
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
@@ -182,13 +184,13 @@ 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;
std::vector<StringName> names;
LocalVector<StringName> names;
names.reserve(p_method_info.arguments.size());
for (size_t i = 0; i < p_method_info.arguments.size(); i++) {
names.push_back(p_method_info.arguments[i].name);
@@ -196,8 +198,8 @@ public:
set_argument_names(names);
}
generate_argument_types((int)p_method_info.arguments.size());
set_return(should_returns);
_generate_argument_types((int)p_method_info.arguments.size());
_set_returns(should_returns);
}
~MethodBindVarArgBase() {}
@@ -208,7 +210,7 @@ private:
}
};
template <class T>
template <typename T>
class MethodBindVarArgT : public MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false> {
friend class MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>;
@@ -231,14 +233,14 @@ private:
}
};
template <class T>
template <typename T>
MethodBind *create_vararg_method_bind(void (T::*p_method)(const Variant **, GDExtensionInt, GDExtensionCallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) {
MethodBind *a = memnew((MethodBindVarArgT<T>)(p_method, p_info, p_return_nil_is_variant));
a->set_instance_class(T::get_class_static());
return a;
}
template <class T, class R>
template <typename T, typename R>
class MethodBindVarArgTR : public MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true> {
friend class MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>;
@@ -260,7 +262,7 @@ private:
}
};
template <class T, class R>
template <typename T, typename R>
MethodBind *create_vararg_method_bind(R (T::*p_method)(const Variant **, GDExtensionInt, GDExtensionCallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) {
MethodBind *a = memnew((MethodBindVarArgTR<T, R>)(p_method, p_info, p_return_nil_is_variant));
a->set_instance_class(T::get_class_static());
@@ -268,8 +270,8 @@ MethodBind *create_vararg_method_bind(R (T::*p_method)(const Variant **, GDExten
}
#ifndef TYPED_METHOD_BIND
class ___UnexistingClass;
#define MB_T ___UnexistingClass
class _gde_UnexistingClass;
#define MB_T _gde_UnexistingClass
#else
#define MB_T T
#endif
@@ -277,9 +279,9 @@ class ___UnexistingClass;
// No return, not const.
#ifdef TYPED_METHOD_BIND
template <class T, class... P>
template <typename T, typename... P>
#else
template <class... P>
template <typename... P>
#endif // TYPED_METHOD_BIND
class MethodBindT : public MethodBind {
void (MB_T::*method)(P...);
@@ -334,12 +336,12 @@ 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));
}
};
template <class T, class... P>
template <typename T, typename... P>
MethodBind *create_method_bind(void (T::*p_method)(P...)) {
#ifdef TYPED_METHOD_BIND
MethodBind *a = memnew((MethodBindT<T, P...>)(p_method));
@@ -353,9 +355,9 @@ MethodBind *create_method_bind(void (T::*p_method)(P...)) {
// No return, const.
#ifdef TYPED_METHOD_BIND
template <class T, class... P>
template <typename T, typename... P>
#else
template <class... P>
template <typename... P>
#endif // TYPED_METHOD_BIND
class MethodBindTC : public MethodBind {
void (MB_T::*method)(P...) const;
@@ -410,12 +412,13 @@ 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);
}
};
template <class T, class... P>
template <typename T, typename... P>
MethodBind *create_method_bind(void (T::*p_method)(P...) const) {
#ifdef TYPED_METHOD_BIND
MethodBind *a = memnew((MethodBindTC<T, P...>)(p_method));
@@ -429,13 +432,12 @@ MethodBind *create_method_bind(void (T::*p_method)(P...) const) {
// Return, not const.
#ifdef TYPED_METHOD_BIND
template <class T, class R, class... P>
template <typename T, typename R, typename... P>
#else
template <class R, class... P>
template <typename R, typename... P>
#endif // TYPED_METHOD_BIND
class MethodBindTR : public MethodBind {
R(MB_T::*method)
(P...);
R (MB_T::*method)(P...);
protected:
// GCC raises warnings in the case P = {} as the comparison is always false...
@@ -492,13 +494,13 @@ 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_return(true);
_set_returns(true);
}
};
template <class T, class R, class... P>
template <typename T, typename R, typename... P>
MethodBind *create_method_bind(R (T::*p_method)(P...)) {
#ifdef TYPED_METHOD_BIND
MethodBind *a = memnew((MethodBindTR<T, R, P...>)(p_method));
@@ -512,13 +514,12 @@ MethodBind *create_method_bind(R (T::*p_method)(P...)) {
// Return, const.
#ifdef TYPED_METHOD_BIND
template <class T, class R, class... P>
template <typename T, typename R, typename... P>
#else
template <class R, class... P>
template <typename R, typename... P>
#endif // TYPED_METHOD_BIND
class MethodBindTRC : public MethodBind {
R(MB_T::*method)
(P...) const;
R (MB_T::*method)(P...) const;
protected:
// GCC raises warnings in the case P = {} as the comparison is always false...
@@ -575,13 +576,14 @@ 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_return(true);
_set_returns(true);
_set_const(true);
}
};
template <class T, class R, class... P>
template <typename T, typename R, typename... P>
MethodBind *create_method_bind(R (T::*p_method)(P...) const) {
#ifdef TYPED_METHOD_BIND
MethodBind *a = memnew((MethodBindTRC<T, R, P...>)(p_method));
@@ -596,7 +598,7 @@ MethodBind *create_method_bind(R (T::*p_method)(P...) const) {
// no return
template <class... P>
template <typename... P>
class MethodBindTS : public MethodBind {
void (*function)(P...);
@@ -646,13 +648,13 @@ 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);
}
};
template <class... P>
template <typename... P>
MethodBind *create_static_method_bind(void (*p_method)(P...)) {
MethodBind *a = memnew((MethodBindTS<P...>)(p_method));
return a;
@@ -660,10 +662,9 @@ MethodBind *create_static_method_bind(void (*p_method)(P...)) {
// return
template <class R, class... P>
template <typename R, typename... P>
class MethodBindTRS : public MethodBind {
R(*function)
(P...);
R (*function)(P...);
protected:
// GCC raises warnings in the case P = {} as the comparison is always false...
@@ -715,19 +716,17 @@ 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_return(true);
_set_static(true);
_set_returns(true);
}
};
template <class R, class... P>
template <typename R, typename... P>
MethodBind *create_static_method_bind(R (*p_method)(P...)) {
MethodBind *a = memnew((MethodBindTRS<R, P...>)(p_method));
return a;
}
} // namespace godot
#endif // GODOT_METHOD_BIND_HPP

View File

@@ -28,17 +28,17 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_METHOD_PTRCALL_HPP
#define GODOT_METHOD_PTRCALL_HPP
#pragma once
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/core/object.hpp>
#include <godot_cpp/godot.hpp>
#include <godot_cpp/variant/variant.hpp>
namespace godot {
template <class T>
template <typename T>
struct PtrToArg {};
#define MAKE_PTRARG(m_type) \
@@ -121,6 +121,9 @@ 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
@@ -160,30 +163,33 @@ MAKE_PTRARG(PackedFloat64Array);
MAKE_PTRARG(PackedStringArray);
MAKE_PTRARG(PackedVector2Array);
MAKE_PTRARG(PackedVector3Array);
MAKE_PTRARG(PackedVector4Array);
MAKE_PTRARG(PackedColorArray);
MAKE_PTRARG_BY_REFERENCE(Variant);
// This is for Object.
template <class T>
template <typename T>
struct PtrToArg<T *> {
static_assert(std::is_base_of<Object, T>::value, "Cannot encode non-Object value as an Object");
_FORCE_INLINE_ static T *convert(const void *p_ptr) {
return reinterpret_cast<T *>(godot::internal::gde_interface->object_get_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr)), godot::internal::token, &T::___binding_callbacks));
return likely(p_ptr) ? reinterpret_cast<T *>(godot::internal::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr)))) : nullptr;
}
typedef Object *EncodeT;
_FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) {
*reinterpret_cast<const void **>(p_ptr) = p_var ? p_var->_owner : nullptr;
*reinterpret_cast<const void **>(p_ptr) = likely(p_var) ? p_var->_owner : nullptr;
}
};
template <class T>
template <typename T>
struct PtrToArg<const T *> {
static_assert(std::is_base_of<Object, T>::value, "Cannot encode non-Object value as an Object");
_FORCE_INLINE_ static const T *convert(const void *p_ptr) {
return reinterpret_cast<const T *>(godot::internal::gde_interface->object_get_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr)), godot::internal::token, &T::___binding_callbacks));
return likely(p_ptr) ? reinterpret_cast<const T *>(godot::internal::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr)))) : nullptr;
}
typedef const Object *EncodeT;
_FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) {
*reinterpret_cast<const void **>(p_ptr) = p_var ? p_var->_owner : nullptr;
*reinterpret_cast<const void **>(p_ptr) = likely(p_var) ? p_var->_owner : nullptr;
}
};
@@ -230,5 +236,3 @@ GDVIRTUAL_NATIVE_PTR(float);
GDVIRTUAL_NATIVE_PTR(double);
} // namespace godot
#endif // GODOT_METHOD_PTRCALL_HPP

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_MUTEX_LOCK_HPP
#define GODOT_MUTEX_LOCK_HPP
#pragma once
#include <godot_cpp/classes/mutex.hpp>
@@ -55,5 +54,3 @@ public:
#define _THREAD_SAFE_UNLOCK_ _thread_safe_.unlock();
} // namespace godot
#endif // GODOT_MUTEX_LOCK_HPP

View File

@@ -28,37 +28,47 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_OBJECT_HPP
#define GODOT_OBJECT_HPP
#pragma once
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/core/object_id.hpp>
#include <godot_cpp/core/property_info.hpp>
#include <godot_cpp/variant/variant.hpp>
#include <godot_cpp/templates/local_vector.hpp>
#include <godot_cpp/classes/object.hpp>
#include <godot_cpp/godot.hpp>
#include <gdextension_interface.h>
#include <vector>
#define ADD_SIGNAL(m_signal) godot::ClassDB::add_signal(get_class_static(), m_signal)
#define ADD_GROUP(m_name, m_prefix) godot::ClassDB::add_property_group(get_class_static(), m_name, m_prefix)
#define ADD_SUBGROUP(m_name, m_prefix) godot::ClassDB::add_property_subgroup(get_class_static(), m_name, m_prefix)
#define ADD_PROPERTY(m_property, m_setter, m_getter) godot::ClassDB::add_property(get_class_static(), m_property, m_setter, m_getter)
#define ADD_SIGNAL(m_signal) ::godot::ClassDB::add_signal(get_class_static(), m_signal)
#define ADD_GROUP(m_name, m_prefix) ::godot::ClassDB::add_property_group(get_class_static(), m_name, m_prefix)
#define ADD_SUBGROUP(m_name, m_prefix) ::godot::ClassDB::add_property_subgroup(get_class_static(), m_name, m_prefix)
#define ADD_PROPERTY(m_property, m_setter, m_getter) ::godot::ClassDB::add_property(get_class_static(), m_property, m_setter, m_getter)
#define ADD_PROPERTYI(m_property, m_setter, m_getter, m_index) ::godot::ClassDB::add_property(get_class_static(), m_property, m_setter, m_getter, m_index)
namespace godot {
namespace internal {
Object *get_object_instance_binding(GodotObject *);
} // namespace internal
struct MethodInfo {
StringName name;
PropertyInfo return_val;
uint32_t flags;
int id = 0;
std::vector<PropertyInfo> arguments;
std::vector<Variant> default_arguments;
LocalVector<PropertyInfo> arguments;
LocalVector<Variant> default_arguments;
GDExtensionClassMethodArgumentMetadata return_val_metadata;
LocalVector<GDExtensionClassMethodArgumentMetadata> arguments_metadata;
inline bool operator==(const MethodInfo &p_method) const { return id == p_method.id; }
inline bool operator<(const MethodInfo &p_method) const { return id == p_method.id ? (name < p_method.name) : (id < p_method.id); }
@@ -69,95 +79,67 @@ struct MethodInfo {
MethodInfo();
MethodInfo(StringName p_name);
template <class... Args>
template <typename... Args>
MethodInfo(StringName p_name, const Args &...args);
MethodInfo(Variant::Type ret);
MethodInfo(Variant::Type ret, StringName p_name);
template <class... Args>
template <typename... Args>
MethodInfo(Variant::Type ret, StringName p_name, const Args &...args);
MethodInfo(const PropertyInfo &p_ret, StringName p_name);
template <class... Args>
template <typename... Args>
MethodInfo(const PropertyInfo &p_ret, StringName p_name, const Args &...);
};
template <class... Args>
template <typename... Args>
MethodInfo::MethodInfo(StringName p_name, const Args &...args) :
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
arguments = { args... };
}
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL), arguments({ args... }) {}
template <class... Args>
template <typename... Args>
MethodInfo::MethodInfo(Variant::Type ret, StringName p_name, const Args &...args) :
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL), arguments({ args... }) {
return_val.type = ret;
arguments = { args... };
}
template <class... Args>
template <typename... Args>
MethodInfo::MethodInfo(const PropertyInfo &p_ret, StringName p_name, const Args &...args) :
name(p_name), return_val(p_ret), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
arguments = { args... };
name(p_name), return_val(p_ret), flags(GDEXTENSION_METHOD_FLAG_NORMAL), arguments({ args... }) {
}
class ObjectID {
uint64_t id = 0;
public:
_FORCE_INLINE_ bool is_ref_counted() const { return (id & (uint64_t(1) << 63)) != 0; }
_FORCE_INLINE_ bool is_valid() const { return id != 0; }
_FORCE_INLINE_ bool is_null() const { return id == 0; }
_FORCE_INLINE_ operator uint64_t() const { return id; }
_FORCE_INLINE_ operator int64_t() const { return id; }
_FORCE_INLINE_ bool operator==(const ObjectID &p_id) const { return id == p_id.id; }
_FORCE_INLINE_ bool operator!=(const ObjectID &p_id) const { return id != p_id.id; }
_FORCE_INLINE_ bool operator<(const ObjectID &p_id) const { return id < p_id.id; }
_FORCE_INLINE_ void operator=(int64_t p_int64) { id = p_int64; }
_FORCE_INLINE_ void operator=(uint64_t p_uint64) { id = p_uint64; }
_FORCE_INLINE_ ObjectID() {}
_FORCE_INLINE_ explicit ObjectID(const uint64_t p_id) { id = p_id; }
_FORCE_INLINE_ explicit ObjectID(const int64_t p_id) { id = p_id; }
};
class ObjectDB {
public:
static Object *get_instance(uint64_t p_object_id) {
GDExtensionObjectPtr obj = internal::gde_interface->object_get_instance_from_id(p_object_id);
GDExtensionObjectPtr obj = internal::gdextension_interface_object_get_instance_from_id(p_object_id);
if (obj == nullptr) {
return nullptr;
}
return reinterpret_cast<Object *>(internal::gde_interface->object_get_instance_binding(obj, internal::token, &Object::___binding_callbacks));
return internal::get_object_instance_binding(obj);
}
};
template <class T>
template <typename T>
T *Object::cast_to(Object *p_object) {
if (p_object == nullptr) {
return nullptr;
}
StringName class_name = T::get_class_static();
GDExtensionObjectPtr casted = internal::gde_interface->object_cast_to(p_object->_owner, internal::gde_interface->classdb_get_class_tag(class_name._native_ptr()));
GDExtensionObjectPtr casted = internal::gdextension_interface_object_cast_to(p_object->_owner, internal::gdextension_interface_classdb_get_class_tag(class_name._native_ptr()));
if (casted == nullptr) {
return nullptr;
}
return reinterpret_cast<T *>(internal::gde_interface->object_get_instance_binding(casted, internal::token, &T::___binding_callbacks));
return dynamic_cast<T *>(internal::get_object_instance_binding(casted));
}
template <class T>
template <typename T>
const T *Object::cast_to(const Object *p_object) {
if (p_object == nullptr) {
return nullptr;
}
StringName class_name = T::get_class_static();
GDExtensionObjectPtr casted = internal::gde_interface->object_cast_to(p_object->_owner, internal::gde_interface->classdb_get_class_tag(class_name._native_ptr()));
GDExtensionObjectPtr casted = internal::gdextension_interface_object_cast_to(p_object->_owner, internal::gdextension_interface_classdb_get_class_tag(class_name._native_ptr()));
if (casted == nullptr) {
return nullptr;
}
return reinterpret_cast<const T *>(internal::gde_interface->object_get_instance_binding(casted, internal::token, &T::___binding_callbacks));
return dynamic_cast<const T *>(internal::get_object_instance_binding(casted));
}
} // namespace godot
#endif // GODOT_OBJECT_HPP

View File

@@ -0,0 +1,59 @@
/**************************************************************************/
/* object_id.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. */
/**************************************************************************/
#pragma once
#include <godot_cpp/core/defs.hpp>
namespace godot {
class ObjectID {
uint64_t id = 0;
public:
_FORCE_INLINE_ bool is_ref_counted() const { return (id & (uint64_t(1) << 63)) != 0; }
_FORCE_INLINE_ bool is_valid() const { return id != 0; }
_FORCE_INLINE_ bool is_null() const { return id == 0; }
_FORCE_INLINE_ operator uint64_t() const { return id; }
_FORCE_INLINE_ operator int64_t() const { return id; }
_FORCE_INLINE_ bool operator==(const ObjectID &p_id) const { return id == p_id.id; }
_FORCE_INLINE_ bool operator!=(const ObjectID &p_id) const { return id != p_id.id; }
_FORCE_INLINE_ bool operator<(const ObjectID &p_id) const { return id < p_id.id; }
_FORCE_INLINE_ void operator=(int64_t p_int64) { id = p_int64; }
_FORCE_INLINE_ void operator=(uint64_t p_uint64) { id = p_uint64; }
_FORCE_INLINE_ ObjectID() {}
_FORCE_INLINE_ explicit ObjectID(const uint64_t p_id) { id = p_id; }
_FORCE_INLINE_ explicit ObjectID(const int64_t p_id) { id = p_id; }
};
} // namespace godot

View File

@@ -0,0 +1,70 @@
/**************************************************************************/
/* print_string.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. */
/**************************************************************************/
#pragma once
#include <godot_cpp/variant/utility_functions.hpp>
namespace godot {
inline void print_error(const Variant &p_variant) {
UtilityFunctions::printerr(p_variant);
}
inline void print_line(const Variant &p_variant) {
UtilityFunctions::print(p_variant);
}
inline void print_line_rich(const Variant &p_variant) {
UtilityFunctions::print_rich(p_variant);
}
template <typename... Args>
void print_error(const Variant &p_variant, Args... p_args) {
UtilityFunctions::printerr(p_variant, p_args...);
}
template <typename... Args>
void print_line(const Variant &p_variant, Args... p_args) {
UtilityFunctions::print(p_variant, p_args...);
}
template <typename... Args>
void print_line_rich(const Variant &p_variant, Args... p_args) {
UtilityFunctions::print_rich(p_variant, p_args...);
}
template <typename... Args>
void print_verbose(const Variant &p_variant, Args... p_args) {
UtilityFunctions::print_verbose(p_variant, p_args...);
}
bool is_print_verbose_enabled();
} // namespace godot

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_PROPERTY_INFO_HPP
#define GODOT_PROPERTY_INFO_HPP
#pragma once
#include <godot_cpp/core/defs.hpp>
@@ -47,9 +46,9 @@ struct PropertyInfo {
Variant::Type type = Variant::NIL;
StringName name;
StringName class_name;
uint32_t hint = 0;
uint32_t hint = PROPERTY_HINT_NONE;
String hint_string;
uint32_t usage = 7;
uint32_t usage = PROPERTY_USAGE_DEFAULT;
PropertyInfo() = default;
@@ -68,8 +67,63 @@ struct PropertyInfo {
PropertyInfo(GDExtensionVariantType p_type, const StringName &p_name, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "", uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const StringName &p_class_name = "") :
PropertyInfo((Variant::Type)p_type, p_name, p_hint, p_hint_string, p_usage, p_class_name) {}
PropertyInfo(const GDExtensionPropertyInfo *p_info) :
PropertyInfo(p_info->type, *reinterpret_cast<StringName *>(p_info->name), (PropertyHint)p_info->hint, *reinterpret_cast<String *>(p_info->hint_string), p_info->usage, *reinterpret_cast<StringName *>(p_info->class_name)) {}
operator Dictionary() const {
Dictionary dict;
dict["name"] = name;
dict["class_name"] = class_name;
dict["type"] = type;
dict["hint"] = hint;
dict["hint_string"] = hint_string;
dict["usage"] = usage;
return dict;
}
static PropertyInfo from_dict(const Dictionary &p_dict) {
PropertyInfo pi;
if (p_dict.has("type")) {
pi.type = Variant::Type(int(p_dict["type"]));
}
if (p_dict.has("name")) {
pi.name = p_dict["name"];
}
if (p_dict.has("class_name")) {
pi.class_name = p_dict["class_name"];
}
if (p_dict.has("hint")) {
pi.hint = PropertyHint(int(p_dict["hint"]));
}
if (p_dict.has("hint_string")) {
pi.hint_string = p_dict["hint_string"];
}
if (p_dict.has("usage")) {
pi.usage = p_dict["usage"];
}
return pi;
}
void _update(GDExtensionPropertyInfo *p_info) {
p_info->type = (GDExtensionVariantType)type;
*(reinterpret_cast<StringName *>(p_info->name)) = name;
p_info->hint = hint;
*(reinterpret_cast<String *>(p_info->hint_string)) = hint_string;
p_info->usage = usage;
*(reinterpret_cast<StringName *>(p_info->class_name)) = class_name;
}
GDExtensionPropertyInfo _to_gdextension() const {
return {
(GDExtensionVariantType)type,
name._native_ptr(),
class_name._native_ptr(),
hint,
hint_string._native_ptr(),
usage,
};
}
};
} // namespace godot
#endif // GODOT_PROPERTY_INFO_HPP

View File

@@ -28,9 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_TYPE_INFO_HPP
#define GODOT_TYPE_INFO_HPP
#pragma once
#include <godot_cpp/core/method_ptrcall.hpp>
#include <godot_cpp/core/object.hpp>
#include <godot_cpp/variant/typed_array.hpp>
#include <godot_cpp/variant/variant.hpp>
@@ -58,6 +58,16 @@ struct TypesAreSame<A, A> {
static bool const value = true;
};
template <auto A, auto B>
struct FunctionsAreSame {
static bool const value = false;
};
template <auto A>
struct FunctionsAreSame<A, A> {
static bool const value = true;
};
template <typename B, typename D>
struct TypeInherits {
static D *get_d();
@@ -90,7 +100,7 @@ static PropertyInfo make_property_info(Variant::Type p_type, const StringName &p
// instead of a forward declaration. You can always forward declare 'T' in a header file, and then
// include the actual declaration of 'T' in the source file where 'GetTypeInfo<T>' is instantiated.
template <class T, typename = void>
template <typename T, typename = void>
struct GetTypeInfo;
#define MAKE_TYPE_INFO(m_type, m_var_type) \
@@ -138,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)
@@ -175,6 +185,7 @@ MAKE_TYPE_INFO(PackedFloat64Array, GDEXTENSION_VARIANT_TYPE_PACKED_FLOAT64_ARRAY
MAKE_TYPE_INFO(PackedStringArray, GDEXTENSION_VARIANT_TYPE_PACKED_STRING_ARRAY)
MAKE_TYPE_INFO(PackedVector2Array, GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR2_ARRAY)
MAKE_TYPE_INFO(PackedVector3Array, GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR3_ARRAY)
MAKE_TYPE_INFO(PackedVector4Array, GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR4_ARRAY)
MAKE_TYPE_INFO(PackedColorArray, GDEXTENSION_VARIANT_TYPE_PACKED_COLOR_ARRAY)
// For variant.
@@ -198,8 +209,8 @@ struct GetTypeInfo<const Variant &> {
template <typename T>
struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
}
@@ -207,8 +218,8 @@ struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type>
template <typename T>
struct GetTypeInfo<const T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
}
@@ -226,8 +237,8 @@ inline String enum_qualified_name_to_class_info_name(const String &p_qualified_n
#define TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_impl) \
template <> \
struct GetTypeInfo<m_impl> { \
static const Variant::Type VARIANT_TYPE = Variant::INT; \
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static constexpr Variant::Type VARIANT_TYPE = Variant::INT; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return make_property_info(Variant::Type::INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_ENUM, \
enum_qualified_name_to_class_info_name(#m_enum)); \
@@ -241,21 +252,21 @@ inline String enum_qualified_name_to_class_info_name(const String &p_qualified_n
TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, const m_enum &)
template <typename T>
inline StringName __constant_get_enum_name(T param, StringName p_constant) {
inline StringName _gde_constant_get_enum_name(T param, StringName p_constant) {
if (GetTypeInfo<T>::VARIANT_TYPE == Variant::NIL) {
ERR_PRINT(("Missing VARIANT_ENUM_CAST for constant's enum: " + String(p_constant)).utf8().get_data());
}
return GetTypeInfo<T>::get_class_info().class_name;
}
template <class T>
template <typename T>
class BitField {
int64_t value = 0;
public:
_FORCE_INLINE_ void set_flag(T p_flag) { value |= p_flag; }
_FORCE_INLINE_ bool has_flag(T p_flag) const { return value & p_flag; }
_FORCE_INLINE_ void clear_flag(T p_flag) { return value &= ~p_flag; }
_FORCE_INLINE_ void clear_flag(T p_flag) { value &= ~p_flag; }
_FORCE_INLINE_ BitField(int64_t p_value) { value = p_value; }
_FORCE_INLINE_ operator int64_t() const { return value; }
_FORCE_INLINE_ operator Variant() const { return value; }
@@ -264,8 +275,8 @@ public:
#define TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_impl) \
template <> \
struct GetTypeInfo<m_impl> { \
static const Variant::Type VARIANT_TYPE = Variant::INT; \
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static constexpr Variant::Type VARIANT_TYPE = Variant::INT; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return make_property_info(Variant::Type::INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \
enum_qualified_name_to_class_info_name(#m_enum)); \
@@ -273,8 +284,8 @@ public:
}; \
template <> \
struct GetTypeInfo<BitField<m_impl>> { \
static const Variant::Type VARIANT_TYPE = Variant::INT; \
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static constexpr Variant::Type VARIANT_TYPE = Variant::INT; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return make_property_info(Variant::Type::INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \
enum_qualified_name_to_class_info_name(#m_enum)); \
@@ -288,14 +299,14 @@ public:
TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, const m_enum &)
template <typename T>
inline StringName __constant_get_bitfield_name(T param, StringName p_constant) {
inline StringName _gde_constant_get_bitfield_name(T param, StringName p_constant) {
if (GetTypeInfo<T>::VARIANT_TYPE == Variant::NIL) {
ERR_PRINT(("Missing VARIANT_ENUM_CAST for constant's bitfield: " + String(p_constant)).utf8().get_data());
}
return GetTypeInfo<BitField<T>>::get_class_info().class_name;
}
template <class T>
template <typename T>
struct PtrToArg<TypedArray<T>> {
_FORCE_INLINE_ static TypedArray<T> convert(const void *p_ptr) {
return TypedArray<T>(*reinterpret_cast<const Array *>(p_ptr));
@@ -306,7 +317,7 @@ struct PtrToArg<TypedArray<T>> {
}
};
template <class T>
template <typename T>
struct PtrToArg<const TypedArray<T> &> {
typedef Array EncodeT;
_FORCE_INLINE_ static TypedArray<T>
@@ -370,11 +381,14 @@ MAKE_TYPED_ARRAY_INFO(Rect2i, Variant::RECT2I)
MAKE_TYPED_ARRAY_INFO(Vector3, Variant::VECTOR3)
MAKE_TYPED_ARRAY_INFO(Vector3i, Variant::VECTOR3I)
MAKE_TYPED_ARRAY_INFO(Transform2D, Variant::TRANSFORM2D)
MAKE_TYPED_ARRAY_INFO(Vector4, Variant::VECTOR4)
MAKE_TYPED_ARRAY_INFO(Vector4i, Variant::VECTOR4I)
MAKE_TYPED_ARRAY_INFO(Plane, Variant::PLANE)
MAKE_TYPED_ARRAY_INFO(Quaternion, Variant::QUATERNION)
MAKE_TYPED_ARRAY_INFO(AABB, Variant::AABB)
MAKE_TYPED_ARRAY_INFO(Basis, Variant::BASIS)
MAKE_TYPED_ARRAY_INFO(Transform3D, Variant::TRANSFORM3D)
MAKE_TYPED_ARRAY_INFO(Projection, Variant::PROJECTION)
MAKE_TYPED_ARRAY_INFO(Color, Variant::COLOR)
MAKE_TYPED_ARRAY_INFO(StringName, Variant::STRING_NAME)
MAKE_TYPED_ARRAY_INFO(NodePath, Variant::NODE_PATH)
@@ -383,20 +397,22 @@ MAKE_TYPED_ARRAY_INFO(Callable, Variant::CALLABLE)
MAKE_TYPED_ARRAY_INFO(Signal, Variant::SIGNAL)
MAKE_TYPED_ARRAY_INFO(Dictionary, Variant::DICTIONARY)
MAKE_TYPED_ARRAY_INFO(Array, Variant::ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedByteArray, Variant::PACKED_BYTE_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedInt32Array, Variant::PACKED_INT32_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedInt64Array, Variant::PACKED_INT64_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedStringArray, Variant::PACKED_STRING_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
/*
MAKE_TYPED_ARRAY_INFO(Vector<uint8_t>, Variant::PACKED_BYTE_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<int32_t>, Variant::PACKED_INT32_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<int64_t>, Variant::PACKED_INT64_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<float>, Variant::PACKED_FLOAT32_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<double>, Variant::PACKED_FLOAT64_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<String>, Variant::PACKED_STRING_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<Vector2>, Variant::PACKED_VECTOR2_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<Vector3>, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<Color>, Variant::PACKED_COLOR_ARRAY)
MAKE_TYPED_ARRAY_INFO(IPAddress, Variant::STRING)
*/
#undef MAKE_TYPED_ARRAY_INFO
#define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info())
} // namespace godot
#endif // GODOT_TYPE_INFO_HPP

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_GODOT_HPP
#define GODOT_GODOT_HPP
#pragma once
#include <gdextension_interface.h>
@@ -37,42 +36,224 @@ namespace godot {
namespace internal {
extern "C" const GDExtensionInterface *gde_interface;
extern "C" GDExtensionInterfaceGetProcAddress gdextension_interface_get_proc_address;
extern "C" GDExtensionClassLibraryPtr library;
extern "C" void *token;
extern "C" GDExtensionGodotVersion godot_version;
// All of the GDExtension interface functions.
extern "C" GDExtensionInterfaceGetGodotVersion gdextension_interface_get_godot_version;
extern "C" GDExtensionInterfaceMemAlloc gdextension_interface_mem_alloc;
extern "C" GDExtensionInterfaceMemRealloc gdextension_interface_mem_realloc;
extern "C" GDExtensionInterfaceMemFree gdextension_interface_mem_free;
extern "C" GDExtensionInterfacePrintError gdextension_interface_print_error;
extern "C" GDExtensionInterfacePrintErrorWithMessage gdextension_interface_print_error_with_message;
extern "C" GDExtensionInterfacePrintWarning gdextension_interface_print_warning;
extern "C" GDExtensionInterfacePrintWarningWithMessage gdextension_interface_print_warning_with_message;
extern "C" GDExtensionInterfacePrintScriptError gdextension_interface_print_script_error;
extern "C" GDExtensionInterfacePrintScriptErrorWithMessage gdextension_interface_print_script_error_with_message;
extern "C" GDExtensionInterfaceGetNativeStructSize gdextension_interface_get_native_struct_size;
extern "C" GDExtensionInterfaceVariantNewCopy gdextension_interface_variant_new_copy;
extern "C" GDExtensionInterfaceVariantNewNil gdextension_interface_variant_new_nil;
extern "C" GDExtensionInterfaceVariantDestroy gdextension_interface_variant_destroy;
extern "C" GDExtensionInterfaceVariantCall gdextension_interface_variant_call;
extern "C" GDExtensionInterfaceVariantCallStatic gdextension_interface_variant_call_static;
extern "C" GDExtensionInterfaceVariantEvaluate gdextension_interface_variant_evaluate;
extern "C" GDExtensionInterfaceVariantSet gdextension_interface_variant_set;
extern "C" GDExtensionInterfaceVariantSetNamed gdextension_interface_variant_set_named;
extern "C" GDExtensionInterfaceVariantSetKeyed gdextension_interface_variant_set_keyed;
extern "C" GDExtensionInterfaceVariantSetIndexed gdextension_interface_variant_set_indexed;
extern "C" GDExtensionInterfaceVariantGet gdextension_interface_variant_get;
extern "C" GDExtensionInterfaceVariantGetNamed gdextension_interface_variant_get_named;
extern "C" GDExtensionInterfaceVariantGetKeyed gdextension_interface_variant_get_keyed;
extern "C" GDExtensionInterfaceVariantGetIndexed gdextension_interface_variant_get_indexed;
extern "C" GDExtensionInterfaceVariantIterInit gdextension_interface_variant_iter_init;
extern "C" GDExtensionInterfaceVariantIterNext gdextension_interface_variant_iter_next;
extern "C" GDExtensionInterfaceVariantIterGet gdextension_interface_variant_iter_get;
extern "C" GDExtensionInterfaceVariantHash gdextension_interface_variant_hash;
extern "C" GDExtensionInterfaceVariantRecursiveHash gdextension_interface_variant_recursive_hash;
extern "C" GDExtensionInterfaceVariantHashCompare gdextension_interface_variant_hash_compare;
extern "C" GDExtensionInterfaceVariantBooleanize gdextension_interface_variant_booleanize;
extern "C" GDExtensionInterfaceVariantDuplicate gdextension_interface_variant_duplicate;
extern "C" GDExtensionInterfaceVariantStringify gdextension_interface_variant_stringify;
extern "C" GDExtensionInterfaceVariantGetType gdextension_interface_variant_get_type;
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;
extern "C" GDExtensionInterfaceVariantGetPtrDestructor gdextension_interface_variant_get_ptr_destructor;
extern "C" GDExtensionInterfaceVariantConstruct gdextension_interface_variant_construct;
extern "C" GDExtensionInterfaceVariantGetPtrSetter gdextension_interface_variant_get_ptr_setter;
extern "C" GDExtensionInterfaceVariantGetPtrGetter gdextension_interface_variant_get_ptr_getter;
extern "C" GDExtensionInterfaceVariantGetPtrIndexedSetter gdextension_interface_variant_get_ptr_indexed_setter;
extern "C" GDExtensionInterfaceVariantGetPtrIndexedGetter gdextension_interface_variant_get_ptr_indexed_getter;
extern "C" GDExtensionInterfaceVariantGetPtrKeyedSetter gdextension_interface_variant_get_ptr_keyed_setter;
extern "C" GDExtensionInterfaceVariantGetPtrKeyedGetter gdextension_interface_variant_get_ptr_keyed_getter;
extern "C" GDExtensionInterfaceVariantGetPtrKeyedChecker gdextension_interface_variant_get_ptr_keyed_checker;
extern "C" GDExtensionInterfaceVariantGetConstantValue gdextension_interface_variant_get_constant_value;
extern "C" GDExtensionInterfaceVariantGetPtrUtilityFunction gdextension_interface_variant_get_ptr_utility_function;
extern "C" GDExtensionInterfaceStringNewWithLatin1Chars gdextension_interface_string_new_with_latin1_chars;
extern "C" GDExtensionInterfaceStringNewWithUtf8Chars gdextension_interface_string_new_with_utf8_chars;
extern "C" GDExtensionInterfaceStringNewWithUtf16Chars gdextension_interface_string_new_with_utf16_chars;
extern "C" GDExtensionInterfaceStringNewWithUtf32Chars gdextension_interface_string_new_with_utf32_chars;
extern "C" GDExtensionInterfaceStringNewWithWideChars gdextension_interface_string_new_with_wide_chars;
extern "C" GDExtensionInterfaceStringNewWithLatin1CharsAndLen gdextension_interface_string_new_with_latin1_chars_and_len;
extern "C" GDExtensionInterfaceStringNewWithUtf8CharsAndLen gdextension_interface_string_new_with_utf8_chars_and_len;
extern "C" GDExtensionInterfaceStringNewWithUtf8CharsAndLen2 gdextension_interface_string_new_with_utf8_chars_and_len2;
extern "C" GDExtensionInterfaceStringNewWithUtf16CharsAndLen gdextension_interface_string_new_with_utf16_chars_and_len;
extern "C" GDExtensionInterfaceStringNewWithUtf16CharsAndLen2 gdextension_interface_string_new_with_utf16_chars_and_len2;
extern "C" GDExtensionInterfaceStringNewWithUtf32CharsAndLen gdextension_interface_string_new_with_utf32_chars_and_len;
extern "C" GDExtensionInterfaceStringNewWithWideCharsAndLen gdextension_interface_string_new_with_wide_chars_and_len;
extern "C" GDExtensionInterfaceStringToLatin1Chars gdextension_interface_string_to_latin1_chars;
extern "C" GDExtensionInterfaceStringToUtf8Chars gdextension_interface_string_to_utf8_chars;
extern "C" GDExtensionInterfaceStringToUtf16Chars gdextension_interface_string_to_utf16_chars;
extern "C" GDExtensionInterfaceStringToUtf32Chars gdextension_interface_string_to_utf32_chars;
extern "C" GDExtensionInterfaceStringToWideChars gdextension_interface_string_to_wide_chars;
extern "C" GDExtensionInterfaceStringOperatorIndex gdextension_interface_string_operator_index;
extern "C" GDExtensionInterfaceStringOperatorIndexConst gdextension_interface_string_operator_index_const;
extern "C" GDExtensionInterfaceStringOperatorPlusEqString gdextension_interface_string_operator_plus_eq_string;
extern "C" GDExtensionInterfaceStringOperatorPlusEqChar gdextension_interface_string_operator_plus_eq_char;
extern "C" GDExtensionInterfaceStringOperatorPlusEqCstr gdextension_interface_string_operator_plus_eq_cstr;
extern "C" GDExtensionInterfaceStringOperatorPlusEqWcstr gdextension_interface_string_operator_plus_eq_wcstr;
extern "C" GDExtensionInterfaceStringOperatorPlusEqC32str gdextension_interface_string_operator_plus_eq_c32str;
extern "C" GDExtensionInterfaceStringResize gdextension_interface_string_resize;
extern "C" GDExtensionInterfaceStringNameNewWithLatin1Chars gdextension_interface_string_name_new_with_latin1_chars;
extern "C" GDExtensionInterfaceXmlParserOpenBuffer gdextension_interface_xml_parser_open_buffer;
extern "C" GDExtensionInterfaceFileAccessStoreBuffer gdextension_interface_file_access_store_buffer;
extern "C" GDExtensionInterfaceFileAccessGetBuffer gdextension_interface_file_access_get_buffer;
extern "C" GDExtensionInterfaceWorkerThreadPoolAddNativeGroupTask gdextension_interface_worker_thread_pool_add_native_group_task;
extern "C" GDExtensionInterfaceWorkerThreadPoolAddNativeTask gdextension_interface_worker_thread_pool_add_native_task;
extern "C" GDExtensionInterfacePackedByteArrayOperatorIndex gdextension_interface_packed_byte_array_operator_index;
extern "C" GDExtensionInterfacePackedByteArrayOperatorIndexConst gdextension_interface_packed_byte_array_operator_index_const;
extern "C" GDExtensionInterfacePackedColorArrayOperatorIndex gdextension_interface_packed_color_array_operator_index;
extern "C" GDExtensionInterfacePackedColorArrayOperatorIndexConst gdextension_interface_packed_color_array_operator_index_const;
extern "C" GDExtensionInterfacePackedFloat32ArrayOperatorIndex gdextension_interface_packed_float32_array_operator_index;
extern "C" GDExtensionInterfacePackedFloat32ArrayOperatorIndexConst gdextension_interface_packed_float32_array_operator_index_const;
extern "C" GDExtensionInterfacePackedFloat64ArrayOperatorIndex gdextension_interface_packed_float64_array_operator_index;
extern "C" GDExtensionInterfacePackedFloat64ArrayOperatorIndexConst gdextension_interface_packed_float64_array_operator_index_const;
extern "C" GDExtensionInterfacePackedInt32ArrayOperatorIndex gdextension_interface_packed_int32_array_operator_index;
extern "C" GDExtensionInterfacePackedInt32ArrayOperatorIndexConst gdextension_interface_packed_int32_array_operator_index_const;
extern "C" GDExtensionInterfacePackedInt64ArrayOperatorIndex gdextension_interface_packed_int64_array_operator_index;
extern "C" GDExtensionInterfacePackedInt64ArrayOperatorIndexConst gdextension_interface_packed_int64_array_operator_index_const;
extern "C" GDExtensionInterfacePackedStringArrayOperatorIndex gdextension_interface_packed_string_array_operator_index;
extern "C" GDExtensionInterfacePackedStringArrayOperatorIndexConst gdextension_interface_packed_string_array_operator_index_const;
extern "C" GDExtensionInterfacePackedVector2ArrayOperatorIndex gdextension_interface_packed_vector2_array_operator_index;
extern "C" GDExtensionInterfacePackedVector2ArrayOperatorIndexConst gdextension_interface_packed_vector2_array_operator_index_const;
extern "C" GDExtensionInterfacePackedVector3ArrayOperatorIndex gdextension_interface_packed_vector3_array_operator_index;
extern "C" GDExtensionInterfacePackedVector3ArrayOperatorIndexConst gdextension_interface_packed_vector3_array_operator_index_const;
extern "C" GDExtensionInterfacePackedVector4ArrayOperatorIndex gdextension_interface_packed_vector4_array_operator_index;
extern "C" GDExtensionInterfacePackedVector4ArrayOperatorIndexConst gdextension_interface_packed_vector4_array_operator_index_const;
extern "C" GDExtensionInterfaceArrayOperatorIndex gdextension_interface_array_operator_index;
extern "C" GDExtensionInterfaceArrayOperatorIndexConst gdextension_interface_array_operator_index_const;
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;
extern "C" GDExtensionInterfaceGlobalGetSingleton gdextension_interface_global_get_singleton;
extern "C" GDExtensionInterfaceObjectGetInstanceBinding gdextension_interface_object_get_instance_binding;
extern "C" GDExtensionInterfaceObjectSetInstanceBinding gdextension_interface_object_set_instance_binding;
extern "C" GDExtensionInterfaceObjectFreeInstanceBinding gdextension_interface_object_free_instance_binding;
extern "C" GDExtensionInterfaceObjectSetInstance gdextension_interface_object_set_instance;
extern "C" GDExtensionInterfaceObjectGetClassName gdextension_interface_object_get_class_name;
extern "C" GDExtensionInterfaceObjectCastTo gdextension_interface_object_cast_to;
extern "C" GDExtensionInterfaceObjectGetInstanceFromId gdextension_interface_object_get_instance_from_id;
extern "C" GDExtensionInterfaceObjectGetInstanceId gdextension_interface_object_get_instance_id;
extern "C" GDExtensionInterfaceObjectHasScriptMethod gdextension_interface_object_has_script_method;
extern "C" GDExtensionInterfaceObjectCallScriptMethod gdextension_interface_object_call_script_method;
extern "C" GDExtensionInterfaceCallableCustomCreate2 gdextension_interface_callable_custom_create2;
extern "C" GDExtensionInterfaceCallableCustomGetUserData gdextension_interface_callable_custom_get_userdata;
extern "C" GDExtensionInterfaceRefGetObject gdextension_interface_ref_get_object;
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" 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" 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;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassProperty gdextension_interface_classdb_register_extension_class_property;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassPropertyIndexed gdextension_interface_classdb_register_extension_class_property_indexed;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassPropertyGroup gdextension_interface_classdb_register_extension_class_property_group;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassPropertySubgroup gdextension_interface_classdb_register_extension_class_property_subgroup;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassSignal gdextension_interface_classdb_register_extension_class_signal;
extern "C" GDExtensionInterfaceClassdbUnregisterExtensionClass gdextension_interface_classdb_unregister_extension_class;
extern "C" GDExtensionInterfaceGetLibraryPath gdextension_interface_get_library_path;
extern "C" GDExtensionInterfaceEditorAddPlugin gdextension_interface_editor_add_plugin;
extern "C" GDExtensionInterfaceEditorRemovePlugin gdextension_interface_editor_remove_plugin;
extern "C" GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars gdextension_interface_editor_help_load_xml_from_utf8_chars;
extern "C" GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen gdextension_interface_editor_help_load_xml_from_utf8_chars_and_len;
extern "C" GDExtensionInterfaceImagePtrw gdextension_interface_image_ptrw;
extern "C" GDExtensionInterfaceImagePtr gdextension_interface_image_ptr;
class DocDataRegistration {
public:
DocDataRegistration(const char *p_hash, int p_uncompressed_size, int p_compressed_size, const unsigned char *p_data);
};
} // namespace internal
enum ModuleInitializationLevel {
MODULE_INITIALIZATION_LEVEL_CORE = GDEXTENSION_INITIALIZATION_CORE,
MODULE_INITIALIZATION_LEVEL_SERVERS = GDEXTENSION_INITIALIZATION_SERVERS,
MODULE_INITIALIZATION_LEVEL_SCENE = GDEXTENSION_INITIALIZATION_SCENE,
MODULE_INITIALIZATION_LEVEL_EDITOR = GDEXTENSION_INITIALIZATION_EDITOR
MODULE_INITIALIZATION_LEVEL_EDITOR = GDEXTENSION_INITIALIZATION_EDITOR,
MODULE_INITIALIZATION_LEVEL_MAX
};
class GDExtensionBinding {
public:
using Callback = void (*)(ModuleInitializationLevel p_level);
static Callback init_callback;
static Callback terminate_callback;
static GDExtensionInitializationLevel minimum_initialization_level;
static GDExtensionBool init(const GDExtensionInterface *p_interface, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);
struct InitData {
GDExtensionInitializationLevel minimum_initialization_level = GDEXTENSION_INITIALIZATION_CORE;
Callback init_callback = nullptr;
Callback terminate_callback = nullptr;
};
public:
static void initialize_level(void *userdata, GDExtensionInitializationLevel p_level);
static void deinitialize_level(void *userdata, GDExtensionInitializationLevel p_level);
class InitObject {
const GDExtensionInterface *gde_interface;
GDExtensionClassLibraryPtr library;
GDExtensionInitialization *initialization;
class InitDataList {
int data_count = 0;
int data_capacity = 0;
InitData **data = nullptr;
public:
InitObject(const GDExtensionInterface *p_interface, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) :
gde_interface(p_interface),
library(p_library),
initialization(r_initialization) {}
void add(InitData *p_cb);
~InitDataList();
};
static bool api_initialized;
static int level_initialized[MODULE_INITIALIZATION_LEVEL_MAX];
static InitDataList initdata;
static GDExtensionBool init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, InitData *p_init_data, GDExtensionInitialization *r_initialization);
public:
static void initialize_level(void *p_userdata, GDExtensionInitializationLevel p_level);
static void deinitialize_level(void *p_userdata, GDExtensionInitializationLevel p_level);
class InitObject {
GDExtensionInterfaceGetProcAddress get_proc_address;
GDExtensionClassLibraryPtr library;
GDExtensionInitialization *initialization;
mutable InitData *init_data = nullptr;
public:
InitObject(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);
void register_initializer(Callback p_init) const;
void register_terminator(Callback p_init) const;
@@ -83,5 +264,3 @@ public:
};
} // namespace godot
#endif // GODOT_GODOT_HPP

View File

@@ -0,0 +1,734 @@
/**************************************************************************/
/* a_hash_map.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. */
/**************************************************************************/
#pragma once
#include <godot_cpp/templates/hash_map.hpp>
namespace godot {
struct HashMapData {
union {
uint64_t data;
struct
{
uint32_t hash;
uint32_t hash_to_key;
};
};
};
static_assert(sizeof(HashMapData) == 8);
/**
* An array-based implementation of a hash map. It is very efficient in terms of performance and
* memory usage. Works like a dynamic array, adding elements to the end of the array, and
* allows you to access array elements by their index by using `get_by_index` method.
* Example:
* ```
* AHashMap<int, Object *> map;
*
* int get_object_id_by_number(int p_number) {
* int id = map.get_index(p_number);
* return id;
* }
*
* Object *get_object_by_id(int p_id) {
* map.get_by_index(p_id).value;
* }
* ```
* Still, don`t erase the elements because ID can break.
*
* When an element erase, its place is taken by the element from the end.
*
* <-------------
* | |
* 6 8 X 9 32 -1 5 -10 7 X X X
* 6 8 7 9 32 -1 5 -10 X X X X
*
*
* Use RBMap if you need to iterate over sorted elements.
*
* Use HashMap if:
* - You need to keep an iterator or const pointer to Key and you intend to add/remove elements in the meantime.
* - You need to preserve the insertion order when using erase.
*
* It is recommended to use `HashMap` if `KeyValue` size is very large.
*/
template <typename TKey, typename TValue,
typename Hasher = HashMapHasherDefault,
typename Comparator = HashMapComparatorDefault<TKey>>
class AHashMap {
public:
// Must be a power of two.
static constexpr uint32_t INITIAL_CAPACITY = 16;
static constexpr uint32_t EMPTY_HASH = 0;
static_assert(EMPTY_HASH == 0, "EMPTY_HASH must always be 0 for the memcpy() optimization.");
private:
typedef KeyValue<TKey, TValue> MapKeyValue;
MapKeyValue *elements = nullptr;
HashMapData *map_data = nullptr;
// Due to optimization, this is `capacity - 1`. Use + 1 to get normal capacity.
uint32_t capacity = 0;
uint32_t num_elements = 0;
uint32_t _hash(const TKey &p_key) const {
uint32_t hash = Hasher::hash(p_key);
if (unlikely(hash == EMPTY_HASH)) {
hash = EMPTY_HASH + 1;
}
return hash;
}
static _FORCE_INLINE_ uint32_t _get_resize_count(uint32_t p_capacity) {
return p_capacity ^ (p_capacity + 1) >> 2; // = get_capacity() * 0.75 - 1; Works only if p_capacity = 2^n - 1.
}
static _FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash, uint32_t p_local_capacity) {
const uint32_t original_pos = p_hash & p_local_capacity;
return (p_pos - original_pos + p_local_capacity + 1) & p_local_capacity;
}
bool _lookup_pos(const TKey &p_key, uint32_t &r_pos, uint32_t &r_hash_pos) const {
if (unlikely(elements == nullptr)) {
return false; // Failed lookups, no elements.
}
return _lookup_pos_with_hash(p_key, r_pos, r_hash_pos, _hash(p_key));
}
bool _lookup_pos_with_hash(const TKey &p_key, uint32_t &r_pos, uint32_t &r_hash_pos, uint32_t p_hash) const {
if (unlikely(elements == nullptr)) {
return false; // Failed lookups, no elements.
}
uint32_t pos = p_hash & capacity;
HashMapData data = map_data[pos];
if (data.hash == p_hash && Comparator::compare(elements[data.hash_to_key].key, p_key)) {
r_pos = data.hash_to_key;
r_hash_pos = pos;
return true;
}
if (data.data == EMPTY_HASH) {
return false;
}
// A collision occurred.
pos = (pos + 1) & capacity;
uint32_t distance = 1;
while (true) {
data = map_data[pos];
if (data.hash == p_hash && Comparator::compare(elements[data.hash_to_key].key, p_key)) {
r_pos = data.hash_to_key;
r_hash_pos = pos;
return true;
}
if (data.data == EMPTY_HASH) {
return false;
}
if (distance > _get_probe_length(pos, data.hash, capacity)) {
return false;
}
pos = (pos + 1) & capacity;
distance++;
}
}
uint32_t _insert_with_hash(uint32_t p_hash, uint32_t p_index) {
uint32_t pos = p_hash & capacity;
if (map_data[pos].data == EMPTY_HASH) {
uint64_t data = ((uint64_t)p_index << 32) | p_hash;
map_data[pos].data = data;
return pos;
}
uint32_t distance = 1;
pos = (pos + 1) & capacity;
HashMapData c_data;
c_data.hash = p_hash;
c_data.hash_to_key = p_index;
while (true) {
if (map_data[pos].data == EMPTY_HASH) {
#ifdef DEV_ENABLED
if (unlikely(distance > 12)) {
WARN_PRINT("Excessive collision count (" +
itos(distance) + "), is the right hash function being used?");
}
#endif
map_data[pos] = c_data;
return pos;
}
// Not an empty slot, let's check the probing length of the existing one.
uint32_t existing_probe_len = _get_probe_length(pos, map_data[pos].hash, capacity);
if (existing_probe_len < distance) {
SWAP(c_data, map_data[pos]);
distance = existing_probe_len;
}
pos = (pos + 1) & capacity;
distance++;
}
}
void _resize_and_rehash(uint32_t p_new_capacity) {
uint32_t real_old_capacity = capacity + 1;
// Capacity can't be 0 and must be 2^n - 1.
capacity = MAX(4u, p_new_capacity);
uint32_t real_capacity = next_power_of_2(capacity);
capacity = real_capacity - 1;
HashMapData *old_map_data = map_data;
map_data = reinterpret_cast<HashMapData *>(Memory::alloc_static(sizeof(HashMapData) * real_capacity));
memset(map_data, 0, sizeof(HashMapData) * real_capacity);
elements = reinterpret_cast<MapKeyValue *>(Memory::realloc_static(elements, sizeof(MapKeyValue) * (_get_resize_count(capacity) + 1)));
if (num_elements != 0) {
for (uint32_t i = 0; i < real_old_capacity; i++) {
HashMapData data = old_map_data[i];
if (data.data != EMPTY_HASH) {
_insert_with_hash(data.hash, data.hash_to_key);
}
}
}
Memory::free_static(old_map_data);
}
int32_t _insert_element(const TKey &p_key, const TValue &p_value, uint32_t p_hash) {
if (unlikely(elements == nullptr)) {
// Allocate on demand to save memory.
uint32_t real_capacity = capacity + 1;
map_data = reinterpret_cast<HashMapData *>(Memory::alloc_static(sizeof(HashMapData) * real_capacity));
memset(map_data, 0, sizeof(HashMapData) * real_capacity);
elements = reinterpret_cast<MapKeyValue *>(Memory::alloc_static(sizeof(MapKeyValue) * (_get_resize_count(capacity) + 1)));
}
if (unlikely(num_elements > _get_resize_count(capacity))) {
_resize_and_rehash(capacity * 2);
}
memnew_placement(&elements[num_elements], MapKeyValue(p_key, p_value));
_insert_with_hash(p_hash, num_elements);
num_elements++;
return num_elements - 1;
}
void _init_from(const AHashMap &p_other) {
capacity = p_other.capacity;
uint32_t real_capacity = capacity + 1;
num_elements = p_other.num_elements;
if (p_other.num_elements == 0) {
return;
}
map_data = reinterpret_cast<HashMapData *>(Memory::alloc_static(sizeof(HashMapData) * real_capacity));
elements = reinterpret_cast<MapKeyValue *>(Memory::alloc_static(sizeof(MapKeyValue) * (_get_resize_count(capacity) + 1)));
if constexpr (std::is_trivially_copyable_v<TKey> && std::is_trivially_copyable_v<TValue>) {
void *destination = elements;
const void *source = p_other.elements;
memcpy(destination, source, sizeof(MapKeyValue) * num_elements);
} else {
for (uint32_t i = 0; i < num_elements; i++) {
memnew_placement(&elements[i], MapKeyValue(p_other.elements[i]));
}
}
memcpy(map_data, p_other.map_data, sizeof(HashMapData) * real_capacity);
}
public:
/* Standard Godot Container API */
_FORCE_INLINE_ uint32_t get_capacity() const { return capacity + 1; }
_FORCE_INLINE_ uint32_t size() const { return num_elements; }
_FORCE_INLINE_ bool is_empty() const {
return num_elements == 0;
}
void clear() {
if (elements == nullptr || num_elements == 0) {
return;
}
memset(map_data, EMPTY_HASH, (capacity + 1) * sizeof(HashMapData));
if constexpr (!(std::is_trivially_destructible_v<TKey> && std::is_trivially_destructible_v<TValue>)) {
for (uint32_t i = 0; i < num_elements; i++) {
elements[i].key.~TKey();
elements[i].value.~TValue();
}
}
num_elements = 0;
}
TValue &get(const TKey &p_key) {
uint32_t pos = 0;
uint32_t hash_pos = 0;
bool exists = _lookup_pos(p_key, pos, hash_pos);
CRASH_COND_MSG(!exists, "AHashMap key not found.");
return elements[pos].value;
}
const TValue &get(const TKey &p_key) const {
uint32_t pos = 0;
uint32_t hash_pos = 0;
bool exists = _lookup_pos(p_key, pos, hash_pos);
CRASH_COND_MSG(!exists, "AHashMap key not found.");
return elements[pos].value;
}
const TValue *getptr(const TKey &p_key) const {
uint32_t pos = 0;
uint32_t hash_pos = 0;
bool exists = _lookup_pos(p_key, pos, hash_pos);
if (exists) {
return &elements[pos].value;
}
return nullptr;
}
TValue *getptr(const TKey &p_key) {
uint32_t pos = 0;
uint32_t hash_pos = 0;
bool exists = _lookup_pos(p_key, pos, hash_pos);
if (exists) {
return &elements[pos].value;
}
return nullptr;
}
bool has(const TKey &p_key) const {
uint32_t _pos = 0;
uint32_t h_pos = 0;
return _lookup_pos(p_key, _pos, h_pos);
}
bool erase(const TKey &p_key) {
uint32_t pos = 0;
uint32_t element_pos = 0;
bool exists = _lookup_pos(p_key, element_pos, pos);
if (!exists) {
return false;
}
uint32_t next_pos = (pos + 1) & capacity;
while (map_data[next_pos].hash != EMPTY_HASH && _get_probe_length(next_pos, map_data[next_pos].hash, capacity) != 0) {
SWAP(map_data[next_pos], map_data[pos]);
pos = next_pos;
next_pos = (next_pos + 1) & capacity;
}
map_data[pos].data = EMPTY_HASH;
elements[element_pos].key.~TKey();
elements[element_pos].value.~TValue();
num_elements--;
if (element_pos < num_elements) {
void *destination = &elements[element_pos];
const void *source = &elements[num_elements];
memcpy(destination, source, sizeof(MapKeyValue));
uint32_t h_pos = 0;
_lookup_pos(elements[num_elements].key, pos, h_pos);
map_data[h_pos].hash_to_key = element_pos;
}
return true;
}
// Replace the key of an entry in-place, without invalidating iterators or changing the entries position during iteration.
// p_old_key must exist in the map and p_new_key must not, unless it is equal to p_old_key.
bool replace_key(const TKey &p_old_key, const TKey &p_new_key) {
if (p_old_key == p_new_key) {
return true;
}
uint32_t pos = 0;
uint32_t element_pos = 0;
ERR_FAIL_COND_V(_lookup_pos(p_new_key, element_pos, pos), false);
ERR_FAIL_COND_V(!_lookup_pos(p_old_key, element_pos, pos), false);
MapKeyValue &element = elements[element_pos];
const_cast<TKey &>(element.key) = p_new_key;
uint32_t next_pos = (pos + 1) & capacity;
while (map_data[next_pos].hash != EMPTY_HASH && _get_probe_length(next_pos, map_data[next_pos].hash, capacity) != 0) {
SWAP(map_data[next_pos], map_data[pos]);
pos = next_pos;
next_pos = (next_pos + 1) & capacity;
}
map_data[pos].data = EMPTY_HASH;
uint32_t hash = _hash(p_new_key);
_insert_with_hash(hash, element_pos);
return true;
}
// Reserves space for a number of elements, useful to avoid many resizes and rehashes.
// If adding a known (possibly large) number of elements at once, must be larger than old capacity.
void reserve(uint32_t p_new_capacity) {
ERR_FAIL_COND_MSG(p_new_capacity < size(), "reserve() called with a capacity smaller than the current size. This is likely a mistake.");
if (elements == nullptr) {
capacity = MAX(4u, p_new_capacity);
capacity = next_power_of_2(capacity) - 1;
return; // Unallocated yet.
}
if (p_new_capacity <= get_capacity()) {
return;
}
_resize_and_rehash(p_new_capacity);
}
/** Iterator API **/
struct ConstIterator {
_FORCE_INLINE_ const MapKeyValue &operator*() const {
return *pair;
}
_FORCE_INLINE_ const MapKeyValue *operator->() const {
return pair;
}
_FORCE_INLINE_ ConstIterator &operator++() {
pair++;
return *this;
}
_FORCE_INLINE_ ConstIterator &operator--() {
pair--;
if (pair < begin) {
pair = end;
}
return *this;
}
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return pair == b.pair; }
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return pair != b.pair; }
_FORCE_INLINE_ explicit operator bool() const {
return pair != end;
}
_FORCE_INLINE_ ConstIterator(MapKeyValue *p_key, MapKeyValue *p_begin, MapKeyValue *p_end) {
pair = p_key;
begin = p_begin;
end = p_end;
}
_FORCE_INLINE_ ConstIterator() {}
_FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) {
pair = p_it.pair;
begin = p_it.begin;
end = p_it.end;
}
_FORCE_INLINE_ void operator=(const ConstIterator &p_it) {
pair = p_it.pair;
begin = p_it.begin;
end = p_it.end;
}
private:
MapKeyValue *pair = nullptr;
MapKeyValue *begin = nullptr;
MapKeyValue *end = nullptr;
};
struct Iterator {
_FORCE_INLINE_ MapKeyValue &operator*() const {
return *pair;
}
_FORCE_INLINE_ MapKeyValue *operator->() const {
return pair;
}
_FORCE_INLINE_ Iterator &operator++() {
pair++;
return *this;
}
_FORCE_INLINE_ Iterator &operator--() {
pair--;
if (pair < begin) {
pair = end;
}
return *this;
}
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return pair == b.pair; }
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return pair != b.pair; }
_FORCE_INLINE_ explicit operator bool() const {
return pair != end;
}
_FORCE_INLINE_ Iterator(MapKeyValue *p_key, MapKeyValue *p_begin, MapKeyValue *p_end) {
pair = p_key;
begin = p_begin;
end = p_end;
}
_FORCE_INLINE_ Iterator() {}
_FORCE_INLINE_ Iterator(const Iterator &p_it) {
pair = p_it.pair;
begin = p_it.begin;
end = p_it.end;
}
_FORCE_INLINE_ void operator=(const Iterator &p_it) {
pair = p_it.pair;
begin = p_it.begin;
end = p_it.end;
}
operator ConstIterator() const {
return ConstIterator(pair, begin, end);
}
private:
MapKeyValue *pair = nullptr;
MapKeyValue *begin = nullptr;
MapKeyValue *end = nullptr;
};
_FORCE_INLINE_ Iterator begin() {
return Iterator(elements, elements, elements + num_elements);
}
_FORCE_INLINE_ Iterator end() {
return Iterator(elements + num_elements, elements, elements + num_elements);
}
_FORCE_INLINE_ Iterator last() {
if (unlikely(num_elements == 0)) {
return Iterator(nullptr, nullptr, nullptr);
}
return Iterator(elements + num_elements - 1, elements, elements + num_elements);
}
Iterator find(const TKey &p_key) {
uint32_t pos = 0;
uint32_t h_pos = 0;
bool exists = _lookup_pos(p_key, pos, h_pos);
if (!exists) {
return end();
}
return Iterator(elements + pos, elements, elements + num_elements);
}
void remove(const Iterator &p_iter) {
if (p_iter) {
erase(p_iter->key);
}
}
_FORCE_INLINE_ ConstIterator begin() const {
return ConstIterator(elements, elements, elements + num_elements);
}
_FORCE_INLINE_ ConstIterator end() const {
return ConstIterator(elements + num_elements, elements, elements + num_elements);
}
_FORCE_INLINE_ ConstIterator last() const {
if (unlikely(num_elements == 0)) {
return ConstIterator(nullptr, nullptr, nullptr);
}
return ConstIterator(elements + num_elements - 1, elements, elements + num_elements);
}
ConstIterator find(const TKey &p_key) const {
uint32_t pos = 0;
uint32_t h_pos = 0;
bool exists = _lookup_pos(p_key, pos, h_pos);
if (!exists) {
return end();
}
return ConstIterator(elements + pos, elements, elements + num_elements);
}
/* Indexing */
const TValue &operator[](const TKey &p_key) const {
uint32_t pos = 0;
uint32_t h_pos = 0;
bool exists = _lookup_pos(p_key, pos, h_pos);
CRASH_COND(!exists);
return elements[pos].value;
}
TValue &operator[](const TKey &p_key) {
uint32_t pos = 0;
uint32_t h_pos = 0;
uint32_t hash = _hash(p_key);
bool exists = _lookup_pos_with_hash(p_key, pos, h_pos, hash);
if (exists) {
return elements[pos].value;
} else {
pos = _insert_element(p_key, TValue(), hash);
return elements[pos].value;
}
}
/* Insert */
Iterator insert(const TKey &p_key, const TValue &p_value) {
uint32_t pos = 0;
uint32_t h_pos = 0;
uint32_t hash = _hash(p_key);
bool exists = _lookup_pos_with_hash(p_key, pos, h_pos, hash);
if (!exists) {
pos = _insert_element(p_key, p_value, hash);
} else {
elements[pos].value = p_value;
}
return Iterator(elements + pos, elements, elements + num_elements);
}
// Inserts an element without checking if it already exists.
Iterator insert_new(const TKey &p_key, const TValue &p_value) {
DEV_ASSERT(!has(p_key));
uint32_t hash = _hash(p_key);
uint32_t pos = _insert_element(p_key, p_value, hash);
return Iterator(elements + pos, elements, elements + num_elements);
}
/* Array methods. */
// Unsafe. Changing keys and going outside the bounds of an array can lead to undefined behavior.
KeyValue<TKey, TValue> *get_elements_ptr() {
return elements;
}
// Returns the element index. If not found, returns -1.
int get_index(const TKey &p_key) {
uint32_t pos = 0;
uint32_t h_pos = 0;
bool exists = _lookup_pos(p_key, pos, h_pos);
if (!exists) {
return -1;
}
return pos;
}
KeyValue<TKey, TValue> &get_by_index(uint32_t p_index) {
CRASH_BAD_UNSIGNED_INDEX(p_index, num_elements);
return elements[p_index];
}
bool erase_by_index(uint32_t p_index) {
if (p_index >= size()) {
return false;
}
return erase(elements[p_index].key);
}
/* Constructors */
AHashMap(const AHashMap &p_other) {
_init_from(p_other);
}
AHashMap(const HashMap<TKey, TValue> &p_other) {
reserve(p_other.size());
for (const KeyValue<TKey, TValue> &E : p_other) {
uint32_t hash = _hash(E.key);
_insert_element(E.key, E.value, hash);
}
}
void operator=(const AHashMap &p_other) {
if (this == &p_other) {
return; // Ignore self assignment.
}
reset();
_init_from(p_other);
}
void operator=(const HashMap<TKey, TValue> &p_other) {
reset();
reserve(p_other.size());
for (const KeyValue<TKey, TValue> &E : p_other) {
uint32_t hash = _hash(E.key);
_insert_element(E.key, E.value, hash);
}
}
AHashMap(uint32_t p_initial_capacity) {
// Capacity can't be 0 and must be 2^n - 1.
capacity = MAX(4u, p_initial_capacity);
capacity = next_power_of_2(capacity) - 1;
}
AHashMap() :
capacity(INITIAL_CAPACITY - 1) {
}
AHashMap(std::initializer_list<KeyValue<TKey, TValue>> p_init) {
reserve(p_init.size());
for (const KeyValue<TKey, TValue> &E : p_init) {
insert(E.key, E.value);
}
}
void reset() {
if (elements != nullptr) {
if constexpr (!(std::is_trivially_destructible_v<TKey> && std::is_trivially_destructible_v<TValue>)) {
for (uint32_t i = 0; i < num_elements; i++) {
elements[i].key.~TKey();
elements[i].value.~TValue();
}
}
Memory::free_static(elements);
Memory::free_static(map_data);
elements = nullptr;
}
capacity = INITIAL_CAPACITY - 1;
num_elements = 0;
}
~AHashMap() {
reset();
}
};
} //namespace godot

View File

@@ -28,112 +28,177 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_COWDATA_HPP
#define GODOT_COWDATA_HPP
#pragma once
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/math.hpp>
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/templates/safe_refcount.hpp>
#include <cstring>
#include <initializer_list>
#include <new>
#include <type_traits>
#include <utility>
namespace godot {
template <class T>
template <typename T>
class Vector;
template <class T, class V>
template <typename T, typename V>
class VMap;
template <typename T>
class CharStringT;
static_assert(std::is_trivially_destructible_v<std::atomic<uint64_t>>);
// Silence a false positive warning (see GH-52119).
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wplacement-new"
#endif
template <class T>
template <typename T>
class CowData {
template <class TV>
template <typename TV>
friend class Vector;
template <class TV, class VV>
template <typename TV, typename VV>
friend class VMap;
template <typename TS>
friend class CharStringT;
public:
typedef int64_t Size;
typedef uint64_t USize;
static constexpr USize MAX_INT = INT64_MAX;
private:
// Function to find the next power of 2 to an integer.
static _FORCE_INLINE_ USize next_po2(USize x) {
if (x == 0) {
return 0;
}
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
if (sizeof(USize) == 8) {
x |= x >> 32;
}
return ++x;
}
// Alignment: ↓ max_align_t ↓ USize ↓ max_align_t
// ┌────────────────────┬──┬─────────────┬──┬───────────...
// │ SafeNumeric<USize> │░░│ USize │░░│ T[]
// │ ref. count │░░│ data size │░░│ data
// └────────────────────┴──┴─────────────┴──┴───────────...
// Offset: ↑ REF_COUNT_OFFSET ↑ SIZE_OFFSET ↑ DATA_OFFSET
static constexpr size_t REF_COUNT_OFFSET = 0;
static constexpr size_t SIZE_OFFSET = ((REF_COUNT_OFFSET + sizeof(SafeNumeric<USize>)) % alignof(USize) == 0) ? (REF_COUNT_OFFSET + sizeof(SafeNumeric<USize>)) : ((REF_COUNT_OFFSET + sizeof(SafeNumeric<USize>)) + alignof(USize) - ((REF_COUNT_OFFSET + sizeof(SafeNumeric<USize>)) % alignof(USize)));
static constexpr size_t DATA_OFFSET = ((SIZE_OFFSET + sizeof(USize)) % alignof(max_align_t) == 0) ? (SIZE_OFFSET + sizeof(USize)) : ((SIZE_OFFSET + sizeof(USize)) + alignof(max_align_t) - ((SIZE_OFFSET + sizeof(USize)) % alignof(max_align_t)));
mutable T *_ptr = nullptr;
// internal helpers
_FORCE_INLINE_ SafeNumeric<uint32_t> *_get_refcount() const {
static _FORCE_INLINE_ SafeNumeric<USize> *_get_refcount_ptr(uint8_t *p_ptr) {
return (SafeNumeric<USize> *)(p_ptr + REF_COUNT_OFFSET);
}
static _FORCE_INLINE_ USize *_get_size_ptr(uint8_t *p_ptr) {
return (USize *)(p_ptr + SIZE_OFFSET);
}
static _FORCE_INLINE_ T *_get_data_ptr(uint8_t *p_ptr) {
return (T *)(p_ptr + DATA_OFFSET);
}
_FORCE_INLINE_ SafeNumeric<USize> *_get_refcount() const {
if (!_ptr) {
return nullptr;
}
return reinterpret_cast<SafeNumeric<uint32_t> *>(_ptr) - 2;
return (SafeNumeric<USize> *)((uint8_t *)_ptr - DATA_OFFSET + REF_COUNT_OFFSET);
}
_FORCE_INLINE_ uint32_t *_get_size() const {
_FORCE_INLINE_ USize *_get_size() const {
if (!_ptr) {
return nullptr;
}
return reinterpret_cast<uint32_t *>(_ptr) - 1;
return (USize *)((uint8_t *)_ptr - DATA_OFFSET + SIZE_OFFSET);
}
_FORCE_INLINE_ T *_get_data() const {
if (!_ptr) {
return nullptr;
_FORCE_INLINE_ USize _get_alloc_size(USize p_elements) const {
return next_po2(p_elements * sizeof(T));
}
_FORCE_INLINE_ bool _get_alloc_size_checked(USize p_elements, USize *out) const {
if (unlikely(p_elements == 0)) {
*out = 0;
return true;
}
return reinterpret_cast<T *>(_ptr);
}
_FORCE_INLINE_ size_t _get_alloc_size(size_t p_elements) const {
return next_power_of_2(p_elements * sizeof(T));
}
_FORCE_INLINE_ bool _get_alloc_size_checked(size_t p_elements, size_t *out) const {
#if defined(__GNUC__)
size_t o;
size_t p;
#if defined(__GNUC__) && defined(IS_32_BIT)
USize o;
USize p;
if (__builtin_mul_overflow(p_elements, sizeof(T), &o)) {
*out = 0;
return false;
}
*out = next_power_of_2(o);
if (__builtin_add_overflow(o, static_cast<size_t>(32), &p)) {
*out = next_po2(o);
if (__builtin_add_overflow(o, static_cast<USize>(32), &p)) {
return false; // No longer allocated here.
}
return true;
#else
// Speed is more important than correctness here, do the operations unchecked
// and hope for the best.
*out = _get_alloc_size(p_elements);
return true;
#endif
return *out;
}
void _unref(void *p_data);
// Decrements the reference count. Deallocates the backing buffer if needed.
// After this function, _ptr is guaranteed to be NULL.
void _unref();
void _ref(const CowData *p_from);
void _ref(const CowData &p_from);
uint32_t _copy_on_write();
USize _copy_on_write();
Error _realloc(Size p_alloc_size);
public:
void operator=(const CowData<T> &p_from) { _ref(p_from); }
void operator=(CowData<T> &&p_from) {
if (_ptr == p_from._ptr) {
return;
}
_unref();
_ptr = p_from._ptr;
p_from._ptr = nullptr;
}
_FORCE_INLINE_ T *ptrw() {
_copy_on_write();
return (T *)_get_data();
return _ptr;
}
_FORCE_INLINE_ const T *ptr() const {
return _get_data();
return _ptr;
}
_FORCE_INLINE_ int size() const {
uint32_t *size = (uint32_t *)_get_size();
_FORCE_INLINE_ Size size() const {
USize *size = (USize *)_get_size();
if (size) {
return *size;
} else {
@@ -144,191 +209,214 @@ public:
_FORCE_INLINE_ void clear() { resize(0); }
_FORCE_INLINE_ bool is_empty() const { return _ptr == nullptr; }
_FORCE_INLINE_ void set(int p_index, const T &p_elem) {
_FORCE_INLINE_ void set(Size p_index, const T &p_elem) {
ERR_FAIL_INDEX(p_index, size());
_copy_on_write();
_get_data()[p_index] = p_elem;
_ptr[p_index] = p_elem;
}
_FORCE_INLINE_ T &get_m(int p_index) {
_FORCE_INLINE_ T &get_m(Size p_index) {
CRASH_BAD_INDEX(p_index, size());
_copy_on_write();
return _get_data()[p_index];
return _ptr[p_index];
}
_FORCE_INLINE_ const T &get(int p_index) const {
_FORCE_INLINE_ const T &get(Size p_index) const {
CRASH_BAD_INDEX(p_index, size());
return _get_data()[p_index];
return _ptr[p_index];
}
Error resize(int p_size);
template <bool p_ensure_zero = false>
Error resize(Size p_size);
_FORCE_INLINE_ void remove_at(int p_index) {
_FORCE_INLINE_ void remove_at(Size p_index) {
ERR_FAIL_INDEX(p_index, size());
T *p = ptrw();
int len = size();
for (int i = p_index; i < len - 1; i++) {
p[i] = p[i + 1];
Size len = size();
for (Size i = p_index; i < len - 1; i++) {
p[i] = std::move(p[i + 1]);
}
resize(len - 1);
}
Error insert(int p_pos, const T &p_val) {
ERR_FAIL_INDEX_V(p_pos, size() + 1, ERR_INVALID_PARAMETER);
resize(size() + 1);
for (int i = (size() - 1); i > p_pos; i--) {
set(i, get(i - 1));
Error insert(Size p_pos, const T &p_val) {
Size new_size = size() + 1;
ERR_FAIL_INDEX_V(p_pos, new_size, ERR_INVALID_PARAMETER);
Error err = resize(new_size);
ERR_FAIL_COND_V(err, err);
T *p = ptrw();
for (Size i = new_size - 1; i > p_pos; i--) {
p[i] = std::move(p[i - 1]);
}
set(p_pos, p_val);
p[p_pos] = p_val;
return OK;
}
int find(const T &p_val, int p_from = 0) const;
Size find(const T &p_val, Size p_from = 0) const;
Size rfind(const T &p_val, Size p_from = -1) const;
Size count(const T &p_val) const;
_FORCE_INLINE_ CowData() {}
_FORCE_INLINE_ ~CowData();
_FORCE_INLINE_ CowData(CowData<T> &p_from) { _ref(p_from); }
_FORCE_INLINE_ ~CowData() { _unref(); }
_FORCE_INLINE_ CowData(std::initializer_list<T> p_init);
_FORCE_INLINE_ CowData(const CowData<T> &p_from) { _ref(p_from); }
_FORCE_INLINE_ CowData(CowData<T> &&p_from) {
_ptr = p_from._ptr;
p_from._ptr = nullptr;
}
};
template <class T>
void CowData<T>::_unref(void *p_data) {
if (!p_data) {
template <typename T>
void CowData<T>::_unref() {
if (!_ptr) {
return;
}
SafeNumeric<uint32_t> *refc = _get_refcount();
SafeNumeric<USize> *refc = _get_refcount();
if (refc->decrement() > 0) {
return; // still in use
// Data is still in use elsewhere.
_ptr = nullptr;
return;
}
// clean up
// Clean up.
// First, invalidate our own reference.
// NOTE: It is required to do so immediately because it must not be observable outside of this
// function after refcount has already been reduced to 0.
// WARNING: It must be done before calling the destructors, because one of them may otherwise
// observe it through a reference to us. In this case, it may try to access the buffer,
// which is illegal after some of the elements in it have already been destructed, and
// may lead to a segmentation fault.
USize current_size = *_get_size();
T *prev_ptr = _ptr;
_ptr = nullptr;
if (!__has_trivial_destructor(T)) {
uint32_t *count = _get_size();
T *data = (T *)(count + 1);
for (uint32_t i = 0; i < *count; ++i) {
// call destructors
data[i].~T();
if constexpr (!std::is_trivially_destructible_v<T>) {
for (USize i = 0; i < current_size; ++i) {
prev_ptr[i].~T();
}
}
// free mem
Memory::free_static((uint8_t *)p_data, true);
Memory::free_static((uint8_t *)prev_ptr - DATA_OFFSET, false);
}
template <class T>
uint32_t CowData<T>::_copy_on_write() {
template <typename T>
typename CowData<T>::USize CowData<T>::_copy_on_write() {
if (!_ptr) {
return 0;
}
SafeNumeric<uint32_t> *refc = _get_refcount();
SafeNumeric<USize> *refc = _get_refcount();
uint32_t rc = refc->get();
USize rc = refc->get();
if (unlikely(rc > 1)) {
/* in use by more than me */
uint32_t current_size = *_get_size();
USize current_size = *_get_size();
uint32_t *mem_new = (uint32_t *)Memory::alloc_static(_get_alloc_size(current_size), true);
uint8_t *mem_new = (uint8_t *)Memory::alloc_static(_get_alloc_size(current_size) + DATA_OFFSET, false);
ERR_FAIL_NULL_V(mem_new, 0);
new (mem_new - 2) SafeNumeric<uint32_t>(1); // refcount
*(mem_new - 1) = current_size; // size
SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr(mem_new);
USize *_size_ptr = _get_size_ptr(mem_new);
T *_data_ptr = _get_data_ptr(mem_new);
T *_data = (T *)(mem_new);
new (_refc_ptr) SafeNumeric<USize>(1); //refcount
*(_size_ptr) = current_size; //size
// initialize new elements
if (__has_trivial_copy(T)) {
memcpy(mem_new, _ptr, current_size * sizeof(T));
if constexpr (std::is_trivially_copyable_v<T>) {
memcpy((uint8_t *)_data_ptr, _ptr, current_size * sizeof(T));
} else {
for (uint32_t i = 0; i < current_size; i++) {
memnew_placement(&_data[i], T(_get_data()[i]));
for (USize i = 0; i < current_size; i++) {
memnew_placement(&_data_ptr[i], T(_ptr[i]));
}
}
_unref(_ptr);
_ptr = _data;
_unref();
_ptr = _data_ptr;
rc = 1;
}
return rc;
}
template <class T>
Error CowData<T>::resize(int p_size) {
template <typename T>
template <bool p_ensure_zero>
Error CowData<T>::resize(Size p_size) {
ERR_FAIL_COND_V(p_size < 0, ERR_INVALID_PARAMETER);
int current_size = size();
Size current_size = size();
if (p_size == current_size) {
return OK;
}
if (p_size == 0) {
// wants to clean up
_unref(_ptr);
_ptr = nullptr;
// Wants to clean up.
_unref(); // Resets _ptr to nullptr.
return OK;
}
// possibly changing size, copy on write
uint32_t rc = _copy_on_write();
_copy_on_write();
size_t current_alloc_size = _get_alloc_size(current_size);
size_t alloc_size;
USize current_alloc_size = _get_alloc_size(current_size);
USize alloc_size;
ERR_FAIL_COND_V(!_get_alloc_size_checked(p_size, &alloc_size), ERR_OUT_OF_MEMORY);
if (p_size > current_size) {
if (alloc_size != current_alloc_size) {
if (current_size == 0) {
// alloc from scratch
uint32_t *ptr = (uint32_t *)Memory::alloc_static(alloc_size, true);
ERR_FAIL_COND_V(!ptr, ERR_OUT_OF_MEMORY);
*(ptr - 1) = 0; // size, currently none
new (ptr - 2) SafeNumeric<uint32_t>(1); // refcount
uint8_t *mem_new = (uint8_t *)Memory::alloc_static(alloc_size + DATA_OFFSET, false);
ERR_FAIL_NULL_V(mem_new, ERR_OUT_OF_MEMORY);
_ptr = (T *)ptr;
SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr(mem_new);
USize *_size_ptr = _get_size_ptr(mem_new);
T *_data_ptr = _get_data_ptr(mem_new);
new (_refc_ptr) SafeNumeric<USize>(1); //refcount
*(_size_ptr) = 0; //size, currently none
_ptr = _data_ptr;
} else {
uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size, true);
ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY);
new (_ptrnew - 2) SafeNumeric<uint32_t>(rc); // refcount
_ptr = (T *)(_ptrnew);
const Error error = _realloc(alloc_size);
if (error) {
return error;
}
}
}
// construct the newly created elements
if (!__has_trivial_constructor(T)) {
T *elems = _get_data();
for (int i = *_get_size(); i < p_size; i++) {
memnew_placement(&elems[i], T);
if constexpr (!std::is_trivially_constructible_v<T>) {
for (Size i = *_get_size(); i < p_size; i++) {
memnew_placement(&_ptr[i], T);
}
} else if (p_ensure_zero) {
memset((void *)(_ptr + current_size), 0, (p_size - current_size) * sizeof(T));
}
*_get_size() = p_size;
} else if (p_size < current_size) {
if (!__has_trivial_destructor(T)) {
if constexpr (!std::is_trivially_destructible_v<T>) {
// deinitialize no longer needed elements
for (uint32_t i = p_size; i < *_get_size(); i++) {
T *t = &_get_data()[i];
for (USize i = p_size; i < *_get_size(); i++) {
T *t = &_ptr[i];
t->~T();
}
}
if (alloc_size != current_alloc_size) {
uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size, true);
ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY);
new (_ptrnew - 2) SafeNumeric<uint32_t>(rc); // refcount
_ptr = (T *)(_ptrnew);
const Error error = _realloc(alloc_size);
if (error) {
return error;
}
}
*_get_size() = p_size;
@@ -337,15 +425,30 @@ Error CowData<T>::resize(int p_size) {
return OK;
}
template <class T>
int CowData<T>::find(const T &p_val, int p_from) const {
int ret = -1;
template <typename T>
Error CowData<T>::_realloc(Size p_alloc_size) {
uint8_t *mem_new = (uint8_t *)Memory::realloc_static(((uint8_t *)_ptr) - DATA_OFFSET, p_alloc_size + DATA_OFFSET, false);
ERR_FAIL_NULL_V(mem_new, ERR_OUT_OF_MEMORY);
SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr(mem_new);
T *_data_ptr = _get_data_ptr(mem_new);
// If we realloc, we're guaranteed to be the only reference.
new (_refc_ptr) SafeNumeric<USize>(1);
_ptr = _data_ptr;
return OK;
}
template <typename T>
typename CowData<T>::Size CowData<T>::find(const T &p_val, Size p_from) const {
Size ret = -1;
if (p_from < 0 || size() == 0) {
return ret;
}
for (int i = p_from; i < size(); i++) {
for (Size i = p_from; i < size(); i++) {
if (get(i) == p_val) {
ret = i;
break;
@@ -355,22 +458,51 @@ int CowData<T>::find(const T &p_val, int p_from) const {
return ret;
}
template <class T>
template <typename T>
typename CowData<T>::Size CowData<T>::rfind(const T &p_val, Size p_from) const {
const Size s = size();
if (p_from < 0) {
p_from = s + p_from;
}
if (p_from < 0 || p_from >= s) {
p_from = s - 1;
}
for (Size i = p_from; i >= 0; i--) {
if (get(i) == p_val) {
return i;
}
}
return -1;
}
template <typename T>
typename CowData<T>::Size CowData<T>::count(const T &p_val) const {
Size amount = 0;
for (Size i = 0; i < size(); i++) {
if (get(i) == p_val) {
amount++;
}
}
return amount;
}
template <typename T>
void CowData<T>::_ref(const CowData *p_from) {
_ref(*p_from);
}
template <class T>
template <typename T>
void CowData<T>::_ref(const CowData &p_from) {
if (_ptr == p_from._ptr) {
return; // self assign, do nothing.
}
_unref(_ptr);
_ptr = nullptr;
_unref(); // Resets _ptr to nullptr.
if (!p_from._ptr) {
return; // nothing to do
return; //nothing to do
}
if (p_from._get_refcount()->conditional_increment() > 0) { // could reference
@@ -378,9 +510,17 @@ void CowData<T>::_ref(const CowData &p_from) {
}
}
template <class T>
CowData<T>::~CowData() {
_unref(_ptr);
template <typename T>
CowData<T>::CowData(std::initializer_list<T> p_init) {
Error err = resize(p_init.size());
if (err != OK) {
return;
}
Size i = 0;
for (const T &element : p_init) {
set(i++, element);
}
}
#if defined(__GNUC__) && !defined(__clang__)
@@ -388,5 +528,3 @@ CowData<T>::~CowData() {
#endif
} // namespace godot
#endif // GODOT_COWDATA_HPP

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_HASH_MAP_HPP
#define GODOT_HASH_MAP_HPP
#pragma once
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/memory.hpp>
@@ -52,7 +51,7 @@ namespace godot {
* The assignment operator copy the pairs from one map to the other.
*/
template <class TKey, class TValue>
template <typename TKey, typename TValue>
struct HashMapElement {
HashMapElement *next = nullptr;
HashMapElement *prev = nullptr;
@@ -62,15 +61,17 @@ struct HashMapElement {
data(p_key, p_value) {}
};
template <class TKey, class TValue,
class Hasher = HashMapHasherDefault,
class Comparator = HashMapComparatorDefault<TKey>,
class Allocator = DefaultTypedAllocator<HashMapElement<TKey, TValue>>>
bool _hashmap_variant_less_than(const Variant &p_left, const Variant &p_right);
template <typename TKey, typename TValue,
typename Hasher = HashMapHasherDefault,
typename Comparator = HashMapComparatorDefault<TKey>,
typename Allocator = DefaultTypedAllocator<HashMapElement<TKey, TValue>>>
class HashMap {
public:
const uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime.
const float MAX_OCCUPANCY = 0.75;
const uint32_t EMPTY_HASH = 0;
static constexpr uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime.
static constexpr float MAX_OCCUPANCY = 0.75;
static constexpr uint32_t EMPTY_HASH = 0;
private:
Allocator element_alloc;
@@ -92,19 +93,20 @@ private:
return hash;
}
_FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash, uint32_t p_capacity) const {
uint32_t original_pos = p_hash % p_capacity;
return (p_pos - original_pos + p_capacity) % p_capacity;
static _FORCE_INLINE_ uint32_t _get_probe_length(const uint32_t p_pos, const uint32_t p_hash, const uint32_t p_capacity, const uint64_t p_capacity_inv) {
const uint32_t original_pos = fastmod(p_hash, p_capacity_inv, p_capacity);
return fastmod(p_pos - original_pos + p_capacity, p_capacity_inv, p_capacity);
}
bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const {
if (elements == nullptr) {
if (elements == nullptr || num_elements == 0) {
return false; // Failed lookups, no elements
}
uint32_t capacity = hash_table_size_primes[capacity_index];
const uint32_t capacity = hash_table_size_primes[capacity_index];
const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index];
uint32_t hash = _hash(p_key);
uint32_t pos = hash % capacity;
uint32_t pos = fastmod(hash, capacity_inv, capacity);
uint32_t distance = 0;
while (true) {
@@ -112,7 +114,7 @@ private:
return false;
}
if (distance > _get_probe_length(pos, hashes[pos], capacity)) {
if (distance > _get_probe_length(pos, hashes[pos], capacity, capacity_inv)) {
return false;
}
@@ -121,17 +123,18 @@ private:
return true;
}
pos = (pos + 1) % capacity;
pos = fastmod((pos + 1), capacity_inv, capacity);
distance++;
}
}
void _insert_with_hash(uint32_t p_hash, HashMapElement<TKey, TValue> *p_value) {
uint32_t capacity = hash_table_size_primes[capacity_index];
const uint32_t capacity = hash_table_size_primes[capacity_index];
const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index];
uint32_t hash = p_hash;
HashMapElement<TKey, TValue> *value = p_value;
uint32_t distance = 0;
uint32_t pos = hash % capacity;
uint32_t pos = fastmod(hash, capacity_inv, capacity);
while (true) {
if (hashes[pos] == EMPTY_HASH) {
@@ -144,14 +147,14 @@ private:
}
// Not an empty slot, let's check the probing length of the existing one.
uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity);
uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity, capacity_inv);
if (existing_probe_len < distance) {
SWAP(hash, hashes[pos]);
SWAP(value, elements[pos]);
distance = existing_probe_len;
}
pos = (pos + 1) % capacity;
pos = fastmod((pos + 1), capacity_inv, capacity);
distance++;
}
}
@@ -251,7 +254,7 @@ public:
}
void clear() {
if (elements == nullptr) {
if (elements == nullptr || num_elements == 0) {
return;
}
uint32_t capacity = hash_table_size_primes[capacity_index];
@@ -270,6 +273,47 @@ public:
num_elements = 0;
}
void sort() {
if (elements == nullptr || num_elements < 2) {
return; // An empty or single element HashMap is already sorted.
}
// Use insertion sort because we want this operation to be fast for the
// common case where the input is already sorted or nearly sorted.
HashMapElement<TKey, TValue> *inserting = head_element->next;
while (inserting != nullptr) {
HashMapElement<TKey, TValue> *after = nullptr;
for (HashMapElement<TKey, TValue> *current = inserting->prev; current != nullptr; current = current->prev) {
if (_hashmap_variant_less_than(inserting->data.key, current->data.key)) {
after = current;
} else {
break;
}
}
HashMapElement<TKey, TValue> *next = inserting->next;
if (after != nullptr) {
// Modify the elements around `inserting` to remove it from its current position.
inserting->prev->next = next;
if (next == nullptr) {
tail_element = inserting->prev;
} else {
next->prev = inserting->prev;
}
// Modify `before` and `after` to insert `inserting` between them.
HashMapElement<TKey, TValue> *before = after->prev;
if (before == nullptr) {
head_element = inserting;
} else {
before->next = inserting;
}
after->prev = inserting;
// Point `inserting` to its new surroundings.
inserting->prev = before;
inserting->next = after;
}
inserting = next;
}
}
TValue &get(const TKey &p_key) {
uint32_t pos = 0;
bool exists = _lookup_pos(p_key, pos);
@@ -317,13 +361,14 @@ public:
return false;
}
uint32_t capacity = hash_table_size_primes[capacity_index];
uint32_t next_pos = (pos + 1) % capacity;
while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity) != 0) {
const uint32_t capacity = hash_table_size_primes[capacity_index];
const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index];
uint32_t next_pos = fastmod((pos + 1), capacity_inv, capacity);
while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity, capacity_inv) != 0) {
SWAP(hashes[next_pos], hashes[pos]);
SWAP(elements[next_pos], elements[pos]);
pos = next_pos;
next_pos = (pos + 1) % capacity;
next_pos = fastmod((pos + 1), capacity_inv, capacity);
}
hashes[pos] = EMPTY_HASH;
@@ -351,6 +396,40 @@ public:
return true;
}
// Replace the key of an entry in-place, without invalidating iterators or changing the entries position during iteration.
// p_old_key must exist in the map and p_new_key must not, unless it is equal to p_old_key.
bool replace_key(const TKey &p_old_key, const TKey &p_new_key) {
if (p_old_key == p_new_key) {
return true;
}
uint32_t pos = 0;
ERR_FAIL_COND_V(_lookup_pos(p_new_key, pos), false);
ERR_FAIL_COND_V(!_lookup_pos(p_old_key, pos), false);
HashMapElement<TKey, TValue> *element = elements[pos];
// Delete the old entries in hashes and elements.
const uint32_t capacity = hash_table_size_primes[capacity_index];
const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index];
uint32_t next_pos = fastmod((pos + 1), capacity_inv, capacity);
while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity, capacity_inv) != 0) {
SWAP(hashes[next_pos], hashes[pos]);
SWAP(elements[next_pos], elements[pos]);
pos = next_pos;
next_pos = fastmod((pos + 1), capacity_inv, capacity);
}
hashes[pos] = EMPTY_HASH;
elements[pos] = nullptr;
// _insert_with_hash will increment this again.
num_elements--;
// Update the HashMapElement with the new key and reinsert it.
const_cast<TKey &>(element->data.key) = p_new_key;
uint32_t hash = _hash(p_new_key);
_insert_with_hash(hash, element);
return true;
}
// Reserves space for a number of elements, useful to avoid many resizes and rehashes.
// If adding a known (possibly large) number of elements at once, must be larger than old capacity.
void reserve(uint32_t p_new_capacity) {
@@ -561,6 +640,13 @@ public:
capacity_index = MIN_CAPACITY_INDEX;
}
HashMap(std::initializer_list<KeyValue<TKey, TValue>> p_init) {
reserve(p_init.size());
for (const KeyValue<TKey, TValue> &E : p_init) {
insert(E.key, E.value);
}
}
uint32_t debug_get_hash(uint32_t p_index) {
if (num_elements == 0) {
return 0;
@@ -587,5 +673,3 @@ public:
};
} // namespace godot
#endif // GODOT_HASH_MAP_HPP

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_HASH_SET_HPP
#define GODOT_HASH_SET_HPP
#pragma once
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/memory.hpp>
@@ -48,9 +47,9 @@ namespace godot {
*
*/
template <class TKey,
class Hasher = HashMapHasherDefault,
class Comparator = HashMapComparatorDefault<TKey>>
template <typename TKey,
typename Hasher = HashMapHasherDefault,
typename Comparator = HashMapComparatorDefault<TKey>>
class HashSet {
public:
static constexpr uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime.
@@ -76,19 +75,20 @@ private:
return hash;
}
_FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash, uint32_t p_capacity) const {
uint32_t original_pos = p_hash % p_capacity;
return (p_pos - original_pos + p_capacity) % p_capacity;
static _FORCE_INLINE_ uint32_t _get_probe_length(const uint32_t p_pos, const uint32_t p_hash, const uint32_t p_capacity, const uint64_t p_capacity_inv) {
const uint32_t original_pos = fastmod(p_hash, p_capacity_inv, p_capacity);
return fastmod(p_pos - original_pos + p_capacity, p_capacity_inv, p_capacity);
}
bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const {
if (keys == nullptr) {
if (keys == nullptr || num_elements == 0) {
return false; // Failed lookups, no elements
}
uint32_t capacity = hash_table_size_primes[capacity_index];
const uint32_t capacity = hash_table_size_primes[capacity_index];
const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index];
uint32_t hash = _hash(p_key);
uint32_t pos = hash % capacity;
uint32_t pos = fastmod(hash, capacity_inv, capacity);
uint32_t distance = 0;
while (true) {
@@ -96,7 +96,7 @@ private:
return false;
}
if (distance > _get_probe_length(pos, hashes[pos], capacity)) {
if (distance > _get_probe_length(pos, hashes[pos], capacity, capacity_inv)) {
return false;
}
@@ -105,17 +105,18 @@ private:
return true;
}
pos = (pos + 1) % capacity;
pos = fastmod(pos + 1, capacity_inv, capacity);
distance++;
}
}
uint32_t _insert_with_hash(uint32_t p_hash, uint32_t p_index) {
uint32_t capacity = hash_table_size_primes[capacity_index];
const uint32_t capacity = hash_table_size_primes[capacity_index];
const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index];
uint32_t hash = p_hash;
uint32_t index = p_index;
uint32_t distance = 0;
uint32_t pos = hash % capacity;
uint32_t pos = fastmod(hash, capacity_inv, capacity);
while (true) {
if (hashes[pos] == EMPTY_HASH) {
@@ -126,7 +127,7 @@ private:
}
// Not an empty slot, let's check the probing length of the existing one.
uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity);
uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity, capacity_inv);
if (existing_probe_len < distance) {
key_to_hash[index] = pos;
SWAP(hash, hashes[pos]);
@@ -134,7 +135,7 @@ private:
distance = existing_probe_len;
}
pos = (pos + 1) % capacity;
pos = fastmod(pos + 1, capacity_inv, capacity);
distance++;
}
}
@@ -237,7 +238,7 @@ public:
}
void clear() {
if (keys == nullptr) {
if (keys == nullptr || num_elements == 0) {
return;
}
uint32_t capacity = hash_table_size_primes[capacity_index];
@@ -265,11 +266,12 @@ public:
}
uint32_t key_pos = pos;
pos = key_to_hash[pos]; // make hash pos
pos = key_to_hash[pos]; //make hash pos
uint32_t capacity = hash_table_size_primes[capacity_index];
uint32_t next_pos = (pos + 1) % capacity;
while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity) != 0) {
const uint32_t capacity = hash_table_size_primes[capacity_index];
const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index];
uint32_t next_pos = fastmod(pos + 1, capacity_inv, capacity);
while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity, capacity_inv) != 0) {
uint32_t kpos = hash_to_key[pos];
uint32_t kpos_next = hash_to_key[next_pos];
SWAP(key_to_hash[kpos], key_to_hash[kpos_next]);
@@ -277,7 +279,7 @@ public:
SWAP(hash_to_key[next_pos], hash_to_key[pos]);
pos = next_pos;
next_pos = (pos + 1) % capacity;
next_pos = fastmod(pos + 1, capacity_inv, capacity);
}
hashes[pos] = EMPTY_HASH;
@@ -444,6 +446,13 @@ public:
capacity_index = MIN_CAPACITY_INDEX;
}
HashSet(std::initializer_list<TKey> p_init) {
reserve(p_init.size());
for (const TKey &E : p_init) {
insert(E);
}
}
void reset() {
clear();
@@ -473,5 +482,3 @@ public:
};
} // namespace godot
#endif // GODOT_HASH_SET_HPP

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_HASHFUNCS_HPP
#define GODOT_HASHFUNCS_HPP
#pragma once
// Needed for fastmod.
#if defined(_MSC_VER)
@@ -38,6 +37,7 @@
#include <godot_cpp/core/math.hpp>
#include <godot_cpp/core/object.hpp>
#include <godot_cpp/templates/pair.hpp>
#include <godot_cpp/variant/aabb.hpp>
#include <godot_cpp/variant/node_path.hpp>
#include <godot_cpp/variant/rect2.hpp>
@@ -67,10 +67,11 @@ namespace godot {
static _FORCE_INLINE_ uint32_t hash_djb2(const char *p_cstr) {
const unsigned char *chr = (const unsigned char *)p_cstr;
uint32_t hash = 5381;
uint32_t c;
uint32_t c = *chr++;
while ((c = *chr++)) {
while (c) {
hash = ((hash << 5) + hash) ^ c; /* hash * 33 ^ c */
c = *chr++;
}
return hash;
@@ -108,6 +109,16 @@ static _FORCE_INLINE_ uint32_t hash_one_uint64(const uint64_t p_int) {
return uint32_t(v);
}
static _FORCE_INLINE_ uint64_t hash64_murmur3_64(uint64_t key, uint64_t seed) {
key ^= seed;
key ^= key >> 33;
key *= 0xff51afd7ed558ccd;
key ^= key >> 33;
key *= 0xc4ceb9fe1a85ec53;
key ^= key >> 33;
return key;
}
#define HASH_MURMUR3_SEED 0x7F07C65
// Murmurhash3 32-bit version.
// All MurmurHash versions are public domain software, and the author disclaims all copyright to their code.
@@ -228,7 +239,7 @@ static _FORCE_INLINE_ uint32_t hash_murmur3_buffer(const void *key, int length,
k1 = hash_rotl32(k1, 15);
k1 *= c2;
h1 ^= k1;
}
};
// Finalize with additional bit mixing.
h1 ^= length;
@@ -253,7 +264,7 @@ static _FORCE_INLINE_ uint32_t hash_djb2_one_float(double p_in, uint32_t p_prev
return ((p_prev << 5) + p_prev) + hash_one_uint64(u.i);
}
template <class T>
template <typename T>
static _FORCE_INLINE_ uint32_t hash_make_uint32_t(T p_in) {
union {
T t;
@@ -286,7 +297,7 @@ static _FORCE_INLINE_ uint64_t hash_djb2_one_64(uint64_t p_in, uint64_t p_prev =
return ((p_prev << 5) + p_prev) ^ p_in;
}
template <class T>
template <typename T>
static _FORCE_INLINE_ uint64_t hash_make_uint64_t(T p_in) {
union {
T t;
@@ -298,53 +309,62 @@ static _FORCE_INLINE_ uint64_t hash_make_uint64_t(T p_in) {
return _u._u64;
}
template <class T>
template <typename T>
class Ref;
struct HashMapHasherDefault {
// Generic hash function for any type.
template <class T>
template <typename T>
static _FORCE_INLINE_ uint32_t hash(const T *p_pointer) { return hash_one_uint64((uint64_t)p_pointer); }
template <class T>
template <typename T>
static _FORCE_INLINE_ uint32_t hash(const Ref<T> &p_ref) { return hash_one_uint64((uint64_t)p_ref.operator->()); }
template <typename F, typename S>
static _FORCE_INLINE_ uint32_t hash(const Pair<F, S> &p_pair) {
uint64_t h1 = hash(p_pair.first);
uint64_t h2 = hash(p_pair.second);
return hash_one_uint64((h1 << 32) | h2);
}
static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); }
static _FORCE_INLINE_ uint32_t hash(const char *p_cstr) { return hash_djb2(p_cstr); }
static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return hash_fmix32(p_wchar); }
static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return hash_fmix32(p_uchar); }
static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return hash_fmix32(p_uchar); }
static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return hash_fmix32(uint32_t(p_wchar)); }
static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return hash_fmix32(uint32_t(p_uchar)); }
static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return hash_fmix32(uint32_t(p_uchar)); }
static _FORCE_INLINE_ uint32_t hash(const RID &p_rid) { return hash_one_uint64(p_rid.get_id()); }
static _FORCE_INLINE_ uint32_t hash(const CharString &p_char_string) { return hash_djb2(p_char_string.get_data()); }
static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); }
static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); }
static _FORCE_INLINE_ uint32_t hash(const ObjectID &p_id) { return hash_one_uint64(p_id); }
static _FORCE_INLINE_ uint32_t hash(const Callable &p_callable) { return p_callable.hash(); }
static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) { return hash_one_uint64(p_int); }
static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash_one_uint64(p_int); }
static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash_one_uint64(uint64_t(p_int)); }
static _FORCE_INLINE_ uint32_t hash(const float p_float) { return hash_murmur3_one_float(p_float); }
static _FORCE_INLINE_ uint32_t hash(const double p_double) { return hash_murmur3_one_double(p_double); }
static _FORCE_INLINE_ uint32_t hash(const uint32_t p_int) { return hash_fmix32(p_int); }
static _FORCE_INLINE_ uint32_t hash(const int32_t p_int) { return hash_fmix32(p_int); }
static _FORCE_INLINE_ uint32_t hash(const uint16_t p_int) { return hash_fmix32(p_int); }
static _FORCE_INLINE_ uint32_t hash(const int16_t p_int) { return hash_fmix32(p_int); }
static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return hash_fmix32(p_int); }
static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return hash_fmix32(p_int); }
static _FORCE_INLINE_ uint32_t hash(const int32_t p_int) { return hash_fmix32(uint32_t(p_int)); }
static _FORCE_INLINE_ uint32_t hash(const uint16_t p_int) { return hash_fmix32(uint32_t(p_int)); }
static _FORCE_INLINE_ uint32_t hash(const int16_t p_int) { return hash_fmix32(uint32_t(p_int)); }
static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return hash_fmix32(uint32_t(p_int)); }
static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return hash_fmix32(uint32_t(p_int)); }
static _FORCE_INLINE_ uint32_t hash(const Vector2i &p_vec) {
uint32_t h = hash_murmur3_one_32(p_vec.x);
h = hash_murmur3_one_32(p_vec.y, h);
uint32_t h = hash_murmur3_one_32(uint32_t(p_vec.x));
h = hash_murmur3_one_32(uint32_t(p_vec.y), h);
return hash_fmix32(h);
}
static _FORCE_INLINE_ uint32_t hash(const Vector3i &p_vec) {
uint32_t h = hash_murmur3_one_32(p_vec.x);
h = hash_murmur3_one_32(p_vec.y, h);
h = hash_murmur3_one_32(p_vec.z, h);
uint32_t h = hash_murmur3_one_32(uint32_t(p_vec.x));
h = hash_murmur3_one_32(uint32_t(p_vec.y), h);
h = hash_murmur3_one_32(uint32_t(p_vec.z), h);
return hash_fmix32(h);
}
static _FORCE_INLINE_ uint32_t hash(const Vector4i &p_vec) {
uint32_t h = hash_murmur3_one_32(p_vec.x);
h = hash_murmur3_one_32(p_vec.y, h);
h = hash_murmur3_one_32(p_vec.z, h);
h = hash_murmur3_one_32(p_vec.w, h);
uint32_t h = hash_murmur3_one_32(uint32_t(p_vec.x));
h = hash_murmur3_one_32(uint32_t(p_vec.y), h);
h = hash_murmur3_one_32(uint32_t(p_vec.z), h);
h = hash_murmur3_one_32(uint32_t(p_vec.w), h);
return hash_fmix32(h);
}
static _FORCE_INLINE_ uint32_t hash(const Vector2 &p_vec) {
@@ -365,11 +385,18 @@ struct HashMapHasherDefault {
h = hash_murmur3_one_real(p_vec.w, h);
return hash_fmix32(h);
}
static _FORCE_INLINE_ uint32_t hash(const Color &p_vec) {
uint32_t h = hash_murmur3_one_float(p_vec.r);
h = hash_murmur3_one_float(p_vec.g, h);
h = hash_murmur3_one_float(p_vec.b, h);
h = hash_murmur3_one_float(p_vec.a, h);
return hash_fmix32(h);
}
static _FORCE_INLINE_ uint32_t hash(const Rect2i &p_rect) {
uint32_t h = hash_murmur3_one_32(p_rect.position.x);
h = hash_murmur3_one_32(p_rect.position.y, h);
h = hash_murmur3_one_32(p_rect.size.x, h);
h = hash_murmur3_one_32(p_rect.size.y, h);
uint32_t h = hash_murmur3_one_32(uint32_t(p_rect.position.x));
h = hash_murmur3_one_32(uint32_t(p_rect.position.y), h);
h = hash_murmur3_one_32(uint32_t(p_rect.size.x), h);
h = hash_murmur3_one_32(uint32_t(p_rect.size.y), h);
return hash_fmix32(h);
}
static _FORCE_INLINE_ uint32_t hash(const Rect2 &p_rect) {
@@ -390,6 +417,19 @@ struct HashMapHasherDefault {
}
};
struct HashHasher {
static _FORCE_INLINE_ uint32_t hash(const int32_t hash) { return hash; }
static _FORCE_INLINE_ uint32_t hash(const uint32_t hash) { return hash; }
static _FORCE_INLINE_ uint64_t hash(const int64_t hash) { return hash; }
static _FORCE_INLINE_ uint64_t hash(const uint64_t hash) { return hash; }
};
// TODO: Fold this into HashMapHasherDefault once C++20 concepts are allowed
template <typename T>
struct HashableHasher {
static _FORCE_INLINE_ uint32_t hash(const T &hashable) { return hashable.hash(); }
};
template <typename T>
struct HashMapComparatorDefault {
static bool compare(const T &p_lhs, const T &p_rhs) {
@@ -411,6 +451,13 @@ struct HashMapComparatorDefault<double> {
}
};
template <>
struct HashMapComparatorDefault<Color> {
static bool compare(const Color &p_lhs, const Color &p_rhs) {
return ((p_lhs.r == p_rhs.r) || (Math::is_nan(p_lhs.r) && Math::is_nan(p_rhs.r))) && ((p_lhs.g == p_rhs.g) || (Math::is_nan(p_lhs.g) && Math::is_nan(p_rhs.g))) && ((p_lhs.b == p_rhs.b) || (Math::is_nan(p_lhs.b) && Math::is_nan(p_rhs.b))) && ((p_lhs.a == p_rhs.a) || (Math::is_nan(p_lhs.a) && Math::is_nan(p_rhs.a)));
}
};
template <>
struct HashMapComparatorDefault<Vector2> {
static bool compare(const Vector2 &p_lhs, const Vector2 &p_rhs) {
@@ -425,9 +472,90 @@ struct HashMapComparatorDefault<Vector3> {
}
};
template <>
struct HashMapComparatorDefault<Vector4> {
static bool compare(const Vector4 &p_lhs, const Vector4 &p_rhs) {
return ((p_lhs.x == p_rhs.x) || (Math::is_nan(p_lhs.x) && Math::is_nan(p_rhs.x))) && ((p_lhs.y == p_rhs.y) || (Math::is_nan(p_lhs.y) && Math::is_nan(p_rhs.y))) && ((p_lhs.z == p_rhs.z) || (Math::is_nan(p_lhs.z) && Math::is_nan(p_rhs.z))) && ((p_lhs.w == p_rhs.w) || (Math::is_nan(p_lhs.w) && Math::is_nan(p_rhs.w)));
}
};
template <>
struct HashMapComparatorDefault<Rect2> {
static bool compare(const Rect2 &p_lhs, const Rect2 &p_rhs) {
return HashMapComparatorDefault<Vector2>().compare(p_lhs.position, p_rhs.position) && HashMapComparatorDefault<Vector2>().compare(p_lhs.size, p_rhs.size);
}
};
template <>
struct HashMapComparatorDefault<AABB> {
static bool compare(const AABB &p_lhs, const AABB &p_rhs) {
return HashMapComparatorDefault<Vector3>().compare(p_lhs.position, p_rhs.position) && HashMapComparatorDefault<Vector3>().compare(p_lhs.size, p_rhs.size);
}
};
template <>
struct HashMapComparatorDefault<Plane> {
static bool compare(const Plane &p_lhs, const Plane &p_rhs) {
return HashMapComparatorDefault<Vector3>().compare(p_lhs.normal, p_rhs.normal) && ((p_lhs.d == p_rhs.d) || (Math::is_nan(p_lhs.d) && Math::is_nan(p_rhs.d)));
}
};
template <>
struct HashMapComparatorDefault<Transform2D> {
static bool compare(const Transform2D &p_lhs, const Transform2D &p_rhs) {
for (int i = 0; i < 3; ++i) {
if (!HashMapComparatorDefault<Vector2>().compare(p_lhs.columns[i], p_rhs.columns[i])) {
return false;
}
}
return true;
}
};
template <>
struct HashMapComparatorDefault<Basis> {
static bool compare(const Basis &p_lhs, const Basis &p_rhs) {
for (int i = 0; i < 3; ++i) {
if (!HashMapComparatorDefault<Vector3>().compare(p_lhs.rows[i], p_rhs.rows[i])) {
return false;
}
}
return true;
}
};
template <>
struct HashMapComparatorDefault<Transform3D> {
static bool compare(const Transform3D &p_lhs, const Transform3D &p_rhs) {
return HashMapComparatorDefault<Basis>().compare(p_lhs.basis, p_rhs.basis) && HashMapComparatorDefault<Vector3>().compare(p_lhs.origin, p_rhs.origin);
}
};
template <>
struct HashMapComparatorDefault<Projection> {
static bool compare(const Projection &p_lhs, const Projection &p_rhs) {
for (int i = 0; i < 4; ++i) {
if (!HashMapComparatorDefault<Vector4>().compare(p_lhs.columns[i], p_rhs.columns[i])) {
return false;
}
}
return true;
}
};
template <>
struct HashMapComparatorDefault<Quaternion> {
static bool compare(const Quaternion &p_lhs, const Quaternion &p_rhs) {
return ((p_lhs.x == p_rhs.x) || (Math::is_nan(p_lhs.x) && Math::is_nan(p_rhs.x))) && ((p_lhs.y == p_rhs.y) || (Math::is_nan(p_lhs.y) && Math::is_nan(p_rhs.y))) && ((p_lhs.z == p_rhs.z) || (Math::is_nan(p_lhs.z) && Math::is_nan(p_rhs.z))) && ((p_lhs.w == p_rhs.w) || (Math::is_nan(p_lhs.w) && Math::is_nan(p_rhs.w)));
}
};
constexpr uint32_t HASH_TABLE_SIZE_MAX = 29;
const uint32_t hash_table_size_primes[HASH_TABLE_SIZE_MAX] = {
inline constexpr uint32_t hash_table_size_primes[HASH_TABLE_SIZE_MAX] = {
5,
13,
23,
@@ -460,7 +588,7 @@ const uint32_t hash_table_size_primes[HASH_TABLE_SIZE_MAX] = {
};
// Computed with elem_i = UINT64_C (0 x FFFFFFFF FFFFFFFF ) / d_i + 1, where d_i is the i-th element of the above array.
const uint64_t hash_table_size_primes_inv[HASH_TABLE_SIZE_MAX] = {
inline constexpr uint64_t hash_table_size_primes_inv[HASH_TABLE_SIZE_MAX] = {
3689348814741910324,
1418980313362273202,
802032351030850071,
@@ -522,5 +650,3 @@ static _FORCE_INLINE_ uint32_t fastmod(const uint32_t n, const uint64_t c, const
}
} // namespace godot
#endif // GODOT_HASHFUNCS_HPP

View File

@@ -28,13 +28,14 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_LIST_HPP
#define GODOT_LIST_HPP
#pragma once
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/templates/sort_array.hpp>
#include <initializer_list>
/**
* Generic Templatized Linked List Implementation.
* The implementation differs from the STL one because
@@ -45,7 +46,7 @@
namespace godot {
template <class T, class A = DefaultAllocator>
template <typename T, typename A = DefaultAllocator>
class List {
struct _Data;
@@ -134,36 +135,13 @@ public:
data->erase(this);
}
void transfer_to_back(List<T, A> *p_dst_list);
_FORCE_INLINE_ Element() {}
};
typedef T ValueType;
struct Iterator {
_FORCE_INLINE_ T &operator*() const {
return E->get();
}
_FORCE_INLINE_ T *operator->() const { return &E->get(); }
_FORCE_INLINE_ Iterator &operator++() {
E = E->next();
return *this;
}
_FORCE_INLINE_ Iterator &operator--() {
E = E->prev();
return *this;
}
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
Iterator(Element *p_E) { E = p_E; }
Iterator() {}
Iterator(const Iterator &p_it) { E = p_it.E; }
private:
Element *E = nullptr;
};
struct ConstIterator {
_FORCE_INLINE_ const T &operator*() const {
return E->get();
@@ -189,6 +167,35 @@ public:
const Element *E = nullptr;
};
struct Iterator {
_FORCE_INLINE_ T &operator*() const {
return E->get();
}
_FORCE_INLINE_ T *operator->() const { return &E->get(); }
_FORCE_INLINE_ Iterator &operator++() {
E = E->next();
return *this;
}
_FORCE_INLINE_ Iterator &operator--() {
E = E->prev();
return *this;
}
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
Iterator(Element *p_E) { E = p_E; }
Iterator() {}
Iterator(const Iterator &p_it) { E = p_it.E; }
operator ConstIterator() const {
return ConstIterator(E);
}
private:
Element *E = nullptr;
};
_FORCE_INLINE_ Iterator begin() {
return Iterator(front());
}
@@ -220,8 +227,8 @@ private:
Element *last = nullptr;
int size_cache = 0;
bool erase(const Element *p_I) {
ERR_FAIL_COND_V(!p_I, false);
bool erase(Element *p_I) {
ERR_FAIL_NULL_V(p_I, false);
ERR_FAIL_COND_V(p_I->data != this, false);
if (first == p_I) {
@@ -240,7 +247,7 @@ private:
p_I->next_ptr->prev_ptr = p_I->prev_ptr;
}
memdelete_allocator<Element, A>(const_cast<Element *>(p_I));
memdelete_allocator<Element, A>(p_I);
size_cache--;
return true;
@@ -410,7 +417,7 @@ public:
/**
* find an element in the list,
*/
template <class T_v>
template <typename T_v>
Element *find(const T_v &p_val) {
Element *it = front();
while (it) {
@@ -426,7 +433,7 @@ public:
/**
* erase an element in the list, by iterator pointing to it. Return true if it was found/erased.
*/
bool erase(const Element *p_I) {
bool erase(Element *p_I) {
if (_data && p_I) {
bool ret = _data->erase(p_I);
@@ -518,8 +525,19 @@ public:
it = it->next();
}
}
void operator=(List &&p_list) {
if (unlikely(this == &p_list)) {
return;
}
T &operator[](int p_index) {
clear();
_data = p_list._data;
p_list._data = nullptr;
}
// Random access to elements, use with care,
// do not use for iteration.
T &get(int p_index) {
CRASH_BAD_INDEX(p_index, size());
Element *I = front();
@@ -532,7 +550,9 @@ public:
return I->get();
}
const T &operator[](int p_index) const {
// Random access to elements, use with care,
// do not use for iteration.
const T &get(int p_index) const {
CRASH_BAD_INDEX(p_index, size());
const Element *I = front();
@@ -646,7 +666,7 @@ public:
sort_custom<Comparator<T>>();
}
template <class C>
template <typename C>
void sort_custom_inplace() {
if (size() < 2) {
return;
@@ -693,7 +713,7 @@ public:
_data->last = to;
}
template <class C>
template <typename C>
struct AuxiliaryComparator {
C compare;
_FORCE_INLINE_ bool operator()(const Element *a, const Element *b) const {
@@ -701,10 +721,10 @@ public:
}
};
template <class C>
template <typename C>
void sort_custom() {
// this version uses auxiliary memory for speed.
// if you don't want to use auxiliary memory, use the in_place version
//this version uses auxiliary memory for speed.
//if you don't want to use auxiliary memory, use the in_place version
int s = size();
if (s < 2) {
@@ -752,9 +772,19 @@ public:
it = it->next();
}
}
List(List &&p_list) {
_data = p_list._data;
p_list._data = nullptr;
}
List() {}
List(std::initializer_list<T> p_init) {
for (const T &E : p_init) {
push_back(E);
}
}
~List() {
clear();
if (_data) {
@@ -764,6 +794,41 @@ public:
}
};
} // namespace godot
template <typename T, typename A>
void List<T, A>::Element::transfer_to_back(List<T, A> *p_dst_list) {
// Detach from current.
#endif // GODOT_LIST_HPP
if (data->first == this) {
data->first = data->first->next_ptr;
}
if (data->last == this) {
data->last = data->last->prev_ptr;
}
if (prev_ptr) {
prev_ptr->next_ptr = next_ptr;
}
if (next_ptr) {
next_ptr->prev_ptr = prev_ptr;
}
data->size_cache--;
// Attach to the back of the new one.
if (!p_dst_list->_data) {
p_dst_list->_data = memnew_allocator(_Data, A);
p_dst_list->_data->first = this;
p_dst_list->_data->last = nullptr;
p_dst_list->_data->size_cache = 0;
prev_ptr = nullptr;
} else {
p_dst_list->_data->last->next_ptr = this;
prev_ptr = p_dst_list->_data->last;
}
p_dst_list->_data->last = this;
next_ptr = nullptr;
data = p_dst_list->_data;
p_dst_list->_data->size_cache++;
}
} // namespace godot

View File

@@ -28,13 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_LOCAL_VECTOR_HPP
#define GODOT_LOCAL_VECTOR_HPP
#pragma once
#include "godot_cpp/core/error_macros.hpp"
#include "godot_cpp/core/memory.hpp"
#include "godot_cpp/templates/sort_array.hpp"
#include "godot_cpp/templates/vector.hpp"
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/templates/sort_array.hpp>
#include <godot_cpp/templates/vector.hpp>
#include <initializer_list>
#include <type_traits>
@@ -43,7 +42,7 @@ namespace godot {
// If tight, it grows strictly as much as needed.
// Otherwise, it grows exponentially (the default and what you want in most cases).
template <class T, class U = uint32_t, bool force_trivial = false, bool tight = false>
template <typename T, typename U = uint32_t, bool force_trivial = false, bool tight = false>
class LocalVector {
private:
U count = 0;
@@ -59,21 +58,18 @@ public:
return data;
}
// Must take a copy instead of a reference (see GH-31736).
_FORCE_INLINE_ void push_back(T p_elem) {
if (unlikely(count == capacity)) {
if (capacity == 0) {
capacity = 1;
} else {
capacity <<= 1;
}
capacity = tight ? (capacity + 1) : MAX((U)1, capacity << 1);
data = (T *)memrealloc(data, capacity * sizeof(T));
CRASH_COND_MSG(!data, "Out of memory");
}
if constexpr (!std::is_trivially_constructible<T>::value && !force_trivial) {
if constexpr (!std::is_trivially_constructible_v<T> && !force_trivial) {
memnew_placement(&data[count++], T(p_elem));
} else {
data[count++] = p_elem;
data[count++] = std::move(p_elem);
}
}
@@ -81,31 +77,49 @@ public:
ERR_FAIL_UNSIGNED_INDEX(p_index, count);
count--;
for (U i = p_index; i < count; i++) {
data[i] = data[i + 1];
data[i] = std::move(data[i + 1]);
}
if constexpr (!std::is_trivially_destructible<T>::value && !force_trivial) {
if constexpr (!std::is_trivially_destructible_v<T> && !force_trivial) {
data[count].~T();
}
}
/// Removes the item copying the last value into the position of the one to
/// remove. It's generally faster than `remove`.
/// remove. It's generally faster than `remove_at`.
void remove_at_unordered(U p_index) {
ERR_FAIL_INDEX(p_index, count);
count--;
if (count > p_index) {
data[p_index] = data[count];
data[p_index] = std::move(data[count]);
}
if constexpr (!std::is_trivially_destructible<T>::value && !force_trivial) {
if constexpr (!std::is_trivially_destructible_v<T> && !force_trivial) {
data[count].~T();
}
}
void erase(const T &p_val) {
_FORCE_INLINE_ bool erase(const T &p_val) {
int64_t idx = find(p_val);
if (idx >= 0) {
remove_at(idx);
return true;
}
return false;
}
U erase_multiple_unordered(const T &p_val) {
U from = 0;
U occurrences = 0;
while (true) {
int64_t idx = find(p_val, from);
if (idx == -1) {
break;
}
remove_at_unordered(idx);
from = idx;
occurrences++;
}
return occurrences;
}
void invert() {
@@ -137,7 +151,7 @@ public:
_FORCE_INLINE_ U size() const { return count; }
void resize(U p_size) {
if (p_size < count) {
if constexpr (!std::is_trivially_destructible<T>::value && !force_trivial) {
if constexpr (!std::is_trivially_destructible_v<T> && !force_trivial) {
for (U i = p_size; i < count; i++) {
data[i].~T();
}
@@ -145,16 +159,11 @@ public:
count = p_size;
} else if (p_size > count) {
if (unlikely(p_size > capacity)) {
if (capacity == 0) {
capacity = 1;
}
while (capacity < p_size) {
capacity <<= 1;
}
capacity = tight ? p_size : nearest_power_of_2_templated(p_size);
data = (T *)memrealloc(data, capacity * sizeof(T));
CRASH_COND_MSG(!data, "Out of memory");
}
if constexpr (!std::is_trivially_constructible<T>::value && !force_trivial) {
if constexpr (!std::is_trivially_constructible_v<T> && !force_trivial) {
for (U i = count; i < p_size; i++) {
memnew_placement(&data[i], T);
}
@@ -238,13 +247,13 @@ public:
void insert(U p_pos, T p_val) {
ERR_FAIL_UNSIGNED_INDEX(p_pos, count + 1);
if (p_pos == count) {
push_back(p_val);
push_back(std::move(p_val));
} else {
resize(count + 1);
for (U i = count - 1; i > p_pos; i--) {
data[i] = data[i - 1];
data[i] = std::move(data[i - 1]);
}
data[p_pos] = p_val;
data[p_pos] = std::move(p_val);
}
}
@@ -257,7 +266,11 @@ public:
return -1;
}
template <class C>
bool has(const T &p_val) const {
return find(p_val) != -1;
}
template <typename C>
void sort_custom() {
U len = count;
if (len == 0) {
@@ -284,9 +297,17 @@ public:
operator Vector<T>() const {
Vector<T> ret;
ret.resize(size());
ret.resize(count);
T *w = ret.ptrw();
memcpy(w, data, sizeof(T) * count);
if (w) {
if constexpr (std::is_trivially_copyable_v<T>) {
memcpy(w, data, sizeof(T) * count);
} else {
for (U i = 0; i < count; i++) {
w[i] = data[i];
}
}
}
return ret;
}
@@ -294,7 +315,9 @@ public:
Vector<uint8_t> ret;
ret.resize(count * sizeof(T));
uint8_t *w = ret.ptrw();
memcpy(w, data, sizeof(T) * count);
if (w) {
memcpy(w, data, sizeof(T) * count);
}
return ret;
}
@@ -311,6 +334,16 @@ public:
data[i] = p_from.data[i];
}
}
_FORCE_INLINE_ LocalVector(LocalVector &&p_from) {
data = p_from.data;
count = p_from.count;
capacity = p_from.capacity;
p_from.data = nullptr;
p_from.count = 0;
p_from.capacity = 0;
}
inline void operator=(const LocalVector &p_from) {
resize(p_from.size());
for (U i = 0; i < p_from.count; i++) {
@@ -323,6 +356,26 @@ public:
data[i] = p_from[i];
}
}
inline void operator=(LocalVector &&p_from) {
if (unlikely(this == &p_from)) {
return;
}
reset();
data = p_from.data;
count = p_from.count;
capacity = p_from.capacity;
p_from.data = nullptr;
p_from.count = 0;
p_from.capacity = 0;
}
inline void operator=(Vector<T> &&p_from) {
resize(p_from.size());
for (U i = 0; i < count; i++) {
data[i] = std::move(p_from[i]);
}
}
_FORCE_INLINE_ ~LocalVector() {
if (data) {
@@ -331,9 +384,7 @@ public:
}
};
template <class T, class U = uint32_t, bool force_trivial = false>
template <typename T, typename U = uint32_t, bool force_trivial = false>
using TightLocalVector = LocalVector<T, U, force_trivial, true>;
} // namespace godot
#endif // GODOT_LOCAL_VECTOR_HPP

View File

@@ -28,80 +28,72 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_PAIR_HPP
#define GODOT_PAIR_HPP
#pragma once
#include <godot_cpp/core/defs.hpp>
namespace godot {
template <class F, class S>
template <typename F, typename S>
struct Pair {
F first;
S second;
F first{};
S second{};
Pair() :
first(),
second() {
}
constexpr Pair() = default;
constexpr Pair(const F &p_first, const S &p_second) :
first(p_first), second(p_second) {}
Pair(F p_first, const S &p_second) :
first(p_first),
second(p_second) {
}
constexpr bool operator==(const Pair &p_other) const { return first == p_other.first && second == p_other.second; }
constexpr bool operator!=(const Pair &p_other) const { return first != p_other.first || second != p_other.second; }
constexpr bool operator<(const Pair &p_other) const { return first == p_other.first ? (second < p_other.second) : (first < p_other.first); }
constexpr bool operator<=(const Pair &p_other) const { return first == p_other.first ? (second <= p_other.second) : (first < p_other.first); }
constexpr bool operator>(const Pair &p_other) const { return first == p_other.first ? (second > p_other.second) : (first > p_other.first); }
constexpr bool operator>=(const Pair &p_other) const { return first == p_other.first ? (second >= p_other.second) : (first > p_other.first); }
};
template <class F, class S>
bool operator==(const Pair<F, S> &pair, const Pair<F, S> &other) {
return (pair.first == other.first) && (pair.second == other.second);
}
template <class F, class S>
bool operator!=(const Pair<F, S> &pair, const Pair<F, S> &other) {
return (pair.first != other.first) || (pair.second != other.second);
}
template <class F, class S>
template <typename F, typename S>
struct PairSort {
bool operator()(const Pair<F, S> &A, const Pair<F, S> &B) const {
if (A.first != B.first) {
return A.first < B.first;
}
return A.second < B.second;
constexpr bool operator()(const Pair<F, S> &p_lhs, const Pair<F, S> &p_rhs) const {
return p_lhs < p_rhs;
}
};
template <class K, class V>
// Pair is zero-constructible if and only if both constrained types are zero-constructible.
template <typename F, typename S>
struct is_zero_constructible<Pair<F, S>> : std::conjunction<is_zero_constructible<F>, is_zero_constructible<S>> {};
template <typename K, typename V>
struct KeyValue {
const K key;
V value;
const K key{};
V value{};
void operator=(const KeyValue &p_kv) = delete;
_FORCE_INLINE_ KeyValue(const KeyValue &p_kv) :
key(p_kv.key),
value(p_kv.value) {
}
_FORCE_INLINE_ KeyValue(const K &p_key, const V &p_value) :
key(p_key),
value(p_value) {
}
KeyValue &operator=(const KeyValue &p_kv) = delete;
KeyValue &operator=(KeyValue &&p_kv) = delete;
constexpr KeyValue(const KeyValue &p_kv) = default;
constexpr KeyValue(KeyValue &&p_kv) = default;
constexpr KeyValue(const K &p_key, const V &p_value) :
key(p_key), value(p_value) {}
constexpr KeyValue(const Pair<K, V> &p_pair) :
key(p_pair.first), value(p_pair.second) {}
constexpr bool operator==(const KeyValue &p_other) const { return key == p_other.key && value == p_other.value; }
constexpr bool operator!=(const KeyValue &p_other) const { return key != p_other.key || value != p_other.value; }
constexpr bool operator<(const KeyValue &p_other) const { return key == p_other.key ? (value < p_other.value) : (key < p_other.key); }
constexpr bool operator<=(const KeyValue &p_other) const { return key == p_other.key ? (value <= p_other.value) : (key < p_other.key); }
constexpr bool operator>(const KeyValue &p_other) const { return key == p_other.key ? (value > p_other.value) : (key > p_other.key); }
constexpr bool operator>=(const KeyValue &p_other) const { return key == p_other.key ? (value >= p_other.value) : (key > p_other.key); }
};
template <class K, class V>
bool operator==(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) {
return (pair.key == other.key) && (pair.value == other.value);
}
template <class K, class V>
bool operator!=(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) {
return (pair.key != other.key) || (pair.value != other.value);
}
template <class K, class V>
template <typename K, typename V>
struct KeyValueSort {
bool operator()(const KeyValue<K, V> &A, const KeyValue<K, V> &B) const {
return A.key < B.key;
constexpr bool operator()(const KeyValue<K, V> &p_lhs, const KeyValue<K, V> &p_rhs) const {
return p_lhs.key < p_rhs.key;
}
};
// KeyValue is zero-constructible if and only if both constrained types are zero-constructible.
template <typename K, typename V>
struct is_zero_constructible<KeyValue<K, V>> : std::conjunction<is_zero_constructible<K>, is_zero_constructible<V>> {};
} // namespace godot
#endif // GODOT_PAIR_HPP

View File

@@ -28,19 +28,20 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_RB_MAP_HPP
#define GODOT_RB_MAP_HPP
#pragma once
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/templates/pair.hpp>
#include <initializer_list>
namespace godot {
// based on the very nice implementation of rb-trees by:
// https://web.archive.org/web/20120507164830/https://web.mit.edu/~emin/www/source_code/red_black_tree/index.html
template <class K, class V, class C = Comparator<K>, class A = DefaultAllocator>
template <typename K, typename V, typename C = Comparator<K>, typename A = DefaultAllocator>
class RBMap {
enum Color {
RED,
@@ -98,6 +99,8 @@ public:
typedef KeyValue<K, V> ValueType;
struct Iterator {
friend class RBMap<K, V, C, A>;
_FORCE_INLINE_ KeyValue<K, V> &operator*() const {
return E->key_value();
}
@@ -111,11 +114,16 @@ public:
return *this;
}
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
_FORCE_INLINE_ bool operator==(const Iterator &p_it) const { return E == p_it.E; }
_FORCE_INLINE_ bool operator!=(const Iterator &p_it) const { return E != p_it.E; }
explicit operator bool() const {
return E != nullptr;
}
Iterator &operator=(const Iterator &p_it) {
E = p_it.E;
return *this;
}
Iterator(Element *p_E) { E = p_E; }
Iterator() {}
Iterator(const Iterator &p_it) { E = p_it.E; }
@@ -138,11 +146,16 @@ public:
return *this;
}
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; }
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; }
_FORCE_INLINE_ bool operator==(const ConstIterator &p_it) const { return E == p_it.E; }
_FORCE_INLINE_ bool operator!=(const ConstIterator &p_it) const { return E != p_it.E; }
explicit operator bool() const {
return E != nullptr;
}
ConstIterator &operator=(const ConstIterator &p_it) {
E = p_it.E;
return *this;
}
ConstIterator(const Element *p_E) { E = p_E; }
ConstIterator() {}
ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
@@ -419,7 +432,7 @@ private:
new_node->right = _data._nil;
new_node->left = _data._nil;
// new_node->data=_data;
//new_node->data=_data;
if (new_parent == _data._root || less(p_key, new_parent->_data.key)) {
new_parent->left = new_node;
@@ -753,6 +766,12 @@ public:
_copy_from(p_map);
}
RBMap(std::initializer_list<KeyValue<K, V>> p_init) {
for (const KeyValue<K, V> &E : p_init) {
insert(E.key, E.value);
}
}
_FORCE_INLINE_ RBMap() {}
~RBMap() {
@@ -761,5 +780,3 @@ public:
};
} // namespace godot
#endif // GODOT_RB_MAP_HPP

View File

@@ -28,17 +28,18 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_RB_SET_HPP
#define GODOT_RB_SET_HPP
#pragma once
#include <godot_cpp/core/memory.hpp>
#include <initializer_list>
// based on the very nice implementation of rb-trees by:
// https://web.archive.org/web/20120507164830/https://web.mit.edu/~emin/www/source_code/red_black_tree/index.html
namespace godot {
template <class T, class C = Comparator<T>, class A = DefaultAllocator>
template <typename T, typename C = Comparator<T>, typename A = DefaultAllocator>
class RBSet {
enum Color {
RED,
@@ -399,7 +400,7 @@ private:
new_node->right = _data._nil;
new_node->left = _data._nil;
new_node->value = p_value;
// new_node->data=_data;
//new_node->data=_data;
if (new_parent == _data._root || less(p_value, new_parent->value)) {
new_parent->left = new_node;
@@ -702,6 +703,12 @@ public:
_copy_from(p_set);
}
RBSet(std::initializer_list<T> p_init) {
for (const T &E : p_init) {
insert(E);
}
}
_FORCE_INLINE_ RBSet() {}
~RBSet() {
@@ -710,5 +717,3 @@ public:
};
} // namespace godot
#endif // GODOT_RB_SET_HPP

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_RID_OWNER_HPP
#define GODOT_RID_OWNER_HPP
#pragma once
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/godot.hpp>
@@ -42,7 +41,7 @@
namespace godot {
template <class T, bool THREAD_SAFE = false>
template <typename T, bool THREAD_SAFE = false>
class RID_Alloc {
T **chunks = nullptr;
uint32_t **free_list_chunks = nullptr;
@@ -186,12 +185,12 @@ public:
}
void initialize_rid(RID p_rid) {
T *mem = get_or_null(p_rid, true);
ERR_FAIL_COND(!mem);
ERR_FAIL_NULL(mem);
memnew_placement(mem, T);
}
void initialize_rid(RID p_rid, const T &p_value) {
T *mem = get_or_null(p_rid, true);
ERR_FAIL_COND(!mem);
ERR_FAIL_NULL(mem);
memnew_placement(mem, T(p_value));
}
@@ -347,7 +346,7 @@ public:
}
};
template <class T, bool THREAD_SAFE = false>
template <typename T, bool THREAD_SAFE = false>
class RID_PtrOwner {
RID_Alloc<T *, THREAD_SAFE> alloc;
@@ -374,7 +373,7 @@ public:
_FORCE_INLINE_ void replace(const RID &p_rid, T *p_new_ptr) {
T **ptr = alloc.get_or_null(p_rid);
ERR_FAIL_COND(!ptr);
ERR_FAIL_NULL(ptr);
*ptr = p_new_ptr;
}
@@ -406,7 +405,7 @@ public:
alloc(p_target_chunk_byte_size) {}
};
template <class T, bool THREAD_SAFE = false>
template <typename T, bool THREAD_SAFE = false>
class RID_Owner {
RID_Alloc<T, THREAD_SAFE> alloc;
@@ -461,5 +460,3 @@ public:
};
} // namespace godot
#endif // GODOT_RID_OWNER_HPP

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_SAFE_REFCOUNT_HPP
#define GODOT_SAFE_REFCOUNT_HPP
#pragma once
#if !defined(NO_THREADS)
@@ -48,7 +47,16 @@ namespace godot {
// value and, as an important benefit, you can be sure the value is properly synchronized
// even with threads that are already running.
template <class T>
// These are used in very specific areas of the engine where it's critical that these guarantees are held
#define SAFE_NUMERIC_TYPE_PUN_GUARANTEES(m_type) \
static_assert(sizeof(SafeNumeric<m_type>) == sizeof(m_type)); \
static_assert(alignof(SafeNumeric<m_type>) == alignof(m_type)); \
static_assert(std::is_trivially_destructible_v<std::atomic<m_type>>);
#define SAFE_FLAG_TYPE_PUN_GUARANTEES \
static_assert(sizeof(SafeFlag) == sizeof(bool)); \
static_assert(alignof(SafeFlag) == alignof(bool));
template <typename T>
class SafeNumeric {
std::atomic<T> value;
@@ -94,6 +102,17 @@ public:
return value.fetch_sub(p_value, std::memory_order_acq_rel) - p_value;
}
_ALWAYS_INLINE_ T bit_or(T p_value) {
return value.fetch_or(p_value, std::memory_order_acq_rel);
}
_ALWAYS_INLINE_ T bit_and(T p_value) {
return value.fetch_and(p_value, std::memory_order_acq_rel);
}
_ALWAYS_INLINE_ T bit_xor(T p_value) {
return value.fetch_xor(p_value, std::memory_order_acq_rel);
}
// Returns the original value instead of the new one
_ALWAYS_INLINE_ T postsub(T p_value) {
return value.fetch_sub(p_value, std::memory_order_acq_rel);
@@ -105,7 +124,8 @@ public:
if (tmp >= p_value) {
return tmp; // already greater, or equal
}
if (value.compare_exchange_weak(tmp, p_value, std::memory_order_release)) {
if (value.compare_exchange_weak(tmp, p_value, std::memory_order_acq_rel)) {
return p_value;
}
}
@@ -117,13 +137,13 @@ public:
if (c == 0) {
return 0;
}
if (value.compare_exchange_weak(c, c + 1, std::memory_order_release)) {
if (value.compare_exchange_weak(c, c + 1, std::memory_order_acq_rel)) {
return c + 1;
}
}
}
_ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) {
_ALWAYS_INLINE_ explicit SafeNumeric(T p_value = static_cast<T>(0)) {
set(p_value);
}
};
@@ -158,6 +178,16 @@ public:
class SafeRefCount {
SafeNumeric<uint32_t> count;
#ifdef DEV_ENABLED
_ALWAYS_INLINE_ void _check_unref_safety() {
// This won't catch every misuse, but it's better than nothing.
CRASH_COND_MSG(count.get() == 0,
"Trying to unreference a SafeRefCount which is already zero is wrong and a symptom of it being misused.\n"
"Upon a SafeRefCount reaching zero any object whose lifetime is tied to it, as well as the ref count itself, must be destroyed.\n"
"Moreover, to guarantee that, no multiple threads should be racing to do the final unreferencing to zero.");
}
#endif
public:
_ALWAYS_INLINE_ bool ref() { // true on success
return count.conditional_increment() != 0;
@@ -168,10 +198,16 @@ public:
}
_ALWAYS_INLINE_ bool unref() { // true if must be disposed of
#ifdef DEV_ENABLED
_check_unref_safety();
#endif
return count.decrement() == 0;
}
_ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
#ifdef DEV_ENABLED
_check_unref_safety();
#endif
return count.decrement();
}
@@ -184,143 +220,6 @@ public:
}
};
#else
template <class T>
class SafeNumeric {
protected:
T value;
public:
_ALWAYS_INLINE_ void set(T p_value) {
value = p_value;
}
_ALWAYS_INLINE_ T get() const {
return value;
}
_ALWAYS_INLINE_ T increment() {
return ++value;
}
_ALWAYS_INLINE_ T postincrement() {
return value++;
}
_ALWAYS_INLINE_ T decrement() {
return --value;
}
_ALWAYS_INLINE_ T postdecrement() {
return value--;
}
_ALWAYS_INLINE_ T add(T p_value) {
return value += p_value;
}
_ALWAYS_INLINE_ T postadd(T p_value) {
T old = value;
value += p_value;
return old;
}
_ALWAYS_INLINE_ T sub(T p_value) {
return value -= p_value;
}
_ALWAYS_INLINE_ T postsub(T p_value) {
T old = value;
value -= p_value;
return old;
}
_ALWAYS_INLINE_ T exchange_if_greater(T p_value) {
if (value < p_value) {
value = p_value;
}
return value;
}
_ALWAYS_INLINE_ T conditional_increment() {
if (value == 0) {
return 0;
} else {
return ++value;
}
}
_ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) :
value(p_value) {
}
};
class SafeFlag {
protected:
bool flag;
public:
_ALWAYS_INLINE_ bool is_set() const {
return flag;
}
_ALWAYS_INLINE_ void set() {
flag = true;
}
_ALWAYS_INLINE_ void clear() {
flag = false;
}
_ALWAYS_INLINE_ void set_to(bool p_value) {
flag = p_value;
}
_ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) :
flag(p_value) {}
};
class SafeRefCount {
uint32_t count = 0;
public:
_ALWAYS_INLINE_ bool ref() { // true on success
if (count != 0) {
++count;
return true;
} else {
return false;
}
}
_ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
if (count != 0) {
return ++count;
} else {
return 0;
}
}
_ALWAYS_INLINE_ bool unref() { // true if must be disposed of
return --count == 0;
}
_ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
return --count;
}
_ALWAYS_INLINE_ uint32_t get() const {
return count;
}
_ALWAYS_INLINE_ void init(uint32_t p_value = 1) {
count = p_value;
}
};
#endif
} // namespace godot
#endif // GODOT_SAFE_REFCOUNT_HPP
#endif // !defined(NO_THREADS)

View File

@@ -28,24 +28,23 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_SEARCH_ARRAY_HPP
#define GODOT_SEARCH_ARRAY_HPP
#pragma once
#include <godot_cpp/templates/sort_array.hpp>
namespace godot {
template <class T, class Comparator = _DefaultComparator<T>>
template <typename T, typename Comparator = _DefaultComparator<T>>
class SearchArray {
public:
Comparator compare;
inline int bisect(const T *p_array, int p_len, const T &p_value, bool p_before) const {
int lo = 0;
int hi = p_len;
inline int64_t bisect(const T *p_array, int64_t p_len, const T &p_value, bool p_before) const {
int64_t lo = 0;
int64_t hi = p_len;
if (p_before) {
while (lo < hi) {
const int mid = (lo + hi) / 2;
const int64_t mid = (lo + hi) / 2;
if (compare(p_array[mid], p_value)) {
lo = mid + 1;
} else {
@@ -54,7 +53,7 @@ public:
}
} else {
while (lo < hi) {
const int mid = (lo + hi) / 2;
const int64_t mid = (lo + hi) / 2;
if (compare(p_value, p_array[mid])) {
hi = mid;
} else {
@@ -67,5 +66,3 @@ public:
};
} // namespace godot
#endif // GODOT_SEARCH_ARRAY_HPP

View File

@@ -28,15 +28,14 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_SELF_LIST_HPP
#define GODOT_SELF_LIST_HPP
#pragma once
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/core/error_macros.hpp>
namespace godot {
template <class T>
template <typename T>
class SelfList {
public:
class List {
@@ -101,11 +100,74 @@ public:
p_elem->_root = nullptr;
}
void clear() {
while (_first) {
remove(_first);
}
}
void sort() {
sort_custom<Comparator<T>>();
}
template <typename C>
void sort_custom() {
if (_first == _last) {
return;
}
SelfList<T> *from = _first;
SelfList<T> *current = from;
SelfList<T> *to = from;
while (current) {
SelfList<T> *next = current->_next;
if (from != current) {
current->_prev = nullptr;
current->_next = from;
SelfList<T> *find = from;
C less;
while (find && less(*find->_self, *current->_self)) {
current->_prev = find;
current->_next = find->_next;
find = find->_next;
}
if (current->_prev) {
current->_prev->_next = current;
} else {
from = current;
}
if (current->_next) {
current->_next->_prev = current;
} else {
to = current;
}
} else {
current->_prev = nullptr;
current->_next = nullptr;
}
current = next;
}
_first = from;
_last = to;
}
_FORCE_INLINE_ SelfList<T> *first() { return _first; }
_FORCE_INLINE_ const SelfList<T> *first() const { return _first; }
// Forbid copying, which has broken behavior.
void operator=(const List &) = delete;
_FORCE_INLINE_ List() {}
_FORCE_INLINE_ ~List() { ERR_FAIL_COND(_first != nullptr); }
_FORCE_INLINE_ ~List() {
// A self list must be empty on destruction.
DEV_ASSERT(_first == nullptr);
}
};
private:
@@ -127,6 +189,9 @@ public:
_FORCE_INLINE_ const SelfList<T> *prev() const { return _prev; }
_FORCE_INLINE_ T *self() const { return _self; }
// Forbid copying, which has broken behavior.
void operator=(const SelfList<T> &) = delete;
_FORCE_INLINE_ SelfList(T *p_self) {
_self = p_self;
}
@@ -139,5 +204,3 @@ public:
};
} // namespace godot
#endif // GODOT_SELF_LIST_HPP

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_SORT_ARRAY_HPP
#define GODOT_SORT_ARRAY_HPP
#pragma once
#include <godot_cpp/core/error_macros.hpp>
@@ -41,7 +40,7 @@ namespace godot {
break; \
}
template <class T>
template <typename T>
struct _DefaultComparator {
_FORCE_INLINE_ bool operator()(const T &a, const T &b) const { return (a < b); }
};
@@ -52,7 +51,7 @@ struct _DefaultComparator {
#define SORT_ARRAY_VALIDATE_ENABLED false
#endif
template <class T, class Comparator = _DefaultComparator<T>, bool Validate = SORT_ARRAY_VALIDATE_ENABLED>
template <typename T, typename Comparator = _DefaultComparator<T>, bool Validate = SORT_ARRAY_VALIDATE_ENABLED>
class SortArray {
enum {
INTROSORT_THRESHOLD = 16
@@ -79,8 +78,8 @@ public:
}
}
inline int bitlog(int n) const {
int k;
inline int64_t bitlog(int64_t n) const {
int64_t k;
for (k = 0; n != 1; n >>= 1) {
++k;
}
@@ -89,8 +88,8 @@ public:
/* Heap / Heapsort functions */
inline void push_heap(int p_first, int p_hole_idx, int p_top_index, T p_value, T *p_array) const {
int parent = (p_hole_idx - 1) / 2;
inline void push_heap(int64_t p_first, int64_t p_hole_idx, int64_t p_top_index, T p_value, T *p_array) const {
int64_t parent = (p_hole_idx - 1) / 2;
while (p_hole_idx > p_top_index && compare(p_array[p_first + parent], p_value)) {
p_array[p_first + p_hole_idx] = p_array[p_first + parent];
p_hole_idx = parent;
@@ -99,17 +98,17 @@ public:
p_array[p_first + p_hole_idx] = p_value;
}
inline void pop_heap(int p_first, int p_last, int p_result, T p_value, T *p_array) const {
inline void pop_heap(int64_t p_first, int64_t p_last, int64_t p_result, T p_value, T *p_array) const {
p_array[p_result] = p_array[p_first];
adjust_heap(p_first, 0, p_last - p_first, p_value, p_array);
}
inline void pop_heap(int p_first, int p_last, T *p_array) const {
inline void pop_heap(int64_t p_first, int64_t p_last, T *p_array) const {
pop_heap(p_first, p_last - 1, p_last - 1, p_array[p_last - 1], p_array);
}
inline void adjust_heap(int p_first, int p_hole_idx, int p_len, T p_value, T *p_array) const {
int top_index = p_hole_idx;
int second_child = 2 * p_hole_idx + 2;
inline void adjust_heap(int64_t p_first, int64_t p_hole_idx, int64_t p_len, T p_value, T *p_array) const {
int64_t top_index = p_hole_idx;
int64_t second_child = 2 * p_hole_idx + 2;
while (second_child < p_len) {
if (compare(p_array[p_first + second_child], p_array[p_first + (second_child - 1)])) {
@@ -128,18 +127,18 @@ public:
push_heap(p_first, p_hole_idx, top_index, p_value, p_array);
}
inline void sort_heap(int p_first, int p_last, T *p_array) const {
inline void sort_heap(int64_t p_first, int64_t p_last, T *p_array) const {
while (p_last - p_first > 1) {
pop_heap(p_first, p_last--, p_array);
}
}
inline void make_heap(int p_first, int p_last, T *p_array) const {
inline void make_heap(int64_t p_first, int64_t p_last, T *p_array) const {
if (p_last - p_first < 2) {
return;
}
int len = p_last - p_first;
int parent = (len - 2) / 2;
int64_t len = p_last - p_first;
int64_t parent = (len - 2) / 2;
while (true) {
adjust_heap(p_first, parent, len, p_array[p_first + parent], p_array);
@@ -150,9 +149,9 @@ public:
}
}
inline void partial_sort(int p_first, int p_last, int p_middle, T *p_array) const {
inline void partial_sort(int64_t p_first, int64_t p_last, int64_t p_middle, T *p_array) const {
make_heap(p_first, p_middle, p_array);
for (int i = p_middle; i < p_last; i++) {
for (int64_t i = p_middle; i < p_last; i++) {
if (compare(p_array[i], p_array[p_first])) {
pop_heap(p_first, p_middle, i, p_array[i], p_array);
}
@@ -160,29 +159,29 @@ public:
sort_heap(p_first, p_middle, p_array);
}
inline void partial_select(int p_first, int p_last, int p_middle, T *p_array) const {
inline void partial_select(int64_t p_first, int64_t p_last, int64_t p_middle, T *p_array) const {
make_heap(p_first, p_middle, p_array);
for (int i = p_middle; i < p_last; i++) {
for (int64_t i = p_middle; i < p_last; i++) {
if (compare(p_array[i], p_array[p_first])) {
pop_heap(p_first, p_middle, i, p_array[i], p_array);
}
}
}
inline int partitioner(int p_first, int p_last, T p_pivot, T *p_array) const {
const int unmodified_first = p_first;
const int unmodified_last = p_last;
inline int64_t partitioner(int64_t p_first, int64_t p_last, T p_pivot, T *p_array) const {
const int64_t unmodified_first = p_first;
const int64_t unmodified_last = p_last;
while (true) {
while (compare(p_array[p_first], p_pivot)) {
if (Validate) {
if constexpr (Validate) {
ERR_BAD_COMPARE(p_first == unmodified_last - 1);
}
p_first++;
}
p_last--;
while (compare(p_pivot, p_array[p_last])) {
if (Validate) {
if constexpr (Validate) {
ERR_BAD_COMPARE(p_last == unmodified_first);
}
p_last--;
@@ -197,7 +196,7 @@ public:
}
}
inline void introsort(int p_first, int p_last, T *p_array, int p_max_depth) const {
inline void introsort(int64_t p_first, int64_t p_last, T *p_array, int64_t p_max_depth) const {
while (p_last - p_first > INTROSORT_THRESHOLD) {
if (p_max_depth == 0) {
partial_sort(p_first, p_last, p_last, p_array);
@@ -206,7 +205,7 @@ public:
p_max_depth--;
int cut = partitioner(
int64_t cut = partitioner(
p_first,
p_last,
median_of_3(
@@ -220,7 +219,7 @@ public:
}
}
inline void introselect(int p_first, int p_nth, int p_last, T *p_array, int p_max_depth) const {
inline void introselect(int64_t p_first, int64_t p_nth, int64_t p_last, T *p_array, int64_t p_max_depth) const {
while (p_last - p_first > 3) {
if (p_max_depth == 0) {
partial_select(p_first, p_nth + 1, p_last, p_array);
@@ -230,7 +229,7 @@ public:
p_max_depth--;
int cut = partitioner(
int64_t cut = partitioner(
p_first,
p_last,
median_of_3(
@@ -249,10 +248,10 @@ public:
insertion_sort(p_first, p_last, p_array);
}
inline void unguarded_linear_insert(int p_last, T p_value, T *p_array) const {
int next = p_last - 1;
inline void unguarded_linear_insert(int64_t p_last, T p_value, T *p_array) const {
int64_t next = p_last - 1;
while (compare(p_value, p_array[next])) {
if (Validate) {
if constexpr (Validate) {
ERR_BAD_COMPARE(next == 0);
}
p_array[p_last] = p_array[next];
@@ -262,10 +261,10 @@ public:
p_array[p_last] = p_value;
}
inline void linear_insert(int p_first, int p_last, T *p_array) const {
inline void linear_insert(int64_t p_first, int64_t p_last, T *p_array) const {
T val = p_array[p_last];
if (compare(val, p_array[p_first])) {
for (int i = p_last; i > p_first; i--) {
for (int64_t i = p_last; i > p_first; i--) {
p_array[i] = p_array[i - 1];
}
@@ -275,22 +274,22 @@ public:
}
}
inline void insertion_sort(int p_first, int p_last, T *p_array) const {
inline void insertion_sort(int64_t p_first, int64_t p_last, T *p_array) const {
if (p_first == p_last) {
return;
}
for (int i = p_first + 1; i != p_last; i++) {
for (int64_t i = p_first + 1; i != p_last; i++) {
linear_insert(p_first, i, p_array);
}
}
inline void unguarded_insertion_sort(int p_first, int p_last, T *p_array) const {
for (int i = p_first; i != p_last; i++) {
inline void unguarded_insertion_sort(int64_t p_first, int64_t p_last, T *p_array) const {
for (int64_t i = p_first; i != p_last; i++) {
unguarded_linear_insert(i, p_array[i], p_array);
}
}
inline void final_insertion_sort(int p_first, int p_last, T *p_array) const {
inline void final_insertion_sort(int64_t p_first, int64_t p_last, T *p_array) const {
if (p_last - p_first > INTROSORT_THRESHOLD) {
insertion_sort(p_first, p_first + INTROSORT_THRESHOLD, p_array);
unguarded_insertion_sort(p_first + INTROSORT_THRESHOLD, p_last, p_array);
@@ -299,18 +298,18 @@ public:
}
}
inline void sort_range(int p_first, int p_last, T *p_array) const {
inline void sort_range(int64_t p_first, int64_t p_last, T *p_array) const {
if (p_first != p_last) {
introsort(p_first, p_last, p_array, bitlog(p_last - p_first) * 2);
final_insertion_sort(p_first, p_last, p_array);
}
}
inline void sort(T *p_array, int p_len) const {
inline void sort(T *p_array, int64_t p_len) const {
sort_range(0, p_len, p_array);
}
inline void nth_element(int p_first, int p_last, int p_nth, T *p_array) const {
inline void nth_element(int64_t p_first, int64_t p_last, int64_t p_nth, T *p_array) const {
if (p_first == p_last || p_nth == p_last) {
return;
}
@@ -319,5 +318,3 @@ public:
};
} // namespace godot
#endif // GODOT_SORT_ARRAY_HPP

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_SPIN_LOCK_HPP
#define GODOT_SPIN_LOCK_HPP
#pragma once
#include <atomic>
@@ -50,5 +49,3 @@ public:
};
} // namespace godot
#endif // GODOT_SPIN_LOCK_HPP

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_THREAD_WORK_POOL_HPP
#define GODOT_THREAD_WORK_POOL_HPP
#pragma once
#include <godot_cpp/classes/os.hpp>
#include <godot_cpp/classes/semaphore.hpp>
@@ -52,7 +51,7 @@ class ThreadWorkPool {
virtual ~BaseWork() = default;
};
template <class C, class M, class U>
template <typename C, typename M, typename U>
struct Work : public BaseWork {
C *instance;
M method;
@@ -94,9 +93,9 @@ class ThreadWorkPool {
}
public:
template <class C, class M, class U>
template <typename C, typename M, typename U>
void begin_work(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) {
ERR_FAIL_COND(!threads); // never initialized
ERR_FAIL_NULL(threads); // Never initialized.
ERR_FAIL_COND(current_work != nullptr);
index.store(0, std::memory_order_release);
@@ -123,18 +122,18 @@ public:
}
bool is_done_dispatching() const {
ERR_FAIL_COND_V(current_work == nullptr, true);
ERR_FAIL_NULL_V(current_work, true);
return index.load(std::memory_order_acquire) >= current_work->max_elements;
}
uint32_t get_work_index() const {
ERR_FAIL_COND_V(current_work == nullptr, 0);
ERR_FAIL_NULL_V(current_work, 0);
uint32_t idx = index.load(std::memory_order_acquire);
return Math::min(idx, current_work->max_elements);
}
void end_work() {
ERR_FAIL_COND(current_work == nullptr);
ERR_FAIL_NULL(current_work);
for (uint32_t i = 0; i < threads_working; i++) {
threads[i].completed.wait();
threads[i].work = nullptr;
@@ -145,7 +144,7 @@ public:
current_work = nullptr;
}
template <class C, class M, class U>
template <typename C, typename M, typename U>
void do_work(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) {
switch (p_elements) {
case 0:
@@ -201,5 +200,3 @@ public:
};
} // namespace godot
#endif // GODOT_THREAD_WORK_POOL_HPP

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_VECTOR_HPP
#define GODOT_VECTOR_HPP
#pragma once
/**
* @class Vector
@@ -47,38 +46,43 @@
namespace godot {
template <class T>
template <typename T>
class VectorWriteProxy {
public:
_FORCE_INLINE_ T &operator[](int p_index) {
_FORCE_INLINE_ T &operator[](typename CowData<T>::Size p_index) {
CRASH_BAD_INDEX(p_index, ((Vector<T> *)(this))->_cowdata.size());
return ((Vector<T> *)(this))->_cowdata.ptrw()[p_index];
}
};
template <class T>
template <typename T>
class Vector {
friend class VectorWriteProxy<T>;
public:
VectorWriteProxy<T> write;
typedef typename CowData<T>::Size Size;
private:
CowData<T> _cowdata;
public:
// Must take a copy instead of a reference (see GH-31736).
bool push_back(T p_elem);
_FORCE_INLINE_ bool append(const T &p_elem) { return push_back(p_elem); } // alias
_FORCE_INLINE_ bool append(const T &p_elem) { return push_back(p_elem); } //alias
void fill(T p_elem);
void remove_at(int p_index) { _cowdata.remove_at(p_index); }
void erase(const T &p_val) {
int idx = find(p_val);
void remove_at(Size p_index) { _cowdata.remove_at(p_index); }
_FORCE_INLINE_ bool erase(const T &p_val) {
Size idx = find(p_val);
if (idx >= 0) {
remove_at(idx);
return true;
}
return false;
}
void reverse();
_FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); }
@@ -86,37 +90,47 @@ public:
_FORCE_INLINE_ void clear() { resize(0); }
_FORCE_INLINE_ bool is_empty() const { return _cowdata.is_empty(); }
_FORCE_INLINE_ T get(int p_index) { return _cowdata.get(p_index); }
_FORCE_INLINE_ const T &get(int p_index) const { return _cowdata.get(p_index); }
_FORCE_INLINE_ void set(int p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); }
_FORCE_INLINE_ int size() const { return _cowdata.size(); }
Error resize(int p_size) { return _cowdata.resize(p_size); }
_FORCE_INLINE_ const T &operator[](int p_index) const { return _cowdata.get(p_index); }
Error insert(int p_pos, T p_val) { return _cowdata.insert(p_pos, p_val); }
int find(const T &p_val, int p_from = 0) const { return _cowdata.find(p_val, p_from); }
_FORCE_INLINE_ T get(Size p_index) { return _cowdata.get(p_index); }
_FORCE_INLINE_ const T &get(Size p_index) const { return _cowdata.get(p_index); }
_FORCE_INLINE_ void set(Size p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); }
_FORCE_INLINE_ Size size() const { return _cowdata.size(); }
Error resize(Size p_size) { return _cowdata.resize(p_size); }
Error resize_zeroed(Size p_size) { return _cowdata.template resize<true>(p_size); }
_FORCE_INLINE_ const T &operator[](Size p_index) const { return _cowdata.get(p_index); }
// Must take a copy instead of a reference (see GH-31736).
Error insert(Size p_pos, T p_val) { return _cowdata.insert(p_pos, p_val); }
Size find(const T &p_val, Size p_from = 0) const { return _cowdata.find(p_val, p_from); }
Size rfind(const T &p_val, Size p_from = -1) const { return _cowdata.rfind(p_val, p_from); }
Size count(const T &p_val) const { return _cowdata.count(p_val); }
// Must take a copy instead of a reference (see GH-31736).
void append_array(Vector<T> p_other);
_FORCE_INLINE_ bool has(const T &p_val) const { return find(p_val) != -1; }
template <class C>
void sort_custom() {
int len = _cowdata.size();
if (len == 0) {
return;
}
T *data = ptrw();
SortArray<T, C> sorter;
sorter.sort(data, len);
}
void sort() {
sort_custom<_DefaultComparator<T>>();
}
int bsearch(const T &p_value, bool p_before) {
SearchArray<T> search;
template <typename Comparator, bool Validate = SORT_ARRAY_VALIDATE_ENABLED, typename... Args>
void sort_custom(Args &&...args) {
Size len = _cowdata.size();
if (len == 0) {
return;
}
T *data = ptrw();
SortArray<T, Comparator, Validate> sorter{ args... };
sorter.sort(data, len);
}
Size bsearch(const T &p_value, bool p_before) {
return bsearch_custom<_DefaultComparator<T>>(p_value, p_before);
}
template <typename Comparator, typename Value, typename... Args>
Size bsearch_custom(const Value &p_value, bool p_before, Args &&...args) {
SearchArray<T, Comparator> search{ args... };
return search.bisect(ptrw(), size(), p_value, p_before);
}
@@ -125,7 +139,7 @@ public:
}
void ordered_insert(const T &p_val) {
int i;
Size i;
for (i = 0; i < _cowdata.size(); i++) {
if (p_val < operator[](i)) {
break;
@@ -134,39 +148,44 @@ public:
insert(i, p_val);
}
inline void operator=(const Vector &p_from) {
_cowdata._ref(p_from._cowdata);
}
void operator=(const Vector &p_from) { _cowdata._ref(p_from._cowdata); }
void operator=(Vector &&p_from) { _cowdata = std::move(p_from._cowdata); }
Vector<uint8_t> to_byte_array() const {
Vector<uint8_t> ret;
ret.resize(size() * sizeof(T));
memcpy(ret.ptrw(), ptr(), sizeof(T) * size());
if (is_empty()) {
return ret;
}
size_t alloc_size = size() * sizeof(T);
ret.resize(alloc_size);
if (alloc_size) {
memcpy(ret.ptrw(), ptr(), alloc_size);
}
return ret;
}
Vector<T> slice(int p_begin, int p_end = INT_MAX) const {
Vector<T> slice(Size p_begin, Size p_end = CowData<T>::MAX_INT) const {
Vector<T> result;
const int s = size();
const Size s = size();
int begin = Math::clamp(p_begin, -s, s);
Size begin = CLAMP(p_begin, -s, s);
if (begin < 0) {
begin += s;
}
int end = Math::clamp(p_end, -s, s);
Size end = CLAMP(p_end, -s, s);
if (end < 0) {
end += s;
}
ERR_FAIL_COND_V(begin > end, result);
int result_size = end - begin;
Size result_size = end - begin;
result.resize(result_size);
const T *const r = ptr();
T *const w = result.ptrw();
for (int i = 0; i < result_size; ++i) {
for (Size i = 0; i < result_size; ++i) {
w[i] = r[begin + i];
}
@@ -174,11 +193,11 @@ public:
}
bool operator==(const Vector<T> &p_arr) const {
int s = size();
Size s = size();
if (s != p_arr.size()) {
return false;
}
for (int i = 0; i < s; i++) {
for (Size i = 0; i < s; i++) {
if (operator[](i) != p_arr[i]) {
return false;
}
@@ -187,11 +206,11 @@ public:
}
bool operator!=(const Vector<T> &p_arr) const {
int s = size();
Size s = size();
if (s != p_arr.size()) {
return true;
}
for (int i = 0; i < s; i++) {
for (Size i = 0; i < s; i++) {
if (operator[](i) != p_arr[i]) {
return true;
}
@@ -264,42 +283,37 @@ public:
}
_FORCE_INLINE_ Vector() {}
_FORCE_INLINE_ Vector(std::initializer_list<T> p_init) {
Error err = _cowdata.resize(p_init.size());
ERR_FAIL_COND(err);
int i = 0;
for (const T &element : p_init) {
_cowdata.set(i++, element);
}
}
_FORCE_INLINE_ Vector(std::initializer_list<T> p_init) :
_cowdata(p_init) {}
_FORCE_INLINE_ Vector(const Vector &p_from) { _cowdata._ref(p_from._cowdata); }
_FORCE_INLINE_ Vector(Vector &&p_from) :
_cowdata(std::move(p_from._cowdata)) {}
_FORCE_INLINE_ ~Vector() {}
};
template <class T>
template <typename T>
void Vector<T>::reverse() {
for (int i = 0; i < size() / 2; i++) {
for (Size i = 0; i < size() / 2; i++) {
T *p = ptrw();
SWAP(p[i], p[size() - i - 1]);
}
}
template <class T>
template <typename T>
void Vector<T>::append_array(Vector<T> p_other) {
const int ds = p_other.size();
const Size ds = p_other.size();
if (ds == 0) {
return;
}
const int bs = size();
const Size bs = size();
resize(bs + ds);
for (int i = 0; i < ds; ++i) {
for (Size i = 0; i < ds; ++i) {
ptrw()[bs + i] = p_other[i];
}
}
template <class T>
template <typename T>
bool Vector<T>::push_back(T p_elem) {
Error err = resize(size() + 1);
ERR_FAIL_COND_V(err, true);
@@ -308,14 +322,12 @@ bool Vector<T>::push_back(T p_elem) {
return false;
}
template <class T>
template <typename T>
void Vector<T>::fill(T p_elem) {
T *p = ptrw();
for (int i = 0; i < size(); i++) {
for (Size i = 0; i < size(); i++) {
p[i] = p_elem;
}
}
} // namespace godot
#endif // GODOT_VECTOR_HPP

View File

@@ -28,14 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_VMAP_HPP
#define GODOT_VMAP_HPP
#pragma once
#include <godot_cpp/templates/cowdata.hpp>
namespace godot {
template <class T, class V>
template <typename T, typename V>
class VMap {
public:
struct Pair {
@@ -73,16 +72,16 @@ private:
middle = (low + high) / 2;
if (p_val < a[middle].key) {
high = middle - 1; // search low end of array
high = middle - 1; //search low end of array
} else if (a[middle].key < p_val) {
low = middle + 1; // search high end of array
low = middle + 1; //search high end of array
} else {
r_exact = true;
return middle;
}
}
// return the position where this would be inserted
//return the position where this would be inserted
if (a[middle].key < p_val) {
middle++;
}
@@ -103,9 +102,9 @@ private:
middle = (low + high) / 2;
if (p_val < a[middle].key) {
high = middle - 1; // search low end of array
high = middle - 1; //search low end of array
} else if (a[middle].key < p_val) {
low = middle + 1; // search high end of array
low = middle + 1; //search high end of array
} else {
return middle;
}
@@ -143,6 +142,9 @@ public:
}
int find_nearest(const T &p_val) const {
if (_cowdata.is_empty()) {
return -1;
}
bool exact;
return _find(p_val, exact);
}
@@ -192,6 +194,8 @@ public:
}
_FORCE_INLINE_ VMap() {}
_FORCE_INLINE_ VMap(std::initializer_list<T> p_init) :
_cowdata(p_init) {}
_FORCE_INLINE_ VMap(const VMap &p_from) { _cowdata._ref(p_from._cowdata); }
inline void operator=(const VMap &p_from) {
@@ -200,5 +204,3 @@ public:
};
} // namespace godot
#endif // GODOT_VMAP_HPP

View File

@@ -28,14 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_VSET_HPP
#define GODOT_VSET_HPP
#pragma once
#include <godot_cpp/templates/vector.hpp>
namespace godot {
template <class T>
template <typename T>
class VSet {
Vector<T> _data;
@@ -60,16 +59,16 @@ class VSet {
middle = (low + high) / 2;
if (p_val < a[middle]) {
high = middle - 1; // search low end of array
high = middle - 1; //search low end of array
} else if (a[middle] < p_val) {
low = middle + 1; // search high end of array
low = middle + 1; //search high end of array
} else {
r_exact = true;
return middle;
}
}
// return the position where this would be inserted
//return the position where this would be inserted
if (a[middle] < p_val) {
middle++;
}
@@ -90,9 +89,9 @@ class VSet {
middle = (low + high) / 2;
if (p_val < a[middle]) {
high = middle - 1; // search low end of array
high = middle - 1; //search low end of array
} else if (a[middle] < p_val) {
low = middle + 1; // search high end of array
low = middle + 1; //search high end of array
} else {
return middle;
}
@@ -138,8 +137,10 @@ public:
inline const T &operator[](int p_index) const {
return _data[p_index];
}
_FORCE_INLINE_ VSet() {}
_FORCE_INLINE_ VSet(std::initializer_list<T> p_init) :
_data(p_init) {}
};
} // namespace godot
#endif // GODOT_VSET_HPP

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_AABB_HPP
#define GODOT_AABB_HPP
#pragma once
#include <godot_cpp/variant/plane.hpp>
#include <godot_cpp/variant/vector3.hpp>
@@ -43,7 +42,7 @@ namespace godot {
class Variant;
struct _NO_DISCARD_ AABB {
struct [[nodiscard]] AABB {
Vector3 position;
Vector3 size;
@@ -65,6 +64,7 @@ struct _NO_DISCARD_ AABB {
bool operator!=(const AABB &p_rval) const;
bool is_equal_approx(const AABB &p_aabb) const;
bool is_finite() const;
_FORCE_INLINE_ bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap
_FORCE_INLINE_ bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap
_FORCE_INLINE_ bool encloses(const AABB &p_aabb) const; /// p_aabb is completely inside this
@@ -72,16 +72,21 @@ struct _NO_DISCARD_ AABB {
AABB merge(const AABB &p_with) const;
void merge_with(const AABB &p_aabb); ///merge with another AABB
AABB intersection(const AABB &p_aabb) const; ///get box where two intersect, empty if no intersection occurs
bool intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector3 *r_clip = nullptr, Vector3 *r_normal = nullptr) const;
bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *r_clip = nullptr, Vector3 *r_normal = nullptr) const;
_FORCE_INLINE_ bool smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t t0, real_t t1) const;
_FORCE_INLINE_ bool smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t p_t0, real_t p_t1) const;
bool intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector3 *r_intersection_point = nullptr, Vector3 *r_normal = nullptr) const;
bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir) const {
bool inside;
return find_intersects_ray(p_from, p_dir, inside);
}
bool find_intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, bool &r_inside, Vector3 *r_intersection_point = nullptr, Vector3 *r_normal = nullptr) const;
_FORCE_INLINE_ bool intersects_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const;
_FORCE_INLINE_ bool inside_convex_shape(const Plane *p_planes, int p_plane_count) const;
bool intersects_plane(const Plane &p_plane) const;
_FORCE_INLINE_ bool has_point(const Vector3 &p_point) const;
_FORCE_INLINE_ Vector3 get_support(const Vector3 &p_normal) const;
_FORCE_INLINE_ Vector3 get_support(const Vector3 &p_direction) const;
Vector3 get_longest_axis() const;
int get_longest_axis_index() const;
@@ -102,7 +107,7 @@ struct _NO_DISCARD_ AABB {
_FORCE_INLINE_ void expand_to(const Vector3 &p_vector); /** expand to contain a point if necessary */
_FORCE_INLINE_ AABB abs() const {
return AABB(Vector3(position.x + MIN(size.x, (real_t)0), position.y + MIN(size.y, (real_t)0), position.z + MIN(size.z, (real_t)0)), size.abs());
return AABB(position + size.minf(0), size.abs());
}
Variant intersects_segment_bind(const Vector3 &p_from, const Vector3 &p_to) const;
@@ -201,22 +206,25 @@ inline bool AABB::encloses(const AABB &p_aabb) const {
return (
(src_min.x <= dst_min.x) &&
(src_max.x > dst_max.x) &&
(src_max.x >= dst_max.x) &&
(src_min.y <= dst_min.y) &&
(src_max.y > dst_max.y) &&
(src_max.y >= dst_max.y) &&
(src_min.z <= dst_min.z) &&
(src_max.z > dst_max.z));
(src_max.z >= dst_max.z));
}
Vector3 AABB::get_support(const Vector3 &p_normal) const {
Vector3 half_extents = size * 0.5f;
Vector3 ofs = position + half_extents;
return Vector3(
(p_normal.x > 0) ? half_extents.x : -half_extents.x,
(p_normal.y > 0) ? half_extents.y : -half_extents.y,
(p_normal.z > 0) ? half_extents.z : -half_extents.z) +
ofs;
Vector3 AABB::get_support(const Vector3 &p_direction) const {
Vector3 support = position;
if (p_direction.x > 0.0f) {
support.x += size.x;
}
if (p_direction.y > 0.0f) {
support.y += size.y;
}
if (p_direction.z > 0.0f) {
support.z += size.z;
}
return support;
}
Vector3 AABB::get_endpoint(int p_point) const {
@@ -402,7 +410,7 @@ inline real_t AABB::get_shortest_axis_size() const {
return max_size;
}
bool AABB::smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t t0, real_t t1) const {
bool AABB::smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t p_t0, real_t p_t1) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) {
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
@@ -453,7 +461,7 @@ bool AABB::smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real
if (tzmax < tmax) {
tmax = tzmax;
}
return ((tmin < t1) && (tmax > t0));
return ((tmin < p_t1) && (tmax > p_t0));
}
void AABB::grow_by(real_t p_amount) {
@@ -490,5 +498,3 @@ AABB AABB::quantized(real_t p_unit) const {
}
} // namespace godot
#endif // GODOT_AABB_HPP

View File

@@ -28,6 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
namespace godot {
namespace helpers {
template <typename T, typename ValueT>

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_BASIS_HPP
#define GODOT_BASIS_HPP
#pragma once
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/variant/quaternion.hpp>
@@ -37,18 +36,18 @@
namespace godot {
struct _NO_DISCARD_ Basis {
struct [[nodiscard]] Basis {
Vector3 rows[3] = {
Vector3(1, 0, 0),
Vector3(0, 1, 0),
Vector3(0, 0, 1)
};
_FORCE_INLINE_ const Vector3 &operator[](int axis) const {
return rows[axis];
_FORCE_INLINE_ const Vector3 &operator[](int p_row) const {
return rows[p_row];
}
_FORCE_INLINE_ Vector3 &operator[](int axis) {
return rows[axis];
_FORCE_INLINE_ Vector3 &operator[](int p_row) {
return rows[p_row];
}
void invert();
@@ -59,21 +58,19 @@ struct _NO_DISCARD_ Basis {
_FORCE_INLINE_ real_t determinant() const;
void from_z(const Vector3 &p_z);
void rotate(const Vector3 &p_axis, real_t p_angle);
Basis rotated(const Vector3 &p_axis, real_t p_angle) const;
void rotate_local(const Vector3 &p_axis, real_t p_angle);
Basis rotated_local(const Vector3 &p_axis, real_t p_angle) const;
void rotate(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ);
Basis rotated(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ) const;
void rotate(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ);
Basis rotated(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ) const;
void rotate(const Quaternion &p_quaternion);
Basis rotated(const Quaternion &p_quaternion) const;
Vector3 get_euler_normalized(EulerOrder p_order = EULER_ORDER_YXZ) const;
Vector3 get_euler_normalized(EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ) const;
void get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const;
void get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const;
Quaternion get_rotation_quaternion() const;
@@ -82,9 +79,9 @@ struct _NO_DISCARD_ Basis {
Vector3 rotref_posscale_decomposition(Basis &rotref) const;
Vector3 get_euler(EulerOrder p_order = EULER_ORDER_YXZ) const;
void set_euler(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ);
static Basis from_euler(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ) {
Vector3 get_euler(EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ) const;
void set_euler(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ);
static Basis from_euler(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ) {
Basis b;
b.set_euler(p_euler, p_order);
return b;
@@ -104,30 +101,29 @@ struct _NO_DISCARD_ Basis {
void scale_orthogonal(const Vector3 &p_scale);
Basis scaled_orthogonal(const Vector3 &p_scale) const;
void make_scale_uniform();
float get_uniform_scale() const;
real_t get_uniform_scale() const;
Vector3 get_scale() const;
Vector3 get_scale_abs() const;
Vector3 get_scale_local() const;
Vector3 get_scale_global() const;
void set_axis_angle_scale(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale);
void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale, EulerOrder p_order = EULER_ORDER_YXZ);
void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale, EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ);
void set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale);
// transposed dot products
_FORCE_INLINE_ real_t tdotx(const Vector3 &v) const {
return rows[0][0] * v[0] + rows[1][0] * v[1] + rows[2][0] * v[2];
_FORCE_INLINE_ real_t tdotx(const Vector3 &p_v) const {
return rows[0][0] * p_v[0] + rows[1][0] * p_v[1] + rows[2][0] * p_v[2];
}
_FORCE_INLINE_ real_t tdoty(const Vector3 &v) const {
return rows[0][1] * v[0] + rows[1][1] * v[1] + rows[2][1] * v[2];
_FORCE_INLINE_ real_t tdoty(const Vector3 &p_v) const {
return rows[0][1] * p_v[0] + rows[1][1] * p_v[1] + rows[2][1] * p_v[2];
}
_FORCE_INLINE_ real_t tdotz(const Vector3 &v) const {
return rows[0][2] * v[0] + rows[1][2] * v[1] + rows[2][2] * v[2];
_FORCE_INLINE_ real_t tdotz(const Vector3 &p_v) const {
return rows[0][2] * p_v[0] + rows[1][2] * p_v[1] + rows[2][2] * p_v[2];
}
bool is_equal_approx(const Basis &p_basis) const;
bool is_finite() const;
bool operator==(const Basis &p_matrix) const;
bool operator!=(const Basis &p_matrix) const;
@@ -140,31 +136,35 @@ struct _NO_DISCARD_ Basis {
_FORCE_INLINE_ Basis operator+(const Basis &p_matrix) const;
_FORCE_INLINE_ void operator-=(const Basis &p_matrix);
_FORCE_INLINE_ Basis operator-(const Basis &p_matrix) const;
_FORCE_INLINE_ void operator*=(const real_t p_val);
_FORCE_INLINE_ Basis operator*(const real_t p_val) const;
_FORCE_INLINE_ void operator*=(real_t p_val);
_FORCE_INLINE_ Basis operator*(real_t p_val) const;
_FORCE_INLINE_ void operator/=(real_t p_val);
_FORCE_INLINE_ Basis operator/(real_t p_val) const;
bool is_orthogonal() const;
bool is_orthonormal() const;
bool is_conformal() const;
bool is_diagonal() const;
bool is_rotation() const;
Basis lerp(const Basis &p_to, const real_t &p_weight) const;
Basis slerp(const Basis &p_to, const real_t &p_weight) const;
Basis lerp(const Basis &p_to, real_t p_weight) const;
Basis slerp(const Basis &p_to, real_t p_weight) const;
void rotate_sh(real_t *p_values);
operator String() const;
/* create / set */
_FORCE_INLINE_ void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz) {
rows[0][0] = xx;
rows[0][1] = xy;
rows[0][2] = xz;
rows[1][0] = yx;
rows[1][1] = yy;
rows[1][2] = yz;
rows[2][0] = zx;
rows[2][1] = zy;
rows[2][2] = zz;
_FORCE_INLINE_ void set(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz) {
rows[0][0] = p_xx;
rows[0][1] = p_xy;
rows[0][2] = p_xz;
rows[1][0] = p_yx;
rows[1][1] = p_yy;
rows[1][2] = p_yz;
rows[2][0] = p_zx;
rows[2][1] = p_zy;
rows[2][2] = p_zz;
}
_FORCE_INLINE_ void set_columns(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z) {
set_column(0, p_x);
@@ -194,20 +194,20 @@ struct _NO_DISCARD_ Basis {
rows[2].zero();
}
_FORCE_INLINE_ Basis transpose_xform(const Basis &m) const {
_FORCE_INLINE_ Basis transpose_xform(const Basis &p_m) const {
return Basis(
rows[0].x * m[0].x + rows[1].x * m[1].x + rows[2].x * m[2].x,
rows[0].x * m[0].y + rows[1].x * m[1].y + rows[2].x * m[2].y,
rows[0].x * m[0].z + rows[1].x * m[1].z + rows[2].x * m[2].z,
rows[0].y * m[0].x + rows[1].y * m[1].x + rows[2].y * m[2].x,
rows[0].y * m[0].y + rows[1].y * m[1].y + rows[2].y * m[2].y,
rows[0].y * m[0].z + rows[1].y * m[1].z + rows[2].y * m[2].z,
rows[0].z * m[0].x + rows[1].z * m[1].x + rows[2].z * m[2].x,
rows[0].z * m[0].y + rows[1].z * m[1].y + rows[2].z * m[2].y,
rows[0].z * m[0].z + rows[1].z * m[1].z + rows[2].z * m[2].z);
rows[0].x * p_m[0].x + rows[1].x * p_m[1].x + rows[2].x * p_m[2].x,
rows[0].x * p_m[0].y + rows[1].x * p_m[1].y + rows[2].x * p_m[2].y,
rows[0].x * p_m[0].z + rows[1].x * p_m[1].z + rows[2].x * p_m[2].z,
rows[0].y * p_m[0].x + rows[1].y * p_m[1].x + rows[2].y * p_m[2].x,
rows[0].y * p_m[0].y + rows[1].y * p_m[1].y + rows[2].y * p_m[2].y,
rows[0].y * p_m[0].z + rows[1].y * p_m[1].z + rows[2].y * p_m[2].z,
rows[0].z * p_m[0].x + rows[1].z * p_m[1].x + rows[2].z * p_m[2].x,
rows[0].z * p_m[0].y + rows[1].z * p_m[1].y + rows[2].z * p_m[2].y,
rows[0].z * p_m[0].z + rows[1].z * p_m[1].z + rows[2].z * p_m[2].z);
}
Basis(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz) {
set(xx, xy, xz, yx, yy, yz, zx, zy, zz);
Basis(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz) {
set(p_xx, p_xy, p_xz, p_yx, p_yy, p_yz, p_zx, p_zy, p_zz);
}
void orthonormalize();
@@ -223,7 +223,7 @@ struct _NO_DISCARD_ Basis {
operator Quaternion() const { return get_quaternion(); }
static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0));
static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false);
Basis(const Quaternion &p_quaternion) { set_quaternion(p_quaternion); }
Basis(const Quaternion &p_quaternion, const Vector3 &p_scale) { set_quaternion_scale(p_quaternion, p_scale); }
@@ -281,18 +281,30 @@ _FORCE_INLINE_ Basis Basis::operator-(const Basis &p_matrix) const {
return ret;
}
_FORCE_INLINE_ void Basis::operator*=(const real_t p_val) {
_FORCE_INLINE_ void Basis::operator*=(real_t p_val) {
rows[0] *= p_val;
rows[1] *= p_val;
rows[2] *= p_val;
}
_FORCE_INLINE_ Basis Basis::operator*(const real_t p_val) const {
_FORCE_INLINE_ Basis Basis::operator*(real_t p_val) const {
Basis ret(*this);
ret *= p_val;
return ret;
}
_FORCE_INLINE_ void Basis::operator/=(real_t p_val) {
rows[0] /= p_val;
rows[1] /= p_val;
rows[2] /= p_val;
}
_FORCE_INLINE_ Basis Basis::operator/(real_t p_val) const {
Basis ret(*this);
ret /= p_val;
return ret;
}
Vector3 Basis::xform(const Vector3 &p_vector) const {
return Vector3(
rows[0].dot(p_vector),
@@ -314,5 +326,3 @@ real_t Basis::determinant() const {
}
} // namespace godot
#endif // GODOT_BASIS_HPP

View File

@@ -0,0 +1,62 @@
/**************************************************************************/
/* callable_custom.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. */
/**************************************************************************/
#pragma once
#include <godot_cpp/core/object_id.hpp>
#include <godot_cpp/variant/string_name.hpp>
namespace godot {
class Object;
class CallableCustomBase {
public:
virtual ObjectID get_object() const = 0;
virtual int get_argument_count(bool &r_is_valid) const;
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const = 0;
virtual ~CallableCustomBase() {}
};
class CallableCustom : public CallableCustomBase {
public:
typedef bool (*CompareEqualFunc)(const CallableCustom *p_a, const CallableCustom *p_b);
typedef bool (*CompareLessFunc)(const CallableCustom *p_a, const CallableCustom *p_b);
virtual uint32_t hash() const = 0;
virtual String get_as_text() const = 0;
virtual CompareEqualFunc get_compare_equal_func() const = 0;
virtual CompareLessFunc get_compare_less_func() const = 0;
virtual bool is_valid() const;
virtual ObjectID get_object() const = 0;
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const = 0;
};
} // namespace godot

View File

@@ -0,0 +1,267 @@
/**************************************************************************/
/* callable_method_pointer.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. */
/**************************************************************************/
#pragma once
#include <godot_cpp/core/binder_common.hpp>
#include <godot_cpp/variant/variant.hpp>
namespace godot {
class CallableCustomMethodPointerBase : public CallableCustomBase {
uint32_t *comp_ptr = nullptr;
uint32_t comp_size;
uint32_t h;
protected:
void _setup(uint32_t *p_base_ptr, uint32_t p_ptr_size);
public:
_FORCE_INLINE_ const uint32_t *get_comp_ptr() const { return comp_ptr; }
_FORCE_INLINE_ uint32_t get_comp_size() const { return comp_size; }
_FORCE_INLINE_ uint32_t get_hash() const { return h; }
};
namespace internal {
Callable create_callable_from_ccmp(CallableCustomMethodPointerBase *p_callable_method_pointer);
} // namespace internal
//
// No return value.
//
template <typename T, typename... P>
class CallableCustomMethodPointer : public CallableCustomMethodPointerBase {
struct Data {
T *instance;
void (T::*method)(P...);
} data;
static_assert(sizeof(Data) % 4 == 0);
public:
virtual ObjectID get_object() const override {
return ObjectID(data.instance->get_instance_id());
}
virtual int get_argument_count(bool &r_is_valid) const override {
r_is_valid = true;
return sizeof...(P);
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
call_with_variant_args(data.instance, data.method, p_arguments, p_argcount, r_call_error);
}
CallableCustomMethodPointer(T *p_instance, void (T::*p_method)(P...)) {
memset(&data, 0, sizeof(Data));
data.instance = p_instance;
data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data));
}
};
template <typename T, typename... P>
Callable create_custom_callable_function_pointer(T *p_instance, void (T::*p_method)(P...)) {
typedef CallableCustomMethodPointer<T, P...> CCMP;
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
return ::godot::internal::create_callable_from_ccmp(ccmp);
}
//
// With return value.
//
template <typename T, typename R, typename... P>
class CallableCustomMethodPointerRet : public CallableCustomMethodPointerBase {
struct Data {
T *instance;
R (T::*method)(P...);
} data;
static_assert(sizeof(Data) % 4 == 0);
public:
virtual ObjectID get_object() const override {
return ObjectID(data.instance->get_instance_id());
}
virtual int get_argument_count(bool &r_is_valid) const override {
r_is_valid = true;
return sizeof...(P);
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
call_with_variant_args_ret(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
}
CallableCustomMethodPointerRet(T *p_instance, R (T::*p_method)(P...)) {
memset(&data, 0, sizeof(Data));
data.instance = p_instance;
data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data));
}
};
template <typename T, typename R, typename... P>
Callable create_custom_callable_function_pointer(T *p_instance, R (T::*p_method)(P...)) {
typedef CallableCustomMethodPointerRet<T, R, P...> CCMP; // Messes with memnew otherwise.
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
return ::godot::internal::create_callable_from_ccmp(ccmp);
}
//
// Const with return value.
//
template <typename T, typename R, typename... P>
class CallableCustomMethodPointerRetC : public CallableCustomMethodPointerBase {
struct Data {
T *instance;
R (T::*method)(P...) const;
} data;
static_assert(sizeof(Data) % 4 == 0);
public:
virtual ObjectID get_object() const override {
return ObjectID(data.instance->get_instance_id());
}
virtual int get_argument_count(bool &r_is_valid) const override {
r_is_valid = true;
return sizeof...(P);
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
call_with_variant_args_retc(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
}
CallableCustomMethodPointerRetC(const T *p_instance, R (T::*p_method)(P...) const) {
memset(&data, 0, sizeof(Data));
data.instance = const_cast<T *>(p_instance);
data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data));
}
};
template <typename T, typename R, typename... P>
Callable create_custom_callable_function_pointer(const T *p_instance, R (T::*p_method)(P...) const) {
typedef CallableCustomMethodPointerRetC<T, R, P...> CCMP; // Messes with memnew otherwise.
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
return ::godot::internal::create_callable_from_ccmp(ccmp);
}
//
// Static method with no return value.
//
template <typename... P>
class CallableCustomStaticMethodPointer : public CallableCustomMethodPointerBase {
struct Data {
void (*method)(P...);
} data;
static_assert(sizeof(Data) % 4 == 0);
public:
virtual ObjectID get_object() const override {
return ObjectID();
}
virtual int get_argument_count(bool &r_is_valid) const override {
r_is_valid = true;
return sizeof...(P);
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error);
r_return_value = Variant();
}
CallableCustomStaticMethodPointer(void (*p_method)(P...)) {
memset(&data, 0, sizeof(Data));
data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data));
}
};
template <typename... P>
Callable create_custom_callable_static_function_pointer(void (*p_method)(P...)) {
typedef CallableCustomStaticMethodPointer<P...> CCMP;
CCMP *ccmp = memnew(CCMP(p_method));
return ::godot::internal::create_callable_from_ccmp(ccmp);
}
//
// Static method with return value.
//
template <typename R, typename... P>
class CallableCustomStaticMethodPointerRet : public CallableCustomMethodPointerBase {
struct Data {
R (*method)(P...);
} data;
static_assert(sizeof(Data) % 4 == 0);
public:
virtual ObjectID get_object() const override {
return ObjectID();
}
virtual int get_argument_count(bool &r_is_valid) const override {
r_is_valid = true;
return sizeof...(P);
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error);
}
CallableCustomStaticMethodPointerRet(R (*p_method)(P...)) {
memset(&data, 0, sizeof(Data));
data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data));
}
};
template <typename R, typename... P>
Callable create_custom_callable_static_function_pointer(R (*p_method)(P...)) {
typedef CallableCustomStaticMethodPointerRet<R, P...> CCMP;
CCMP *ccmp = memnew(CCMP(p_method));
return ::godot::internal::create_callable_from_ccmp(ccmp);
}
//
// The API:
//
#define callable_mp(I, M) ::godot::create_custom_callable_function_pointer(I, M)
#define callable_mp_static(M) ::godot::create_custom_callable_static_function_pointer(M)
} // namespace godot

File diff suppressed because it is too large Load Diff

View File

@@ -28,86 +28,112 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_CHAR_STRING_HPP
#define GODOT_CHAR_STRING_HPP
#pragma once
#include <godot_cpp/templates/cowdata.hpp>
#include <cstddef>
#include <cstdint>
namespace godot {
class CharString {
friend class String;
template <typename T>
class CharStringT;
const char *_data = nullptr;
int _length = 0;
template <typename T>
class CharProxy {
template <typename TS>
friend class CharStringT;
CharString(const char *str, int length);
const int64_t _index;
CowData<T> &_cowdata;
static inline const T _null = 0;
_FORCE_INLINE_ CharProxy(const int64_t &p_index, CowData<T> &p_cowdata) :
_index(p_index),
_cowdata(p_cowdata) {}
public:
int length() const;
const char *get_data() const;
_FORCE_INLINE_ CharProxy(const CharProxy<T> &p_other) :
_index(p_other._index),
_cowdata(p_other._cowdata) {}
CharString(CharString &&p_str);
void operator=(CharString &&p_str);
CharString() {}
~CharString();
_FORCE_INLINE_ operator T() const {
if (unlikely(_index == _cowdata.size())) {
return _null;
}
return _cowdata.get(_index);
}
_FORCE_INLINE_ const T *operator&() const {
return _cowdata.ptr() + _index;
}
_FORCE_INLINE_ void operator=(const T &p_other) const {
_cowdata.set(_index, p_other);
}
_FORCE_INLINE_ void operator=(const CharProxy<T> &p_other) const {
_cowdata.set(_index, p_other.operator T());
}
};
class Char16String {
template <typename T>
class CharStringT {
friend class String;
const char16_t *_data = nullptr;
int _length = 0;
Char16String(const char16_t *str, int length);
CowData<T> _cowdata;
static inline const T _null = 0;
public:
int length() const;
const char16_t *get_data() const;
_FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); }
_FORCE_INLINE_ const T *ptr() const { return _cowdata.ptr(); }
_FORCE_INLINE_ int64_t size() const { return _cowdata.size(); }
Error resize(int64_t p_size) { return _cowdata.resize(p_size); }
Char16String(Char16String &&p_str);
void operator=(Char16String &&p_str);
Char16String() {}
~Char16String();
_FORCE_INLINE_ T get(int64_t p_index) const { return _cowdata.get(p_index); }
_FORCE_INLINE_ void set(int64_t p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); }
_FORCE_INLINE_ const T &operator[](int64_t p_index) const {
if (unlikely(p_index == _cowdata.size())) {
return _null;
}
return _cowdata.get(p_index);
}
_FORCE_INLINE_ CharProxy<T> operator[](int64_t p_index) { return CharProxy<T>(p_index, _cowdata); }
_FORCE_INLINE_ CharStringT() {}
_FORCE_INLINE_ CharStringT(const CharStringT<T> &p_str) { _cowdata._ref(p_str._cowdata); }
_FORCE_INLINE_ void operator=(const CharStringT<T> &p_str) { _cowdata._ref(p_str._cowdata); }
_FORCE_INLINE_ CharStringT(const T *p_cstr) { copy_from(p_cstr); }
void operator=(const T *p_cstr);
bool operator<(const CharStringT<T> &p_right) const;
CharStringT<T> &operator+=(T p_char);
int64_t length() const { return size() ? size() - 1 : 0; }
const T *get_data() const;
operator const T *() const { return get_data(); }
protected:
void copy_from(const T *p_cstr);
};
class Char32String {
friend class String;
template <>
const char *CharStringT<char>::get_data() const;
const char32_t *_data = nullptr;
int _length = 0;
template <>
const char16_t *CharStringT<char16_t>::get_data() const;
Char32String(const char32_t *str, int length);
template <>
const char32_t *CharStringT<char32_t>::get_data() const;
public:
int length() const;
const char32_t *get_data() const;
template <>
const wchar_t *CharStringT<wchar_t>::get_data() const;
Char32String(Char32String &&p_str);
void operator=(Char32String &&p_str);
Char32String() {}
~Char32String();
};
class CharWideString {
friend class String;
const wchar_t *_data = nullptr;
int _length = 0;
CharWideString(const wchar_t *str, int length);
public:
int length() const;
const wchar_t *get_data() const;
CharWideString(CharWideString &&p_str);
void operator=(CharWideString &&p_str);
CharWideString() {}
~CharWideString();
};
typedef CharStringT<char> CharString;
typedef CharStringT<char16_t> Char16String;
typedef CharStringT<char32_t> Char32String;
typedef CharStringT<wchar_t> CharWideString;
} // namespace godot
#endif // GODOT_CHAR_STRING_HPP

View File

@@ -28,63 +28,107 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_CHAR_UTILS_HPP
#define GODOT_CHAR_UTILS_HPP
#pragma once
static _FORCE_INLINE_ bool is_ascii_upper_case(char32_t c) {
return (c >= 'A' && c <= 'Z');
#include "char_range.inc.hpp"
namespace godot {
#define BSEARCH_CHAR_RANGE(m_array) \
int low = 0; \
int high = sizeof(m_array) / sizeof(m_array[0]) - 1; \
int middle = (low + high) / 2; \
\
while (low <= high) { \
if (p_char < m_array[middle].start) { \
high = middle - 1; \
} else if (p_char > m_array[middle].end) { \
low = middle + 1; \
} else { \
return true; \
} \
\
middle = (low + high) / 2; \
} \
\
return false
constexpr bool is_unicode_identifier_start(char32_t p_char) {
BSEARCH_CHAR_RANGE(xid_start);
}
static _FORCE_INLINE_ bool is_ascii_lower_case(char32_t c) {
return (c >= 'a' && c <= 'z');
constexpr bool is_unicode_identifier_continue(char32_t p_char) {
BSEARCH_CHAR_RANGE(xid_continue);
}
static _FORCE_INLINE_ bool is_digit(char32_t c) {
return (c >= '0' && c <= '9');
constexpr bool is_unicode_upper_case(char32_t p_char) {
BSEARCH_CHAR_RANGE(uppercase_letter);
}
static _FORCE_INLINE_ bool is_hex_digit(char32_t c) {
return (is_digit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
constexpr bool is_unicode_lower_case(char32_t p_char) {
BSEARCH_CHAR_RANGE(lowercase_letter);
}
static _FORCE_INLINE_ bool is_binary_digit(char32_t c) {
return (c == '0' || c == '1');
constexpr bool is_unicode_letter(char32_t p_char) {
BSEARCH_CHAR_RANGE(unicode_letter);
}
static _FORCE_INLINE_ bool is_ascii_char(char32_t c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
#undef BSEARCH_CHAR_RANGE
constexpr bool is_ascii_upper_case(char32_t p_char) {
return (p_char >= 'A' && p_char <= 'Z');
}
static _FORCE_INLINE_ bool is_ascii_alphanumeric_char(char32_t c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
constexpr bool is_ascii_lower_case(char32_t p_char) {
return (p_char >= 'a' && p_char <= 'z');
}
static _FORCE_INLINE_ bool is_ascii_identifier_char(char32_t c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
constexpr bool is_digit(char32_t p_char) {
return (p_char >= '0' && p_char <= '9');
}
static _FORCE_INLINE_ bool is_symbol(char32_t c) {
return c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t' || c == ' ');
constexpr bool is_hex_digit(char32_t p_char) {
return (is_digit(p_char) || (p_char >= 'a' && p_char <= 'f') || (p_char >= 'A' && p_char <= 'F'));
}
static _FORCE_INLINE_ bool is_control(char32_t p_char) {
constexpr bool is_binary_digit(char32_t p_char) {
return (p_char == '0' || p_char == '1');
}
constexpr bool is_ascii_alphabet_char(char32_t p_char) {
return (p_char >= 'a' && p_char <= 'z') || (p_char >= 'A' && p_char <= 'Z');
}
constexpr bool is_ascii_alphanumeric_char(char32_t p_char) {
return (p_char >= 'a' && p_char <= 'z') || (p_char >= 'A' && p_char <= 'Z') || (p_char >= '0' && p_char <= '9');
}
constexpr bool is_ascii_identifier_char(char32_t p_char) {
return (p_char >= 'a' && p_char <= 'z') || (p_char >= 'A' && p_char <= 'Z') || (p_char >= '0' && p_char <= '9') || p_char == '_';
}
constexpr bool is_symbol(char32_t p_char) {
return p_char != '_' && ((p_char >= '!' && p_char <= '/') || (p_char >= ':' && p_char <= '@') || (p_char >= '[' && p_char <= '`') || (p_char >= '{' && p_char <= '~') || p_char == '\t' || p_char == ' ');
}
constexpr bool is_control(char32_t p_char) {
return (p_char <= 0x001f) || (p_char >= 0x007f && p_char <= 0x009f);
}
static _FORCE_INLINE_ bool is_whitespace(char32_t p_char) {
return (p_char == ' ') || (p_char == 0x00a0) || (p_char == 0x1680) || (p_char >= 0x2000 && p_char <= 0x200a) || (p_char == 0x202f) || (p_char == 0x205f) || (p_char == 0x3000) || (p_char == 0x2028) || (p_char == 0x2029) || (p_char >= 0x0009 && p_char <= 0x000d) || (p_char == 0x0085);
constexpr bool is_whitespace(char32_t p_char) {
return (p_char == ' ') || (p_char == 0x00a0) || (p_char == 0x1680) || (p_char >= 0x2000 && p_char <= 0x200b) || (p_char == 0x202f) || (p_char == 0x205f) || (p_char == 0x3000) || (p_char == 0x2028) || (p_char == 0x2029) || (p_char >= 0x0009 && p_char <= 0x000d) || (p_char == 0x0085);
}
static _FORCE_INLINE_ bool is_linebreak(char32_t p_char) {
constexpr bool is_linebreak(char32_t p_char) {
return (p_char >= 0x000a && p_char <= 0x000d) || (p_char == 0x0085) || (p_char == 0x2028) || (p_char == 0x2029);
}
static _FORCE_INLINE_ bool is_punct(char32_t p_char) {
constexpr bool is_punct(char32_t p_char) {
return (p_char >= ' ' && p_char <= '/') || (p_char >= ':' && p_char <= '@') || (p_char >= '[' && p_char <= '^') || (p_char == '`') || (p_char >= '{' && p_char <= '~') || (p_char >= 0x2000 && p_char <= 0x206f) || (p_char >= 0x3000 && p_char <= 0x303f);
}
static _FORCE_INLINE_ bool is_underscore(char32_t p_char) {
constexpr bool is_underscore(char32_t p_char) {
return (p_char == '_');
}
#endif // GODOT_CHAR_UTILS_HPP
} // namespace godot

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_COLOR_HPP
#define GODOT_COLOR_HPP
#pragma once
#include <godot_cpp/core/math.hpp>
@@ -37,7 +36,7 @@ namespace godot {
class String;
struct _NO_DISCARD_ Color {
struct [[nodiscard]] Color {
union {
struct {
float r;
@@ -103,12 +102,10 @@ struct _NO_DISCARD_ Color {
_FORCE_INLINE_ Color lerp(const Color &p_to, float p_weight) const {
Color res = *this;
res.r += (p_weight * (p_to.r - r));
res.g += (p_weight * (p_to.g - g));
res.b += (p_weight * (p_to.b - b));
res.a += (p_weight * (p_to.a - a));
res.r = Math::lerp(res.r, p_to.r, p_weight);
res.g = Math::lerp(res.g, p_to.g, p_weight);
res.b = Math::lerp(res.b, p_to.b, p_weight);
res.a = Math::lerp(res.a, p_to.a, p_weight);
return res;
}
@@ -129,33 +126,46 @@ struct _NO_DISCARD_ Color {
}
_FORCE_INLINE_ uint32_t to_rgbe9995() const {
const float pow2to9 = 512.0f;
const float B = 15.0f;
const float N = 9.0f;
// https://github.com/microsoft/DirectX-Graphics-Samples/blob/v10.0.19041.0/MiniEngine/Core/Color.cpp
static const float kMaxVal = float(0x1FF << 7);
static const float kMinVal = float(1.f / (1 << 16));
float sharedexp = 65408.000f; // Result of: ((pow2to9 - 1.0f) / pow2to9) * powf(2.0f, 31.0f - 15.0f)
// Clamp RGB to [0, 1.FF*2^16]
const float _r = CLAMP(r, 0.0f, kMaxVal);
const float _g = CLAMP(g, 0.0f, kMaxVal);
const float _b = CLAMP(b, 0.0f, kMaxVal);
float cRed = MAX(0.0f, MIN(sharedexp, r));
float cGreen = MAX(0.0f, MIN(sharedexp, g));
float cBlue = MAX(0.0f, MIN(sharedexp, b));
// Compute the maximum channel, no less than 1.0*2^-15
const float MaxChannel = MAX(MAX(_r, _g), MAX(_b, kMinVal));
float cMax = MAX(cRed, MAX(cGreen, cBlue));
// Take the exponent of the maximum channel (rounding up the 9th bit) and
// add 15 to it. When added to the channels, it causes the implicit '1.0'
// bit and the first 8 mantissa bits to be shifted down to the low 9 bits
// of the mantissa, rounding the truncated bits.
union {
float f;
uint32_t i;
} R, G, B, E;
float expp = MAX(-B - 1.0f, floor(Math::log(cMax) / (real_t)Math_LN2)) + 1.0f + B;
E.f = MaxChannel;
E.i += 0x07804000; // Add 15 to the exponent and 0x4000 to the mantissa
E.i &= 0x7F800000; // Zero the mantissa
float sMax = (float)floor((cMax / Math::pow(2.0f, expp - B - N)) + 0.5f);
// This shifts the 9-bit values we need into the lowest bits, rounding as
// needed. Note that if the channel has a smaller exponent than the max
// channel, it will shift even more. This is intentional.
R.f = _r + E.f;
G.f = _g + E.f;
B.f = _b + E.f;
float exps = expp + 1.0f;
// Convert the Bias to the correct exponent in the upper 5 bits.
E.i <<= 4;
E.i += 0x10000000;
if (0.0f <= sMax && sMax < pow2to9) {
exps = expp;
}
float sRed = Math::floor((cRed / pow(2.0f, exps - B - N)) + 0.5f);
float sGreen = Math::floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f);
float sBlue = Math::floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f);
return (uint32_t(Math::fast_ftoi(sRed)) & 0x1FF) | ((uint32_t(Math::fast_ftoi(sGreen)) & 0x1FF) << 9) | ((uint32_t(Math::fast_ftoi(sBlue)) & 0x1FF) << 18) | ((uint32_t(Math::fast_ftoi(exps)) & 0x1F) << 27);
// Combine the fields. RGB floats have unwanted data in the upper 9
// bits. Only red needs to mask them off because green and blue shift
// it out to the left.
return E.i | (B.i << 18U) | (G.i << 9U) | (R.i & 511U);
}
_FORCE_INLINE_ Color blend(const Color &p_over) const {
@@ -174,16 +184,16 @@ struct _NO_DISCARD_ Color {
_FORCE_INLINE_ Color srgb_to_linear() const {
return Color(
r < 0.04045f ? r * (1.0f / 12.92f) : Math::pow((r + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
g < 0.04045f ? g * (1.0f / 12.92f) : Math::pow((g + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
b < 0.04045f ? b * (1.0f / 12.92f) : Math::pow((b + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
r < 0.04045f ? r * (1.0f / 12.92f) : Math::pow(float((r + 0.055) * (1.0 / (1.0 + 0.055))), 2.4f),
g < 0.04045f ? g * (1.0f / 12.92f) : Math::pow(float((g + 0.055) * (1.0 / (1.0 + 0.055))), 2.4f),
b < 0.04045f ? b * (1.0f / 12.92f) : Math::pow(float((b + 0.055) * (1.0 / (1.0 + 0.055))), 2.4f),
a);
}
_FORCE_INLINE_ Color linear_to_srgb() const {
return Color(
r < 0.0031308f ? 12.92f * r : (1.0f + 0.055f) * Math::pow(r, 1.0f / 2.4f) - 0.055f,
g < 0.0031308f ? 12.92f * g : (1.0f + 0.055f) * Math::pow(g, 1.0f / 2.4f) - 0.055f,
b < 0.0031308f ? 12.92f * b : (1.0f + 0.055f) * Math::pow(b, 1.0f / 2.4f) - 0.055f, a);
r < 0.0031308f ? 12.92f * r : (1.0 + 0.055) * Math::pow(r, 1.0f / 2.4f) - 0.055,
g < 0.0031308f ? 12.92f * g : (1.0 + 0.055) * Math::pow(g, 1.0f / 2.4f) - 0.055,
b < 0.0031308f ? 12.92f * b : (1.0 + 0.055) * Math::pow(b, 1.0f / 2.4f) - 0.055, a);
}
static Color hex(uint32_t p_hex);
@@ -199,6 +209,7 @@ struct _NO_DISCARD_ Color {
static Color from_string(const String &p_string, const Color &p_default);
static Color from_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0f);
static Color from_rgbe9995(uint32_t p_rgbe);
static Color from_rgba8(int64_t p_r8, int64_t p_g8, int64_t p_b8, int64_t p_a8 = 255);
_FORCE_INLINE_ bool operator<(const Color &p_color) const; // Used in set keys.
operator String() const;
@@ -285,5 +296,3 @@ _FORCE_INLINE_ Color operator*(float p_scalar, const Color &p_color) {
}
} // namespace godot
#endif // GODOT_COLOR_HPP

View File

@@ -28,6 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
namespace godot {
// Names from https://en.wikipedia.org/wiki/X11_color_names
@@ -185,7 +187,6 @@ static NamedColor named_colors[] = {
{ "WHITE_SMOKE", Color::hex(0xF5F5F5FF) },
{ "YELLOW", Color::hex(0xFFFF00FF) },
{ "YELLOW_GREEN", Color::hex(0x9ACD32FF) },
{ nullptr, Color() },
};
} // namespace godot

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_PLANE_HPP
#define GODOT_PLANE_HPP
#pragma once
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/variant/vector3.hpp>
@@ -38,7 +37,7 @@ namespace godot {
class Variant;
struct _NO_DISCARD_ Plane {
struct [[nodiscard]] Plane {
Vector3 normal;
real_t d = 0;
@@ -50,7 +49,7 @@ struct _NO_DISCARD_ Plane {
/* Plane-Point operations */
_FORCE_INLINE_ Vector3 center() const { return normal * d; }
_FORCE_INLINE_ Vector3 get_center() const { return normal * d; }
Vector3 get_any_perpendicular_normal() const;
_FORCE_INLINE_ bool is_point_over(const Vector3 &p_point) const; ///< Point is over plane
@@ -77,6 +76,7 @@ struct _NO_DISCARD_ Plane {
Plane operator-() const { return Plane(-normal, -d); }
bool is_equal_approx(const Plane &p_plane) const;
bool is_equal_approx_any_side(const Plane &p_plane) const;
bool is_finite() const;
_FORCE_INLINE_ bool operator==(const Plane &p_plane) const;
_FORCE_INLINE_ bool operator!=(const Plane &p_plane) const;
@@ -136,5 +136,3 @@ bool Plane::operator!=(const Plane &p_plane) const {
}
} // namespace godot
#endif // GODOT_PLANE_HPP

View File

@@ -28,10 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_PROJECTION_HPP
#define GODOT_PROJECTION_HPP
#pragma once
#include <godot_cpp/core/math.hpp>
#include <godot_cpp/templates/vector.hpp>
#include <godot_cpp/variant/vector3.hpp>
#include <godot_cpp/variant/vector4.hpp>
@@ -44,7 +44,7 @@ struct Rect2;
struct Transform3D;
struct Vector2;
struct _NO_DISCARD_ Projection {
struct [[nodiscard]] Projection {
enum Planes {
PLANE_NEAR,
PLANE_FAR,
@@ -56,21 +56,21 @@ struct _NO_DISCARD_ Projection {
Vector4 columns[4];
_FORCE_INLINE_ const Vector4 &operator[](const int p_axis) const {
_FORCE_INLINE_ const Vector4 &operator[](int p_axis) const {
DEV_ASSERT((unsigned int)p_axis < 4);
return columns[p_axis];
}
_FORCE_INLINE_ Vector4 &operator[](const int p_axis) {
_FORCE_INLINE_ Vector4 &operator[](int p_axis) {
DEV_ASSERT((unsigned int)p_axis < 4);
return columns[p_axis];
}
float determinant() const;
real_t determinant() const;
void set_identity();
void set_zero();
void set_light_bias();
void set_depth_correction(bool p_flip_y = true);
void set_depth_correction(bool p_flip_y = true, bool p_reverse_z = true, bool p_remap_z = true);
void set_light_atlas_rect(const Rect2 &p_rect);
void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false);
@@ -107,7 +107,7 @@ struct _NO_DISCARD_ Projection {
real_t get_fov() const;
bool is_orthogonal() const;
Array get_projection_planes(const Transform3D &p_transform) const;
Vector<Plane> get_projection_planes(const Transform3D &p_transform) const;
bool get_endpoints(const Transform3D &p_transform, Vector3 *p_8points) const;
Vector2 get_viewport_half_extents() const;
@@ -149,10 +149,11 @@ struct _NO_DISCARD_ Projection {
return !(*this == p_cam);
}
float get_lod_multiplier() const;
real_t get_lod_multiplier() const;
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();
};
@@ -167,5 +168,3 @@ Vector3 Projection::xform(const Vector3 &p_vec3) const {
}
} // namespace godot
#endif // GODOT_PROJECTION_HPP

View File

@@ -28,15 +28,15 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_QUATERNION_HPP
#define GODOT_QUATERNION_HPP
#pragma once
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/core/math.hpp>
#include <godot_cpp/variant/vector3.hpp>
namespace godot {
struct _NO_DISCARD_ Quaternion {
struct [[nodiscard]] Quaternion {
union {
struct {
real_t x;
@@ -47,14 +47,15 @@ struct _NO_DISCARD_ Quaternion {
real_t components[4] = { 0, 0, 0, 1.0 };
};
_FORCE_INLINE_ real_t &operator[](int idx) {
return components[idx];
_FORCE_INLINE_ real_t &operator[](int p_idx) {
return components[p_idx];
}
_FORCE_INLINE_ const real_t &operator[](int idx) const {
return components[idx];
_FORCE_INLINE_ const real_t &operator[](int p_idx) const {
return components[p_idx];
}
_FORCE_INLINE_ real_t length_squared() const;
bool is_equal_approx(const Quaternion &p_quaternion) const;
bool is_finite() const;
real_t length() const;
void normalize();
Quaternion normalized() const;
@@ -65,14 +66,13 @@ struct _NO_DISCARD_ Quaternion {
_FORCE_INLINE_ real_t dot(const Quaternion &p_q) const;
real_t angle_to(const Quaternion &p_to) const;
Vector3 get_euler_xyz() const;
Vector3 get_euler_yxz() const;
Vector3 get_euler() const { return get_euler_yxz(); }
Vector3 get_euler(EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ) const;
static Quaternion from_euler(const Vector3 &p_euler);
Quaternion slerp(const Quaternion &p_to, const real_t &p_weight) const;
Quaternion slerpni(const Quaternion &p_to, const real_t &p_weight) const;
Quaternion spherical_cubic_interpolate(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const;
Quaternion spherical_cubic_interpolate_in_time(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const;
Quaternion slerp(const Quaternion &p_to, real_t p_weight) const;
Quaternion slerpni(const Quaternion &p_to, real_t p_weight) const;
Quaternion spherical_cubic_interpolate(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, real_t p_weight) const;
Quaternion spherical_cubic_interpolate_in_time(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, real_t p_weight, real_t p_b_t, real_t p_pre_a_t, real_t p_post_b_t) const;
Vector3 get_axis() const;
real_t get_angle() const;
@@ -88,28 +88,28 @@ struct _NO_DISCARD_ Quaternion {
void operator*=(const Quaternion &p_q);
Quaternion operator*(const Quaternion &p_q) const;
_FORCE_INLINE_ Vector3 xform(const Vector3 &v) const {
_FORCE_INLINE_ Vector3 xform(const Vector3 &p_v) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V_MSG(!is_normalized(), v, "The quaternion must be normalized.");
ERR_FAIL_COND_V_MSG(!is_normalized(), p_v, "The quaternion " + operator String() + " must be normalized.");
#endif
Vector3 u(x, y, z);
Vector3 uv = u.cross(v);
return v + ((uv * w) + u.cross(uv)) * ((real_t)2);
Vector3 uv = u.cross(p_v);
return p_v + ((uv * w) + u.cross(uv)) * ((real_t)2);
}
_FORCE_INLINE_ Vector3 xform_inv(const Vector3 &v) const {
return inverse().xform(v);
_FORCE_INLINE_ Vector3 xform_inv(const Vector3 &p_v) const {
return inverse().xform(p_v);
}
_FORCE_INLINE_ void operator+=(const Quaternion &p_q);
_FORCE_INLINE_ void operator-=(const Quaternion &p_q);
_FORCE_INLINE_ void operator*=(const real_t &s);
_FORCE_INLINE_ void operator/=(const real_t &s);
_FORCE_INLINE_ Quaternion operator+(const Quaternion &q2) const;
_FORCE_INLINE_ Quaternion operator-(const Quaternion &q2) const;
_FORCE_INLINE_ void operator*=(real_t p_s);
_FORCE_INLINE_ void operator/=(real_t p_s);
_FORCE_INLINE_ Quaternion operator+(const Quaternion &p_q2) const;
_FORCE_INLINE_ Quaternion operator-(const Quaternion &p_q2) const;
_FORCE_INLINE_ Quaternion operator-() const;
_FORCE_INLINE_ Quaternion operator*(const real_t &s) const;
_FORCE_INLINE_ Quaternion operator/(const real_t &s) const;
_FORCE_INLINE_ Quaternion operator*(real_t p_s) const;
_FORCE_INLINE_ Quaternion operator/(real_t p_s) const;
_FORCE_INLINE_ bool operator==(const Quaternion &p_quaternion) const;
_FORCE_INLINE_ bool operator!=(const Quaternion &p_quaternion) const;
@@ -127,8 +127,6 @@ struct _NO_DISCARD_ Quaternion {
Quaternion(const Vector3 &p_axis, real_t p_angle);
Quaternion(const Vector3 &p_euler);
Quaternion(const Quaternion &p_q) :
x(p_q.x),
y(p_q.y),
@@ -143,16 +141,25 @@ struct _NO_DISCARD_ Quaternion {
w = p_q.w;
}
Quaternion(const Vector3 &v0, const Vector3 &v1) { // Shortest arc.
Vector3 c = v0.cross(v1);
real_t d = v0.dot(v1);
if (d < -1.0f + (real_t)CMP_EPSILON) {
x = 0;
y = 1;
z = 0;
Quaternion(const Vector3 &p_v0, const Vector3 &p_v1) { // Shortest arc.
#ifdef MATH_CHECKS
ERR_FAIL_COND_MSG(p_v0.is_zero_approx() || p_v1.is_zero_approx(), "The vectors must not be zero.");
#endif
constexpr real_t ALMOST_ONE = 1.0f - (real_t)CMP_EPSILON;
Vector3 n0 = p_v0.normalized();
Vector3 n1 = p_v1.normalized();
real_t d = n0.dot(n1);
if (Math::abs(d) > ALMOST_ONE) {
if (d >= 0) {
return; // Vectors are same.
}
Vector3 axis = n0.get_any_perpendicular();
x = axis.x;
y = axis.y;
z = axis.z;
w = 0;
} else {
Vector3 c = n0.cross(n1);
real_t s = Math::sqrt((1.0f + d) * 2.0f);
real_t rs = 1.0f / s;
@@ -186,25 +193,25 @@ void Quaternion::operator-=(const Quaternion &p_q) {
w -= p_q.w;
}
void Quaternion::operator*=(const real_t &s) {
x *= s;
y *= s;
z *= s;
w *= s;
void Quaternion::operator*=(real_t p_s) {
x *= p_s;
y *= p_s;
z *= p_s;
w *= p_s;
}
void Quaternion::operator/=(const real_t &s) {
*this *= 1.0f / s;
void Quaternion::operator/=(real_t p_s) {
*this *= 1.0f / p_s;
}
Quaternion Quaternion::operator+(const Quaternion &q2) const {
Quaternion Quaternion::operator+(const Quaternion &p_q2) const {
const Quaternion &q1 = *this;
return Quaternion(q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w);
return Quaternion(q1.x + p_q2.x, q1.y + p_q2.y, q1.z + p_q2.z, q1.w + p_q2.w);
}
Quaternion Quaternion::operator-(const Quaternion &q2) const {
Quaternion Quaternion::operator-(const Quaternion &p_q2) const {
const Quaternion &q1 = *this;
return Quaternion(q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w);
return Quaternion(q1.x - p_q2.x, q1.y - p_q2.y, q1.z - p_q2.z, q1.w - p_q2.w);
}
Quaternion Quaternion::operator-() const {
@@ -212,12 +219,12 @@ Quaternion Quaternion::operator-() const {
return Quaternion(-q2.x, -q2.y, -q2.z, -q2.w);
}
Quaternion Quaternion::operator*(const real_t &s) const {
return Quaternion(x * s, y * s, z * s, w * s);
Quaternion Quaternion::operator*(real_t p_s) const {
return Quaternion(x * p_s, y * p_s, z * p_s, w * p_s);
}
Quaternion Quaternion::operator/(const real_t &s) const {
return *this * (1.0f / s);
Quaternion Quaternion::operator/(real_t p_s) const {
return *this * (1.0f / p_s);
}
bool Quaternion::operator==(const Quaternion &p_quaternion) const {
@@ -228,10 +235,8 @@ bool Quaternion::operator!=(const Quaternion &p_quaternion) const {
return x != p_quaternion.x || y != p_quaternion.y || z != p_quaternion.z || w != p_quaternion.w;
}
_FORCE_INLINE_ Quaternion operator*(const real_t &p_real, const Quaternion &p_quaternion) {
_FORCE_INLINE_ Quaternion operator*(real_t p_real, const Quaternion &p_quaternion) {
return p_quaternion * p_real;
}
} // namespace godot
#endif // GODOT_QUATERNION_HPP

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_RECT2_HPP
#define GODOT_RECT2_HPP
#pragma once
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/variant/vector2.hpp>
@@ -40,7 +39,7 @@ class String;
struct Rect2i;
struct Transform2D;
struct _NO_DISCARD_ Rect2 {
struct [[nodiscard]] Rect2 {
Point2 position;
Size2 size;
@@ -53,7 +52,7 @@ struct _NO_DISCARD_ Rect2 {
_FORCE_INLINE_ Vector2 get_center() const { return position + (size * 0.5f); }
inline bool intersects(const Rect2 &p_rect, const bool p_include_borders = false) const {
inline bool intersects(const Rect2 &p_rect, bool p_include_borders = false) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || p_rect.size.x < 0 || p_rect.size.y < 0)) {
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
@@ -106,17 +105,17 @@ struct _NO_DISCARD_ Rect2 {
}
if (p_point.y < position.y) {
real_t d = position.y - p_point.y;
dist = inside ? d : Math::min(dist, d);
dist = inside ? d : MIN(dist, d);
inside = false;
}
if (p_point.x >= (position.x + size.x)) {
real_t d = p_point.x - (position.x + size.x);
dist = inside ? d : Math::min(dist, d);
dist = inside ? d : MIN(dist, d);
inside = false;
}
if (p_point.y >= (position.y + size.y)) {
real_t d = p_point.y - (position.y + size.y);
dist = inside ? d : Math::min(dist, d);
dist = inside ? d : MIN(dist, d);
inside = false;
}
@@ -146,7 +145,7 @@ struct _NO_DISCARD_ Rect2 {
return size.x > 0.0f && size.y > 0.0f;
}
// Returns the instersection between two Rect2s or an empty Rect2 if there is no intersection
// Returns the intersection between two Rect2s or an empty Rect2 if there is no intersection.
inline Rect2 intersection(const Rect2 &p_rect) const {
Rect2 new_rect = p_rect;
@@ -154,14 +153,12 @@ struct _NO_DISCARD_ Rect2 {
return Rect2();
}
new_rect.position.x = Math::max(p_rect.position.x, position.x);
new_rect.position.y = Math::max(p_rect.position.y, position.y);
new_rect.position = p_rect.position.max(position);
Point2 p_rect_end = p_rect.position + p_rect.size;
Point2 end = position + size;
new_rect.size.x = Math::min(p_rect_end.x, end.x) - new_rect.position.x;
new_rect.size.y = Math::min(p_rect_end.y, end.y) - new_rect.position.y;
new_rect.size = p_rect_end.min(end) - new_rect.position;
return new_rect;
}
@@ -174,11 +171,9 @@ struct _NO_DISCARD_ Rect2 {
#endif
Rect2 new_rect;
new_rect.position.x = Math::min(p_rect.position.x, position.x);
new_rect.position.y = Math::min(p_rect.position.y, position.y);
new_rect.position = p_rect.position.min(position);
new_rect.size.x = Math::max(p_rect.position.x + p_rect.size.x, position.x + size.x);
new_rect.size.y = Math::max(p_rect.position.y + p_rect.size.y, position.y + size.y);
new_rect.size = (p_rect.position + p_rect.size).max(position + size);
new_rect.size = new_rect.size - new_rect.position; // Make relative again.
@@ -209,6 +204,7 @@ struct _NO_DISCARD_ Rect2 {
}
bool is_equal_approx(const Rect2 &p_rect) const;
bool is_finite() const;
bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; }
bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; }
@@ -283,16 +279,22 @@ struct _NO_DISCARD_ Rect2 {
}
_FORCE_INLINE_ Rect2 abs() const {
return Rect2(Point2(position.x + Math::min(size.x, (real_t)0), position.y + Math::min(size.y, (real_t)0)), size.abs());
return Rect2(position + size.minf(0), size.abs());
}
Vector2 get_support(const Vector2 &p_normal) const {
Vector2 half_extents = size * 0.5f;
Vector2 ofs = position + half_extents;
return Vector2(
(p_normal.x > 0) ? -half_extents.x : half_extents.x,
(p_normal.y > 0) ? -half_extents.y : half_extents.y) +
ofs;
_FORCE_INLINE_ Rect2 round() const {
return Rect2(position.round(), size.round());
}
Vector2 get_support(const Vector2 &p_direction) const {
Vector2 support = position;
if (p_direction.x > 0.0f) {
support.x += size.x;
}
if (p_direction.y > 0.0f) {
support.y += size.y;
}
return support;
}
_FORCE_INLINE_ bool intersects_filled_polygon(const Vector2 *p_points, int p_point_count) const {
@@ -308,14 +310,14 @@ struct _NO_DISCARD_ Rect2 {
i_f = i;
Vector2 r = (b - a);
float l = r.length();
const real_t l = r.length();
if (l == 0.0f) {
continue;
}
// Check inside.
Vector2 tg = r.orthogonal();
float s = tg.dot(center) - tg.dot(a);
const real_t s = tg.dot(center) - tg.dot(a);
if (s < 0.0f) {
side_plus++;
} else {
@@ -331,8 +333,8 @@ struct _NO_DISCARD_ Rect2 {
Vector2 t13 = (position - a) * ir;
Vector2 t24 = (end - a) * ir;
float tmin = Math::max(Math::min(t13.x, t24.x), Math::min(t13.y, t24.y));
float tmax = Math::min(Math::max(t13.x, t24.x), Math::max(t13.y, t24.y));
const real_t tmin = MAX(MIN(t13.x, t24.x), MIN(t13.y, t24.y));
const real_t tmax = MIN(MAX(t13.x, t24.x), MAX(t13.y, t24.y));
// if tmax < 0, ray (line) is intersecting AABB, but the whole AABB is behind us
if (tmax < 0 || tmin > tmax || tmin >= l) {
@@ -372,5 +374,3 @@ struct _NO_DISCARD_ Rect2 {
};
} // namespace godot
#endif // GODOT_RECT2_HPP

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_RECT2I_HPP
#define GODOT_RECT2I_HPP
#pragma once
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/variant/vector2i.hpp>
@@ -39,7 +38,7 @@ namespace godot {
class String;
struct Rect2;
struct _NO_DISCARD_ Rect2i {
struct [[nodiscard]] Rect2i {
Point2i position;
Size2i size;
@@ -89,7 +88,7 @@ struct _NO_DISCARD_ Rect2i {
return size.x > 0 && size.y > 0;
}
// Returns the instersection between two Rect2is or an empty Rect2i if there is no intersection
// Returns the intersection between two Rect2is or an empty Rect2i if there is no intersection.
inline Rect2i intersection(const Rect2i &p_rect) const {
Rect2i new_rect = p_rect;
@@ -97,14 +96,12 @@ struct _NO_DISCARD_ Rect2i {
return Rect2i();
}
new_rect.position.x = Math::max(p_rect.position.x, position.x);
new_rect.position.y = Math::max(p_rect.position.y, position.y);
new_rect.position = p_rect.position.max(position);
Point2i p_rect_end = p_rect.position + p_rect.size;
Point2i end = position + size;
new_rect.size.x = Math::min(p_rect_end.x, end.x) - new_rect.position.x;
new_rect.size.y = Math::min(p_rect_end.y, end.y) - new_rect.position.y;
new_rect.size = p_rect_end.min(end) - new_rect.position;
return new_rect;
}
@@ -117,11 +114,9 @@ struct _NO_DISCARD_ Rect2i {
#endif
Rect2i new_rect;
new_rect.position.x = Math::min(p_rect.position.x, position.x);
new_rect.position.y = Math::min(p_rect.position.y, position.y);
new_rect.position = p_rect.position.min(position);
new_rect.size.x = Math::max(p_rect.position.x + p_rect.size.x, position.x + size.x);
new_rect.size.y = Math::max(p_rect.position.y + p_rect.size.y, position.y + size.y);
new_rect.size = (p_rect.position + p_rect.size).max(position + size);
new_rect.size = new_rect.size - new_rect.position; // Make relative again.
@@ -219,7 +214,7 @@ struct _NO_DISCARD_ Rect2i {
}
_FORCE_INLINE_ Rect2i abs() const {
return Rect2i(Point2i(position.x + Math::min(size.x, 0), position.y + Math::min(size.y, 0)), size.abs());
return Rect2i(position + size.mini(0), size.abs());
}
_FORCE_INLINE_ void set_end(const Vector2i &p_end) {
@@ -245,5 +240,3 @@ struct _NO_DISCARD_ Rect2i {
};
} // namespace godot
#endif // GODOT_RECT2I_HPP

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_TRANSFORM2D_HPP
#define GODOT_TRANSFORM2D_HPP
#pragma once
#include <godot_cpp/variant/packed_vector2_array.hpp>
#include <godot_cpp/variant/rect2.hpp>
@@ -39,22 +38,25 @@ namespace godot {
class String;
struct _NO_DISCARD_ Transform2D {
// Warning #1: basis of Transform2D is stored differently from Basis. In terms of columns array, the basis matrix looks like "on paper":
struct [[nodiscard]] Transform2D {
// WARNING: The basis of Transform2D is stored differently from Basis.
// In terms of columns array, the basis matrix looks like "on paper":
// M = (columns[0][0] columns[1][0])
// (columns[0][1] columns[1][1])
// This is such that the columns, which can be interpreted as basis vectors of the coordinate system "painted" on the object, can be accessed as columns[i].
// Note that this is the opposite of the indices in mathematical texts, meaning: $M_{12}$ in a math book corresponds to columns[1][0] here.
// This is such that the columns, which can be interpreted as basis vectors
// of the coordinate system "painted" on the object, can be accessed as columns[i].
// NOTE: This is the opposite of the indices in mathematical texts,
// meaning: $M_{12}$ in a math book corresponds to columns[1][0] here.
// This requires additional care when working with explicit indices.
// See https://en.wikipedia.org/wiki/Row-_and_column-major_order for further reading.
// Warning #2: 2D be aware that unlike 3D code, 2D code uses a left-handed coordinate system: Y-axis points down,
// and angle is measure from +X to +Y in a clockwise-fashion.
// WARNING: Be aware that unlike 3D code, 2D code uses a left-handed coordinate system:
// Y-axis points down, and angle is measure from +X to +Y in a clockwise-fashion.
Vector2 columns[3];
_FORCE_INLINE_ real_t tdotx(const Vector2 &v) const { return columns[0][0] * v.x + columns[1][0] * v.y; }
_FORCE_INLINE_ real_t tdoty(const Vector2 &v) const { return columns[0][1] * v.x + columns[1][1] * v.y; }
_FORCE_INLINE_ real_t tdotx(const Vector2 &p_v) const { return columns[0][0] * p_v.x + columns[1][0] * p_v.y; }
_FORCE_INLINE_ real_t tdoty(const Vector2 &p_v) const { return columns[0][1] * p_v.x + columns[1][1] * p_v.y; }
const Vector2 &operator[](int p_idx) const { return columns[p_idx]; }
Vector2 &operator[](int p_idx) { return columns[p_idx]; }
@@ -65,20 +67,20 @@ struct _NO_DISCARD_ Transform2D {
void affine_invert();
Transform2D affine_inverse() const;
void set_rotation(const real_t p_rot);
void set_rotation(real_t p_rot);
real_t get_rotation() const;
real_t get_skew() const;
void set_skew(const real_t p_angle);
_FORCE_INLINE_ void set_rotation_and_scale(const real_t p_rot, const Size2 &p_scale);
_FORCE_INLINE_ void set_rotation_scale_and_skew(const real_t p_rot, const Size2 &p_scale, const real_t p_skew);
void rotate(const real_t p_angle);
void set_skew(real_t p_angle);
_FORCE_INLINE_ void set_rotation_and_scale(real_t p_rot, const Size2 &p_scale);
_FORCE_INLINE_ void set_rotation_scale_and_skew(real_t p_rot, const Size2 &p_scale, real_t p_skew);
void rotate(real_t p_angle);
void scale(const Size2 &p_scale);
void scale_basis(const Size2 &p_scale);
void translate_local(const real_t p_tx, const real_t p_ty);
void translate_local(real_t p_tx, real_t p_ty);
void translate_local(const Vector2 &p_translation);
real_t basis_determinant() const;
real_t determinant() const;
Size2 get_scale() const;
void set_scale(const Size2 &p_scale);
@@ -86,19 +88,20 @@ struct _NO_DISCARD_ Transform2D {
_FORCE_INLINE_ const Vector2 &get_origin() const { return columns[2]; }
_FORCE_INLINE_ void set_origin(const Vector2 &p_origin) { columns[2] = p_origin; }
Transform2D basis_scaled(const Size2 &p_scale) const;
Transform2D scaled(const Size2 &p_scale) const;
Transform2D scaled_local(const Size2 &p_scale) const;
Transform2D translated(const Vector2 &p_offset) const;
Transform2D translated_local(const Vector2 &p_offset) const;
Transform2D rotated(const real_t p_angle) const;
Transform2D rotated_local(const real_t p_angle) const;
Transform2D rotated(real_t p_angle) const;
Transform2D rotated_local(real_t p_angle) const;
Transform2D untranslated() const;
void orthonormalize();
Transform2D orthonormalized() const;
bool is_conformal() const;
bool is_equal_approx(const Transform2D &p_transform) const;
bool is_finite() const;
Transform2D looking_at(const Vector2 &p_target) const;
@@ -107,10 +110,12 @@ struct _NO_DISCARD_ Transform2D {
void operator*=(const Transform2D &p_transform);
Transform2D operator*(const Transform2D &p_transform) const;
void operator*=(const real_t p_val);
Transform2D operator*(const real_t p_val) const;
void operator*=(real_t p_val);
Transform2D operator*(real_t p_val) const;
void operator/=(real_t p_val);
Transform2D operator/(real_t p_val) const;
Transform2D interpolate_with(const Transform2D &p_transform, const real_t p_c) const;
Transform2D interpolate_with(const Transform2D &p_transform, real_t p_c) const;
_FORCE_INLINE_ Vector2 basis_xform(const Vector2 &p_vec) const;
_FORCE_INLINE_ Vector2 basis_xform_inv(const Vector2 &p_vec) const;
@@ -123,13 +128,13 @@ struct _NO_DISCARD_ Transform2D {
operator String() const;
Transform2D(const real_t xx, const real_t xy, const real_t yx, const real_t yy, const real_t ox, const real_t oy) {
columns[0][0] = xx;
columns[0][1] = xy;
columns[1][0] = yx;
columns[1][1] = yy;
columns[2][0] = ox;
columns[2][1] = oy;
Transform2D(real_t p_xx, real_t p_xy, real_t p_yx, real_t p_yy, real_t p_ox, real_t p_oy) {
columns[0][0] = p_xx;
columns[0][1] = p_xy;
columns[1][0] = p_yx;
columns[1][1] = p_yy;
columns[2][0] = p_ox;
columns[2][1] = p_oy;
}
Transform2D(const Vector2 &p_x, const Vector2 &p_y, const Vector2 &p_origin) {
@@ -138,9 +143,9 @@ struct _NO_DISCARD_ Transform2D {
columns[2] = p_origin;
}
Transform2D(const real_t p_rot, const Vector2 &p_pos);
Transform2D(real_t p_rot, const Vector2 &p_pos);
Transform2D(const real_t p_rot, const Size2 &p_scale, const real_t p_skew, const Vector2 &p_pos);
Transform2D(real_t p_rot, const Size2 &p_scale, real_t p_skew, const Vector2 &p_pos);
Transform2D() {
columns[0][0] = 1.0;
@@ -188,14 +193,14 @@ Rect2 Transform2D::xform(const Rect2 &p_rect) const {
return new_rect;
}
void Transform2D::set_rotation_and_scale(const real_t p_rot, const Size2 &p_scale) {
void Transform2D::set_rotation_and_scale(real_t p_rot, const Size2 &p_scale) {
columns[0][0] = Math::cos(p_rot) * p_scale.x;
columns[1][1] = Math::cos(p_rot) * p_scale.y;
columns[1][0] = -Math::sin(p_rot) * p_scale.y;
columns[0][1] = Math::sin(p_rot) * p_scale.x;
}
void Transform2D::set_rotation_scale_and_skew(const real_t p_rot, const Size2 &p_scale, const real_t p_skew) {
void Transform2D::set_rotation_scale_and_skew(real_t p_rot, const Size2 &p_scale, real_t p_skew) {
columns[0][0] = Math::cos(p_rot) * p_scale.x;
columns[1][1] = Math::cos(p_rot + p_skew) * p_scale.y;
columns[1][0] = -Math::sin(p_rot + p_skew) * p_scale.y;
@@ -246,5 +251,3 @@ PackedVector2Array Transform2D::xform_inv(const PackedVector2Array &p_array) con
}
} // namespace godot
#endif // GODOT_TRANSFORM2D_HPP

View File

@@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_TRANSFORM3D_HPP
#define GODOT_TRANSFORM3D_HPP
#pragma once
#include <godot_cpp/core/math.hpp>
#include <godot_cpp/variant/aabb.hpp>
@@ -39,7 +38,7 @@
namespace godot {
struct _NO_DISCARD_ Transform3D {
struct [[nodiscard]] Transform3D {
Basis basis;
Vector3 origin;
@@ -55,8 +54,8 @@ struct _NO_DISCARD_ Transform3D {
void rotate(const Vector3 &p_axis, real_t p_angle);
void rotate_basis(const Vector3 &p_axis, real_t p_angle);
void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0));
Transform3D looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)) const;
void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false);
Transform3D looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false) const;
void scale(const Vector3 &p_scale);
Transform3D scaled(const Vector3 &p_scale) const;
@@ -78,6 +77,7 @@ struct _NO_DISCARD_ Transform3D {
void orthogonalize();
Transform3D orthogonalized() const;
bool is_equal_approx(const Transform3D &p_transform) const;
bool is_finite() const;
bool operator==(const Transform3D &p_transform) const;
bool operator!=(const Transform3D &p_transform) const;
@@ -104,8 +104,10 @@ struct _NO_DISCARD_ Transform3D {
void operator*=(const Transform3D &p_transform);
Transform3D operator*(const Transform3D &p_transform) const;
void operator*=(const real_t p_val);
Transform3D operator*(const real_t p_val) const;
void operator*=(real_t p_val);
Transform3D operator*(real_t p_val) const;
void operator/=(real_t p_val);
Transform3D operator/(real_t p_val) const;
Transform3D interpolate_with(const Transform3D &p_transform, real_t p_c) const;
@@ -115,11 +117,11 @@ struct _NO_DISCARD_ Transform3D {
basis.xform(v));
}
void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t tx, real_t ty, real_t tz) {
basis.set(xx, xy, xz, yx, yy, yz, zx, zy, zz);
origin.x = tx;
origin.y = ty;
origin.z = tz;
void set(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_tx, real_t p_ty, real_t p_tz) {
basis.set(p_xx, p_xy, p_xz, p_yx, p_yy, p_yz, p_zx, p_zy, p_zz);
origin.x = p_tx;
origin.y = p_ty;
origin.z = p_tz;
}
operator String() const;
@@ -127,7 +129,7 @@ struct _NO_DISCARD_ Transform3D {
Transform3D() {}
Transform3D(const Basis &p_basis, const Vector3 &p_origin = Vector3());
Transform3D(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin);
Transform3D(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz);
Transform3D(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_ox, real_t p_oy, real_t p_oz);
};
_FORCE_INLINE_ Vector3 Transform3D::xform(const Vector3 &p_vector) const {
@@ -271,5 +273,3 @@ _FORCE_INLINE_ Plane Transform3D::xform_inv_fast(const Plane &p_plane, const Tra
}
} // namespace godot
#endif // GODOT_TRANSFORM3D_HPP

View File

@@ -28,15 +28,14 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_TYPED_ARRAY_HPP
#define GODOT_TYPED_ARRAY_HPP
#pragma once
#include <godot_cpp/variant/array.hpp>
#include <godot_cpp/variant/variant.hpp>
namespace godot {
template <class T>
template <typename T>
class TypedArray : public Array {
public:
_FORCE_INLINE_ void operator=(const Array &p_array) {
@@ -44,11 +43,18 @@ public:
_ref(p_array);
}
_FORCE_INLINE_ TypedArray(const Variant &p_variant) :
Array(p_variant.operator Array(), Variant::OBJECT, T::get_class_static(), Variant()) {
TypedArray(Array(p_variant)) {
}
_FORCE_INLINE_ TypedArray(const Array &p_array) :
Array(p_array, Variant::OBJECT, T::get_class_static(), Variant()) {
_FORCE_INLINE_ TypedArray(const Array &p_array) {
set_typed(Variant::OBJECT, T::get_class_static(), Variant());
if (is_same_typed(p_array)) {
_ref(p_array);
} else {
assign(p_array);
}
}
_FORCE_INLINE_ TypedArray(std::initializer_list<Variant> p_init) :
TypedArray(Array(p_init)) {}
_FORCE_INLINE_ TypedArray() {
set_typed(Variant::OBJECT, T::get_class_static(), Variant());
}
@@ -64,17 +70,27 @@ public:
ERR_FAIL_COND_MSG(!is_same_typed(p_array), "Cannot assign an array with a different element type."); \
_ref(p_array); \
} \
_FORCE_INLINE_ TypedArray(const Variant &p_variant) : \
Array(p_variant.operator Array(), m_variant_type, StringName(), Variant()) { \
_FORCE_INLINE_ TypedArray(std::initializer_list<Variant> p_init) : \
Array(Array(p_init), m_variant_type, StringName(), Variant()) { \
} \
_FORCE_INLINE_ TypedArray(const Array &p_array) : \
Array(p_array, m_variant_type, StringName(), Variant()) { \
_FORCE_INLINE_ TypedArray(const Variant &p_variant) : \
TypedArray(Array(p_variant)) { \
} \
_FORCE_INLINE_ TypedArray(const Array &p_array) { \
set_typed(m_variant_type, StringName(), Variant()); \
if (is_same_typed(p_array)) { \
_ref(p_array); \
} else { \
assign(p_array); \
} \
} \
_FORCE_INLINE_ TypedArray() { \
set_typed(m_variant_type, StringName(), Variant()); \
} \
};
// All Variant::OBJECT types are intentionally omitted from this list because they are handled by
// the unspecialized TypedArray definition.
MAKE_TYPED_ARRAY(bool, Variant::BOOL)
MAKE_TYPED_ARRAY(uint8_t, Variant::INT)
MAKE_TYPED_ARRAY(int8_t, Variant::INT)
@@ -94,11 +110,14 @@ MAKE_TYPED_ARRAY(Rect2i, Variant::RECT2I)
MAKE_TYPED_ARRAY(Vector3, Variant::VECTOR3)
MAKE_TYPED_ARRAY(Vector3i, Variant::VECTOR3I)
MAKE_TYPED_ARRAY(Transform2D, Variant::TRANSFORM2D)
MAKE_TYPED_ARRAY(Vector4, Variant::VECTOR4)
MAKE_TYPED_ARRAY(Vector4i, Variant::VECTOR4I)
MAKE_TYPED_ARRAY(Plane, Variant::PLANE)
MAKE_TYPED_ARRAY(Quaternion, Variant::QUATERNION)
MAKE_TYPED_ARRAY(AABB, Variant::AABB)
MAKE_TYPED_ARRAY(Basis, Variant::BASIS)
MAKE_TYPED_ARRAY(Transform3D, Variant::TRANSFORM3D)
MAKE_TYPED_ARRAY(Projection, Variant::PROJECTION)
MAKE_TYPED_ARRAY(Color, Variant::COLOR)
MAKE_TYPED_ARRAY(StringName, Variant::STRING_NAME)
MAKE_TYPED_ARRAY(NodePath, Variant::NODE_PATH)
@@ -115,8 +134,11 @@ MAKE_TYPED_ARRAY(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY)
MAKE_TYPED_ARRAY(PackedStringArray, Variant::PACKED_STRING_ARRAY)
MAKE_TYPED_ARRAY(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY)
MAKE_TYPED_ARRAY(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPED_ARRAY(PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY)
MAKE_TYPED_ARRAY(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
// If the IPAddress struct is added to godot-cpp, the following could also be added:
//MAKE_TYPED_ARRAY(IPAddress, Variant::STRING)
#undef MAKE_TYPED_ARRAY
} // namespace godot
#endif // GODOT_TYPED_ARRAY_HPP

View File

@@ -0,0 +1,465 @@
/**************************************************************************/
/* 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. */
/**************************************************************************/
#pragma once
#include <godot_cpp/core/type_info.hpp>
#include <godot_cpp/templates/pair.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());
}
_FORCE_INLINE_ TypedDictionary(std::initializer_list<KeyValue<K, V>> p_init) :
Dictionary() {
set_typed(Variant::OBJECT, K::get_class_static(), Variant(), Variant::OBJECT, V::get_class_static(), Variant());
for (const KeyValue<K, V> &E : p_init) {
operator[](E.key) = E.value;
}
}
};
//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()); \
} \
_FORCE_INLINE_ TypedDictionary(std::initializer_list<KeyValue<T, m_type>> p_init) : \
Dictionary() { \
set_typed(Variant::OBJECT, T::get_class_static(), Variant(), m_variant_type, StringName(), Variant()); \
for (const KeyValue<T, m_type> &E : p_init) { \
operator[](E.key) = E.value; \
} \
} \
}; \
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()); \
} \
_FORCE_INLINE_ TypedDictionary(std::initializer_list<KeyValue<m_type, T>> p_init) : \
Dictionary() { \
set_typed(m_variant_type, StringName(), Variant(), Variant::OBJECT, std::remove_pointer<T>::type::get_class_static(), Variant()); \
for (const KeyValue<m_type, T> &E : p_init) { \
operator[](E.key) = E.value; \
} \
} \
};
#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()); \
} \
_FORCE_INLINE_ TypedDictionary(std::initializer_list<KeyValue<m_type_key, m_type_value>> p_init) : \
Dictionary() { \
set_typed(m_variant_type_key, StringName(), Variant(), m_variant_type_value, StringName(), Variant()); \
for (const KeyValue<m_type_key, m_type_value> &E : p_init) { \
operator[](E.key) = E.value; \
} \
} \
};
#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

View File

@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_VARIANT_HPP
#define GODOT_VARIANT_HPP
#pragma once
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/variant/array.hpp>
#include <godot_cpp/variant/builtin_types.hpp>
#include <godot_cpp/variant/variant_size.hpp>
@@ -47,10 +47,9 @@ class ObjectID;
class Variant {
uint8_t opaque[GODOT_CPP_VARIANT_SIZE]{ 0 };
_FORCE_INLINE_ GDExtensionVariantPtr _native_ptr() const { return const_cast<uint8_t(*)[GODOT_CPP_VARIANT_SIZE]>(&opaque); }
friend class GDExtensionBinding;
friend class MethodBind;
friend class VariantInternal;
static void init_bindings();
@@ -102,6 +101,7 @@ public:
PACKED_VECTOR2_ARRAY,
PACKED_VECTOR3_ARRAY,
PACKED_COLOR_ARRAY,
PACKED_VECTOR4_ARRAY,
VARIANT_MAX
};
@@ -122,6 +122,7 @@ public:
OP_NEGATE,
OP_POSITIVE,
OP_MODULE,
OP_POWER,
// bitwise
OP_SHIFT_LEFT,
OP_SHIFT_RIGHT,
@@ -144,6 +145,7 @@ private:
static GDExtensionTypeFromVariantConstructorFunc to_type_constructor[VARIANT_MAX];
public:
_FORCE_INLINE_ GDExtensionVariantPtr _native_ptr() const { return const_cast<uint8_t (*)[GODOT_CPP_VARIANT_SIZE]>(&opaque); }
Variant();
Variant(std::nullptr_t n) :
Variant() {}
@@ -154,10 +156,18 @@ public:
Variant(int64_t v);
Variant(int32_t v) :
Variant(static_cast<int64_t>(v)) {}
Variant(uint32_t v) :
Variant(int16_t v) :
Variant(static_cast<int64_t>(v)) {}
Variant(int8_t v) :
Variant(static_cast<int64_t>(v)) {}
Variant(uint64_t v) :
Variant(static_cast<int64_t>(v)) {}
Variant(uint32_t v) :
Variant(static_cast<int64_t>(v)) {}
Variant(uint16_t v) :
Variant(static_cast<int64_t>(v)) {}
Variant(uint8_t v) :
Variant(static_cast<int64_t>(v)) {}
Variant(double v);
Variant(float v) :
Variant((double)v) {}
@@ -204,13 +214,18 @@ public:
Variant(const PackedVector2Array &v);
Variant(const PackedVector3Array &v);
Variant(const PackedColorArray &v);
Variant(const PackedVector4Array &v);
~Variant();
operator bool() const;
operator int64_t() const;
operator int32_t() const;
operator int16_t() const;
operator int8_t() const;
operator uint64_t() const;
operator uint32_t() const;
operator uint16_t() const;
operator uint8_t() const;
operator double() const;
operator float() const;
operator String() const;
@@ -248,6 +263,9 @@ public:
operator PackedVector2Array() const;
operator PackedVector3Array() const;
operator PackedColorArray() const;
operator PackedVector4Array() const;
Object *get_validated_object() const;
Variant &operator=(const Variant &other);
Variant &operator=(Variant &&other);
@@ -255,25 +273,33 @@ public:
bool operator!=(const Variant &other) const;
bool operator<(const Variant &other) const;
void call(const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error);
void callp(const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error);
template <class... Args>
template <typename... Args>
Variant call(const StringName &method, Args... args) {
std::array<Variant, sizeof...(args)> vargs = { args... };
std::array<const Variant *, sizeof...(args)> argptrs;
for (size_t i = 0; i < vargs.size(); i++) {
argptrs[i] = &vargs[i];
}
Variant result;
GDExtensionCallError error;
std::array<GDExtensionConstVariantPtr, sizeof...(Args)> call_args = { Variant(args)... };
call(method, call_args.data(), call_args.size(), result, error);
callp(method, argptrs.data(), argptrs.size(), result, error);
return result;
}
static void call_static(Variant::Type type, const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error);
static void callp_static(Variant::Type type, const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error);
template <class... Args>
template <typename... Args>
static Variant call_static(Variant::Type type, const StringName &method, Args... args) {
std::array<Variant, sizeof...(args)> vargs = { args... };
std::array<const Variant *, sizeof...(args)> argptrs;
for (size_t i = 0; i < vargs.size(); i++) {
argptrs[i] = &vargs[i];
}
Variant result;
GDExtensionCallError error;
std::array<GDExtensionConstVariantPtr, sizeof...(Args)> call_args = { Variant(args)... };
call_static(type, method, call_args.data(), call_args.size(), result, error);
callp_static(type, method, argptrs.data(), argptrs.size(), sizeof...(args), result, error);
return result;
}
@@ -304,8 +330,6 @@ public:
bool booleanize() const;
String stringify() const;
Variant duplicate(bool deep = false) const;
static void blend(const Variant &a, const Variant &b, float c, Variant &r_dst);
static void interpolate(const Variant &a, const Variant &b, float c, Variant &r_dst);
static String get_type_name(Variant::Type type);
static bool can_convert(Variant::Type from, Variant::Type to);
@@ -334,6 +358,72 @@ String vformat(const String &p_text, const VarArgs... p_args) {
return p_text % args_array;
}
} // namespace godot
Variant &Array::Iterator::operator*() const {
return *elem_ptr;
}
#endif // GODOT_VARIANT_HPP
Variant *Array::Iterator::operator->() const {
return elem_ptr;
}
Array::Iterator &Array::Iterator::operator++() {
elem_ptr++;
return *this;
}
Array::Iterator &Array::Iterator::operator--() {
elem_ptr--;
return *this;
}
const Variant &Array::ConstIterator::operator*() const {
return *elem_ptr;
}
const Variant *Array::ConstIterator::operator->() const {
return elem_ptr;
}
Array::ConstIterator &Array::ConstIterator::operator++() {
elem_ptr++;
return *this;
}
Array::ConstIterator &Array::ConstIterator::operator--() {
elem_ptr--;
return *this;
}
Array::Iterator Array::begin() {
return Array::Iterator(ptrw());
}
Array::Iterator Array::end() {
return Array::Iterator(ptrw() + size());
}
Array::ConstIterator Array::begin() const {
return Array::ConstIterator(ptr());
}
Array::ConstIterator Array::end() const {
return Array::ConstIterator(ptr() + size());
}
Array::Array(std::initializer_list<Variant> p_init) :
Array() {
ERR_FAIL_COND(resize(p_init.size()) != 0);
size_t i = 0;
for (const Variant &element : p_init) {
set(i++, element);
}
}
#include <godot_cpp/variant/builtin_vararg_methods.hpp>
#ifdef REAL_T_IS_DOUBLE
using PackedRealArray = PackedFloat64Array;
#else
using PackedRealArray = PackedFloat32Array;
#endif // REAL_T_IS_DOUBLE
} // namespace godot

View File

@@ -0,0 +1,506 @@
/**************************************************************************/
/* 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. */
/**************************************************************************/
#pragma once
#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

Some files were not shown because too many files have changed in this diff Show More