Compare commits

...

132 Commits

Author SHA1 Message Date
David Snopek
4d5d707d60 Merge pull request #1572 from dsnopek/4.1-cherrypicks-13
Cherry-picks for the godot-cpp 4.1 branch - 13th batch
2024-09-11 17:15:09 -05:00
George L. Albany
fad74366cd Fix GCC 14 -Wtemplate-id-cdtor warning
As was fixed with godotengine/godot#91208

(cherry picked from commit 7b31f39bea)
2024-09-04 10:16:26 -05:00
Fabio Alessandrelli
d421c98461 [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.

(cherry picked from commit f36acd8e31)
2024-09-04 10:16:17 -05:00
Aaron Franke
592a7762cd [4.2] Fix missing MAKE_TYPED_ARRAY_INFO for Packed*Arrays
(cherry picked from commit a0d56336c3)
2024-09-04 10:16:01 -05:00
Mikael Hermansson
76c0a4b4ae Fix incorrect generation of some C++ operators
(cherry picked from commit 9949d09f3e)
2024-09-04 10:13:33 -05:00
Raul Santos
67145b323b 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.

(cherry picked from commit 4829199081)
2024-09-04 10:13:23 -05:00
Klaim (Joël Lamotte)
d529fc5b69 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.

(cherry picked from commit 738859f49b)
2024-09-04 10:10:04 -05:00
Chris Cranford
9a4ba00b0e Make sure _get and _set dispatch up the class hierarchy
(cherry picked from commit c77d44f3f6)
2024-09-04 10:09:27 -05:00
Rémi Verschelde
bc6cfd70d8 SCons: Remove old Python 2 compat code
(cherry picked from commit 958776dfc3)
2024-09-04 10:09:15 -05:00
A Thousand Ships
09b735ac97 [CI] Upload build cache before running tests
(cherry picked from commit 76b38de01a)
2024-09-04 10:03:23 -05:00
Fabio Alessandrelli
9e860a84a0 [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.

(cherry picked from commit 1bb543b6f4)
2024-09-04 10:03:13 -05:00
Fabio Alessandrelli
9b4c5f0562 [SCons] Add option to build without threads
This is relevant for the Web platform, where builds with and without
threads are incompatible.

(cherry picked from commit b0296bb562)
2024-09-04 09:58:58 -05:00
David Snopek
a4f9d22ac5 Merge pull request #1529 from dsnopek/4.1-cherrypicks-12
Cherry-picks for the godot-cpp 4.1 branch - 12th batch
2024-07-17 12:28:25 -05:00
A Thousand Ships
7dd2d24805 Fix sharing of typed arrays from constructor
(cherry picked from commit 41aa71f8c3)
2024-07-17 09:58:09 -05:00
Yuri Sizov
18b81efbf3 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.

(cherry picked from commit 2b34bd0d8b)
2024-07-17 09:57:10 -05:00
Thaddeus Crews
430637bf1a SCons: Add silence_msvc option
(cherry picked from commit 1989b1bf57)
2024-07-17 09:57:01 -05:00
Thaddeus Crews
ca26922a19 Integrate .pre-commit-config.yaml
(cherry picked from commit e0d363aad8)
2024-07-17 09:56:32 -05:00
Thaddeus Crews
edce0b7178 Fix #include formatting
(cherry picked from commit 999018e7d1)
2024-07-17 09:53:29 -05:00
Thaddeus Crews
23325b9ab0 Add .editorconfig, consolidate .gitattributes
(cherry picked from commit 7a96d0314e)
2024-07-17 09:53:19 -05:00
Fabio Alessandrelli
208b70dbef [CI] Update macOS workers to macos-latest
GitHub actions no longer allow `macos-11` runners

(cherry picked from commit 2dd8917508)
2024-07-17 09:53:07 -05:00
A Thousand Ships
1f57a8d76e Fix some style details in generation
(cherry picked from commit e7a13e3bf4)
2024-07-17 09:48:31 -05:00
A Thousand Ships
f16814ee05 Enforce p_ prefixes for arguments in binds
(cherry picked from commit 9e2771f918)
2024-07-17 09:37:59 -05:00
Fabio Alessandrelli
22beef8cbc Add support for build profiles.
Allow enabling or disabling specific classes (which will not be built).

(cherry picked from commit 1186c488bd)
2024-07-17 09:34:07 -05:00
David Snopek
2e7f5512d1 Merge pull request #1491 from dsnopek/4.1-cherrypicks-11
Cherry-picks for the godot-cpp 4.1 branch - 11th batch
2024-06-14 13:32:54 -05:00
David Snopek
5880be034c [4.1] Allow selecting Godot version to run the tests with
(cherry picked from commit f88b6a2f00)
2024-06-14 11:44:39 -05:00
A Thousand Ships
a648650c5d Add default argument processing for NodePath
(cherry picked from commit 37e7a6da05)
2024-06-14 10:40:04 -05:00
A Thousand Ships
65058828a6 Fix generating default values for StringName
Cases other than `&""` were not processed correctly

(cherry picked from commit 6cd6c8923a)
2024-06-14 10:38:34 -05:00
David Snopek
f067a9bff0 Fix vararg methods forwarded to the ClassDB singleton
(cherry picked from commit e04a26b2bc)
2024-06-14 10:37:44 -05:00
Richard Hozák
6ba31a1800 Fix warnings emitted with -Wall
(cherry picked from commit 8c6cc1ec15)
2024-06-14 10:37:27 -05:00
David Snopek
8269c0102a Explicitly refer to godot namespace in GDREGISTER_*_CLASS() macros
(cherry picked from commit 246a803954)
2024-06-14 10:31:04 -05:00
DmitriySalnikov
5f864cd8de [Scons] Added the ability to change the visibility of symbols
(cherry picked from commit f5e4f95cde)
2024-06-14 10:28:30 -05:00
David Snopek
32becf6a13 Merge pull request #1466 from dsnopek/4.1-cherrypicks-10
Cherry-picks for the godot-cpp 4.1 branch - 10th batch
2024-05-28 08:35:20 -05:00
David Snopek
7b93607779 Fix NOTIFICATION_POSTINITIALIZE sent twice to native parent class
(cherry picked from commit 06373ce1cf)
2024-05-17 17:11:27 -05:00
Daylily-Zeleen
1ab42ec6c5 mark return value of get_class_static and get_parent_class_static as const
(cherry picked from commit 3db8549e19)
2024-05-17 16:58:32 -05:00
David Snopek
6328728dc2 Allow forwarding from ClassDB to ClassDBSingleton to support enumerations
(cherry picked from commit e1b3b32db5)
2024-05-17 16:57:33 -05:00
David Snopek
6123c86f06 Correctly handle Object * arguments that were encoded as nullptr
(cherry picked from commit 37542dc2ec)
2024-05-17 16:56:37 -05:00
David Snopek
fff665e0f5 Give compile-time error if registering a class without its own _bind_methods() function
(cherry picked from commit ca46ef4d25)
2024-05-17 16:55:41 -05:00
pupil1337
82ea3f74a4 Add static_assert() for register_class
(cherry picked from commit 1fa7a9cb19)
2024-05-17 16:54:44 -05:00
A Thousand Ships
11cd9a0727 [Math] Add is_finite methods
(cherry picked from commit d389171905)
2024-05-17 16:54:00 -05:00
Chris Cranford
a75e33c333 Implement to/from dict helpers for PropertyInfo/MethodInfo
(cherry picked from commit 2a041b5240)
2024-05-17 16:53:43 -05:00
David Snopek
d24983d682 Backport miscellaneous changes that can't be cherry-picked
(cherry picked from commit 9afbdb9cf6)
2024-05-17 16:51:42 -05:00
David Snopek
4b0ee13327 gdextension: Sync with upstream commit fe0e8e55752b0c2e64997025717b491703e0f8ad (4.1.4-stable) 2024-04-17 13:02:32 -05:00
David Snopek
e4978558e6 Merge pull request #1441 from dsnopek/4.1-cherrypicks-9
Cherry-picks for the godot-cpp 4.1 branch - 9th batch
2024-04-17 12:58:30 -05:00
Chris Cranford
30ebe5fdf9 Fix PropertyInfo to use hint/usage default constants
(cherry picked from commit e160966163)
2024-04-17 11:01:33 -05:00
thimenesup
e897dbe58a Fix Projection create_orthogonal being incorrect
Title

(cherry picked from commit e4ae69f607)
2024-04-17 11:00:56 -05:00
Thaddeus Crews
28a6609c0b Implement verbose toggle from godot repo
(cherry picked from commit b05c21bb1d)
2024-04-17 10:58:41 -05:00
dependabot[bot]
7f3e725a8a 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>
(cherry picked from commit 32ca574f49)
2024-04-17 10:58:31 -05:00
Thaddeus Crews
8e5d7c9268 Use GDREGISTER defines in example
(cherry picked from commit a537b4af4d)
2024-04-17 10:58:16 -05:00
David Snopek
974e6c6f86 Merge pull request #1411 from dsnopek/4.1-cherrypicks-8
Cherry-picks for the godot-cpp 4.1 branch - 8th batch
2024-04-08 13:09:01 -05:00
A Thousand Ships
c8fa4c0fd0 Fix incorrect utility call signature
(cherry picked from commit d055b575fb)
2024-04-08 11:40:05 -05:00
ytnuf
594a93f8ac 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

(cherry picked from commit 5c12bd2287)
2024-04-08 11:39:53 -05:00
Thaddeus Crews
9e48c45bfc Enforce template syntax typename over class
(cherry picked from commit 87f5fb0691)
2024-04-08 11:39:21 -05:00
David Snopek
76d6ce7136 Avoid creating most objects that Godot is going to use placement new to initialize
(cherry picked from commit c4fde852e6)
2024-04-08 11:30:23 -05:00
bruvzg
e99d7b3b7e [Packed*Array] Add support for initializer lists.
(cherry picked from commit 8c98a90f32)
2024-04-08 11:29:39 -05:00
A Thousand Ships
07e245e3e4 Fix invalid void return in BitField
(cherry picked from commit 7ed8ef7221)
2024-03-11 13:33:57 -05:00
Marc Gilleron
ed576f8318 Fix explicit namespaces in macros
(cherry picked from commit e607790647)
2024-03-11 13:33:44 -05:00
David Snopek
f7a9d32f32 Fix _notification with parent and child classes
(cherry picked from commit 23c010900c)
2024-03-11 13:31:19 -05:00
bruvzg
08da55cd0b [Core] Improve CowData and Memory metadata alignment.
(cherry picked from commit b173a4d935)
2024-03-11 13:11:26 -05:00
Fabio Alessandrelli
670c4d0eac [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`.

(cherry picked from commit 16df4bff30)
2024-03-11 13:06:57 -05:00
Fabio Alessandrelli
bab62a4d72 [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/`)

(cherry picked from commit baaad7ada2)
2024-03-11 13:01:23 -05:00
DaylilyZeleen
1ac8627b2e Fix object return value of builtin types' methods.
(cherry picked from commit 6a3753c076)
2024-03-11 12:59:32 -05:00
bruvzg
6202bf141e Switch to 64-bit ints.
(cherry picked from commit 59a5a8b104)
2024-03-11 12:59:19 -05:00
David Snopek
4b63d795e4 Merge pull request #1373 from dsnopek/4.1-cherrypicks-7
Cherry-picks for the godot-cpp 4.1 branch - 7th batch
2024-02-16 09:37:17 -06:00
MJacred
2cc967787a Update README: fix godot-cpp issue tracker url
(cherry picked from commit 8a535d0ecc)
2024-01-24 08:44:28 -06:00
nightblade9
6884ca9be0 Update README.md with basic pre-requisites
(cherry picked from commit ee169b201b)
2024-01-22 15:53:49 -06:00
Daylily-Zeleen
dde0bbb93d Remove "godot" namespace when binding global constants.
(cherry picked from commit bd40a94424)
2024-01-22 15:53:49 -06:00
A Thousand Ships
1c03aa7746 Add missing OP_POWER operator to Variant
(cherry picked from commit f037a697eb)
2024-01-22 15:53:49 -06:00
ArchLinus
82475b215b Add an error message if android NDK is not installed
(cherry picked from commit 718d0baea3)
2024-01-22 15:53:49 -06:00
Aaron Franke
49098fbdc7 Allow detecting when building as a GDExtension
(cherry picked from commit e17c7bf530)
2024-01-22 15:53:49 -06:00
dependabot[bot]
756190705e 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>
(cherry picked from commit a7becb43e6)
2024-01-22 15:53:49 -06:00
Rémi Verschelde
2e42c7020e 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.

(cherry picked from commit 41517eacb1)
2024-01-22 15:53:49 -06:00
David Snopek
e9273e8528 Avoid error from -Werror=type-limits on GCC 11
(cherry picked from commit cad5be53b1)
2024-01-22 15:53:49 -06:00
David Snopek
b1bd58d7da Send NOTIFICATION_POSTINITIALIZE to extension classes
(cherry picked from commit 20c4e843b0)
2024-01-22 15:53:49 -06:00
LAK132
d5a2e8e797 Fix file list issues when trying to build with meson via cmake
(cherry picked from commit 39c139c814)
2024-01-22 15:53:49 -06:00
Bytzo
6bb4b1d321 Prevent CMake from always including debug symbols
(cherry picked from commit db884e9b1d)
2024-01-22 15:53:49 -06:00
DmitriySalnikov
51aeda7437 [Scons] Set the minimum Android API level to 21
(cherry picked from commit 79d2a9c456)
2024-01-22 15:53:49 -06:00
dependabot[bot]
cd904155a8 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>
(cherry picked from commit 78bf5a42ed)
2024-01-22 15:53:49 -06:00
bruvzg
b622b11df3 [iOS] Fix initialisation/termination of multiple statically linked extensions.
(cherry picked from commit adc9def046)
2024-01-22 15:53:49 -06:00
Rémi Verschelde
92449b46e1 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.

(cherry picked from commit eea33b4133)
2024-01-22 15:53:49 -06:00
Thaddeus Crews
e8b6887b36 Add missing int→Variant conversions
(cherry picked from commit bcac96c8c2)
2024-01-22 15:53:49 -06:00
Rémi Verschelde
631cd5fe37 Merge pull request #1306 from dsnopek/4.1-cherrypicks-6
Cherry-picks for the godot-cpp 4.1 branch - 6th batch
2023-11-13 20:28:26 +01:00
Alex Drozd
731a10a4ea ignoring venv in .gitignore
(cherry picked from commit 92dd34ae96)
2023-11-13 13:00:24 -06:00
Thaddeus Crews
a1ae58448c fix is_msvc and use_hot_reload variables
(cherry picked from commit 648b8c4489)
2023-11-13 13:00:24 -06:00
Thaddeus Crews
805cdde0b7 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

(cherry picked from commit 6eb5d450bd)
2023-11-13 13:00:24 -06:00
Fredia Huya-Kouadio
29335d8f5c Update the environment variables used to access the Android NDK toolchain
(cherry picked from commit 86dbd5fa0d)
2023-11-13 13:00:24 -06:00
Rémi Verschelde
c5f47b2a4e 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.

(cherry picked from commit 306774b5a4)
2023-11-13 19:15:07 +01:00
Rémi Verschelde
df5b1a9a69 gdextension: Sync with upstream commit fc79201851a16215f9554884aa242ed957801b10 (4.1.3-stable) 2023-11-09 13:25:22 +01:00
Rémi Verschelde
04b34077d8 Merge pull request #1281 from dsnopek/4.1-cherrypicks-5
Cherry-picks for the godot-cpp 4.1 branch - 5th batch
2023-10-24 11:38:55 +02:00
David Snopek
9d813310bb Add protections against registering classes that didn't use GDCLASS()
(cherry picked from commit a61cdc8860)
2023-10-23 10:11:04 -05:00
Rémi Verschelde
ef8a499eac SCons: Disable C++ exception handling by default
Counterpart to https://github.com/godotengine/godot/pull/80612.

(cherry picked from commit bf1c03ab5f)
2023-10-23 10:10:59 -05:00
gilzoide
698da13d66 Fix return value and r_valid value in Variant::iter_init and iter_next
(cherry picked from commit 60dfa3445a)
2023-10-22 14:47:10 -05:00
Adam Scott
8295486fdb 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.

(cherry picked from commit 2d5024ac8e)
2023-10-22 14:46:58 -05:00
Thaddeus Crews
7704a9d054 Let gdextension_dir function as only argument
(cherry picked from commit 7a5cbcac21)
2023-10-22 14:46:48 -05:00
David Snopek
f7ffc4fe4d Automatically register only engine classes whose header has been included
(cherry picked from commit b507b3e591)
2023-10-22 14:46:26 -05:00
Fabio Alessandrelli
62cb5eac47 [SCons] Rename javascript tool to web
And clean it up a bit.

(cherry picked from commit 18bfa133ab)
2023-10-22 14:03:20 -05:00
Mikael Hermansson
03ea717742 Declare explicit specializations for CharStringT
(cherry picked from commit 6e05b978b8)
2023-10-22 14:03:10 -05:00
Rémi Verschelde
e389f7a50c Merge pull request #1261 from dsnopek/4.1-cherrypicks-4
Cherry-picks for the godot-cpp 4.1 branch - 4th batch
2023-10-12 18:08:12 +02:00
Nick Maltbie
0b1c8bcac3 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.

(cherry picked from commit 2b4bcbb0ce)
2023-10-09 08:43:36 -05:00
Matthew Murphy
857d8e3a56 Fix variant call compiler error
Co-authored-by: David Snopek <dsnopek@gmail.com>
(cherry picked from commit ca3e25de04)
2023-10-09 08:43:23 -05:00
David Snopek
ec6e51b3a4 Handle missing instance binding callbacks by finding the closest parent
(cherry picked from commit 52ca3ef547)
2023-10-09 08:42:55 -05:00
Adam Scott
f8054cca80 Add support to import custom variables from parent SConstruct (redux)
(cherry picked from commit 982e01ec7f)
2023-10-09 08:42:43 -05:00
A Thousand Ships
59ebcfd744 Fix allocation size overflow check in CowData
(cherry picked from commit 06ffc7e952)
2023-10-09 08:42:31 -05:00
A Thousand Ships
205beacc5b Replace ERR_FAIL_COND with ERR_FAIL_NULL where applicable
(cherry picked from commit 1e5767693e)
2023-10-09 08:42:16 -05:00
Rémi Verschelde
3b3f357de9 CI: Fix MinGW install error by pinning to earlier version
Works around https://github.com/egor-tensin/setup-mingw/issues/14.

(cherry picked from commit 0369f6fea0)
2023-10-04 15:21:01 +02:00
Rémi Verschelde
48b92acf8c gdextension: Sync with upstream commit 399c9dc393f6f84c0b4e4d4117906c70c048ecf2 (4.1.2-stable) 2023-10-04 12:02:54 +02:00
Rémi Verschelde
4eed2d7be0 Merge pull request #1244 from dsnopek/4.1-cherrypicks-3
Cherry-picks for the godot-cpp 4.1 branch - 3rd batch
2023-09-20 23:48:26 +02:00
David Snopek
bc82ae8b0b Add static methods to ClassDB for the methods bound to the ClassDB singleton
(cherry picked from commit 6f913563d8)
2023-09-19 21:30:03 -05:00
David Snopek
590e267902 Load 'print_error_with_message' function
(cherry picked from commit 634ed09ec0)
2023-09-19 21:29:29 -05:00
David Snopek
3be7ec4162 Check that GDExtension is opened by compatible Godot version
(cherry picked from commit fecb2959b4)
2023-09-19 21:27:40 -05:00
DmitriySalnikov
dd8e1def67 [SCons] Fixed crashes in several scripts
(cherry picked from commit 0e5975dd26)
2023-09-19 21:23:20 -05:00
David Snopek
dcd7a69512 Ensure that PtrToArg specializations for native structs are used
(cherry picked from commit 3cd3f24150)
2023-09-19 21:22:54 -05:00
dependabot[bot]
354ed1e79d 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>
(cherry picked from commit 5d4ff63930)
2023-09-19 21:22:20 -05:00
A Thousand Ships
014132d4c0 Ensure const correctness for wrappers
(cherry picked from commit f651df5e7a)
2023-09-19 21:21:20 -05:00
David Snopek
bc980b59ff Merge pull request #1227 from dsnopek/4.1-cherrypicks-2
Cherry-picks for the godot-cpp 4.1 branch - 2nd batch
2023-09-02 12:38:20 -05:00
A Thousand Ships
c3771fb065 Fix formatting of compatibility_minimum examples
Without quotes the values is parsed as a float, breaking in various
cases.

(cherry picked from commit b3596a18e1)
2023-09-01 17:08:03 -05:00
Fabio Alessandrelli
63755b2a32 [SCons] Move the GodotCPP build to its own tool.
(cherry picked from commit f8b4f60cb9)
2023-09-01 17:07:53 -05:00
David Snopek
ce5dd378d9 Clarify versions and examples in the README
(cherry picked from commit 1588dc8437)
2023-09-01 17:07:41 -05:00
A Thousand Ships
c6fe6533f9 Fix link to test project in readme
Also updated format for library paths

(cherry picked from commit e586e11637)
2023-09-01 17:07:30 -05:00
A Thousand Ships
170a691a7e Add remaining component-wise min/max functions to Vector*
(cherry picked from commit 52eb77efd4)
2023-09-01 17:07:18 -05:00
Rémi Verschelde
738ef9baf8 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.

(cherry picked from commit 600e749d9b)
2023-09-01 17:07:03 -05:00
Adam Scott
c7afd0f89a Fix forgotten not operator
(cherry picked from commit f5c8e5190f)
2023-09-01 17:06:51 -05:00
Adam Scott
6789b29b72 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.

(cherry picked from commit 5c262844ad)
2023-09-01 17:06:39 -05:00
David Snopek
960c906da1 Add automated tests to verify some previous fixes
(cherry picked from commit d5fab0b9f8)
2023-09-01 17:06:20 -05:00
Marc Gilleron
0f2d3652e5 Added generated version header
(cherry picked from commit c6b2c82570)
2023-09-01 17:06:03 -05:00
David Snopek
28494f0bd5 Merge pull request #1205 from dsnopek/4.1-cherrypicks-1
Cherry-picks for the godot-cpp 4.1 branch - 1st batch
2023-08-11 10:35:12 -05:00
Feiyun Wang
4fb9af7fb2 Statically link mingw/msvc runtime libraries on Windows
Co-authored-by: David Snopek <dsnopek@gmail.com>
(cherry picked from commit a745c2ac47)
2023-08-10 09:10:04 -05:00
Fabio Alessandrelli
6fa6b8b178 [SCons] Merge OSXCross tools into platofrm ones
(cherry picked from commit 6d195137fe)
2023-08-10 09:09:49 -05:00
Fabio Alessandrelli
784c3dc012 [SCons] Add option to generate a compilation database.
(cherry picked from commit 2586ad016e)
2023-08-10 09:09:30 -05:00
Adam Scott
7a9b323931 Add platform macros
(cherry picked from commit 9d9f4279ed)
2023-08-10 09:09:14 -05:00
Marc Gilleron
e75ec636db Don't cache null forever if a singleton isn't available yet
# Conflicts:
#	binding_generator.py

(cherry picked from commit 548c758677)
2023-08-10 09:08:56 -05:00
David Snopek
5dda0212f6 In generated methods, only construct the method StringName the first time
(cherry picked from commit efc16b49d9)
2023-08-10 09:06:33 -05:00
David Snopek
011965d864 Attempt to fully implement CharString
(cherry picked from commit 4df112cd95)
2023-08-10 09:06:09 -05:00
128 changed files with 3878 additions and 2591 deletions

16
.editorconfig Normal file
View File

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

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

View File

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

View File

@@ -0,0 +1,17 @@
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

@@ -4,6 +4,8 @@ on: [push, pull_request]
env:
# Only used for the cache key. Increment version to force clean build.
GODOT_BASE_BRANCH: master
# Used to select the version of Godot to run the tests with.
GODOT_TEST_VERSION: 4.1.4-stable
concurrency:
group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}
@@ -52,7 +54,7 @@ jobs:
cache-name: windows-x86_64-mingw
- name: 🍎 macOS (universal)
os: macos-11
os: macos-latest
platform: macos
artifact-name: godot-cpp-macos-universal-release
artifact-path: bin/libgodot-cpp.macos.template_release.universal.a
@@ -65,12 +67,12 @@ jobs:
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
flags: arch=arm64
run-tests: false
cache-name: android-arm64
- name: 🍏 iOS (arm64)
os: macos-11
os: macos-latest
platform: ios
artifact-name: godot-cpp-ios-arm64-release
artifact-path: bin/libgodot-cpp.ios.template_release.arm64.a
@@ -78,62 +80,88 @@ jobs:
run-tests: false
cache-name: ios-arm64
- name: 🌐 Web (wasm32)
os: ubuntu-20.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
EM_CACHE_FOLDER: "emsdk-cache"
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Godot build cache
uses: ./.github/actions/godot-cache
- name: Restore Godot build cache
uses: ./.github/actions/godot-cache-restore
with:
cache-name: ${{ matrix.cache-name }}
continue-on-error: true
- name: Set up Python (for SCons)
uses: actions/setup-python@v4
uses: actions/setup-python@v5
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: Android dependencies
if: ${{ matrix.platform == 'android' }}
uses: nttld/setup-ndk@v1
with:
ndk-version: r23c
link-to-sdk: true
- name: Web dependencies
if: ${{ matrix.platform == 'web' }}
uses: mymindstorm/setup-emsdk@v14
with:
version: ${{env.EM_VERSION}}
actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
- name: Setup MinGW for Windows/MinGW build
if: ${{ matrix.platform == 'windows' && matrix.flags == 'use_mingw=yes' }}
uses: egor-tensin/setup-mingw@v2
with:
version: 12.2.0
- 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 platform=${{ matrix.platform }} verbose=yes build_library=no ${{ matrix.flags }}
scons -c
- name: Build godot-cpp (debug)
run: |
scons platform=${{ matrix.platform }} target=template_debug ${{ matrix.flags }}
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 }} target=template_debug ${{ matrix.flags }} build_library=no
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 }} target=template_release ${{ matrix.flags }}
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 }}
if: ${{ matrix.run-tests && env.GODOT_TEST_VERSION == 'master' }}
with:
repo: godotengine/godot
branch: master
@@ -146,15 +174,28 @@ jobs:
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: |
chmod +x ./godot-artifacts/godot.linuxbsd.editor.x86_64.mono
./godot-artifacts/godot.linuxbsd.editor.x86_64.mono --headless --version
$GODOT --headless --version
cd test
# Need to run the editor so .godot is generated... but it crashes! Ignore that :-)
(cd project && (../../godot-artifacts/godot.linuxbsd.editor.x86_64.mono --editor --headless --quit >/dev/null 2>&1 || true))
GODOT=../godot-artifacts/godot.linuxbsd.editor.x86_64.mono ./run-tests.sh
(cd project && (timeout 30 $GODOT --editor --headless --quit >/dev/null 2>&1 || true))
./run-tests.sh
- name: Upload artifact
uses: actions/upload-artifact@v3
@@ -168,7 +209,7 @@ jobs:
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: recursive
@@ -192,7 +233,7 @@ jobs:
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: recursive
@@ -216,7 +257,7 @@ jobs:
runs-on: windows-2019
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: recursive

View File

@@ -7,48 +7,27 @@ concurrency:
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
- name: Get changed files
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
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
if [ "${{ github.event_name }}" == "pull_request" ]; then
files=$(git diff-tree --no-commit-id --name-only -r HEAD^1..HEAD 2> /dev/null || true)
elif [ "${{ github.event_name }}" == "push" -a "${{ github.event.forced }}" == "false" -a "${{ github.event.created }}" == "false" ]; then
files=$(git diff-tree --no-commit-id --name-only -r ${{ github.event.before }}..${{ github.event.after }} 2> /dev/null || true)
fi
files=$(echo "$files" | grep -v 'thirdparty' | xargs -I {} sh -c 'echo "\"./{}\""' | tr '\n' ' ')
echo "CHANGED_FILES=$files" >> $GITHUB_ENV
- 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: 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: Style checks via pre-commit
uses: pre-commit/action@v3.0.1
with:
extra_args: --verbose --hook-stage manual --files ${{ env.CHANGED_FILES }}

6
.gitignore vendored
View File

@@ -8,7 +8,7 @@
include/gen
src/gen
# Build configuarion.
# Build configuration.
/custom.py
# Misc
@@ -191,3 +191,7 @@ godot.creator.*
# compile commands (https://clang.llvm.org/docs/JSONCompilationDatabase.html)
compile_commands.json
# Python development
.venv
venv

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

@@ -0,0 +1,64 @@
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: v17.0.6
hooks:
- id: clang-format
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.4
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.971
hooks:
- id: mypy
files: \.py$
types_or: [text]
- repo: https://github.com/codespell-project/codespell
rev: v2.3.0
hooks:
- id: codespell
additional_dependencies: [tomli]
- 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

@@ -3,7 +3,7 @@
#
# 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_SYSTEM_HEADERS Mark the header files as SYSTEM. This may be useful to suppress 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")
@@ -37,7 +37,7 @@
# Todo
# Test build for Windows, Mac and mingw.
cmake_minimum_required(VERSION 3.12)
cmake_minimum_required(VERSION 3.13)
project(godot-cpp LANGUAGES CXX)
option(GENERATE_TEMPLATE_GET_NODE "Generate a template version of the Node class's get_node." ON)
@@ -47,11 +47,6 @@ option(GODOT_CPP_WARNING_AS_ERROR "Treat warnings as errors" OFF)
# Add path to modules
list( APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" )
# Check if we are building ourself or being included
if(${PROJECT_NAME} STREQUAL ${CMAKE_PROJECT_NAME})
set(GODOT_CPP_BUILDING_SELF 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>" )
@@ -72,21 +67,22 @@ 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(FLOAT_PRECISION "single" CACHE STRING "")
if ("${FLOAT_PRECISION}" STREQUAL "double")
add_definitions(-DREAL_T_IS_DOUBLE)
endif()
set(GODOT_COMPILE_FLAGS )
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# using Visual Studio C++
set(GODOT_COMPILE_FLAGS "/EHsc /utf-8") # /GF /MP
set(GODOT_COMPILE_FLAGS "/utf-8") # /GF /MP
if(CMAKE_BUILD_TYPE MATCHES Debug)
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MDd") # /Od /RTC1 /Zi
@@ -98,15 +94,28 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
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")
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0 -g")
else()
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -O3")
endif(CMAKE_BUILD_TYPE MATCHES Debug)
endif()
# Disable exception handling. Godot doesn't use exceptions anywhere, and this
# saves around 20% of binary size and very significant build time (GH-80513).
option(GODOT_DISABLE_EXCEPTIONS OFF "Force disabling exception handling code")
if (GODOT_DISABLE_EXCEPTIONS)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -D_HAS_EXCEPTIONS=0")
else()
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-exceptions")
endif()
else()
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /EHsc")
endif()
endif()
# Generate source from the bindings file
find_package(Python3 3.4 REQUIRED) # pathlib should be present
if(GENERATE_TEMPLATE_GET_NODE)
@@ -118,6 +127,7 @@ 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
OUTPUT_STRIP_TRAILING_WHITESPACE
)
add_custom_command(OUTPUT ${GENERATED_FILES_LIST}
@@ -143,12 +153,6 @@ 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()
endif()
target_compile_features(${PROJECT_NAME}
PRIVATE
cxx_std_17

View File

@@ -2,11 +2,15 @@
> **Warning**
>
> This repository's `master` branch is only usable with the latest version of
> Godot's ([GDExtension](https://godotengine.org/article/introducing-gd-extensions))
> API (Godot 4.1 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 Godot 4.0.x, switch to the [`4.0`](https://github.com/godotengine/godot-cpp/tree/4.0) branch.
> For users of stable branches, switch to the branch matching your target Godot version:
> - [`4.0`](https://github.com/godotengine/godot-cpp/tree/4.0)
> - [`4.1`](https://github.com/godotengine/godot-cpp/tree/4.1)
>
> 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.
@@ -52,9 +56,10 @@ 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.
[Godot issue tracker](https://github.com/godotengine/godot/issues?q=is%3Aissue+is%3Aopen+label%3Atopic%3Agdextension)
and the [godot-cpp issue tracker](https://github.com/godotengine/godot-cpp/issues)
for a list of known issues, and be sure to provide feedback on issues and PRs
which affect your use of this extension.
## Contributing
@@ -68,7 +73,10 @@ so formatting is done before your changes are submitted.
## 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/contributing/development/compiling/index.html#building-for-target-platforms).
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,
@@ -76,22 +84,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
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.
```
@@ -123,12 +131,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/gdextension/gdextension_cpp_example.html).

View File

@@ -1,85 +1,25 @@
#!/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
EnsureSConsVersion(4, 0)
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>")
try:
Import("env")
except:
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="")
env.PrependENVPath("PATH", os.getenv("PATH"))
# 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)
# 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):
@@ -87,143 +27,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(
key="platform",
help="Target platform",
default=env.get("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(
key="target",
help="Compilation target",
default=env.get("target", "template_debug"),
allowed_values=("editor", "template_release", "template_debug"),
)
)
opts.Add(
PathVariable(
key="gdextension_dir",
help="Path to a custom directory containing GDExtension interface header and API JSON file",
default=env.get("gdextension_dir", None),
validator=validate_gdextension_dir,
)
)
opts.Add(
PathVariable(
key="custom_api_file",
help="Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`)",
default=env.get("custom_api_file", None),
validator=validate_api_file,
)
)
opts.Add(
BoolVariable(
key="generate_bindings",
help="Force GDExtension API bindings generation. Auto-detected by default.",
default=env.get("generate_bindings", False),
)
)
opts.Add(
BoolVariable(
key="generate_template_get_node",
help="Generate a template version of the Node class's get_node.",
default=env.get("generate_template_get_node", True),
)
)
opts.Add(BoolVariable(key="build_library", help="Build the godot-cpp library.", default=env.get("build_library", True)))
opts.Add(
EnumVariable(
key="precision",
help="Set the floating-point precision level",
default=env.get("precision", "single"),
allowed_values=("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(
key="arch",
help="CPU architecture",
default=env.get("arch", ""),
allowed_values=architecture_array,
map=architecture_aliases,
)
)
# Targets flags tool (optimizations, debug symbols)
target_tool = Tool("targets", toolpath=["tools"])
target_tool.options(opts)
cpp_tool = Tool("godotcpp", toolpath=["tools"])
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:
@@ -231,66 +40,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

View File

@@ -2,10 +2,10 @@
"header": {
"version_major": 4,
"version_minor": 1,
"version_patch": 1,
"version_patch": 4,
"version_status": "stable",
"version_build": "official",
"version_full_name": "Godot Engine v4.1.1.stable.official"
"version_full_name": "Godot Engine v4.1.4.stable.official"
},
"builtin_class_sizes": [
{
@@ -2593,6 +2593,22 @@
"name": "KEY_LAUNCHF",
"value": 4194415
},
{
"name": "KEY_GLOBE",
"value": 4194416
},
{
"name": "KEY_KEYBOARD",
"value": 4194417
},
{
"name": "KEY_JIS_EISU",
"value": 4194418
},
{
"name": "KEY_JIS_KANA",
"value": 4194419
},
{
"name": "KEY_UNKNOWN",
"value": 8388607
@@ -2880,22 +2896,6 @@
{
"name": "KEY_SECTION",
"value": 167
},
{
"name": "KEY_GLOBE",
"value": 4194416
},
{
"name": "KEY_KEYBOARD",
"value": 4194417
},
{
"name": "KEY_JIS_EISU",
"value": 4194418
},
{
"name": "KEY_JIS_KANA",
"value": 4194419
}
]
},
@@ -95246,13 +95246,6 @@
}
]
},
{
"name": "FramebufferCacheRD",
"is_refcounted": false,
"is_instantiable": false,
"inherits": "Object",
"api_type": "core"
},
{
"name": "GDExtension",
"is_refcounted": true,
@@ -113089,6 +113082,29 @@
}
]
},
{
"name": "should_ignore_device",
"is_const": true,
"is_vararg": false,
"is_static": false,
"is_virtual": false,
"hash": 2522259332,
"return_value": {
"type": "bool"
},
"arguments": [
{
"name": "vendor_id",
"type": "int",
"meta": "int32"
},
{
"name": "product_id",
"type": "int",
"meta": "int32"
}
]
},
{
"name": "get_connected_joypads",
"is_const": false,
@@ -122009,6 +122025,10 @@
{
"name": "BAKE_ERROR_USER_ABORTED",
"value": 8
},
{
"name": "BAKE_ERROR_TEXTURE_SIZE_TOO_SMALL",
"value": 9
}
]
},
@@ -149258,6 +149278,93 @@
}
]
},
{
"name": "OpenXRInteractionProfileMetadata",
"is_refcounted": false,
"is_instantiable": true,
"inherits": "Object",
"api_type": "core",
"methods": [
{
"name": "register_top_level_path",
"is_const": false,
"is_vararg": false,
"is_static": false,
"is_virtual": false,
"hash": 254767734,
"arguments": [
{
"name": "display_name",
"type": "String"
},
{
"name": "openxr_path",
"type": "String"
},
{
"name": "openxr_extension_name",
"type": "String"
}
]
},
{
"name": "register_interaction_profile",
"is_const": false,
"is_vararg": false,
"is_static": false,
"is_virtual": false,
"hash": 254767734,
"arguments": [
{
"name": "display_name",
"type": "String"
},
{
"name": "openxr_path",
"type": "String"
},
{
"name": "openxr_extension_name",
"type": "String"
}
]
},
{
"name": "register_io_path",
"is_const": false,
"is_vararg": false,
"is_static": false,
"is_virtual": false,
"hash": 3443511926,
"arguments": [
{
"name": "interaction_profile",
"type": "String"
},
{
"name": "display_name",
"type": "String"
},
{
"name": "toplevel_path",
"type": "String"
},
{
"name": "openxr_path",
"type": "String"
},
{
"name": "openxr_extension_name",
"type": "String"
},
{
"name": "action_type",
"type": "enum::OpenXRAction.ActionType"
}
]
}
]
},
{
"name": "OpenXRInterface",
"is_refcounted": true,
@@ -198879,6 +198986,23 @@
}
]
},
{
"name": "debug_canvas_item_get_rect",
"is_const": false,
"is_vararg": false,
"is_static": false,
"is_virtual": false,
"hash": 624227424,
"return_value": {
"type": "Rect2"
},
"arguments": [
{
"name": "item",
"type": "RID"
}
]
},
{
"name": "canvas_light_create",
"is_const": false,
@@ -251426,6 +251550,43 @@
}
]
},
{
"name": "set_text_overrun_behavior",
"is_const": false,
"is_vararg": false,
"is_static": false,
"is_virtual": false,
"hash": 1940772195,
"arguments": [
{
"name": "column",
"type": "int",
"meta": "int32"
},
{
"name": "overrun_behavior",
"type": "enum::TextServer.OverrunBehavior"
}
]
},
{
"name": "get_text_overrun_behavior",
"is_const": true,
"is_vararg": false,
"is_static": false,
"is_virtual": false,
"hash": 3782727860,
"return_value": {
"type": "enum::TextServer.OverrunBehavior"
},
"arguments": [
{
"name": "column",
"type": "int",
"meta": "int32"
}
]
},
{
"name": "set_structured_text_bidi_override",
"is_const": false,
@@ -255076,13 +255237,6 @@
}
]
},
{
"name": "UniformSetCacheRD",
"is_refcounted": false,
"is_instantiable": false,
"inherits": "Object",
"api_type": "core"
},
{
"name": "VBoxContainer",
"is_refcounted": false,

View File

@@ -0,0 +1,62 @@
/**************************************************************************/
/* 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. */
/**************************************************************************/
#ifndef GODOT_EDITOR_PLUGIN_REGISTRATION_HPP
#define GODOT_EDITOR_PLUGIN_REGISTRATION_HPP
#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
#endif // GODOT_EDITOR_PLUGIN_REGISTRATION_HPP

View File

@@ -45,7 +45,7 @@ namespace godot {
class RefCounted;
template <class T>
template <typename T>
class Ref {
T *reference = nullptr;
@@ -63,7 +63,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;
@@ -108,7 +108,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) {
@@ -144,7 +144,7 @@ public:
}
}
template <class T_Other>
template <typename T_Other>
void reference_ptr(T_Other *p_ptr) {
if (reference == p_ptr) {
return;
@@ -161,7 +161,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) {
@@ -226,7 +226,7 @@ public:
}
};
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;
@@ -248,7 +248,7 @@ struct PtrToArg<Ref<T>> {
}
};
template <class T>
template <typename T>
struct PtrToArg<const Ref<T> &> {
typedef Ref<T> EncodeT;
@@ -259,7 +259,7 @@ struct PtrToArg<const Ref<T> &> {
}
};
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;
@@ -269,7 +269,7 @@ struct GetTypeInfo<Ref<T>, typename EnableIf<TypeInherits<RefCounted, T>::value>
}
};
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;

View File

@@ -76,14 +76,15 @@ protected:
uint32_t plist_size = 0;
void _postinitialize();
virtual void _notificationv(int32_t p_what) {}
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;
}
@@ -95,11 +96,31 @@ public:
GodotObject *_owner = nullptr;
};
namespace internal {
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) \
private: \
void operator=(const m_class &p_rval) {} \
void operator=(const m_class & /*p_rval*/) {} \
friend class ::godot::ClassDB; \
\
protected: \
@@ -132,24 +153,27 @@ protected:
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 ::godot::String (::godot::Wrapped::*_get_to_string())() const { \
return (::godot::String(::godot::Wrapped::*)() const) & m_class::_to_string; \
} \
\
template <class T, class B> \
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,12 +187,12 @@ 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(#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(); \
} \
\
@@ -179,32 +203,36 @@ public:
\
static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what) { \
if (p_instance && m_class::_get_notification()) { \
m_inherits::notification_bind(p_instance, p_what); \
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); \
} \
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; \
} \
@@ -280,7 +308,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,14 +316,14 @@ public:
} \
} \
\
static void *_gde_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 _gde_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 _gde_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; \
} \
\
@@ -303,82 +331,116 @@ public:
_gde_binding_create_callback, \
_gde_binding_free_callback, \
_gde_binding_reference_callback, \
};
}; \
\
protected: \
virtual void _notificationv(int32_t p_what) override { \
m_class::notification_bind(this, p_what); \
} \
\
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 &_gde_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 *_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_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; \
\
protected: \
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const override { \
return &_gde_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 _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 GDExtensionObjectPtr create(void *data) { \
return nullptr; \
} \
\
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:
// 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)
#endif // GODOT_WRAPPED_HPP

View File

@@ -83,7 +83,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 +95,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 +107,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,7 +144,7 @@ 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);
@@ -159,7 +159,7 @@ 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);
@@ -174,7 +174,7 @@ 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);
@@ -189,47 +189,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 +241,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 +253,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;
@@ -264,7 +264,7 @@ void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), co
#endif
}
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;
@@ -276,7 +276,7 @@ void call_with_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) co
(void)p_args;
}
template <class T, class... 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 std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
@@ -311,7 +311,7 @@ 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>
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 std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
@@ -346,7 +346,7 @@ 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>
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 std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
@@ -381,7 +381,7 @@ 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>
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 std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
@@ -423,7 +423,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 +431,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 +443,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 +451,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 +461,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 +469,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 +482,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,7 +493,7 @@ void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_arg
#endif
}
template <class... P>
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 std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
@@ -528,17 +528,17 @@ 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, 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,7 +549,7 @@ void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_ar
#endif
}
template <class R, class... P>
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 std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
@@ -584,12 +584,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)>{});
}

View File

@@ -32,6 +32,7 @@
#define GODOT_BUILTIN_PTRCALL_HPP
#include <gdextension_interface.h>
#include <godot_cpp/core/object.hpp>
#include <array>
@@ -39,13 +40,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 +65,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);

View File

@@ -38,6 +38,8 @@
#include <godot_cpp/core/method_bind.hpp>
#include <godot_cpp/core/object.hpp>
#include <godot_cpp/classes/class_db_singleton.hpp>
#include <list>
#include <set>
#include <string>
@@ -112,24 +114,26 @@ private:
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>
template <typename T, bool is_abstract>
static void _register_class(bool p_virtual = false);
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 <class T>
static void register_engine_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;
}
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>
template <typename 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);
static void add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix);
@@ -146,27 +150,32 @@ public:
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::_gde_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::_gde_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); \
::godot::ClassDB::bind_virtual_method(m_class::get_class_static(), #m_method, _call##m_method); \
}
template <class T, bool is_abstract>
template <typename T, bool is_abstract>
void ClassDB::_register_class(bool p_virtual) {
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
@@ -212,22 +221,17 @@ 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 T>
void ClassDB::register_engine_class() {
instance_binding_callbacks[T::get_class_static()] = &T::_gde_binding_callbacks;
}
template <class N, class M, typename... VarArgs>
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];
@@ -238,7 +242,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];
@@ -250,10 +254,10 @@ 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>
template <typename 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) {
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);
@@ -282,10 +286,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>();
} // namespace godot
CLASSDB_SINGLETON_VARIANT_CAST;
#endif // GODOT_CLASS_DB_HPP

View File

@@ -108,7 +108,7 @@ typedef float real_t;
// Generic swap template.
#ifndef SWAP
#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y))
template <class T>
template <typename T>
inline void __swap_tmpl(T &x, T &y) {
T aux = x;
x = y;

View File

@@ -43,7 +43,7 @@ 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... } };
@@ -54,7 +54,7 @@ O *_call_native_mb_ret_obj(const GDExtensionMethodBindPtr mb, void *instance, co
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;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
@@ -62,13 +62,13 @@ R _call_native_mb_ret(const GDExtensionMethodBindPtr mb, void *instance, const A
return 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::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;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
@@ -76,15 +76,15 @@ R _call_utility_ret(GDExtensionPtrUtilityFunction func, const Args &...args) {
return 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::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());

View File

@@ -84,7 +84,7 @@ constexpr auto CLAMP(const T m_a, const T2 m_min, const T3 m_max) {
// Generic swap template.
#ifndef SWAP
#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y))
template <class T>
template <typename T>
inline void __swap_tmpl(T &x, T &y) {
T aux = x;
x = y;
@@ -138,7 +138,7 @@ static inline int get_shift_from_power_of_2(unsigned int p_bits) {
return -1;
}
template <class T>
template <typename T>
static _FORCE_INLINE_ T nearest_power_of_2_templated(T x) {
--x;
@@ -613,6 +613,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) {

View File

@@ -40,10 +40,6 @@
#include <type_traits>
#ifndef PAD_ALIGN
#define PAD_ALIGN 16 //must always be greater than this at much
#endif
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
@@ -68,6 +64,18 @@ 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);
@@ -75,7 +83,7 @@ public:
_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;
@@ -91,28 +99,28 @@ _ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
#define memnew_placement(m_placement, m_class) ::godot::_post_initialize(new (m_placement, sizeof(m_class), "") m_class)
// Generic comparator used in Map, List, etc.
template <class T>
template <typename 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::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 +133,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,12 +156,14 @@ 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 */
@@ -162,11 +176,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();

View File

@@ -132,7 +132,7 @@ public:
std::vector<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;
@@ -147,7 +147,7 @@ public:
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)
@@ -208,7 +208,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 +231,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 +260,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());
@@ -277,9 +277,9 @@ class _gde_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...);
@@ -339,7 +339,7 @@ public:
}
};
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 +353,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;
@@ -412,10 +412,11 @@ public:
method = p_method;
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,9 +430,9 @@ 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)
@@ -498,7 +499,7 @@ public:
}
};
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,9 +513,9 @@ 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)
@@ -578,10 +579,11 @@ public:
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
set_return(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...);
@@ -652,7 +654,7 @@ public:
}
};
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,7 +662,7 @@ 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...);
@@ -722,7 +724,7 @@ public:
}
};
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;

View File

@@ -39,7 +39,7 @@
namespace godot {
template <class T>
template <typename T>
struct PtrToArg {};
#define MAKE_PTRARG(m_type) \
@@ -166,25 +166,27 @@ 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::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr))));
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::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr))));
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;
}
};

View File

@@ -45,10 +45,10 @@
#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)
namespace godot {
@@ -75,31 +75,31 @@ 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... };
}
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) {
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... };
@@ -138,7 +138,7 @@ public:
}
};
template <class T>
template <typename T>
T *Object::cast_to(Object *p_object) {
if (p_object == nullptr) {
return nullptr;
@@ -151,7 +151,7 @@ T *Object::cast_to(Object *p_object) {
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;

View File

@@ -47,9 +47,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,6 +68,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

View File

@@ -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) \
@@ -248,14 +258,14 @@ inline StringName _gde_constant_get_enum_name(T param, StringName p_constant) {
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; }
@@ -295,7 +305,7 @@ inline StringName _gde_constant_get_bitfield_name(T param, StringName p_constant
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 +316,7 @@ struct PtrToArg<TypedArray<T>> {
}
};
template <class T>
template <typename T>
struct PtrToArg<const TypedArray<T> &> {
typedef Array EncodeT;
_FORCE_INLINE_ static TypedArray<T>
@@ -383,17 +393,15 @@ 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(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(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(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
#define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info())

View File

@@ -187,29 +187,44 @@ 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 {
private:
static void register_engine_classes();
public:
using Callback = void (*)(ModuleInitializationLevel p_level);
static Callback init_callback;
static Callback terminate_callback;
static GDExtensionInitializationLevel minimum_initialization_level;
static GDExtensionBool init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);
struct InitData {
GDExtensionInitializationLevel minimum_initialization_level = GDEXTENSION_INITIALIZATION_CORE;
Callback init_callback = nullptr;
Callback terminate_callback = nullptr;
};
class InitDataList {
int data_count = 0;
int data_capacity = 0;
InitData **data = nullptr;
public:
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 *userdata, GDExtensionInitializationLevel p_level);
static void deinitialize_level(void *userdata, GDExtensionInitializationLevel p_level);
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);

View File

@@ -32,108 +32,160 @@
#define GODOT_COWDATA_HPP
#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 <new>
#include <type_traits>
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);
void _ref(const CowData *p_from);
void _ref(const CowData &p_from);
uint32_t _copy_on_write();
USize _copy_on_write();
public:
void operator=(const CowData<T> &p_from) { _ref(p_from); }
_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,41 +196,42 @@ 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++) {
Size len = size();
for (Size i = p_index; i < len - 1; i++) {
p[i] = p[i + 1];
}
resize(len - 1);
}
Error insert(int p_pos, const T &p_val) {
Error insert(Size 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--) {
for (Size i = (size() - 1); i > p_pos; i--) {
set(i, get(i - 1));
}
set(p_pos, p_val);
@@ -186,83 +239,88 @@ public:
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(CowData<T> &p_from) { _ref(p_from); };
};
template <class T>
template <typename T>
void CowData<T>::_unref(void *p_data) {
if (!p_data) {
return;
}
SafeNumeric<uint32_t> *refc = _get_refcount();
SafeNumeric<USize> *refc = _get_refcount();
if (refc->decrement() > 0) {
return; // still in use
}
// clean up
if (!__has_trivial_destructor(T)) {
uint32_t *count = _get_size();
if constexpr (!std::is_trivially_destructible_v<T>) {
USize *count = _get_size();
T *data = (T *)(count + 1);
for (uint32_t i = 0; i < *count; ++i) {
for (USize i = 0; i < *count; ++i) {
// call destructors
data[i].~T();
}
}
// free mem
Memory::free_static((uint8_t *)p_data, true);
Memory::free_static(((uint8_t *)p_data) - 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;
_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;
@@ -276,59 +334,71 @@ Error CowData<T>::resize(int p_size) {
}
// possibly changing size, copy on write
uint32_t rc = _copy_on_write();
USize rc = _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
uint8_t *mem_new = (uint8_t *)Memory::realloc_static(((uint8_t *)_ptr) - DATA_OFFSET, alloc_size + DATA_OFFSET, false);
ERR_FAIL_NULL_V(mem_new, ERR_OUT_OF_MEMORY);
_ptr = (T *)(_ptrnew);
SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr(mem_new);
T *_data_ptr = _get_data_ptr(mem_new);
new (_refc_ptr) SafeNumeric<USize>(rc); //refcount
_ptr = _data_ptr;
}
}
// 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
uint8_t *mem_new = (uint8_t *)Memory::realloc_static(((uint8_t *)_ptr) - DATA_OFFSET, alloc_size + DATA_OFFSET, false);
ERR_FAIL_NULL_V(mem_new, ERR_OUT_OF_MEMORY);
_ptr = (T *)(_ptrnew);
SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr(mem_new);
T *_data_ptr = _get_data_ptr(mem_new);
new (_refc_ptr) SafeNumeric<USize>(rc); //refcount
_ptr = _data_ptr;
}
*_get_size() = p_size;
@@ -337,15 +407,15 @@ 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>
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,12 +425,42 @@ 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.
@@ -378,7 +478,7 @@ void CowData<T>::_ref(const CowData &p_from) {
}
}
template <class T>
template <typename T>
CowData<T>::~CowData() {
_unref(_ptr);
}

View File

@@ -52,7 +52,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,10 +62,10 @@ 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>>>
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.

View File

@@ -48,9 +48,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.

View File

@@ -253,7 +253,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 +286,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,15 +298,15 @@ 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->()); }
static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); }

View File

@@ -45,7 +45,7 @@
namespace godot {
template <class T, class A = DefaultAllocator>
template <typename T, typename A = DefaultAllocator>
class List {
struct _Data;
@@ -221,7 +221,7 @@ private:
int size_cache = 0;
bool erase(const Element *p_I) {
ERR_FAIL_COND_V(!p_I, false);
ERR_FAIL_NULL_V(p_I, false);
ERR_FAIL_COND_V(p_I->data != this, false);
if (first == p_I) {
@@ -410,7 +410,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) {
@@ -646,7 +646,7 @@ public:
sort_custom<Comparator<T>>();
}
template <class C>
template <typename C>
void sort_custom_inplace() {
if (size() < 2) {
return;
@@ -693,7 +693,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,7 +701,7 @@ 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

View File

@@ -31,10 +31,10 @@
#ifndef GODOT_LOCAL_VECTOR_HPP
#define GODOT_LOCAL_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 <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 +43,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;
@@ -257,7 +257,7 @@ public:
return -1;
}
template <class C>
template <typename C>
void sort_custom() {
U len = count;
if (len == 0) {
@@ -331,7 +331,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

View File

@@ -33,7 +33,7 @@
namespace godot {
template <class F, class S>
template <typename F, typename S>
struct Pair {
F first;
S second;
@@ -49,17 +49,17 @@ struct Pair {
}
};
template <class F, class S>
template <typename F, typename 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>
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) {
@@ -69,7 +69,7 @@ struct PairSort {
}
};
template <class K, class V>
template <typename K, typename V>
struct KeyValue {
const K key;
V value;
@@ -85,17 +85,17 @@ struct KeyValue {
}
};
template <class K, class V>
template <typename K, typename 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>
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;

View File

@@ -40,7 +40,7 @@ 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,

View File

@@ -38,7 +38,7 @@
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,

View File

@@ -42,7 +42,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 +186,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 +347,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 +374,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 +406,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;

View File

@@ -48,7 +48,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<std::atomic<m_type>>::value);
#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;
@@ -123,7 +132,7 @@ public:
}
}
_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);
}
};
@@ -186,7 +195,7 @@ public:
#else
template <class T>
template <typename T>
class SafeNumeric {
protected:
T value;

View File

@@ -35,7 +35,7 @@
namespace godot {
template <class T, class Comparator = _DefaultComparator<T>>
template <typename T, typename Comparator = _DefaultComparator<T>>
class SearchArray {
public:
Comparator compare;

View File

@@ -36,7 +36,7 @@
namespace godot {
template <class T>
template <typename T>
class SelfList {
public:
class List {

View File

@@ -41,7 +41,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 +52,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

View File

@@ -52,7 +52,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 +94,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 +123,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 +145,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:

View File

@@ -47,38 +47,42 @@
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:
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,45 @@ 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); }
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); }
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();
void sort() {
sort_custom<_DefaultComparator<T>>();
}
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, C> sorter;
SortArray<T, Comparator, Validate> sorter{ args... };
sorter.sort(data, len);
}
void sort() {
sort_custom<_DefaultComparator<T>>();
Size bsearch(const T &p_value, bool p_before) {
return bsearch_custom<_DefaultComparator<T>>(p_value, p_before);
}
int bsearch(const T &p_value, bool p_before) {
SearchArray<T> search;
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 +137,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;
@@ -140,33 +152,36 @@ public:
Vector<uint8_t> to_byte_array() const {
Vector<uint8_t> ret;
if (is_empty()) {
return ret;
}
ret.resize(size() * sizeof(T));
memcpy(ret.ptrw(), ptr(), sizeof(T) * 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 +189,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 +202,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;
}
@@ -268,7 +283,7 @@ public:
Error err = _cowdata.resize(p_init.size());
ERR_FAIL_COND(err);
int i = 0;
Size i = 0;
for (const T &element : p_init) {
_cowdata.set(i++, element);
}
@@ -278,28 +293,28 @@ public:
_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,10 +323,10 @@ 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;
}
}

View File

@@ -35,7 +35,7 @@
namespace godot {
template <class T, class V>
template <typename T, typename V>
class VMap {
public:
struct Pair {

View File

@@ -35,7 +35,7 @@
namespace godot {
template <class T>
template <typename T>
class VSet {
Vector<T> _data;

View File

@@ -65,6 +65,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

View File

@@ -28,6 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_ARRAY_HELPERS_HPP
#define GODOT_ARRAY_HELPERS_HPP
namespace godot {
namespace helpers {
template <typename T, typename ValueT>
@@ -48,3 +51,5 @@ T append_all(T appendable) {
}
} // namespace helpers
} // namespace godot
#endif // GODOT_ARRAY_HELPERS_HPP

View File

@@ -128,6 +128,7 @@ struct _NO_DISCARD_ Basis {
}
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;

View File

@@ -31,82 +31,111 @@
#ifndef GODOT_CHAR_STRING_HPP
#define GODOT_CHAR_STRING_HPP
#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

View File

@@ -28,6 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_COLOR_NAMES_INC_HPP
#define GODOT_COLOR_NAMES_INC_HPP
namespace godot {
// Names from https://en.wikipedia.org/wiki/X11_color_names
@@ -189,3 +192,5 @@ static NamedColor named_colors[] = {
};
} // namespace godot
#endif // GODOT_COLOR_NAMES_INC_HPP

View File

@@ -77,6 +77,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;

View File

@@ -55,6 +55,7 @@ struct _NO_DISCARD_ Quaternion {
}
_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;

View File

@@ -146,7 +146,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;
@@ -209,6 +209,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; }

View File

@@ -89,7 +89,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;

View File

@@ -99,6 +99,7 @@ struct _NO_DISCARD_ Transform2D {
void orthonormalize();
Transform2D orthonormalized() const;
bool is_equal_approx(const Transform2D &p_transform) const;
bool is_finite() const;
Transform2D looking_at(const Vector2 &p_target) const;

View File

@@ -78,6 +78,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;

View File

@@ -36,7 +36,7 @@
namespace godot {
template <class T>
template <typename T>
class TypedArray : public Array {
public:
_FORCE_INLINE_ void operator=(const Array &p_array) {
@@ -44,10 +44,15 @@ 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() {
set_typed(Variant::OBJECT, T::get_class_static(), Variant());
@@ -65,10 +70,15 @@ public:
_ref(p_array); \
} \
_FORCE_INLINE_ TypedArray(const Variant &p_variant) : \
Array(p_variant.operator Array(), m_variant_type, StringName(), Variant()) { \
TypedArray(Array(p_variant)) { \
} \
_FORCE_INLINE_ TypedArray(const Array &p_array) : \
Array(p_array, m_variant_type, StringName(), 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()); \

View File

@@ -47,8 +47,6 @@ 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;
@@ -122,6 +120,7 @@ public:
OP_NEGATE,
OP_POSITIVE,
OP_MODULE,
OP_POWER,
// bitwise
OP_SHIFT_LEFT,
OP_SHIFT_RIGHT,
@@ -144,6 +143,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 +154,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) {}
@@ -209,8 +217,12 @@ public:
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;
@@ -255,25 +267,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;
}

View File

@@ -123,6 +123,7 @@ struct _NO_DISCARD_ Vector2 {
bool is_equal_approx(const Vector2 &p_v) const;
bool is_zero_approx() const;
bool is_finite() const;
Vector2 operator+(const Vector2 &p_v) const;
void operator+=(const Vector2 &p_v);

View File

@@ -78,6 +78,14 @@ struct _NO_DISCARD_ Vector3 {
return x < y ? (y < z ? Vector3::AXIS_Z : Vector3::AXIS_Y) : (x < z ? Vector3::AXIS_Z : Vector3::AXIS_X);
}
Vector3 min(const Vector3 &p_vector3) const {
return Vector3(MIN(x, p_vector3.x), MIN(y, p_vector3.y), MIN(z, p_vector3.z));
}
Vector3 max(const Vector3 &p_vector3) const {
return Vector3(MAX(x, p_vector3.x), MAX(y, p_vector3.y), MAX(z, p_vector3.z));
}
_FORCE_INLINE_ real_t length() const;
_FORCE_INLINE_ real_t length_squared() const;
@@ -138,6 +146,7 @@ struct _NO_DISCARD_ Vector3 {
bool is_equal_approx(const Vector3 &p_v) const;
bool is_zero_approx() const;
bool is_finite() const;
/* Operators */

View File

@@ -71,6 +71,14 @@ struct _NO_DISCARD_ Vector3i {
Vector3i::Axis min_axis_index() const;
Vector3i::Axis max_axis_index() const;
Vector3i min(const Vector3i &p_vector3i) const {
return Vector3i(MIN(x, p_vector3i.x), MIN(y, p_vector3i.y), MIN(z, p_vector3i.z));
}
Vector3i max(const Vector3i &p_vector3i) const {
return Vector3i(MAX(x, p_vector3i.x), MAX(y, p_vector3i.y), MAX(z, p_vector3i.z));
}
_FORCE_INLINE_ int64_t length_squared() const;
_FORCE_INLINE_ double length() const;

View File

@@ -70,9 +70,18 @@ struct _NO_DISCARD_ Vector4 {
Vector4::Axis min_axis_index() const;
Vector4::Axis max_axis_index() const;
Vector4 min(const Vector4 &p_vector4) const {
return Vector4(MIN(x, p_vector4.x), MIN(y, p_vector4.y), MIN(z, p_vector4.z), MIN(w, p_vector4.w));
}
Vector4 max(const Vector4 &p_vector4) const {
return Vector4(MAX(x, p_vector4.x), MAX(y, p_vector4.y), MAX(z, p_vector4.z), MAX(w, p_vector4.w));
}
_FORCE_INLINE_ real_t length_squared() const;
bool is_equal_approx(const Vector4 &p_vec4) const;
bool is_zero_approx() const;
bool is_finite() const;
real_t length() const;
void normalize();
Vector4 normalized() const;

View File

@@ -73,6 +73,14 @@ struct _NO_DISCARD_ Vector4i {
Vector4i::Axis min_axis_index() const;
Vector4i::Axis max_axis_index() const;
Vector4i min(const Vector4i &p_vector4i) const {
return Vector4i(MIN(x, p_vector4i.x), MIN(y, p_vector4i.y), MIN(z, p_vector4i.z), MIN(w, p_vector4i.w));
}
Vector4i max(const Vector4i &p_vector4i) const {
return Vector4i(MAX(x, p_vector4i.x), MAX(y, p_vector4i.y), MAX(z, p_vector4i.z), MAX(w, p_vector4i.w));
}
_FORCE_INLINE_ int64_t length_squared() const;
_FORCE_INLINE_ double length() const;

View File

@@ -1,37 +0,0 @@
# Git hooks for Godot Engine
This folder contains Git hooks meant to be installed locally by Godot Engine
contributors to make sure they comply with our requirements.
## List of hooks
- Pre-commit hook for `clang-format`: Applies `clang-format` to the staged
files before accepting a commit; blocks the commit and generates a patch if
the style is not respected.
You may need to edit the file if your `clang-format` binary is not in the
`PATH`, or if you want to enable colored output with `pygmentize`.
- Pre-commit hook for `black`: Applies `black` to the staged Python files
before accepting a commit.
- Pre-commit hook for `make_rst`: Checks the class reference syntax using
`make_rst.py`.
## Installation
Copy all the files from this folder into your `.git/hooks` folder, and make
sure the hooks and helper scripts are executable.
#### Linux/MacOS
The hooks rely on bash scripts and tools which should be in the system `PATH`,
so they should work out of the box on Linux/macOS.
#### Windows
##### clang-format
- Download LLVM for Windows (version 13 or later) from
<https://releases.llvm.org/download.html>
- Make sure LLVM is added to the `PATH` during installation
##### black
- Python installation: make sure Python is added to the `PATH`
- Install `black` - in any console: `pip3 install black`

View File

@@ -1,48 +0,0 @@
#!/bin/sh
# Provide the canonicalize filename (physical filename with out any symlinks)
# like the GNU version readlink with the -f option regardless of the version of
# readlink (GNU or BSD).
# This file is part of a set of unofficial pre-commit hooks available
# at github.
# Link: https://github.com/githubbrowser/Pre-commit-hooks
# Contact: David Martin, david.martin.mailbox@googlemail.com
###########################################################
# There should be no need to change anything below this line.
# Canonicalize by recursively following every symlink in every component of the
# specified filename. This should reproduce the results of the GNU version of
# readlink with the -f option.
#
# Reference: https://stackoverflow.com/questions/1055671/how-can-i-get-the-behavior-of-gnus-readlink-f-on-a-mac
canonicalize_filename () {
local target_file="$1"
local physical_directory=""
local result=""
# Need to restore the working directory after work.
local working_dir="`pwd`"
cd -- "$(dirname -- "$target_file")"
target_file="$(basename -- "$target_file")"
# Iterate down a (possible) chain of symlinks
while [ -L "$target_file" ]
do
target_file="$(readlink -- "$target_file")"
cd -- "$(dirname -- "$target_file")"
target_file="$(basename -- "$target_file")"
done
# Compute the canonicalized name by finding the physical path
# for the directory we're in and appending the target file.
physical_directory="`pwd -P`"
result="$physical_directory/$target_file"
# restore the working directory after work.
cd -- "$working_dir"
echo "$result"
}

View File

@@ -1,50 +0,0 @@
#!/bin/sh
# Git pre-commit hook that runs multiple hooks specified in $HOOKS.
# Make sure this script is executable. Bypass hooks with git commit --no-verify.
# This file is part of a set of unofficial pre-commit hooks available
# at github.
# Link: https://github.com/githubbrowser/Pre-commit-hooks
# Contact: David Martin, david.martin.mailbox@googlemail.com
###########################################################
# CONFIGURATION:
# pre-commit hooks to be executed. They should be in the same .git/hooks/ folder
# as this script. Hooks should return 0 if successful and nonzero to cancel the
# commit. They are executed in the order in which they are listed.
#HOOKS="pre-commit-compile pre-commit-uncrustify"
HOOKS="pre-commit-clang-format pre-commit-black"
###########################################################
# There should be no need to change anything below this line.
. "$(dirname -- "$0")/canonicalize_filename.sh"
# exit on error
set -e
# Absolute path to this script, e.g. /home/user/bin/foo.sh
SCRIPT="$(canonicalize_filename "$0")"
# Absolute path this script is in, thus /home/user/bin
SCRIPTPATH="$(dirname -- "$SCRIPT")"
for hook in $HOOKS
do
echo "Running hook: $hook"
# run hook if it exists
# if it returns with nonzero exit with 1 and thus abort the commit
if [ -f "$SCRIPTPATH/$hook" ]; then
"$SCRIPTPATH/$hook"
if [ $? != 0 ]; then
exit 1
fi
else
echo "Error: file $hook not found."
echo "Aborting commit. Make sure the hook is in $SCRIPTPATH and executable."
echo "You can disable it by removing it from the list in $SCRIPT."
echo "You can skip all pre-commit hooks with --no-verify (not recommended)."
exit 1
fi
done

View File

@@ -1,202 +0,0 @@
#!/usr/bin/env bash
# git pre-commit hook that runs a black stylecheck.
# Based on pre-commit-clang-format.
##################################################################
# SETTINGS
# Set path to black binary.
BLACK=`which black 2>/dev/null`
BLACK_OPTIONS="-l 120"
# Remove any older patches from previous commits. Set to true or false.
DELETE_OLD_PATCHES=false
# File types to parse.
FILE_NAMES="SConstruct SCsub"
FILE_EXTS=".py"
# Use pygmentize instead of cat to parse diff with highlighting.
# Install it with `pip install pygments` (Linux) or `easy_install Pygments` (Mac)
PYGMENTIZE=`which pygmentize 2>/dev/null`
if [ ! -z "$PYGMENTIZE" ]; then
READER="pygmentize -l diff"
else
READER=cat
fi
# Path to zenity
ZENITY=`which zenity 2>/dev/null`
# Path to xmessage
XMSG=`which xmessage 2>/dev/null`
# Path to powershell (Windows only)
PWSH=`which powershell 2>/dev/null`
##################################################################
# There should be no need to change anything below this line.
. "$(dirname -- "$0")/canonicalize_filename.sh"
# exit on error
set -e
# check whether the given file matches any of the set extensions
matches_name_or_extension() {
local filename=$(basename "$1")
local extension=".${filename##*.}"
for name in $FILE_NAMES; do [[ "$name" == "$filename" ]] && return 0; done
for ext in $FILE_EXTS; do [[ "$ext" == "$extension" ]] && return 0; done
return 1
}
# necessary check for initial commit
if git rev-parse --verify HEAD >/dev/null 2>&1 ; then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
if [ ! -x "$BLACK" ] ; then
if [ ! -t 1 ] ; then
if [ -x "$ZENITY" ] ; then
$ZENITY --error --title="Error" --text="Error: black executable not found."
exit 1
elif [ -x "$XMSG" ] ; then
$XMSG -center -title "Error" "Error: black executable not found."
exit 1
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
winmessage="$(canonicalize_filename "./.git/hooks/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -center -title "Error" --text "Error: black executable not found."
exit 1
fi
fi
printf "Error: black executable not found.\n"
printf "Set the correct path in $(canonicalize_filename "$0").\n"
exit 1
fi
# create a random filename to store our generated patch
prefix="pre-commit-black"
suffix="$(date +%s)"
patch="/tmp/$prefix-$suffix.patch"
# clean up any older black patches
$DELETE_OLD_PATCHES && rm -f /tmp/$prefix*.patch
# create one patch containing all changes to the files
git diff-index --cached --diff-filter=ACMR --name-only $against -- | while read file;
do
# ignore thirdparty files
if grep -q "thirdparty" <<< $file; then
continue;
fi
# ignore file if not one of the names or extensions we handle
if ! matches_name_or_extension "$file"; then
continue;
fi
# format our file with black, create a patch with diff and append it to our $patch
# The sed call is necessary to transform the patch from
# --- $file timestamp
# +++ $file timestamp
# to both lines working on the same file and having a/ and b/ prefix.
# Else it can not be applied with 'git apply'.
"$BLACK" "$BLACK_OPTIONS" --diff "$file" | \
sed -e "1s|--- |--- a/|" -e "2s|+++ |+++ b/|" >> "$patch"
done
# if no patch has been generated all is ok, clean up the file stub and exit
if [ ! -s "$patch" ] ; then
printf "Files in this commit comply with the black formatter rules.\n"
rm -f "$patch"
exit 0
fi
# a patch has been created, notify the user and exit
printf "\nThe following differences were found between the code to commit "
printf "and the black formatter rules:\n\n"
if [ -t 1 ] ; then
$READER "$patch"
printf "\n"
# Allows us to read user input below, assigns stdin to keyboard
exec < /dev/tty
terminal="1"
else
cat "$patch"
printf "\n"
# Allows non zero zenity/powershell output
set +e
terminal="0"
fi
while true; do
if [ $terminal = "0" ] ; then
if [ -x "$ZENITY" ] ; then
choice=$($ZENITY --text-info --filename="$patch" --width=800 --height=600 --title="Do you want to apply that patch?" --ok-label="Apply" --cancel-label="Do not apply" --extra-button="Apply and stage")
if [ "$?" = "0" ] ; then
yn="Y"
else
if [ "$choice" = "Apply and stage" ] ; then
yn="S"
else
yn="N"
fi
fi
elif [ -x "$XMSG" ] ; then
$XMSG -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"
choice=$?
if [ "$choice" = "100" ] ; then
yn="Y"
elif [ "$choice" = "200" ] ; then
yn="S"
else
yn="N"
fi
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
winmessage="$(canonicalize_filename "./.git/hooks/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"
choice=$?
if [ "$choice" = "100" ] ; then
yn="Y"
elif [ "$choice" = "200" ] ; then
yn="S"
else
yn="N"
fi
else
printf "Error: zenity, xmessage, or powershell executable not found.\n"
exit 1
fi
else
read -p "Do you want to apply that patch (Y - Apply, N - Do not apply, S - Apply and stage files)? [Y/N/S] " yn
fi
case $yn in
[Yy] ) git apply $patch;
printf "The patch was applied. You can now stage the changes and commit again.\n\n";
break
;;
[Nn] ) printf "\nYou can apply these changes with:\n git apply $patch\n";
printf "(may need to be called from the root directory of your repository)\n";
printf "Aborting commit. Apply changes and commit again or skip checking with";
printf " --no-verify (not recommended).\n\n";
break
;;
[Ss] ) git apply $patch;
git diff-index --cached --diff-filter=ACMR --name-only $against -- | while read file;
do git add $file;
done
printf "The patch was applied and the changed files staged. You can now commit.\n\n";
break
;;
* ) echo "Please answer yes or no."
;;
esac
done
exit 1 # we don't commit in any case

View File

@@ -1,242 +0,0 @@
#!/usr/bin/env bash
# git pre-commit hook that runs a clang-format stylecheck.
# Features:
# - abort commit when commit does not comply with the style guidelines
# - create a patch of the proposed style changes
# Modifications for clang-format by rene.milk@wwu.de
# This file is part of a set of unofficial pre-commit hooks available
# at github.
# Link: https://github.com/githubbrowser/Pre-commit-hooks
# Contact: David Martin, david.martin.mailbox@googlemail.com
# Some quality of life modifications made for Godot Engine.
##################################################################
# SETTINGS
# Set path to clang-format binary.
CLANG_FORMAT=`which clang-format 2>/dev/null`
# Remove any older patches from previous commits. Set to true or false.
DELETE_OLD_PATCHES=false
# Only parse files with the extensions in FILE_EXTS. Set to true or false.
# If false every changed file in the commit will be parsed with clang-format.
# If true only files matching one of the extensions are parsed with clang-format.
PARSE_EXTS=true
# File types to parse. Only effective when PARSE_EXTS is true.
FILE_EXTS=".c .h .cpp .hpp .cc .hh .cxx .m .mm .inc .java .glsl"
# Use pygmentize instead of cat to parse diff with highlighting.
# Install it with `pip install pygments` (Linux) or `easy_install Pygments` (Mac)
PYGMENTIZE=`which pygmentize 2>/dev/null`
if [ ! -z "$PYGMENTIZE" ]; then
READER="pygmentize -l diff"
else
READER=cat
fi
# Path to zenity
ZENITY=`which zenity 2>/dev/null`
# Path to xmessage
XMSG=`which xmessage 2>/dev/null`
# Path to powershell (Windows only)
PWSH=`which powershell 2>/dev/null`
##################################################################
# There should be no need to change anything below this line.
. "$(dirname -- "$0")/canonicalize_filename.sh"
# exit on error
set -e
# check whether the given file matches any of the set extensions
matches_extension() {
local filename=$(basename "$1")
local extension=".${filename##*.}"
local ext
for ext in $FILE_EXTS; do [[ "$ext" == "$extension" ]] && return 0; done
return 1
}
# necessary check for initial commit
if git rev-parse --verify HEAD >/dev/null 2>&1 ; then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# To get consistent formatting, we recommend contributors to use the same
# clang-format version as CI.
RECOMMENDED_CLANG_FORMAT_MAJOR_MIN="12"
RECOMMENDED_CLANG_FORMAT_MAJOR_MAX="13"
if [ ! -x "$CLANG_FORMAT" ] ; then
message="Error: clang-format executable not found. Please install clang-format $RECOMMENDED_CLANG_FORMAT_MAJOR_MAX."
if [ ! -t 1 ] ; then
if [ -x "$ZENITY" ] ; then
$ZENITY --error --title="Error" --text="$message"
exit 1
elif [ -x "$XMSG" ] ; then
$XMSG -center -title "Error" "$message"
exit 1
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
winmessage="$(canonicalize_filename "./.git/hooks/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -center -title "Error" --text "$message"
exit 1
fi
fi
printf "$message\n"
printf "Set the correct path in $(canonicalize_filename "$0").\n"
exit 1
fi
# The returned string can be inconsistent depending on where clang-format comes from.
# Example output strings reported by `clang-format --version`:
# - Ubuntu: "Ubuntu clang-format version 11.0.0-2"
# - Fedora: "clang-format version 11.0.0 (Fedora 11.0.0-2.fc33)"
CLANG_FORMAT_VERSION="$(clang-format --version | sed "s/[^0-9\.]*\([0-9\.]*\).*/\1/")"
CLANG_FORMAT_MAJOR="$(echo "$CLANG_FORMAT_VERSION" | cut -d. -f1)"
if [[ "$CLANG_FORMAT_MAJOR" -lt "$RECOMMENDED_CLANG_FORMAT_MAJOR_MIN" || "$CLANG_FORMAT_MAJOR" -gt "$RECOMMENDED_CLANG_FORMAT_MAJOR_MAX" ]]; then
echo "Warning: Your clang-format binary is the wrong version ($CLANG_FORMAT_VERSION, expected between $RECOMMENDED_CLANG_FORMAT_MAJOR_MIN and $RECOMMENDED_CLANG_FORMAT_MAJOR_MAX)."
echo " Consider upgrading or downgrading clang-format as formatting may not be applied correctly."
fi
# create a random filename to store our generated patch
prefix="pre-commit-clang-format"
suffix="$(date +%s)"
patch="/tmp/$prefix-$suffix.patch"
# clean up any older clang-format patches
$DELETE_OLD_PATCHES && rm -f /tmp/$prefix*.patch
# create one patch containing all changes to the files
git diff-index --cached --diff-filter=ACMR --name-only $against -- | while read file;
do
# ignore thirdparty files
if grep -q "thirdparty" <<< $file; then
continue;
fi
if grep -q "platform/android/java/lib/src/com" <<< $file; then
continue;
fi
if grep -q "\-so_wrap." <<< $file; then
continue;
fi
# ignore file if we do check for file extensions and the file
# does not match any of the extensions specified in $FILE_EXTS
if $PARSE_EXTS && ! matches_extension "$file"; then
continue;
fi
# clang-format our sourcefile, create a patch with diff and append it to our $patch
# The sed call is necessary to transform the patch from
# --- $file timestamp
# +++ - timestamp
# to both lines working on the same file and having a/ and b/ prefix.
# Else it can not be applied with 'git apply'.
"$CLANG_FORMAT" -style=file "$file" --Wno-error=unknown | \
diff -u "$file" - | \
sed -e "1s|--- |--- a/|" -e "2s|+++ -|+++ b/$file|" >> "$patch"
done
# if no patch has been generated all is ok, clean up the file stub and exit
if [ ! -s "$patch" ] ; then
printf "Files in this commit comply with the clang-format rules.\n"
rm -f "$patch"
exit 0
fi
# a patch has been created, notify the user and exit
printf "\nThe following differences were found between the code to commit "
printf "and the clang-format rules:\n\n"
if [ -t 1 ] ; then
$READER "$patch"
printf "\n"
# Allows us to read user input below, assigns stdin to keyboard
exec < /dev/tty
terminal="1"
else
cat "$patch"
printf "\n"
# Allows non zero zenity/powershell output
set +e
terminal="0"
fi
while true; do
if [ $terminal = "0" ] ; then
if [ -x "$ZENITY" ] ; then
choice=$($ZENITY --text-info --filename="$patch" --width=800 --height=600 --title="Do you want to apply that patch?" --ok-label="Apply" --cancel-label="Do not apply" --extra-button="Apply and stage")
if [ "$?" = "0" ] ; then
yn="Y"
else
if [ "$choice" = "Apply and stage" ] ; then
yn="S"
else
yn="N"
fi
fi
elif [ -x "$XMSG" ] ; then
$XMSG -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"
choice=$?
if [ "$choice" = "100" ] ; then
yn="Y"
elif [ "$choice" = "200" ] ; then
yn="S"
else
yn="N"
fi
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
winmessage="$(canonicalize_filename "./.git/hooks/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"
choice=$?
if [ "$choice" = "100" ] ; then
yn="Y"
elif [ "$choice" = "200" ] ; then
yn="S"
else
yn="N"
fi
else
printf "Error: zenity, xmessage, or powershell executable not found.\n"
exit 1
fi
else
read -p "Do you want to apply that patch (Y - Apply, N - Do not apply, S - Apply and stage files)? [Y/N/S] " yn
fi
case $yn in
[Yy] ) git apply $patch;
printf "The patch was applied. You can now stage the changes and commit again.\n\n";
break
;;
[Nn] ) printf "\nYou can apply these changes with:\n git apply $patch\n";
printf "(may need to be called from the root directory of your repository)\n";
printf "Aborting commit. Apply changes and commit again or skip checking with";
printf " --no-verify (not recommended).\n\n";
break
;;
[Ss] ) git apply $patch;
git diff-index --cached --diff-filter=ACMR --name-only $against -- | while read file;
do git add $file;
done
printf "The patch was applied and the changed files staged. You can now commit.\n\n";
break
;;
* ) echo "Please answer yes or no."
;;
esac
done
exit 1 # we don't commit in any case

View File

@@ -1,103 +0,0 @@
Param (
[string]$file = "",
[string]$text = "",
[string]$buttons = "OK:0",
[string]$default = "",
[switch]$nearmouse = $false,
[switch]$center = $false,
[string]$geometry = "",
[int32]$timeout = 0,
[string]$title = "Message"
)
Add-Type -assembly System.Windows.Forms
$global:Result = 0
$main_form = New-Object System.Windows.Forms.Form
$main_form.Text = $title
$geometry_data = $geometry.Split("+")
if ($geometry_data.Length -ge 1) {
$size_data = $geometry_data[0].Split("x")
if ($size_data.Length -eq 2) {
$main_form.Width = $size_data[0]
$main_form.Height = $size_data[1]
}
}
if ($geometry_data.Length -eq 3) {
$main_form.StartPosition = [System.Windows.Forms.FormStartPosition]::Manual
$main_form.Location = New-Object System.Drawing.Point($geometry_data[1], $geometry_data[2])
}
if ($nearmouse) {
$main_form.StartPosition = [System.Windows.Forms.FormStartPosition]::Manual
$main_form.Location = System.Windows.Forms.Cursor.Position
}
if ($center) {
$main_form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen
}
$main_form.SuspendLayout()
$button_panel = New-Object System.Windows.Forms.FlowLayoutPanel
$button_panel.SuspendLayout()
$button_panel.FlowDirection = [System.Windows.Forms.FlowDirection]::RightToLeft
$button_panel.Dock = [System.Windows.Forms.DockStyle]::Bottom
$button_panel.Autosize = $true
if ($file -ne "") {
$text = [IO.File]::ReadAllText($file).replace("`n", "`r`n")
}
if ($text -ne "") {
$text_box = New-Object System.Windows.Forms.TextBox
$text_box.Multiline = $true
$text_box.ReadOnly = $true
$text_box.Autosize = $true
$text_box.Text = $text
$text_box.Select(0,0)
$text_box.Dock = [System.Windows.Forms.DockStyle]::Fill
$main_form.Controls.Add($text_box)
}
$buttons_array = $buttons.Split(",")
foreach ($button in $buttons_array) {
$button_data = $button.Split(":")
$button_ctl = New-Object System.Windows.Forms.Button
if ($button_data.Length -eq 2) {
$button_ctl.Tag = $button_data[1]
} else {
$button_ctl.Tag = 100 + $buttons_array.IndexOf($button)
}
if ($default -eq $button_data[0]) {
$main_form.AcceptButton = $button_ctl
}
$button_ctl.Autosize = $true
$button_ctl.Text = $button_data[0]
$button_ctl.Add_Click(
{
Param($sender)
$global:Result = $sender.Tag
$main_form.Close()
}
)
$button_panel.Controls.Add($button_ctl)
}
$main_form.Controls.Add($button_panel)
$button_panel.ResumeLayout($false)
$main_form.ResumeLayout($false)
if ($timeout -gt 0) {
$timer = New-Object System.Windows.Forms.Timer
$timer.Add_Tick(
{
$global:Result = 0
$main_form.Close()
}
)
$timer.Interval = $timeout
$timer.Start()
}
$dlg_res = $main_form.ShowDialog()
[Environment]::Exit($global:Result)

View File

@@ -1,25 +0,0 @@
#!/usr/bin/env bash
# This script runs black on all Python files in the repo.
set -uo pipefail
# Apply black.
echo -e "Formatting Python files..."
PY_FILES=$(git ls-files -- '*SConstruct' '*SCsub' '*.py' ':!:.git/*' ':!:thirdparty/*')
black -l 120 $PY_FILES
diff=$(git diff --color)
# If no patch has been generated all is OK, clean up, and exit.
if [ -z "$diff" ] ; then
printf "Files in this commit comply with the black style rules.\n"
exit 0
fi
# A patch has been created, notify the user, clean up, and exit.
printf "\n*** The following differences were found between the code "
printf "and the formatting rules:\n\n"
echo "$diff"
printf "\n*** Aborting, please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\n"
exit 1

View File

@@ -9,8 +9,8 @@ if len(sys.argv) < 2:
fname = sys.argv[1]
fileread = open(fname.strip(), "r")
file_contents = fileread.read()
with open(fname.strip(), "r", encoding="utf-8") as fileread:
file_contents = fileread.read()
# If find "ERROR: AddressSanitizer:", then happens invalid read or write
# This is critical bug, so we need to fix this as fast as possible
@@ -25,6 +25,8 @@ if (
file_contents.find("Program crashed with signal") != -1
or file_contents.find("Dumping the backtrace") != -1
or file_contents.find("Segmentation fault (core dumped)") != -1
or file_contents.find("Aborted (core dumped)") != -1
or file_contents.find("terminate called without an active exception") != -1
):
print("FATAL ERROR: Godot has been crashed.")
sys.exit(52)

View File

@@ -1,12 +1,12 @@
#!/usr/bin/env python
import os, sys
import os
import sys
from pathlib import Path
sys.path.insert(1, os.path.join(os.path.dirname(__file__), "..", ".."))
from binding_generator import get_file_list, generate_bindings
from binding_generator import generate_bindings, get_file_list
api_filepath = "gdextension/extension_api.json"
bits = "64"

View File

@@ -1,38 +0,0 @@
#!/usr/bin/env bash
# This script runs clang-format and fixes copyright headers on all relevant files in the repo.
# This is the primary script responsible for fixing style violations.
set -uo pipefail
# Loops through all code files tracked by Git.
git ls-files -- '*.c' '*.h' '*.cpp' '*.hpp' '*.cc' '*.hh' '*.cxx' '*.m' '*.mm' '*.inc' |
while read -r f; do
# Run clang-format.
clang-format --Wno-error=unknown -i "$f"
# Fix copyright headers, but not all files get them.
if [[ "$f" == *"inc" ]]; then
continue
elif [[ "$f" == *"glsl" ]]; then
continue
elif [[ "$f" == "test/"* ]]; then
continue
fi
python misc/scripts/copyright_headers.py "$f"
done
diff=$(git diff --color)
# If no patch has been generated all is OK, clean up, and exit.
if [ -z "$diff" ] ; then
printf "Files in this commit comply with the clang-tidy style rules.\n"
exit 0
fi
# A patch has been created, notify the user, clean up, and exit.
printf "\n*** The following changes have been made to comply with the formatting rules:\n\n"
echo "$diff"
printf "\n*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\n"
exit 1

View File

@@ -1,5 +0,0 @@
#!/bin/sh
SKIP_LIST="./thirdparty,*.gen.*,*.po,*.pot,package-lock.json,./core/string/locales.h,./DONORS.md,./misc/scripts/codespell.sh"
IGNORE_LIST="ba,childs,curvelinear,expct,fave,findn,gird,inout,lod,nd,numer,ois,ro,statics,te,varn"
codespell -w -q 3 -S "${SKIP_LIST}" -L "${IGNORE_LIST}"

View File

@@ -1,6 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
header = """\
@@ -35,61 +36,61 @@ header = """\
/**************************************************************************/
"""
fname = sys.argv[1]
if len(sys.argv) < 2:
print("Invalid usage of copyright_headers.py, it should be called with a path to one or multiple files.")
sys.exit(1)
# Handle replacing $filename with actual filename and keep alignment
fsingle = fname.strip()
if fsingle.find("/") != -1:
fsingle = fsingle[fsingle.rfind("/") + 1 :]
rep_fl = "$filename"
rep_fi = fsingle
len_fl = len(rep_fl)
len_fi = len(rep_fi)
# Pad with spaces to keep alignment
if len_fi < len_fl:
for x in range(len_fl - len_fi):
rep_fi += " "
elif len_fl < len_fi:
for x in range(len_fi - len_fl):
rep_fl += " "
if header.find(rep_fl) != -1:
text = header.replace(rep_fl, rep_fi)
else:
text = header.replace("$filename", fsingle)
text += "\n"
for f in sys.argv[1:]:
fname = f
# We now have the proper header, so we want to ignore the one in the original file
# and potentially empty lines and badly formatted lines, while keeping comments that
# come after the header, and then keep everything non-header unchanged.
# To do so, we skip empty lines that may be at the top in a first pass.
# In a second pass, we skip all consecutive comment lines starting with "/*",
# then we can append the rest (step 2).
# Handle replacing $filename with actual filename and keep alignment
fsingle = os.path.basename(fname.strip())
rep_fl = "$filename"
rep_fi = fsingle
len_fl = len(rep_fl)
len_fi = len(rep_fi)
# Pad with spaces to keep alignment
if len_fi < len_fl:
for x in range(len_fl - len_fi):
rep_fi += " "
elif len_fl < len_fi:
for x in range(len_fi - len_fl):
rep_fl += " "
if header.find(rep_fl) != -1:
text = header.replace(rep_fl, rep_fi)
else:
text = header.replace("$filename", fsingle)
text += "\n"
fileread = open(fname.strip(), "r")
line = fileread.readline()
header_done = False
# We now have the proper header, so we want to ignore the one in the original file
# and potentially empty lines and badly formatted lines, while keeping comments that
# come after the header, and then keep everything non-header unchanged.
# To do so, we skip empty lines that may be at the top in a first pass.
# In a second pass, we skip all consecutive comment lines starting with "/*",
# then we can append the rest (step 2).
while line.strip() == "": # Skip empty lines at the top
line = fileread.readline()
with open(fname.strip(), "r", encoding="utf-8") as fileread:
line = fileread.readline()
header_done = False
if line.find("/**********") == -1: # Godot header starts this way
# Maybe starting with a non-Godot comment, abort header magic
header_done = True
while line.strip() == "" and line != "": # Skip empty lines at the top
line = fileread.readline()
while not header_done: # Handle header now
if line.find("/*") != 0: # No more starting with a comment
header_done = True
if line.strip() != "":
if line.find("/**********") == -1: # Godot header starts this way
# Maybe starting with a non-Godot comment, abort header magic
header_done = True
while not header_done: # Handle header now
if line.find("/*") != 0: # No more starting with a comment
header_done = True
if line.strip() != "":
text += line
line = fileread.readline()
while line != "": # Dump everything until EOF
text += line
line = fileread.readline()
line = fileread.readline()
while line != "": # Dump everything until EOF
text += line
line = fileread.readline()
fileread.close()
# Write
filewrite = open(fname.strip(), "w")
filewrite.write(text)
filewrite.close()
# Write
with open(fname.strip(), "w", encoding="utf-8", newline="\n") as filewrite:
filewrite.write(text)

View File

@@ -0,0 +1,46 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
if len(sys.argv) < 2:
print("Invalid usage of file_format.py, it should be called with a path to one or multiple files.")
sys.exit(1)
BOM = b"\xef\xbb\xbf"
changed = []
invalid = []
for file in sys.argv[1:]:
try:
with open(file, "rt", encoding="utf-8") as f:
original = f.read()
except UnicodeDecodeError:
invalid.append(file)
continue
if original == "":
continue
revamp = "\n".join([line.rstrip("\n\r\t ") for line in original.splitlines(True)]).rstrip("\n") + "\n"
new_raw = revamp.encode(encoding="utf-8")
if new_raw.startswith(BOM):
new_raw = new_raw[len(BOM) :]
with open(file, "rb") as f:
old_raw = f.read()
if old_raw != new_raw:
changed.append(file)
with open(file, "wb") as f:
f.write(new_raw)
if changed:
for file in changed:
print(f"FIXED: {file}")
if invalid:
for file in invalid:
print(f"REQUIRES MANUAL CHANGES: {file}")
sys.exit(1)

View File

@@ -1,41 +0,0 @@
#!/usr/bin/env bash
# This script ensures proper POSIX text file formatting and a few other things.
# This is supplementary to clang_format.sh and black_format.sh, but should be
# run before them.
# We need dos2unix and recode.
if [ ! -x "$(command -v dos2unix)" -o ! -x "$(command -v recode)" ]; then
printf "Install 'dos2unix' and 'recode' to use this script.\n"
fi
set -uo pipefail
IFS=$'\n\t'
# Loops through all text files tracked by Git.
git grep -zIl '' |
while IFS= read -rd '' f; do
# Ensure that files are UTF-8 formatted.
recode UTF-8 "$f" 2> /dev/null
# Ensure that files have LF line endings and do not contain a BOM.
dos2unix "$f" 2> /dev/null
# Remove trailing space characters and ensures that files end
# with newline characters. -l option handles newlines conveniently.
perl -i -ple 's/\s*$//g' "$f"
done
diff=$(git diff --color)
# If no patch has been generated all is OK, clean up, and exit.
if [ -z "$diff" ] ; then
printf "Files in this commit comply with the formatting rules.\n"
rm -f patch.patch
exit 0
fi
# A patch has been created, notify the user, clean up, and exit.
printf "\n*** The following differences were found between the code "
printf "and the formatting rules:\n\n"
echo "$diff"
printf "\n*** Aborting, please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\n"
exit 1

View File

@@ -0,0 +1,127 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
from pathlib import Path
if len(sys.argv) < 2:
print("Invalid usage of header_guards.py, it should be called with a path to one or multiple files.")
sys.exit(1)
HEADER_CHECK_OFFSET = 30
HEADER_BEGIN_OFFSET = 31
HEADER_END_OFFSET = -1
changed = []
invalid = []
for file in sys.argv[1:]:
with open(file, "rt", encoding="utf-8", newline="\n") as f:
lines = f.readlines()
if len(lines) <= HEADER_BEGIN_OFFSET:
continue # Most likely a dummy file.
if lines[HEADER_CHECK_OFFSET].startswith("#import"):
continue # Early catch obj-c file.
name = f"GODOT_{Path(file).name}".upper().replace(".", "_").replace("-", "_").replace(" ", "_")
HEADER_CHECK = f"#ifndef {name}\n"
HEADER_BEGIN = f"#define {name}\n"
HEADER_END = f"#endif // {name}\n"
if (
lines[HEADER_CHECK_OFFSET] == HEADER_CHECK
and lines[HEADER_BEGIN_OFFSET] == HEADER_BEGIN
and lines[HEADER_END_OFFSET] == HEADER_END
):
continue
# Guards might exist but with the wrong names.
if (
lines[HEADER_CHECK_OFFSET].startswith("#ifndef")
and lines[HEADER_BEGIN_OFFSET].startswith("#define")
and lines[HEADER_END_OFFSET].startswith("#endif")
):
lines[HEADER_CHECK_OFFSET] = HEADER_CHECK
lines[HEADER_BEGIN_OFFSET] = HEADER_BEGIN
lines[HEADER_END_OFFSET] = HEADER_END
with open(file, "wt", encoding="utf-8", newline="\n") as f:
f.writelines(lines)
changed.append(file)
continue
header_check = -1
header_begin = -1
header_end = -1
pragma_once = -1
objc = False
for idx, line in enumerate(lines):
if not line.startswith("#"):
continue
elif line.startswith("#ifndef") and header_check == -1:
header_check = idx
elif line.startswith("#define") and header_begin == -1:
header_begin = idx
elif line.startswith("#endif") and header_end == -1:
header_end = idx
elif line.startswith("#pragma once"):
pragma_once = idx
break
elif line.startswith("#import"):
objc = True
break
if objc:
continue
if pragma_once != -1:
lines.pop(pragma_once)
lines.insert(HEADER_CHECK_OFFSET, HEADER_CHECK)
lines.insert(HEADER_BEGIN_OFFSET, HEADER_BEGIN)
lines.append("\n")
lines.append(HEADER_END)
with open(file, "wt", encoding="utf-8", newline="\n") as f:
f.writelines(lines)
changed.append(file)
continue
if header_check == -1 and header_begin == -1 and header_end == -1:
# Guards simply didn't exist
lines.insert(HEADER_CHECK_OFFSET, HEADER_CHECK)
lines.insert(HEADER_BEGIN_OFFSET, HEADER_BEGIN)
lines.append("\n")
lines.append(HEADER_END)
with open(file, "wt", encoding="utf-8", newline="\n") as f:
f.writelines(lines)
changed.append(file)
continue
if header_check != -1 and header_begin != -1 and header_end != -1:
# All prepends "found", see if we can salvage this.
if header_check == header_begin - 1 and header_begin < header_end:
lines.pop(header_check)
lines.pop(header_begin - 1)
lines.pop(header_end - 2)
if lines[header_end - 3] == "\n":
lines.pop(header_end - 3)
lines.insert(HEADER_CHECK_OFFSET, HEADER_CHECK)
lines.insert(HEADER_BEGIN_OFFSET, HEADER_BEGIN)
lines.append("\n")
lines.append(HEADER_END)
with open(file, "wt", encoding="utf-8", newline="\n") as f:
f.writelines(lines)
changed.append(file)
continue
invalid.append(file)
if changed:
for file in changed:
print(f"FIXED: {file}")
if invalid:
for file in invalid:
print(f"REQUIRES MANUAL CHANGES: {file}")
sys.exit(1)

View File

@@ -1,60 +0,0 @@
#!/bin/bash
if [ ! -f "SConstruct" ]; then
echo "Warning: This script is intended to be run from the root of the Godot repository."
echo "Some of the paths checks may not work as intended from a different folder."
fi
files_invalid_guard=""
for file in $(find . -name "*.hpp" -print); do
# Skip generated files.
if [[ "$file" == "./gen/"* || "$file" == "./include/gen/"* ]]; then continue; fi
# Skip the test project.
if [[ "$file" == "./test/"* ]]; then continue; fi
bname=$(basename $file .hpp)
# NOTE: The "GODOT_CPP_" prefix is already used by the generated
# bindings, so we can't use that. We'll use "GODOT_" instead.
prefix="GODOT_"
# ^^ is bash builtin for UPPERCASE.
guard="${prefix}${bname^^}_HPP"
# Replaces guards to use computed name.
# We also add some \n to make sure there's a proper separation.
sed -i $file -e "0,/ifndef/s/#ifndef.*/\n#ifndef $guard/"
sed -i $file -e "0,/define/s/#define.*/#define $guard\n/"
sed -i $file -e "$ s/#endif.*/\n#endif \/\/ $guard/"
# Removes redundant \n added before, if they weren't needed.
sed -i $file -e "/^$/N;/^\n$/D"
# Check that first ifndef (should be header guard) is at the expected position.
# If not it can mean we have some code before the guard that should be after.
# "31" is the expected line with the copyright header.
first_ifndef=$(grep -n -m 1 "ifndef" $file | sed 's/\([0-9]*\).*/\1/')
if [[ "$first_ifndef" != "31" ]]; then
files_invalid_guard+="$file\n"
fi
done
if [[ ! -z "$files_invalid_guard" ]]; then
echo -e "The following files were found to have potentially invalid header guard:\n"
echo -e "$files_invalid_guard"
fi
diff=$(git diff --color)
# If no diff has been generated all is OK, clean up, and exit.
if [ -z "$diff" ] ; then
printf "Files in this commit comply with the header guards formatting rules.\n"
exit 0
fi
# A diff has been created, notify the user, clean up, and exit.
printf "\n*** The following differences were found between the code "
printf "and the header guards formatting rules:\n\n"
echo "$diff"
printf "\n*** Aborting, please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\n"
exit 1

View File

@@ -1,11 +0,0 @@
[mypy]
ignore_missing_imports = true
disallow_any_generics = True
pretty = True
show_column_numbers = True
warn_redundant_casts = True
warn_return_any = True
warn_unreachable = True
namespace_packages = True
explicit_package_bases = True

View File

@@ -1,6 +0,0 @@
#!/usr/bin/env bash
set -uo pipefail
echo -e "Python: mypy static analysis..."
mypy --config-file=./misc/scripts/mypy.ini .

58
pyproject.toml Normal file
View File

@@ -0,0 +1,58 @@
[tool.mypy]
disallow_any_generics = true
explicit_package_bases = true
ignore_missing_imports = true
namespace_packages = true
no_implicit_optional = true
pretty = true
scripts_are_modules = true
show_column_numbers = true
warn_redundant_casts = true
warn_return_any = true
warn_unreachable = true
[tool.ruff]
extend-include = ["SConstruct"]
line-length = 120
target-version = "py37"
[tool.ruff.lint]
extend-select = [
"I", # isort
]
[tool.ruff.lint.per-file-ignores]
"SConstruct" = [
"F821", # Undefined name
]
[tool.codespell]
enable-colors = ""
write-changes = ""
check-hidden = ""
quiet-level = 3
builtin = "clear,rare,en-GB_to_en-US"
ignore-words-list = """\
breaked,
cancelled,
checkin,
curvelinear,
doubleclick,
expct,
findn,
gird,
hel,
inout,
labelin,
lod,
mis,
nd,
numer,
ot,
outin,
requestor,
te,
textin,
thirdparty,
vai
"""

View File

@@ -1,5 +1,5 @@
/**************************************************************************/
/* editor_plugin.cpp */
/* editor_plugin_registration.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,9 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/classes/editor_plugin.hpp>
#include <godot_cpp/classes/editor_plugin_registration.hpp>
#include <godot_cpp/variant/string_name.hpp>
#include <godot_cpp/variant/variant.hpp>
namespace godot {

View File

@@ -28,12 +28,16 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <vector>
#include <godot_cpp/classes/wrapped.hpp>
#include <godot_cpp/variant/builtin_types.hpp>
#include <godot_cpp/classes/object.hpp>
#include <godot_cpp/core/class_db.hpp>
namespace godot {
const StringName *Wrapped::_get_extension_class_name() const {
@@ -46,6 +50,9 @@ void Wrapped::_postinitialize() {
godot::internal::gdextension_interface_object_set_instance(_owner, reinterpret_cast<GDExtensionConstStringNamePtr>(extension_class), this);
}
godot::internal::gdextension_interface_object_set_instance_binding(_owner, godot::internal::token, this, _get_bindings_callbacks());
if (extension_class) {
_notificationv(Object::NOTIFICATION_POSTINITIALIZE);
}
}
Wrapped::Wrapped(const StringName p_godot_class) {
@@ -60,4 +67,29 @@ void postinitialize_handler(Wrapped *p_wrapped) {
p_wrapped->_postinitialize();
}
namespace internal {
std::vector<EngineClassRegistrationCallback> &get_engine_class_registration_callbacks() {
static std::vector<EngineClassRegistrationCallback> engine_class_registration_callbacks;
return engine_class_registration_callbacks;
}
void add_engine_class_registration_callback(EngineClassRegistrationCallback p_callback) {
get_engine_class_registration_callbacks().push_back(p_callback);
}
void register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
ClassDB::_register_engine_class(p_name, p_callbacks);
}
void register_engine_classes() {
std::vector<EngineClassRegistrationCallback> &engine_class_registration_callbacks = get_engine_class_registration_callbacks();
for (EngineClassRegistrationCallback cb : engine_class_registration_callbacks) {
cb();
}
engine_class_registration_callbacks.clear();
}
} // namespace internal
} // namespace godot

View File

@@ -77,7 +77,7 @@ void ClassDB::add_property(const StringName &p_class, const PropertyInfo &p_pinf
if (p_setter != String("")) {
setter = get_method(p_class, p_setter);
ERR_FAIL_COND_MSG(!setter, String("Setter method '{0}::{1}()' not found for property '{2}::{3}'.").format(Array::make(p_class, p_setter, p_class, p_pinfo.name)));
ERR_FAIL_NULL_MSG(setter, String("Setter method '{0}::{1}()' not found for property '{2}::{3}'.").format(Array::make(p_class, p_setter, p_class, p_pinfo.name)));
size_t exp_args = 1 + (p_index >= 0 ? 1 : 0);
ERR_FAIL_COND_MSG((int)exp_args != setter->get_argument_count(), String("Setter method '{0}::{1}()' must take a single argument.").format(Array::make(p_class, p_setter)));
@@ -86,7 +86,7 @@ void ClassDB::add_property(const StringName &p_class, const PropertyInfo &p_pinf
ERR_FAIL_COND_MSG(p_getter == String(""), String("Getter method must be specified for '{0}::{1}'.").format(Array::make(p_class, p_pinfo.name)));
MethodBind *getter = get_method(p_class, p_getter);
ERR_FAIL_COND_MSG(!getter, String("Getter method '{0}::{1}()' not found for property '{2}::{3}'.").format(Array::make(p_class, p_getter, p_class, p_pinfo.name)));
ERR_FAIL_NULL_MSG(getter, String("Getter method '{0}::{1}()' not found for property '{2}::{3}'.").format(Array::make(p_class, p_getter, p_class, p_pinfo.name)));
{
size_t exp_args = 0 + (p_index >= 0 ? 1 : 0);
ERR_FAIL_COND_MSG((int)exp_args != getter->get_argument_count(), String("Getter method '{0}::{1}()' must not take any argument.").format(Array::make(p_class, p_getter)));
@@ -318,7 +318,18 @@ GDExtensionClassCallVirtual ClassDB::get_virtual_func(void *p_userdata, GDExtens
const GDExtensionInstanceBindingCallbacks *ClassDB::get_instance_binding_callbacks(const StringName &p_class) {
std::unordered_map<StringName, const GDExtensionInstanceBindingCallbacks *>::iterator callbacks_it = instance_binding_callbacks.find(p_class);
ERR_FAIL_COND_V_MSG(callbacks_it == instance_binding_callbacks.end(), nullptr, String("Cannot find instance binding callbacks for class '{0}'.").format(Array::make(p_class)));
if (likely(callbacks_it != instance_binding_callbacks.end())) {
return callbacks_it->second;
}
// If we don't have an instance binding callback for the given class, find the closest parent where we do.
StringName class_name = p_class;
do {
class_name = get_parent_class(class_name);
ERR_FAIL_COND_V_MSG(class_name == StringName(), nullptr, String("Cannot find instance binding callbacks for class '{0}'.").format(Array::make(p_class)));
callbacks_it = instance_binding_callbacks.find(class_name);
} while (callbacks_it == instance_binding_callbacks.end());
return callbacks_it->second;
}
@@ -349,6 +360,7 @@ void ClassDB::initialize(GDExtensionInitializationLevel p_level) {
}
void ClassDB::deinitialize(GDExtensionInitializationLevel p_level) {
std::set<StringName> to_erase;
for (std::vector<StringName>::reverse_iterator i = class_register_order.rbegin(); i != class_register_order.rend(); ++i) {
const StringName &name = *i;
const ClassInfo &cl = classes[name];
@@ -359,9 +371,20 @@ void ClassDB::deinitialize(GDExtensionInitializationLevel p_level) {
internal::gdextension_interface_classdb_unregister_extension_class(internal::library, name._native_ptr());
for (auto method : cl.method_map) {
for (const std::pair<const StringName, MethodBind *> &method : cl.method_map) {
memdelete(method.second);
}
classes.erase(name);
to_erase.insert(name);
}
{
// The following is equivalent to c++20 `std::erase_if(class_register_order, [&](const StringName& name){ return to_erase.contains(name); });`
std::vector<StringName>::iterator it = std::remove_if(class_register_order.begin(), class_register_order.end(), [&](const StringName &p_name) {
return to_erase.count(p_name) > 0;
});
class_register_order.erase(it, class_register_order.end());
}
}

View File

@@ -36,17 +36,17 @@ namespace godot {
void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
#ifdef DEBUG_ENABLED
bool prepad = false; // Alredy pre paded in the engine.
bool prepad = false; // Already pre paded in the engine.
#else
bool prepad = p_pad_align;
#endif
void *mem = internal::gdextension_interface_mem_alloc(p_bytes + (prepad ? PAD_ALIGN : 0));
ERR_FAIL_COND_V(!mem, nullptr);
void *mem = internal::gdextension_interface_mem_alloc(p_bytes + (prepad ? DATA_OFFSET : 0));
ERR_FAIL_NULL_V(mem, nullptr);
if (prepad) {
uint8_t *s8 = (uint8_t *)mem;
return s8 + PAD_ALIGN;
return s8 + DATA_OFFSET;
} else {
return mem;
}
@@ -63,16 +63,16 @@ void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) {
uint8_t *mem = (uint8_t *)p_memory;
#ifdef DEBUG_ENABLED
bool prepad = false; // Alredy pre paded in the engine.
bool prepad = false; // Already pre paded in the engine.
#else
bool prepad = p_pad_align;
#endif
if (prepad) {
mem -= PAD_ALIGN;
mem = (uint8_t *)internal::gdextension_interface_mem_realloc(mem, p_bytes + PAD_ALIGN);
ERR_FAIL_COND_V(!mem, nullptr);
return mem + PAD_ALIGN;
mem -= DATA_OFFSET;
mem = (uint8_t *)internal::gdextension_interface_mem_realloc(mem, p_bytes + DATA_OFFSET);
ERR_FAIL_NULL_V(mem, nullptr);
return mem + DATA_OFFSET;
} else {
return (uint8_t *)internal::gdextension_interface_mem_realloc(mem, p_bytes);
}
@@ -82,13 +82,13 @@ void Memory::free_static(void *p_ptr, bool p_pad_align) {
uint8_t *mem = (uint8_t *)p_ptr;
#ifdef DEBUG_ENABLED
bool prepad = false; // Alredy pre paded in the engine.
bool prepad = false; // Already pre paded in the engine.
#else
bool prepad = p_pad_align;
#endif
if (prepad) {
mem -= PAD_ALIGN;
mem -= DATA_OFFSET;
}
internal::gdextension_interface_mem_free(mem);
}

View File

@@ -60,8 +60,66 @@ Object *get_object_instance_binding(GodotObject *p_engine_object) {
return reinterpret_cast<Object *>(gdextension_interface_object_get_instance_binding(p_engine_object, token, binding_callbacks));
}
TypedArray<Dictionary> convert_property_list(const std::vector<PropertyInfo> &p_list) {
TypedArray<Dictionary> va;
for (const PropertyInfo &pi : p_list) {
va.push_back(Dictionary(pi));
}
return va;
}
} // namespace internal
MethodInfo::operator Dictionary() const {
Dictionary dict;
dict["name"] = name;
dict["args"] = internal::convert_property_list(arguments);
Array da;
for (size_t i = 0; i < default_arguments.size(); i++) {
da.push_back(default_arguments[i]);
}
dict["default_args"] = da;
dict["flags"] = flags;
dict["id"] = id;
Dictionary r = return_val;
dict["return"] = r;
return dict;
}
MethodInfo MethodInfo::from_dict(const Dictionary &p_dict) {
MethodInfo mi;
if (p_dict.has("name")) {
mi.name = p_dict["name"];
}
Array args;
if (p_dict.has("args")) {
args = p_dict["args"];
}
for (int i = 0; i < args.size(); i++) {
Dictionary d = args[i];
mi.arguments.push_back(PropertyInfo::from_dict(d));
}
Array defargs;
if (p_dict.has("default_args")) {
defargs = p_dict["default_args"];
}
for (int i = 0; i < defargs.size(); i++) {
mi.default_arguments.push_back(defargs[i]);
}
if (p_dict.has("return")) {
mi.return_val = PropertyInfo::from_dict(p_dict["return"]);
}
if (p_dict.has("flags")) {
mi.flags = p_dict["flags"];
}
return mi;
}
MethodInfo::MethodInfo() :
flags(GDEXTENSION_METHOD_FLAG_NORMAL) {}

View File

@@ -30,10 +30,11 @@
#include <godot_cpp/godot.hpp>
#include <godot_cpp/classes/editor_plugin.hpp>
#include <godot_cpp/classes/editor_plugin_registration.hpp>
#include <godot_cpp/classes/wrapped.hpp>
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/core/version.hpp>
#include <godot_cpp/variant/variant.hpp>
#include <godot_cpp/core/error_macros.hpp>
@@ -188,13 +189,19 @@ GDExtensionInterfaceEditorRemovePlugin gdextension_interface_editor_remove_plugi
} // namespace internal
GDExtensionBinding::Callback GDExtensionBinding::init_callback = nullptr;
GDExtensionBinding::Callback GDExtensionBinding::terminate_callback = nullptr;
GDExtensionInitializationLevel GDExtensionBinding::minimum_initialization_level = GDEXTENSION_INITIALIZATION_CORE;
bool GDExtensionBinding::api_initialized = false;
int GDExtensionBinding::level_initialized[MODULE_INITIALIZATION_LEVEL_MAX] = { 0 };
GDExtensionBinding::InitDataList GDExtensionBinding::initdata;
#define LOAD_PROC_ADDRESS(m_name, m_type) \
internal::gdextension_interface_##m_name = (m_type)p_get_proc_address(#m_name); \
ERR_FAIL_NULL_V_MSG(internal::gdextension_interface_##m_name, false, "Unable to load GDExtension interface function " #m_name "()")
#define ERR_PRINT_EARLY(m_msg) \
internal::gdextension_interface_print_error(m_msg, FUNCTION_STR, __FILE__, __LINE__, false)
#define LOAD_PROC_ADDRESS(m_name, m_type) \
internal::gdextension_interface_##m_name = (m_type)p_get_proc_address(#m_name); \
if (!internal::gdextension_interface_##m_name) { \
ERR_PRINT_EARLY("Unable to load GDExtension interface function " #m_name "()"); \
return false; \
}
// Partial definition of the legacy interface so we can detect it and show an error.
typedef struct {
@@ -211,20 +218,34 @@ typedef struct {
GDExtensionInterfacePrintErrorWithMessage print_error_with_message;
} LegacyGDExtensionInterface;
GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, InitData *p_init_data, GDExtensionInitialization *r_initialization) {
if (!p_init_data || !p_init_data->init_callback) {
ERR_FAIL_V_MSG(false, "Initialization callback must be defined.");
}
if (api_initialized) {
r_initialization->initialize = initialize_level;
r_initialization->deinitialize = deinitialize_level;
r_initialization->userdata = p_init_data;
r_initialization->minimum_initialization_level = p_init_data->minimum_initialization_level;
return true;
}
// Make sure we weren't passed the legacy struct.
uint32_t *raw_interface = (uint32_t *)(void *)p_get_proc_address;
if (raw_interface[0] == 4 && raw_interface[1] == 0) {
// Use the legacy interface only to give a nice error.
LegacyGDExtensionInterface *legacy_interface = (LegacyGDExtensionInterface *)p_get_proc_address;
internal::gdextension_interface_print_error_with_message = (GDExtensionInterfacePrintErrorWithMessage)legacy_interface->print_error_with_message;
ERR_FAIL_V_MSG(false, "Cannot load a GDExtension built for Godot 4.1+ in Godot 4.0.");
internal::gdextension_interface_print_error = (GDExtensionInterfacePrintError)legacy_interface->print_error;
ERR_PRINT_EARLY("Cannot load a GDExtension built for Godot 4.1+ in Godot 4.0.");
return false;
}
// Load the "print_error_with_message" function first (needed by the ERR_FAIL_NULL_V_MSG() macro).
internal::gdextension_interface_print_error_with_message = (GDExtensionInterfacePrintErrorWithMessage)p_get_proc_address("print_error_with_message");
if (!internal::gdextension_interface_print_error_with_message) {
printf("ERROR: Unable to load GDExtension interface function print_error_with_message().\n");
// Load the "print_error" function first (needed by the ERR_PRINT_EARLY() macro).
internal::gdextension_interface_print_error = (GDExtensionInterfacePrintError)p_get_proc_address("print_error");
if (!internal::gdextension_interface_print_error) {
printf("ERROR: Unable to load GDExtension interface function print_error().\n");
return false;
}
@@ -233,10 +254,38 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
internal::token = p_library;
LOAD_PROC_ADDRESS(get_godot_version, GDExtensionInterfaceGetGodotVersion);
internal::gdextension_interface_get_godot_version(&internal::godot_version);
// Check that godot-cpp was compiled using an extension_api.json older or at the
// same version as the Godot that is loading it.
bool compatible;
if (internal::godot_version.major != GODOT_VERSION_MAJOR) {
compatible = internal::godot_version.major > GODOT_VERSION_MAJOR;
} else if (internal::godot_version.minor != GODOT_VERSION_MINOR) {
compatible = internal::godot_version.minor > GODOT_VERSION_MINOR;
} else {
#if GODOT_VERSION_PATCH > 0
compatible = internal::godot_version.patch >= GODOT_VERSION_PATCH;
#else
// Prevent -Wtype-limits warning due to unsigned comparison.
compatible = true;
#endif
}
if (!compatible) {
// We need to use snprintf() here because vformat() uses Variant, and we haven't loaded
// the GDExtension interface far enough to use Variants yet.
char msg[128];
snprintf(msg, 128, "Cannot load a GDExtension built for Godot %d.%d.%d using an older version of Godot (%d.%d.%d).",
GODOT_VERSION_MAJOR, GODOT_VERSION_MINOR, GODOT_VERSION_PATCH,
internal::godot_version.major, internal::godot_version.minor, internal::godot_version.patch);
ERR_PRINT_EARLY(msg);
return false;
}
LOAD_PROC_ADDRESS(mem_alloc, GDExtensionInterfaceMemAlloc);
LOAD_PROC_ADDRESS(mem_realloc, GDExtensionInterfaceMemRealloc);
LOAD_PROC_ADDRESS(mem_free, GDExtensionInterfaceMemFree);
LOAD_PROC_ADDRESS(print_error, GDExtensionInterfacePrintError);
LOAD_PROC_ADDRESS(print_error_with_message, GDExtensionInterfacePrintErrorWithMessage);
LOAD_PROC_ADDRESS(print_warning, GDExtensionInterfacePrintWarning);
LOAD_PROC_ADDRESS(print_warning_with_message, GDExtensionInterfacePrintWarningWithMessage);
LOAD_PROC_ADDRESS(print_script_error, GDExtensionInterfacePrintScriptError);
@@ -368,63 +417,98 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
LOAD_PROC_ADDRESS(editor_add_plugin, GDExtensionInterfaceEditorAddPlugin);
LOAD_PROC_ADDRESS(editor_remove_plugin, GDExtensionInterfaceEditorRemovePlugin);
// Load the Godot version.
internal::gdextension_interface_get_godot_version(&internal::godot_version);
r_initialization->initialize = initialize_level;
r_initialization->deinitialize = deinitialize_level;
r_initialization->minimum_initialization_level = minimum_initialization_level;
ERR_FAIL_COND_V_MSG(init_callback == nullptr, false, "Initialization callback must be defined.");
r_initialization->userdata = p_init_data;
r_initialization->minimum_initialization_level = p_init_data->minimum_initialization_level;
Variant::init_bindings();
register_engine_classes();
godot::internal::register_engine_classes();
api_initialized = true;
return true;
}
#undef LOAD_PROC_ADDRESS
#undef ERR_PRINT_EARLY
void GDExtensionBinding::initialize_level(void *userdata, GDExtensionInitializationLevel p_level) {
void GDExtensionBinding::initialize_level(void *p_userdata, GDExtensionInitializationLevel p_level) {
ERR_FAIL_COND(static_cast<ModuleInitializationLevel>(p_level) >= MODULE_INITIALIZATION_LEVEL_MAX);
ClassDB::current_level = p_level;
if (init_callback) {
init_callback(static_cast<ModuleInitializationLevel>(p_level));
InitData *init_data = static_cast<InitData *>(p_userdata);
if (init_data && init_data->init_callback) {
init_data->init_callback(static_cast<ModuleInitializationLevel>(p_level));
}
ClassDB::initialize(p_level);
if (level_initialized[p_level] == 0) {
ClassDB::initialize(p_level);
}
level_initialized[p_level]++;
}
void GDExtensionBinding::deinitialize_level(void *userdata, GDExtensionInitializationLevel p_level) {
void GDExtensionBinding::deinitialize_level(void *p_userdata, GDExtensionInitializationLevel p_level) {
ERR_FAIL_COND(static_cast<ModuleInitializationLevel>(p_level) >= MODULE_INITIALIZATION_LEVEL_MAX);
ClassDB::current_level = p_level;
if (terminate_callback) {
terminate_callback(static_cast<ModuleInitializationLevel>(p_level));
InitData *init_data = static_cast<InitData *>(p_userdata);
if (init_data && init_data->terminate_callback) {
init_data->terminate_callback(static_cast<ModuleInitializationLevel>(p_level));
}
EditorPlugins::deinitialize(p_level);
ClassDB::deinitialize(p_level);
level_initialized[p_level]--;
if (level_initialized[p_level] == 0) {
EditorPlugins::deinitialize(p_level);
ClassDB::deinitialize(p_level);
}
}
void GDExtensionBinding::InitDataList::add(InitData *p_data) {
if (data_count == data_capacity) {
void *new_ptr = realloc(data, sizeof(InitData *) * (data_capacity + 32));
if (new_ptr) {
data = (InitData **)(new_ptr);
data_capacity += 32;
} else {
ERR_FAIL_MSG("Unable to allocate memory for extension callbacks.");
}
}
data[data_count++] = p_data;
}
GDExtensionBinding::InitDataList::~InitDataList() {
for (int i = 0; i < data_count; i++) {
if (data[i]) {
delete data[i];
}
}
if (data) {
free(data);
}
}
GDExtensionBinding::InitObject::InitObject(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
get_proc_address = p_get_proc_address;
library = p_library;
initialization = r_initialization;
init_data = new InitData();
GDExtensionBinding::initdata.add(init_data);
}
void GDExtensionBinding::InitObject::register_initializer(Callback p_init) const {
GDExtensionBinding::init_callback = p_init;
init_data->init_callback = p_init;
}
void GDExtensionBinding::InitObject::register_terminator(Callback p_terminate) const {
GDExtensionBinding::terminate_callback = p_terminate;
init_data->terminate_callback = p_terminate;
}
void GDExtensionBinding::InitObject::set_minimum_library_initialization_level(ModuleInitializationLevel p_level) const {
GDExtensionBinding::minimum_initialization_level = static_cast<GDExtensionInitializationLevel>(p_level);
init_data->minimum_initialization_level = static_cast<GDExtensionInitializationLevel>(p_level);
}
GDExtensionBool GDExtensionBinding::InitObject::init() const {
return GDExtensionBinding::init(get_proc_address, library, initialization);
return GDExtensionBinding::init(get_proc_address, library, init_data, initialization);
}
} // namespace godot

View File

@@ -78,6 +78,10 @@ bool AABB::is_equal_approx(const AABB &p_aabb) const {
return position.is_equal_approx(p_aabb.position) && size.is_equal_approx(p_aabb.size);
}
bool AABB::is_finite() const {
return position.is_finite() && size.is_finite();
}
AABB AABB::intersection(const AABB &p_aabb) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) {

View File

@@ -692,6 +692,10 @@ bool Basis::is_equal_approx(const Basis &p_basis) const {
return rows[0].is_equal_approx(p_basis.rows[0]) && rows[1].is_equal_approx(p_basis.rows[1]) && rows[2].is_equal_approx(p_basis.rows[2]);
}
bool Basis::is_finite() const {
return rows[0].is_finite() && rows[1].is_finite() && rows[2].is_finite();
}
bool Basis::operator==(const Basis &p_matrix) const {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
@@ -812,7 +816,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
return;
}
// As we have reached here there are no singularities so we can handle normally.
double s = Math::sqrt((rows[2][1] - rows[1][2]) * (rows[2][1] - rows[1][2]) + (rows[0][2] - rows[2][0]) * (rows[0][2] - rows[2][0]) + (rows[1][0] - rows[0][1]) * (rows[1][0] - rows[0][1])); // Used to normalise.
double s = Math::sqrt((rows[2][1] - rows[1][2]) * (rows[2][1] - rows[1][2]) + (rows[0][2] - rows[2][0]) * (rows[0][2] - rows[2][0]) + (rows[1][0] - rows[0][1]) * (rows[1][0] - rows[0][1])); // Used to normalize.
if (Math::abs(s) < CMP_EPSILON) {
// Prevent divide by zero, should not happen if matrix is orthogonal and should be caught by singularity test above.

View File

@@ -38,117 +38,121 @@
#include <godot_cpp/godot.hpp>
#include <cmath>
#include <string>
namespace godot {
int CharString::length() const {
return _length;
}
template <typename L, typename R>
_FORCE_INLINE_ bool is_str_less(const L *l_ptr, const R *r_ptr) {
while (true) {
const char32_t l = *l_ptr;
const char32_t r = *r_ptr;
const char *CharString::get_data() const {
return _data;
}
if (l == 0 && r == 0) {
return false;
} else if (l == 0) {
return true;
} else if (r == 0) {
return false;
} else if (l < r) {
return true;
} else if (l > r) {
return false;
}
CharString::CharString(CharString &&p_str) {
SWAP(_length, p_str._length);
SWAP(_data, p_str._data);
}
void CharString::operator=(CharString &&p_str) {
SWAP(_length, p_str._length);
SWAP(_data, p_str._data);
}
CharString::CharString(const char *str, int length) :
_data(str), _length(length) {}
CharString::~CharString() {
if (_data != nullptr) {
memdelete_arr(_data);
l_ptr++;
r_ptr++;
}
}
int Char16String::length() const {
return _length;
template <typename T>
bool CharStringT<T>::operator<(const CharStringT<T> &p_right) const {
if (length() == 0) {
return p_right.length() != 0;
}
return is_str_less(get_data(), p_right.get_data());
}
const char16_t *Char16String::get_data() const {
return _data;
template <typename T>
CharStringT<T> &CharStringT<T>::operator+=(T p_char) {
const int64_t lhs_len = length();
resize(lhs_len + 2);
T *dst = ptrw();
dst[lhs_len] = p_char;
dst[lhs_len + 1] = 0;
return *this;
}
Char16String::Char16String(Char16String &&p_str) {
SWAP(_length, p_str._length);
SWAP(_data, p_str._data);
template <typename T>
void CharStringT<T>::operator=(const T *p_cstr) {
copy_from(p_cstr);
}
void Char16String::operator=(Char16String &&p_str) {
SWAP(_length, p_str._length);
SWAP(_data, p_str._data);
}
Char16String::Char16String(const char16_t *str, int length) :
_data(str), _length(length) {}
Char16String::~Char16String() {
if (_data != nullptr) {
memdelete_arr(_data);
template <>
const char *CharStringT<char>::get_data() const {
if (size()) {
return &operator[](0);
} else {
return "";
}
}
int Char32String::length() const {
return _length;
}
const char32_t *Char32String::get_data() const {
return _data;
}
Char32String::Char32String(Char32String &&p_str) {
SWAP(_length, p_str._length);
SWAP(_data, p_str._data);
}
void Char32String::operator=(Char32String &&p_str) {
SWAP(_length, p_str._length);
SWAP(_data, p_str._data);
}
Char32String::Char32String(const char32_t *str, int length) :
_data(str), _length(length) {}
Char32String::~Char32String() {
if (_data != nullptr) {
memdelete_arr(_data);
template <>
const char16_t *CharStringT<char16_t>::get_data() const {
if (size()) {
return &operator[](0);
} else {
return u"";
}
}
int CharWideString::length() const {
return _length;
}
const wchar_t *CharWideString::get_data() const {
return _data;
}
CharWideString::CharWideString(CharWideString &&p_str) {
SWAP(_length, p_str._length);
SWAP(_data, p_str._data);
}
void CharWideString::operator=(CharWideString &&p_str) {
SWAP(_length, p_str._length);
SWAP(_data, p_str._data);
}
CharWideString::CharWideString(const wchar_t *str, int length) :
_data(str), _length(length) {}
CharWideString::~CharWideString() {
if (_data != nullptr) {
memdelete_arr(_data);
template <>
const char32_t *CharStringT<char32_t>::get_data() const {
if (size()) {
return &operator[](0);
} else {
return U"";
}
}
template <>
const wchar_t *CharStringT<wchar_t>::get_data() const {
if (size()) {
return &operator[](0);
} else {
return L"";
}
}
template <typename T>
void CharStringT<T>::copy_from(const T *p_cstr) {
if (!p_cstr) {
resize(0);
return;
}
size_t len = std::char_traits<T>::length(p_cstr);
if (len == 0) {
resize(0);
return;
}
Error err = resize(++len); // include terminating null char
ERR_FAIL_COND_MSG(err != OK, "Failed to copy C-string.");
memcpy(ptrw(), p_cstr, len);
}
template class CharStringT<char>;
template class CharStringT<char16_t>;
template class CharStringT<char32_t>;
template class CharStringT<wchar_t>;
// Custom String functions that are not part of bound API.
// It's easier to have them written in C++ directly than in a Python script that generates them.
@@ -168,23 +172,23 @@ String::String(const char32_t *from) {
internal::gdextension_interface_string_new_with_utf32_chars(_native_ptr(), from);
}
String String::utf8(const char *from, int len) {
String String::utf8(const char *from, int64_t len) {
String ret;
ret.parse_utf8(from, len);
return ret;
}
void String::parse_utf8(const char *from, int len) {
void String::parse_utf8(const char *from, int64_t len) {
internal::gdextension_interface_string_new_with_utf8_chars_and_len(_native_ptr(), from, len);
}
String String::utf16(const char16_t *from, int len) {
String String::utf16(const char16_t *from, int64_t len) {
String ret;
ret.parse_utf16(from, len);
return ret;
}
void String::parse_utf16(const char16_t *from, int len) {
void String::parse_utf16(const char16_t *from, int64_t len) {
internal::gdextension_interface_string_new_with_utf16_chars_and_len(_native_ptr(), from, len);
}
@@ -226,58 +230,63 @@ String rtoss(double p_val) {
}
CharString String::utf8() const {
int length = internal::gdextension_interface_string_to_utf8_chars(_native_ptr(), nullptr, 0);
int size = length + 1;
char *cstr = memnew_arr(char, size);
internal::gdextension_interface_string_to_utf8_chars(_native_ptr(), cstr, length);
int64_t length = internal::gdextension_interface_string_to_utf8_chars(_native_ptr(), nullptr, 0);
int64_t size = length + 1;
CharString str;
str.resize(size);
internal::gdextension_interface_string_to_utf8_chars(_native_ptr(), str.ptrw(), length);
cstr[length] = '\0';
str[length] = '\0';
return CharString(cstr, length);
return str;
}
CharString String::ascii() const {
int length = internal::gdextension_interface_string_to_latin1_chars(_native_ptr(), nullptr, 0);
int size = length + 1;
char *cstr = memnew_arr(char, size);
internal::gdextension_interface_string_to_latin1_chars(_native_ptr(), cstr, length);
int64_t length = internal::gdextension_interface_string_to_latin1_chars(_native_ptr(), nullptr, 0);
int64_t size = length + 1;
CharString str;
str.resize(size);
internal::gdextension_interface_string_to_latin1_chars(_native_ptr(), str.ptrw(), length);
cstr[length] = '\0';
str[length] = '\0';
return CharString(cstr, length);
return str;
}
Char16String String::utf16() const {
int length = internal::gdextension_interface_string_to_utf16_chars(_native_ptr(), nullptr, 0);
int size = length + 1;
char16_t *cstr = memnew_arr(char16_t, size);
internal::gdextension_interface_string_to_utf16_chars(_native_ptr(), cstr, length);
int64_t length = internal::gdextension_interface_string_to_utf16_chars(_native_ptr(), nullptr, 0);
int64_t size = length + 1;
Char16String str;
str.resize(size);
internal::gdextension_interface_string_to_utf16_chars(_native_ptr(), str.ptrw(), length);
cstr[length] = '\0';
str[length] = '\0';
return Char16String(cstr, length);
return str;
}
Char32String String::utf32() const {
int length = internal::gdextension_interface_string_to_utf32_chars(_native_ptr(), nullptr, 0);
int size = length + 1;
char32_t *cstr = memnew_arr(char32_t, size);
internal::gdextension_interface_string_to_utf32_chars(_native_ptr(), cstr, length);
int64_t length = internal::gdextension_interface_string_to_utf32_chars(_native_ptr(), nullptr, 0);
int64_t size = length + 1;
Char32String str;
str.resize(size);
internal::gdextension_interface_string_to_utf32_chars(_native_ptr(), str.ptrw(), length);
cstr[length] = '\0';
str[length] = '\0';
return Char32String(cstr, length);
return str;
}
CharWideString String::wide_string() const {
int length = internal::gdextension_interface_string_to_wide_chars(_native_ptr(), nullptr, 0);
int size = length + 1;
wchar_t *cstr = memnew_arr(wchar_t, size);
internal::gdextension_interface_string_to_wide_chars(_native_ptr(), cstr, length);
int64_t length = internal::gdextension_interface_string_to_wide_chars(_native_ptr(), nullptr, 0);
int64_t size = length + 1;
CharWideString str;
str.resize(size);
internal::gdextension_interface_string_to_wide_chars(_native_ptr(), str.ptrw(), length);
cstr[length] = '\0';
str[length] = '\0';
return CharWideString(cstr, length);
return str;
}
String &String::operator=(const char *p_str) {
@@ -377,11 +386,11 @@ String &String::operator+=(const char32_t *p_str) {
return *this;
}
const char32_t &String::operator[](int p_index) const {
const char32_t &String::operator[](int64_t p_index) const {
return *internal::gdextension_interface_string_operator_index_const((GDExtensionStringPtr)this, p_index);
}
char32_t &String::operator[](int p_index) {
char32_t &String::operator[](int64_t p_index) {
return *internal::gdextension_interface_string_operator_index((GDExtensionStringPtr)this, p_index);
}

View File

@@ -192,7 +192,7 @@ void Color::set_hsv(float p_h, float p_s, float p_v, float p_alpha) {
a = p_alpha;
if (p_s == 0.0f) {
// Achromatic (grey)
// Achromatic (gray)
r = g = b = p_v;
return;
}

View File

@@ -46,11 +46,11 @@
namespace godot {
const uint8_t &PackedByteArray::operator[](int p_index) const {
const uint8_t &PackedByteArray::operator[](int64_t p_index) const {
return *internal::gdextension_interface_packed_byte_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
}
uint8_t &PackedByteArray::operator[](int p_index) {
uint8_t &PackedByteArray::operator[](int64_t p_index) {
return *internal::gdextension_interface_packed_byte_array_operator_index((GDExtensionTypePtr *)this, p_index);
}
@@ -62,12 +62,12 @@ uint8_t *PackedByteArray::ptrw() {
return internal::gdextension_interface_packed_byte_array_operator_index((GDExtensionTypePtr *)this, 0);
}
const Color &PackedColorArray::operator[](int p_index) const {
const Color &PackedColorArray::operator[](int64_t p_index) const {
const Color *color = (const Color *)internal::gdextension_interface_packed_color_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
return *color;
}
Color &PackedColorArray::operator[](int p_index) {
Color &PackedColorArray::operator[](int64_t p_index) {
Color *color = (Color *)internal::gdextension_interface_packed_color_array_operator_index((GDExtensionTypePtr *)this, p_index);
return *color;
}
@@ -80,11 +80,11 @@ Color *PackedColorArray::ptrw() {
return (Color *)internal::gdextension_interface_packed_color_array_operator_index((GDExtensionTypePtr *)this, 0);
}
const float &PackedFloat32Array::operator[](int p_index) const {
const float &PackedFloat32Array::operator[](int64_t p_index) const {
return *internal::gdextension_interface_packed_float32_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
}
float &PackedFloat32Array::operator[](int p_index) {
float &PackedFloat32Array::operator[](int64_t p_index) {
return *internal::gdextension_interface_packed_float32_array_operator_index((GDExtensionTypePtr *)this, p_index);
}
@@ -96,11 +96,11 @@ float *PackedFloat32Array::ptrw() {
return internal::gdextension_interface_packed_float32_array_operator_index((GDExtensionTypePtr *)this, 0);
}
const double &PackedFloat64Array::operator[](int p_index) const {
const double &PackedFloat64Array::operator[](int64_t p_index) const {
return *internal::gdextension_interface_packed_float64_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
}
double &PackedFloat64Array::operator[](int p_index) {
double &PackedFloat64Array::operator[](int64_t p_index) {
return *internal::gdextension_interface_packed_float64_array_operator_index((GDExtensionTypePtr *)this, p_index);
}
@@ -112,11 +112,11 @@ double *PackedFloat64Array::ptrw() {
return internal::gdextension_interface_packed_float64_array_operator_index((GDExtensionTypePtr *)this, 0);
}
const int32_t &PackedInt32Array::operator[](int p_index) const {
const int32_t &PackedInt32Array::operator[](int64_t p_index) const {
return *internal::gdextension_interface_packed_int32_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
}
int32_t &PackedInt32Array::operator[](int p_index) {
int32_t &PackedInt32Array::operator[](int64_t p_index) {
return *internal::gdextension_interface_packed_int32_array_operator_index((GDExtensionTypePtr *)this, p_index);
}
@@ -128,11 +128,11 @@ int32_t *PackedInt32Array::ptrw() {
return internal::gdextension_interface_packed_int32_array_operator_index((GDExtensionTypePtr *)this, 0);
}
const int64_t &PackedInt64Array::operator[](int p_index) const {
const int64_t &PackedInt64Array::operator[](int64_t p_index) const {
return *internal::gdextension_interface_packed_int64_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
}
int64_t &PackedInt64Array::operator[](int p_index) {
int64_t &PackedInt64Array::operator[](int64_t p_index) {
return *internal::gdextension_interface_packed_int64_array_operator_index((GDExtensionTypePtr *)this, p_index);
}
@@ -144,12 +144,12 @@ int64_t *PackedInt64Array::ptrw() {
return internal::gdextension_interface_packed_int64_array_operator_index((GDExtensionTypePtr *)this, 0);
}
const String &PackedStringArray::operator[](int p_index) const {
const String &PackedStringArray::operator[](int64_t p_index) const {
const String *string = (const String *)internal::gdextension_interface_packed_string_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
return *string;
}
String &PackedStringArray::operator[](int p_index) {
String &PackedStringArray::operator[](int64_t p_index) {
String *string = (String *)internal::gdextension_interface_packed_string_array_operator_index((GDExtensionTypePtr *)this, p_index);
return *string;
}
@@ -162,12 +162,12 @@ String *PackedStringArray::ptrw() {
return (String *)internal::gdextension_interface_packed_string_array_operator_index((GDExtensionTypePtr *)this, 0);
}
const Vector2 &PackedVector2Array::operator[](int p_index) const {
const Vector2 &PackedVector2Array::operator[](int64_t p_index) const {
const Vector2 *vec = (const Vector2 *)internal::gdextension_interface_packed_vector2_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
return *vec;
}
Vector2 &PackedVector2Array::operator[](int p_index) {
Vector2 &PackedVector2Array::operator[](int64_t p_index) {
Vector2 *vec = (Vector2 *)internal::gdextension_interface_packed_vector2_array_operator_index((GDExtensionTypePtr *)this, p_index);
return *vec;
}
@@ -180,12 +180,12 @@ Vector2 *PackedVector2Array::ptrw() {
return (Vector2 *)internal::gdextension_interface_packed_vector2_array_operator_index((GDExtensionTypePtr *)this, 0);
}
const Vector3 &PackedVector3Array::operator[](int p_index) const {
const Vector3 &PackedVector3Array::operator[](int64_t p_index) const {
const Vector3 *vec = (const Vector3 *)internal::gdextension_interface_packed_vector3_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
return *vec;
}
Vector3 &PackedVector3Array::operator[](int p_index) {
Vector3 &PackedVector3Array::operator[](int64_t p_index) {
Vector3 *vec = (Vector3 *)internal::gdextension_interface_packed_vector3_array_operator_index((GDExtensionTypePtr *)this, p_index);
return *vec;
}
@@ -198,12 +198,12 @@ Vector3 *PackedVector3Array::ptrw() {
return (Vector3 *)internal::gdextension_interface_packed_vector3_array_operator_index((GDExtensionTypePtr *)this, 0);
}
const Variant &Array::operator[](int p_index) const {
const Variant &Array::operator[](int64_t p_index) const {
const Variant *var = (const Variant *)internal::gdextension_interface_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
return *var;
}
Variant &Array::operator[](int p_index) {
Variant &Array::operator[](int64_t p_index) {
Variant *var = (Variant *)internal::gdextension_interface_array_operator_index((GDExtensionTypePtr *)this, p_index);
return *var;
}

View File

@@ -178,6 +178,10 @@ bool Plane::is_equal_approx(const Plane &p_plane) const {
return normal.is_equal_approx(p_plane.normal) && Math::is_equal_approx(d, p_plane.d);
}
bool Plane::is_finite() const {
return normal.is_finite() && Math::is_finite(d);
}
Plane::operator String() const {
return "[N: " + normal.operator String() + ", D: " + String::num_real(d, false) + "]";
}

View File

@@ -136,7 +136,7 @@ Projection Projection::create_for_hmd(int p_eye, real_t p_aspect, real_t p_intra
Projection Projection::create_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar) {
Projection proj;
proj.set_orthogonal(p_left, p_right, p_bottom, p_top, p_zfar, p_zfar);
proj.set_orthogonal(p_left, p_right, p_bottom, p_top, p_znear, p_zfar);
return proj;
}

View File

@@ -81,6 +81,10 @@ bool Quaternion::is_equal_approx(const Quaternion &p_quaternion) const {
return Math::is_equal_approx(x, p_quaternion.x) && Math::is_equal_approx(y, p_quaternion.y) && Math::is_equal_approx(z, p_quaternion.z) && Math::is_equal_approx(w, p_quaternion.w);
}
bool Quaternion::is_finite() const {
return Math::is_finite(x) && Math::is_finite(y) && Math::is_finite(z) && Math::is_finite(w);
}
real_t Quaternion::length() const {
return Math::sqrt(length_squared());
}

View File

@@ -40,6 +40,10 @@ bool Rect2::is_equal_approx(const Rect2 &p_rect) const {
return position.is_equal_approx(p_rect.position) && size.is_equal_approx(p_rect.size);
}
bool Rect2::is_finite() const {
return position.is_finite() && size.is_finite();
}
bool Rect2::intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos, Point2 *r_normal) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) {

View File

@@ -170,6 +170,10 @@ bool Transform2D::is_equal_approx(const Transform2D &p_transform) const {
return columns[0].is_equal_approx(p_transform.columns[0]) && columns[1].is_equal_approx(p_transform.columns[1]) && columns[2].is_equal_approx(p_transform.columns[2]);
}
bool Transform2D::is_finite() const {
return columns[0].is_finite() && columns[1].is_finite() && columns[2].is_finite();
}
Transform2D Transform2D::looking_at(const Vector2 &p_target) const {
Transform2D return_trans = Transform2D(get_rotation(), get_origin());
Vector2 target_position = affine_inverse().xform(p_target);

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