mirror of
https://github.com/godotengine/godot-cpp.git
synced 2026-01-01 05:48:37 +03:00
Compare commits
1018 Commits
godot-3.3.
...
4.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5cc777a89 | ||
|
|
b1e2ac5cbb | ||
|
|
53caa6adbc | ||
|
|
a9abdb5f0c | ||
|
|
9892f63abb | ||
|
|
7b4ca64761 | ||
|
|
6cdac999c2 | ||
|
|
48544896ee | ||
|
|
443c075fa3 | ||
|
|
52937a3850 | ||
|
|
888f46bbcc | ||
|
|
de7e5b9145 | ||
|
|
8fffe3b558 | ||
|
|
dcd0842fab | ||
|
|
dacaa81f2f | ||
|
|
40e65753f9 | ||
|
|
2dee0cc4de | ||
|
|
3f454d142d | ||
|
|
f3a1a2fd45 | ||
|
|
08e4c89da9 | ||
|
|
86d0dbe695 | ||
|
|
dc87cb6b97 | ||
|
|
4b9cd6ae9d | ||
|
|
fba9ecd0da | ||
|
|
59ad323dd1 | ||
|
|
9dc2e15d90 | ||
|
|
2d96b62774 | ||
|
|
2cd6221286 | ||
|
|
d6a47a28c7 | ||
|
|
f2303ba0cc | ||
|
|
c9da56cca2 | ||
|
|
3449c4e1d3 | ||
|
|
0899cf6098 | ||
|
|
06fbf3ce95 | ||
|
|
d5bdde9509 | ||
|
|
9ded2402dc | ||
|
|
575f317bf1 | ||
|
|
56571dc584 | ||
|
|
94d74979ce | ||
|
|
bf26191ead | ||
|
|
af78f2778f | ||
|
|
30a395bf43 | ||
|
|
a3d5d6d4d3 | ||
|
|
e751531290 | ||
|
|
2de650b82a | ||
|
|
5fe58bcd1e | ||
|
|
daf8ac1c33 | ||
|
|
b12aeb1b38 | ||
|
|
fa0b4cffc0 | ||
|
|
e52b4ea4fd | ||
|
|
20459da676 | ||
|
|
1cce4d15ab | ||
|
|
17ca325aeb | ||
|
|
e298f430b5 | ||
|
|
1ac33c906e | ||
|
|
842a7f621f | ||
|
|
37d255af6c | ||
|
|
762db4e4d6 | ||
|
|
c823e84ff2 | ||
|
|
26cb3292a0 | ||
|
|
150e45071b | ||
|
|
fbbf9ec4ef | ||
|
|
2e4c350b83 | ||
|
|
9b98377a62 | ||
|
|
92e6ea7303 | ||
|
|
11773e52b0 | ||
|
|
937b1d809a | ||
|
|
738859f49b | ||
|
|
9da1e0cee1 | ||
|
|
3f4590f8e1 | ||
|
|
e3e8101e8c | ||
|
|
26459dc47b | ||
|
|
daf6ad3649 | ||
|
|
c77d44f3f6 | ||
|
|
f2b521f55a | ||
|
|
628606b28b | ||
|
|
958776dfc3 | ||
|
|
0a1e31fa45 | ||
|
|
8012716ee3 | ||
|
|
76b38de01a | ||
|
|
6d939e6878 | ||
|
|
56cd3fd99e | ||
|
|
99926d8e20 | ||
|
|
e65ec904b8 | ||
|
|
2b34bd0d8b | ||
|
|
53b546e1df | ||
|
|
7abe4ca9e4 | ||
|
|
316dde80ba | ||
|
|
7d7799b56e | ||
|
|
90c6ea2a12 | ||
|
|
1989b1bf57 | ||
|
|
7a96d0314e | ||
|
|
999018e7d1 | ||
|
|
e0d363aad8 | ||
|
|
c414c2b37d | ||
|
|
78b63203d4 | ||
|
|
0efc6cddbc | ||
|
|
e7a13e3bf4 | ||
|
|
ed1e963a31 | ||
|
|
068e930c6a | ||
|
|
2dd8917508 | ||
|
|
89831ff333 | ||
|
|
f2ac49aea5 | ||
|
|
1186c488bd | ||
|
|
8cdd56e149 | ||
|
|
f1b7ba3e06 | ||
|
|
5d8f80bc55 | ||
|
|
9e2771f918 | ||
|
|
ee9acbcf10 | ||
|
|
64f1bc847a | ||
|
|
1bb543b6f4 | ||
|
|
37e7a6da05 | ||
|
|
6c4064125b | ||
|
|
9f6fe36633 | ||
|
|
2360f84513 | ||
|
|
6cd6c8923a | ||
|
|
e04a26b2bc | ||
|
|
c5986e666f | ||
|
|
7d4758eace | ||
|
|
4f7439d4cf | ||
|
|
fe0647202b | ||
|
|
7f74fe7bb2 | ||
|
|
41aa71f8c3 | ||
|
|
8c6cc1ec15 | ||
|
|
21d526e5e5 | ||
|
|
246a803954 | ||
|
|
45be6d0bd4 | ||
|
|
21b86b6770 | ||
|
|
76cbc66785 | ||
|
|
3e9afccae8 | ||
|
|
b697ba8896 | ||
|
|
e4a4d76cb3 | ||
|
|
3db8549e19 | ||
|
|
340dde31a2 | ||
|
|
6b39ed0732 | ||
|
|
16cad7ba24 | ||
|
|
798fbab653 | ||
|
|
88df025aa0 | ||
|
|
85172dad1b | ||
|
|
996d229b26 | ||
|
|
5bad5d6958 | ||
|
|
e3f3cb58b7 | ||
|
|
17a82e7f94 | ||
|
|
f5c2b38724 | ||
|
|
3d0d9cd0e2 | ||
|
|
43be24f34c | ||
|
|
a434850069 | ||
|
|
d0bdd6096c | ||
|
|
12a1283663 | ||
|
|
23178e81ff | ||
|
|
505076c9a9 | ||
|
|
b0296bb562 | ||
|
|
54fe2f9891 | ||
|
|
8cc78cfea9 | ||
|
|
2cd3d39108 | ||
|
|
1d829f2e4a | ||
|
|
ca46ef4d25 | ||
|
|
e23b117ac3 | ||
|
|
d304f12dcd | ||
|
|
61450b3e1b | ||
|
|
06373ce1cf | ||
|
|
e1b3b32db5 | ||
|
|
2a041b5240 | ||
|
|
ad307e4b9c | ||
|
|
6873658d26 | ||
|
|
9ff49b7b1b | ||
|
|
048f49af39 | ||
|
|
e160966163 | ||
|
|
e4ae69f607 | ||
|
|
4b7661a60a | ||
|
|
d389171905 | ||
|
|
b65970860e | ||
|
|
1fa7a9cb19 | ||
|
|
a537b4af4d | ||
|
|
b05c21bb1d | ||
|
|
37542dc2ec | ||
|
|
b02124595f | ||
|
|
d055b575fb | ||
|
|
7d4a24caab | ||
|
|
3715bfe253 | ||
|
|
44d78ec881 | ||
|
|
5c12bd2287 | ||
|
|
87ecf17242 | ||
|
|
a62f633ceb | ||
|
|
ec166295ba | ||
|
|
916b4ff2d5 | ||
|
|
fb79d5ff98 | ||
|
|
e6b6df5893 | ||
|
|
d78fe9853f | ||
|
|
12ebe4b180 | ||
|
|
efb46f7f82 | ||
|
|
7cff8ca896 | ||
|
|
87f5fb0691 | ||
|
|
e607790647 | ||
|
|
7ed8ef7221 | ||
|
|
cc1217a43c | ||
|
|
f444616553 | ||
|
|
fc986c2d12 | ||
|
|
8c98a90f32 | ||
|
|
8b92368165 | ||
|
|
e55b792fea | ||
|
|
c4fde852e6 | ||
|
|
23c010900c | ||
|
|
f90085917b | ||
|
|
a6d9393341 | ||
|
|
16df4bff30 | ||
|
|
620104e700 | ||
|
|
349b081b18 | ||
|
|
baaad7ada2 | ||
|
|
fb884573ea | ||
|
|
5fcc43e54d | ||
|
|
9a13efa0e3 | ||
|
|
8fbb7cf795 | ||
|
|
6a3753c076 | ||
|
|
7c547c6c6b | ||
|
|
349b5a3146 | ||
|
|
b173a4d935 | ||
|
|
32ca574f49 | ||
|
|
36847f6af0 | ||
|
|
8a535d0ecc | ||
|
|
cd5673bf2e | ||
|
|
0145e900f3 | ||
|
|
6c04514039 | ||
|
|
480a0f8c06 | ||
|
|
5f350e2572 | ||
|
|
3943e41d2f | ||
|
|
0ddef6ed96 | ||
|
|
64529361b4 | ||
|
|
edf1637c2c | ||
|
|
ee169b201b | ||
|
|
59a5a8b104 | ||
|
|
bd40a94424 | ||
|
|
f037a697eb | ||
|
|
dd62b9685f | ||
|
|
8d13acca91 | ||
|
|
b1769a70f0 | ||
|
|
b733102f4a | ||
|
|
718d0baea3 | ||
|
|
b77cb648c3 | ||
|
|
3f44e9b404 | ||
|
|
1c19d627aa | ||
|
|
646c71c277 | ||
|
|
e17c7bf530 | ||
|
|
0a078d9ec9 | ||
|
|
31179ee47c | ||
|
|
48afa82f29 | ||
|
|
39ca745d0d | ||
|
|
a7becb43e6 | ||
|
|
41517eacb1 | ||
|
|
17137b2e2e | ||
|
|
cad5be53b1 | ||
|
|
54136ee835 | ||
|
|
0f78fc45bd | ||
|
|
11b2700b23 | ||
|
|
20c4e843b0 | ||
|
|
f3143c7a9c | ||
|
|
943d1c8cdf | ||
|
|
588d869a3b | ||
|
|
5be275d73b | ||
|
|
4fed88afcf | ||
|
|
7fb8acaa53 | ||
|
|
2f16eddf15 | ||
|
|
adc9def046 | ||
|
|
32409472b7 | ||
|
|
79d2a9c456 | ||
|
|
d0fdc3adf3 | ||
|
|
78bf5a42ed | ||
|
|
f5e4f95cde | ||
|
|
6fd4e151b8 | ||
|
|
e854e0b592 | ||
|
|
fa10d1a303 | ||
|
|
eea33b4133 | ||
|
|
7cd79e4cc6 | ||
|
|
8d17966e81 | ||
|
|
f426b12b5b | ||
|
|
4439a4a569 | ||
|
|
c4b7b08c91 | ||
|
|
9d528c30ee | ||
|
|
3d22ab88a3 | ||
|
|
5deb29b283 | ||
|
|
c51c5425ba | ||
|
|
306774b5a4 | ||
|
|
39c139c814 | ||
|
|
73757e3a9f | ||
|
|
adb0cfc59c | ||
|
|
29b34d92bb | ||
|
|
cc89bd2132 | ||
|
|
4af46132c2 | ||
|
|
bcac96c8c2 | ||
|
|
d239312e7b | ||
|
|
59392bc1fa | ||
|
|
92dd34ae96 | ||
|
|
648b8c4489 | ||
|
|
d33bd47219 | ||
|
|
2dfe7929de | ||
|
|
93260e1700 | ||
|
|
e4eee8b12d | ||
|
|
86dbd5fa0d | ||
|
|
6eb5d450bd | ||
|
|
db884e9b1d | ||
|
|
c1196a1ab0 | ||
|
|
4b76485a4e | ||
|
|
f79bd795d5 | ||
|
|
1ab94699c5 | ||
|
|
c82f2a3714 | ||
|
|
edb52293d9 | ||
|
|
379ce2b5e5 | ||
|
|
a61cdc8860 | ||
|
|
bf1c03ab5f | ||
|
|
421c61e730 | ||
|
|
d733663e8b | ||
|
|
0a6a19e33b | ||
|
|
5182624141 | ||
|
|
7a260f5e93 | ||
|
|
2d5024ac8e | ||
|
|
7a3cfe8089 | ||
|
|
5c4a7dc7b2 | ||
|
|
a926b96103 | ||
|
|
7a5cbcac21 | ||
|
|
64eac01d04 | ||
|
|
b507b3e591 | ||
|
|
4320c62c76 | ||
|
|
18bfa133ab | ||
|
|
c4d3f019da | ||
|
|
4f0eb2f520 | ||
|
|
292a50dd08 | ||
|
|
6e05b978b8 | ||
|
|
55618ebf58 | ||
|
|
29248c31ae | ||
|
|
3d814f9e4a | ||
|
|
ef2f63a00c | ||
|
|
5134c82573 | ||
|
|
cd61a9bbe8 | ||
|
|
96bec613a0 | ||
|
|
6ad187cc7e | ||
|
|
98737b2678 | ||
|
|
0369f6fea0 | ||
|
|
2b4bcbb0ce | ||
|
|
bf2f9e2f55 | ||
|
|
df849651d9 | ||
|
|
60dfa3445a | ||
|
|
c44c3d5ebf | ||
|
|
c18c1916c3 | ||
|
|
4314f91b7d | ||
|
|
db15731e4d | ||
|
|
381df0081a | ||
|
|
a963b8b7c7 | ||
|
|
3a02feddc3 | ||
|
|
a3dfbbde85 | ||
|
|
b1fd1b65fd | ||
|
|
52ca3ef547 | ||
|
|
0d6de7a80e | ||
|
|
06ffc7e952 | ||
|
|
73500966ae | ||
|
|
634ed09ec0 | ||
|
|
1e5767693e | ||
|
|
6caf4909d4 | ||
|
|
aa6867e6c9 | ||
|
|
16ffb2795a | ||
|
|
ca3e25de04 | ||
|
|
b488f009bd | ||
|
|
80f98de905 | ||
|
|
0e5975dd26 | ||
|
|
5cdc2fc099 | ||
|
|
adcc95534b | ||
|
|
82e960a810 | ||
|
|
f651df5e7a | ||
|
|
5d4ff63930 | ||
|
|
982e01ec7f | ||
|
|
2d1f852baf | ||
|
|
0db95a92a6 | ||
|
|
8990d5a40e | ||
|
|
54092861f1 | ||
|
|
9ada7065d6 | ||
|
|
b3596a18e1 | ||
|
|
9a6c741d5d | ||
|
|
c2d99fd519 | ||
|
|
dd9586b841 | ||
|
|
f8b4f60cb9 | ||
|
|
6d9416eb17 | ||
|
|
f0405f18a3 | ||
|
|
c370f0f24a | ||
|
|
1588dc8437 | ||
|
|
a7d3f00b26 | ||
|
|
e586e11637 | ||
|
|
7ed7a84782 | ||
|
|
112e41bd8f | ||
|
|
52eb77efd4 | ||
|
|
74b352e979 | ||
|
|
f5c8e5190f | ||
|
|
524bbd3ee9 | ||
|
|
3cd3f24150 | ||
|
|
5c262844ad | ||
|
|
df5500565a | ||
|
|
d5fab0b9f8 | ||
|
|
fecb2959b4 | ||
|
|
5eebc6b20c | ||
|
|
600e749d9b | ||
|
|
c47bd60c73 | ||
|
|
a745c2ac47 | ||
|
|
5834e16a22 | ||
|
|
6f913563d8 | ||
|
|
845226d66a | ||
|
|
d168dd021e | ||
|
|
494b51698d | ||
|
|
8bc1c1dbeb | ||
|
|
c5d8447861 | ||
|
|
c6b2c82570 | ||
|
|
1d49bef096 | ||
|
|
d15550fdee | ||
|
|
baf0b9e0f7 | ||
|
|
7d8cb7c155 | ||
|
|
9d9f4279ed | ||
|
|
6d195137fe | ||
|
|
2586ad016e | ||
|
|
548c758677 | ||
|
|
3162be28e5 | ||
|
|
ef5a185dc4 | ||
|
|
1009da4d7e | ||
|
|
749b0b9ae0 | ||
|
|
67bd2eac44 | ||
|
|
a9209ce881 | ||
|
|
efc16b49d9 | ||
|
|
d1aeba771a | ||
|
|
8155f35b29 | ||
|
|
67501f1ee2 | ||
|
|
d627942b64 | ||
|
|
d2b8ff4e9c | ||
|
|
3536803e9e | ||
|
|
ff6f5792d2 | ||
|
|
4b1072e4da | ||
|
|
3e44ad1867 | ||
|
|
155f2e2a62 | ||
|
|
80986f8497 | ||
|
|
a4784e12b9 | ||
|
|
4df112cd95 | ||
|
|
bfc9e0bd93 | ||
|
|
2377f7ec75 | ||
|
|
20be441026 | ||
|
|
82edc89cfa | ||
|
|
130644c061 | ||
|
|
ca78bcf558 | ||
|
|
2d4ec829a0 | ||
|
|
f56f45156b | ||
|
|
f0065bd801 | ||
|
|
f1ad719ffc | ||
|
|
db2394dbe7 | ||
|
|
1bc9ca7b57 | ||
|
|
6f7e80bbb6 | ||
|
|
be25a50617 | ||
|
|
d28a3cbbd5 | ||
|
|
d12cf071bb | ||
|
|
ac98dd2752 | ||
|
|
ee5cf3a11d | ||
|
|
3074d22815 | ||
|
|
92a139d31e | ||
|
|
b5a3aeb8ee | ||
|
|
ad726015e7 | ||
|
|
c669f0b78a | ||
|
|
59bffc94a8 | ||
|
|
aef9ea7387 | ||
|
|
0c466ddb67 | ||
|
|
6347ce2550 | ||
|
|
2078c00bab | ||
|
|
e7c57a39db | ||
|
|
2e45bd8373 | ||
|
|
0d0d5a670b | ||
|
|
8052f818b4 | ||
|
|
08bc2ef680 | ||
|
|
6f0649a86d | ||
|
|
1fd3f82d3a | ||
|
|
48635729b9 | ||
|
|
e75ebffb70 | ||
|
|
431e30bc32 | ||
|
|
1c18413de0 | ||
|
|
813827c26a | ||
|
|
a5c6ca5920 | ||
|
|
7f94f90b01 | ||
|
|
cb0b105402 | ||
|
|
feaba551b5 | ||
|
|
e9942db502 | ||
|
|
093f0673f5 | ||
|
|
9d1c396c54 | ||
|
|
e31e15bb3b | ||
|
|
1f1a373041 | ||
|
|
4f2b1ed2e8 | ||
|
|
c2c5c85ef4 | ||
|
|
c1ff169bf3 | ||
|
|
2a15286060 | ||
|
|
ba4b50118d | ||
|
|
2f07eb07ee | ||
|
|
964c515d75 | ||
|
|
517db6686a | ||
|
|
f5133c08a5 | ||
|
|
07c914b479 | ||
|
|
0068320ff1 | ||
|
|
8a3faaa649 | ||
|
|
75af9003dc | ||
|
|
f9ccf28374 | ||
|
|
706006ec83 | ||
|
|
516fad14e4 | ||
|
|
52e63ddd22 | ||
|
|
2379034958 | ||
|
|
50e97de636 | ||
|
|
99f6de1dfc | ||
|
|
0704528b4c | ||
|
|
e72bc1a12f | ||
|
|
9607a51b52 | ||
|
|
fccceb8736 | ||
|
|
d081b4bab6 | ||
|
|
b01f0cf99b | ||
|
|
2a221300de | ||
|
|
f2cb5a7414 | ||
|
|
a614f61015 | ||
|
|
f2b97528c1 | ||
|
|
6d4d18a4fa | ||
|
|
37f6e35974 | ||
|
|
014eda2535 | ||
|
|
552f1383bf | ||
|
|
1166783725 | ||
|
|
2d5e5c0fd6 | ||
|
|
d177752be1 | ||
|
|
c1d4fb2b68 | ||
|
|
f59fd96ab4 | ||
|
|
1df83331de | ||
|
|
40d3cfd97b | ||
|
|
2ef10f9754 | ||
|
|
a8be6aa8dd | ||
|
|
0f3a0913f1 | ||
|
|
1c625befa3 | ||
|
|
64be8c1507 | ||
|
|
a8d8485060 | ||
|
|
ae1afba8d1 | ||
|
|
6b92eda819 | ||
|
|
d174b47e51 | ||
|
|
1909113889 | ||
|
|
00b29630ba | ||
|
|
6528c7177f | ||
|
|
860182fe01 | ||
|
|
12c6099737 | ||
|
|
1ae0147aad | ||
|
|
e6b636cc51 | ||
|
|
2a9b21e46a | ||
|
|
07e2e20f7b | ||
|
|
04731d2b78 | ||
|
|
952bde1db3 | ||
|
|
b0f9ca7918 | ||
|
|
2eb375e486 | ||
|
|
67be0c95e1 | ||
|
|
abca497b72 | ||
|
|
5dd2928790 | ||
|
|
69b525494b | ||
|
|
3d74e661b7 | ||
|
|
d3f17c1dca | ||
|
|
1351710a18 | ||
|
|
72a7c61750 | ||
|
|
d64d97cb17 | ||
|
|
cf3d995e8c | ||
|
|
0dfe0d0166 | ||
|
|
dbd43ac107 | ||
|
|
cb15429e4a | ||
|
|
6f2bba3630 | ||
|
|
b21026e061 | ||
|
|
151ea35c5f | ||
|
|
0c6e26dabe | ||
|
|
c721b62c2f | ||
|
|
512ec5b236 | ||
|
|
51c79565e0 | ||
|
|
734d9ef092 | ||
|
|
931f1a3f34 | ||
|
|
2b7094f342 | ||
|
|
8ee9cab8f8 | ||
|
|
9fd33b5cde | ||
|
|
129c358a72 | ||
|
|
47140cdad0 | ||
|
|
6877a0abcd | ||
|
|
2f785c9da1 | ||
|
|
18eed144ca | ||
|
|
d4e1dfe5dc | ||
|
|
3da6db4fe4 | ||
|
|
e75647056b | ||
|
|
f99aa47581 | ||
|
|
99de0a872e | ||
|
|
8d6982be3b | ||
|
|
104997e83e | ||
|
|
c0eaadac86 | ||
|
|
e52d4b6486 | ||
|
|
0233683173 | ||
|
|
72d537fd95 | ||
|
|
91a4a03356 | ||
|
|
fce753c05d | ||
|
|
1f6b0118dc | ||
|
|
a0b0560e20 | ||
|
|
bab247dcb6 | ||
|
|
1e8eb1c1f2 | ||
|
|
0d926a76a7 | ||
|
|
49a478a879 | ||
|
|
b7eeddcf52 | ||
|
|
992d85e6f8 | ||
|
|
c21705982e | ||
|
|
c02e644679 | ||
|
|
c20ecea090 | ||
|
|
f74c472203 | ||
|
|
9fb5b764af | ||
|
|
f24ee56c5d | ||
|
|
fe79449969 | ||
|
|
f9f9a1bab4 | ||
|
|
bb13b957de | ||
|
|
32859ea25c | ||
|
|
fe86a94dcf | ||
|
|
f1d501f977 | ||
|
|
4c5cfe3876 | ||
|
|
fa405a8337 | ||
|
|
576bd17285 | ||
|
|
12c022ee37 | ||
|
|
4a4e2b0239 | ||
|
|
6bebaa36bf | ||
|
|
17170fe23c | ||
|
|
edf02f8319 | ||
|
|
d04ce481c4 | ||
|
|
c7e34c2f9d | ||
|
|
fbf7f7bc36 | ||
|
|
6c2f9196d7 | ||
|
|
00db31c4f0 | ||
|
|
d9c72c6773 | ||
|
|
243ec87918 | ||
|
|
dc38c72432 | ||
|
|
1858e349c8 | ||
|
|
bb5579d075 | ||
|
|
2745d341aa | ||
|
|
10467e3062 | ||
|
|
6e7a24d390 | ||
|
|
ce3c08359a | ||
|
|
ed4d3d36f9 | ||
|
|
b6ba0dca13 | ||
|
|
3b82d5937b | ||
|
|
d1963dc133 | ||
|
|
a706a9ceb9 | ||
|
|
e24b6b0e51 | ||
|
|
0e81f89dd3 | ||
|
|
73ad6717e9 | ||
|
|
727673a043 | ||
|
|
35ec1403dc | ||
|
|
adf4802f4b | ||
|
|
a9c341656d | ||
|
|
f33dfdbe26 | ||
|
|
01960ffc9f | ||
|
|
1044251a9e | ||
|
|
3abd5e131f | ||
|
|
b21931c4a3 | ||
|
|
779eaba428 | ||
|
|
cddaf50ff8 | ||
|
|
6696bebfa6 | ||
|
|
16a3c32da9 | ||
|
|
d17b256fdd | ||
|
|
5282009121 | ||
|
|
592bd15c7a | ||
|
|
bcfa3bf320 | ||
|
|
f69f1bb58f | ||
|
|
db8679443f | ||
|
|
0eba81ef79 | ||
|
|
3f3253ec2f | ||
|
|
65eeb94f75 | ||
|
|
67c9b2f8f4 | ||
|
|
40d181d2f3 | ||
|
|
1507253bd5 | ||
|
|
50a534bf55 | ||
|
|
91afc08de1 | ||
|
|
0455f72ede | ||
|
|
4e5d0ee3a8 | ||
|
|
d25cae9b61 | ||
|
|
047b08922d | ||
|
|
64b2c9be0b | ||
|
|
fc879c04c8 | ||
|
|
d479208a8f | ||
|
|
3e91ec1729 | ||
|
|
fa4d18f21c | ||
|
|
e51df8450c | ||
|
|
fb8253c912 | ||
|
|
cd2232eddf | ||
|
|
e40aa112ee | ||
|
|
c001d0e5c7 | ||
|
|
5de2c059d1 | ||
|
|
e83d472c00 | ||
|
|
8670305589 | ||
|
|
e26a75cd0c | ||
|
|
e30c858c5d | ||
|
|
a330342e4f | ||
|
|
d5e8675fd6 | ||
|
|
bef1fa091c | ||
|
|
0b87aaa74c | ||
|
|
8e717acf48 | ||
|
|
aaee30e5c5 | ||
|
|
7ba459ae7b | ||
|
|
9a2e8d907b | ||
|
|
b11ff9d876 | ||
|
|
d20c4200db | ||
|
|
942cd466ed | ||
|
|
3450a1ab16 | ||
|
|
03d1120d6a | ||
|
|
d910b72cb7 | ||
|
|
d4cef0bd43 | ||
|
|
53b0892791 | ||
|
|
c543a3cbe1 | ||
|
|
a35994ce7b | ||
|
|
99c004f689 | ||
|
|
f8f25980e1 | ||
|
|
e7372cbe85 | ||
|
|
3276688c82 | ||
|
|
6f3bdab090 | ||
|
|
f24cc8be03 | ||
|
|
16606cde39 | ||
|
|
be7ed4c775 | ||
|
|
440c4ed703 | ||
|
|
36273baa7e | ||
|
|
420c86eb90 | ||
|
|
7735ab48c4 | ||
|
|
e45234fbbc | ||
|
|
3e97626b67 | ||
|
|
2bf983e638 | ||
|
|
024b6d2d9e | ||
|
|
dff13ff129 | ||
|
|
081d425277 | ||
|
|
e272d92827 | ||
|
|
c263b3e38c | ||
|
|
43cdc2e037 | ||
|
|
204e504d68 | ||
|
|
91fcde48d4 | ||
|
|
0d7da02dc4 | ||
|
|
446cacde15 | ||
|
|
f71c711646 | ||
|
|
76ad89fe0b | ||
|
|
862d1f1fdd | ||
|
|
02cdec2f91 | ||
|
|
f64c049f0c | ||
|
|
162705fbed | ||
|
|
bcf27d8af4 | ||
|
|
6d1073d867 | ||
|
|
1863bd88ad | ||
|
|
24f97739a1 | ||
|
|
9220e9dd34 | ||
|
|
270ad28931 | ||
|
|
f454253005 | ||
|
|
fa111d7078 | ||
|
|
8498f64a50 | ||
|
|
624aeae2d3 | ||
|
|
8ba1c059da | ||
|
|
4c85682c9d | ||
|
|
9e210c1a02 | ||
|
|
fd8173f109 | ||
|
|
9aa129caab | ||
|
|
54e1385729 | ||
|
|
78cbae910d | ||
|
|
8d4de1b537 | ||
|
|
7f44a1b44e | ||
|
|
89ca5440a2 | ||
|
|
80a5c4f322 | ||
|
|
0943dfc34a | ||
|
|
59fca06354 | ||
|
|
e87eb347ae | ||
|
|
dcd4460c88 | ||
|
|
95574c1b11 | ||
|
|
3cc1409210 | ||
|
|
a0b6203854 | ||
|
|
91c56a0ad1 | ||
|
|
0ee980abae | ||
|
|
8772a7faca | ||
|
|
4bd0dab16b | ||
|
|
165ad14b0f | ||
|
|
9b4519280a | ||
|
|
3c73d1a7a2 | ||
|
|
c7a30aec03 | ||
|
|
c2b35fb226 | ||
|
|
3ceb321b8e | ||
|
|
cdcd473371 | ||
|
|
17c1d1fd50 | ||
|
|
c0fead40e9 | ||
|
|
cc1a2e1986 | ||
|
|
9fc3fd7196 | ||
|
|
cdc8f74939 | ||
|
|
b038fe556b | ||
|
|
713b122b84 | ||
|
|
bffedfed1e | ||
|
|
666a378336 | ||
|
|
7901986dcf | ||
|
|
794dea0dd7 | ||
|
|
d894f48f25 | ||
|
|
d8a65edc4a | ||
|
|
89786cf032 | ||
|
|
7850785ccb | ||
|
|
8dbfe03d17 | ||
|
|
93f2091185 | ||
|
|
a0fcd8a735 | ||
|
|
7adc5360d7 | ||
|
|
832e04b93b | ||
|
|
5bbcd42378 | ||
|
|
40f5bfda22 | ||
|
|
4d99c82327 | ||
|
|
4bebac4372 | ||
|
|
b8ae658981 | ||
|
|
8dbaf5a7ff | ||
|
|
e3119e7d05 | ||
|
|
851ec2f923 | ||
|
|
e5c4351bc7 | ||
|
|
eaaf941c10 | ||
|
|
5c32dc3948 | ||
|
|
95a2303e37 | ||
|
|
6f8e2308d5 | ||
|
|
031a83b0ea | ||
|
|
24e4aeb2c6 | ||
|
|
d00e46966d | ||
|
|
e06d5cd414 | ||
|
|
f262ae9a6f | ||
|
|
8bf5a532de | ||
|
|
20a17eb71d | ||
|
|
fa698ddd12 | ||
|
|
1ad24f1d5d | ||
|
|
b47dfb6a5c | ||
|
|
b2331e1f6d | ||
|
|
0b050442da | ||
|
|
2cf7cf1304 | ||
|
|
69aefe5c79 | ||
|
|
6123a61a49 | ||
|
|
24f5cd2d48 | ||
|
|
60037decc3 | ||
|
|
4963e6f3fc | ||
|
|
fad357bbe6 | ||
|
|
057a771fda | ||
|
|
b7ade95edc | ||
|
|
5eb1c54116 | ||
|
|
d9d68550d9 | ||
|
|
3d4d004fb6 | ||
|
|
28027394f5 | ||
|
|
c6109fb08e | ||
|
|
93de1b2b0b | ||
|
|
7bcf579a37 | ||
|
|
817efdd484 | ||
|
|
13603e4050 | ||
|
|
c4f12ccc3c | ||
|
|
82bc102581 | ||
|
|
1632322ce0 | ||
|
|
b869ef660f | ||
|
|
5f1030d119 | ||
|
|
f4d2bfd77b | ||
|
|
b8b9a2fad9 | ||
|
|
024f09e1ea | ||
|
|
3846201fbb | ||
|
|
b6c18d489d | ||
|
|
b1385953fe | ||
|
|
2f3ead0281 | ||
|
|
d97dc518d3 | ||
|
|
73ef81a8de | ||
|
|
4368f14e9d | ||
|
|
3b5ea2f423 | ||
|
|
0987fd6b0e | ||
|
|
a94148ca4c | ||
|
|
1cbf121b08 | ||
|
|
101d61b64a | ||
|
|
8ead641b08 | ||
|
|
d154ffbe86 | ||
|
|
76bad22978 | ||
|
|
1f03394643 | ||
|
|
df87396cf3 | ||
|
|
6fdcb18f6a | ||
|
|
4d9fe6dfaa | ||
|
|
7e3321d1b2 | ||
|
|
917b0c2ca3 | ||
|
|
e36180f377 | ||
|
|
6a464b53f1 | ||
|
|
65dc3e89c7 | ||
|
|
6f9d3c31d0 | ||
|
|
7fa81e798b | ||
|
|
d9111350b9 | ||
|
|
3bb86f1e01 | ||
|
|
a8cd21ac07 | ||
|
|
309db943e9 | ||
|
|
9bc489eb2a | ||
|
|
7aaab11b0f | ||
|
|
bf8fc4c53d | ||
|
|
be34bcfff1 | ||
|
|
b6b64bcd70 | ||
|
|
63531a89b1 | ||
|
|
f5172016b8 | ||
|
|
9d5caf6baa | ||
|
|
90b7d056ee | ||
|
|
dcc52f4321 | ||
|
|
cf3fcab6b4 | ||
|
|
75b180d2cd | ||
|
|
df0e28fe43 | ||
|
|
24c94e4af0 | ||
|
|
3d237fc7d7 | ||
|
|
4dddd0b55b | ||
|
|
31eddf9e87 | ||
|
|
4e2411ad98 | ||
|
|
f227a0179f | ||
|
|
b9b606d271 | ||
|
|
2ce688d2ad | ||
|
|
dfa395c5ed | ||
|
|
a263344653 | ||
|
|
02d98387a1 | ||
|
|
836cc4d3dc | ||
|
|
cfd3fa97d1 | ||
|
|
5fa9b765dc | ||
|
|
3475ad69b3 | ||
|
|
c5fd3d00d2 | ||
|
|
e07d3b9a97 | ||
|
|
76c4adb7f8 | ||
|
|
f3315aeff6 | ||
|
|
f32d95b6d9 | ||
|
|
37938a1761 | ||
|
|
c608277bcf | ||
|
|
adbbf1a3a1 | ||
|
|
f58a2f25a2 | ||
|
|
3fcb8a4d1e | ||
|
|
50512f0dee | ||
|
|
d619c612d5 | ||
|
|
1e2eafe777 | ||
|
|
55ba2602db | ||
|
|
adbc0bfe00 | ||
|
|
b008810c01 | ||
|
|
5cacce7a26 | ||
|
|
94efe3d410 | ||
|
|
8d25e04d28 | ||
|
|
c2b690439f | ||
|
|
271e33658d | ||
|
|
5336c7e97b | ||
|
|
fd76008f63 | ||
|
|
7d01234211 | ||
|
|
b3c7581cf9 | ||
|
|
957f86c3e3 | ||
|
|
b1dbaad396 | ||
|
|
ef528d3a86 | ||
|
|
5148aad3d4 | ||
|
|
c7fc804112 | ||
|
|
d9e643db2b | ||
|
|
2f92b4a37d | ||
|
|
230fd4bc08 | ||
|
|
480ad9ffed | ||
|
|
67f9109d1f | ||
|
|
ad11bbb584 | ||
|
|
0f47ba54ee | ||
|
|
6a720e5c7c | ||
|
|
3cebc33414 | ||
|
|
b28853aff1 | ||
|
|
b90d0ac555 | ||
|
|
5826fd5259 | ||
|
|
1f96a0d16c | ||
|
|
80fdb9146f | ||
|
|
a44e9aa3f9 | ||
|
|
d5e0fc8e7c | ||
|
|
92d25bcda6 | ||
|
|
68ebc9b2a8 | ||
|
|
cbf52c2764 | ||
|
|
0e3bc393d5 | ||
|
|
fad6329699 | ||
|
|
ea7324afe8 | ||
|
|
59d38a4119 | ||
|
|
42dd64f22f | ||
|
|
b4632e317d | ||
|
|
cc88df05e7 | ||
|
|
2b1100c878 | ||
|
|
7a2a7ea9e4 | ||
|
|
b21069c573 | ||
|
|
fab017c91a | ||
|
|
38ee8bfcf7 | ||
|
|
e839199848 | ||
|
|
02802b1d0e | ||
|
|
aef0f1e248 | ||
|
|
dfa526ce16 | ||
|
|
f5858ef6c6 | ||
|
|
46c63af715 | ||
|
|
3a5bd21092 | ||
|
|
50774cf0fb | ||
|
|
f24dcf4ff9 | ||
|
|
3b40a38c66 | ||
|
|
8eb6f129f8 | ||
|
|
e8030ed1cf | ||
|
|
b7f03837a2 | ||
|
|
6daaeb6dba | ||
|
|
a904518075 | ||
|
|
b07559882c | ||
|
|
dd72ce151a | ||
|
|
9d4e51011a | ||
|
|
f19bb9f57c | ||
|
|
3a9ff8de7a | ||
|
|
feafe0da36 | ||
|
|
df9164b9bd | ||
|
|
f3dea4b752 | ||
|
|
5615c92173 | ||
|
|
a0634cca3f | ||
|
|
b3a4a2cf93 | ||
|
|
8bcf32a619 | ||
|
|
e4ed48976a | ||
|
|
ee70866894 | ||
|
|
bd82460780 | ||
|
|
bfdf55afd9 | ||
|
|
b8658d3733 | ||
|
|
83ef64079b | ||
|
|
74cee6e6b7 | ||
|
|
4e8508ad53 | ||
|
|
407710b622 | ||
|
|
907d35126e | ||
|
|
228014bec8 | ||
|
|
3de367920f | ||
|
|
055f3141f8 | ||
|
|
7a693df988 | ||
|
|
0fba89df67 | ||
|
|
c109d4e5dc | ||
|
|
654836a135 | ||
|
|
6b31e67dd3 | ||
|
|
bba8393af7 | ||
|
|
cf5428e103 | ||
|
|
95ff72706d | ||
|
|
1db7630d01 | ||
|
|
3fe276c02f | ||
|
|
f579039a0a | ||
|
|
a3f1175f1c | ||
|
|
5f24388b04 |
111
.clang-format
111
.clang-format
@@ -1,31 +1,40 @@
|
||||
# Commented out parameters are those with the same value as base LLVM style
|
||||
# Commented out parameters are those with the same value as base LLVM style.
|
||||
# We can uncomment them if we want to change their value, or enforce the
|
||||
# chosen value in case the base style changes (last sync: Clang 6.0.1).
|
||||
# chosen value in case the base style changes (last sync: Clang 14.0).
|
||||
---
|
||||
### General config, applies to all languages ###
|
||||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
# AlignConsecutiveAssignments: false
|
||||
# AlignConsecutiveDeclarations: false
|
||||
# AlignArrayOfStructures: None
|
||||
# AlignConsecutiveMacros: None
|
||||
# AlignConsecutiveAssignments: None
|
||||
# AlignConsecutiveBitFields: None
|
||||
# AlignConsecutiveDeclarations: None
|
||||
# AlignEscapedNewlines: Right
|
||||
# AlignOperands: true
|
||||
AlignOperands: DontAlign
|
||||
AlignTrailingComments: false
|
||||
# AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
# AllowShortBlocksOnASingleLine: false
|
||||
# AllowShortEnumsOnASingleLine: true
|
||||
# AllowShortBlocksOnASingleLine: Never
|
||||
# AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
# AllowShortIfStatementsOnASingleLine: false
|
||||
# AllowShortFunctionsOnASingleLine: All
|
||||
# AllowShortLambdasOnASingleLine: All
|
||||
# AllowShortIfStatementsOnASingleLine: Never
|
||||
# AllowShortLoopsOnASingleLine: false
|
||||
# AlwaysBreakAfterDefinitionReturnType: None
|
||||
# AlwaysBreakAfterReturnType: None
|
||||
# AlwaysBreakBeforeMultilineStrings: false
|
||||
# AlwaysBreakTemplateDeclarations: false
|
||||
# AlwaysBreakTemplateDeclarations: MultiLine
|
||||
# AttributeMacros:
|
||||
# - __capability
|
||||
# BinPackArguments: true
|
||||
# BinPackParameters: true
|
||||
# BraceWrapping:
|
||||
# AfterCaseLabel: false
|
||||
# AfterClass: false
|
||||
# AfterControlStatement: false
|
||||
# AfterControlStatement: Never
|
||||
# AfterEnum: false
|
||||
# AfterFunction: false
|
||||
# AfterNamespace: false
|
||||
@@ -35,32 +44,44 @@ AllowShortFunctionsOnASingleLine: Inline
|
||||
# AfterExternBlock: false
|
||||
# BeforeCatch: false
|
||||
# BeforeElse: false
|
||||
# BeforeLambdaBody: false
|
||||
# BeforeWhile: false
|
||||
# IndentBraces: false
|
||||
# SplitEmptyFunction: true
|
||||
# SplitEmptyRecord: true
|
||||
# SplitEmptyNamespace: true
|
||||
# BreakBeforeBinaryOperators: None
|
||||
# BreakBeforeConceptDeclarations: true
|
||||
# BreakBeforeBraces: Attach
|
||||
# BreakBeforeInheritanceComma: false
|
||||
BreakBeforeTernaryOperators: false
|
||||
# BreakInheritanceList: BeforeColon
|
||||
# BreakBeforeTernaryOperators: true
|
||||
# BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: AfterColon
|
||||
# BreakStringLiterals: true
|
||||
ColumnLimit: 0
|
||||
# CommentPragmas: '^ IWYU pragma:'
|
||||
# QualifierAlignment: Leave
|
||||
# CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 8
|
||||
ContinuationIndentWidth: 8
|
||||
Cpp11BracedListStyle: false
|
||||
# DeriveLineEnding: true
|
||||
# DerivePointerAlignment: false
|
||||
# DisableFormat: false
|
||||
# EmptyLineAfterAccessModifier: Never
|
||||
# EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
# ExperimentalAutoDetectBinPacking: false
|
||||
# PackConstructorInitializers: BinPack
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
# AllowAllConstructorInitializersOnNextLine: true
|
||||
# FixNamespaceComments: true
|
||||
# ForEachMacros:
|
||||
# - foreach
|
||||
# - Q_FOREACH
|
||||
# - BOOST_FOREACH
|
||||
# IfMacros:
|
||||
# - KJ_IF_MAYBE
|
||||
# IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '".*"'
|
||||
@@ -70,13 +91,21 @@ IncludeCategories:
|
||||
- Regex: '^<.*'
|
||||
Priority: 3
|
||||
# IncludeIsMainRegex: '(Test)?$'
|
||||
# IncludeIsMainSourceRegex: ''
|
||||
# IndentAccessModifiers: false
|
||||
IndentCaseLabels: true
|
||||
# IndentCaseBlocks: false
|
||||
# IndentGotoLabels: true
|
||||
# IndentPPDirectives: None
|
||||
# IndentExternBlock: AfterExternBlock
|
||||
# IndentRequires: false
|
||||
IndentWidth: 4
|
||||
# IndentWrappedFunctionNames: false
|
||||
# InsertTrailingCommas: None
|
||||
# JavaScriptQuotes: Leave
|
||||
# JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
# LambdaBodyIndentation: Signature
|
||||
# MacroBlockBegin: ''
|
||||
# MacroBlockEnd: ''
|
||||
# MaxEmptyLinesToKeep: 1
|
||||
@@ -85,39 +114,81 @@ KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
# PenaltyBreakBeforeFirstCallParameter: 19
|
||||
# PenaltyBreakComment: 300
|
||||
# PenaltyBreakFirstLessLess: 120
|
||||
# PenaltyBreakOpenParenthesis: 0
|
||||
# PenaltyBreakString: 1000
|
||||
# PenaltyBreakTemplateDeclaration: 10
|
||||
# PenaltyExcessCharacter: 1000000
|
||||
# PenaltyReturnTypeOnItsOwnLine: 60
|
||||
# PenaltyIndentedWhitespace: 0
|
||||
# PointerAlignment: Right
|
||||
# RawStringFormats:
|
||||
# - Delimiter: pb
|
||||
# Language: TextProto
|
||||
# BasedOnStyle: google
|
||||
# PPIndentWidth: -1
|
||||
# ReferenceAlignment: Pointer
|
||||
# ReflowComments: true
|
||||
# SortIncludes: true
|
||||
# RemoveBracesLLVM: false
|
||||
# SeparateDefinitionBlocks: Leave
|
||||
# ShortNamespaceLines: 1
|
||||
# SortIncludes: CaseSensitive
|
||||
# SortJavaStaticImport: Before
|
||||
# SortUsingDeclarations: true
|
||||
# SpaceAfterCStyleCast: false
|
||||
# SpaceAfterLogicalNot: false
|
||||
# SpaceAfterTemplateKeyword: true
|
||||
# SpaceBeforeAssignmentOperators: true
|
||||
# SpaceBeforeCaseColon: false
|
||||
# SpaceBeforeCpp11BracedList: false
|
||||
# SpaceBeforeCtorInitializerColon: true
|
||||
# SpaceBeforeInheritanceColon: true
|
||||
# SpaceBeforeParens: ControlStatements
|
||||
# SpaceBeforeParensOptions:
|
||||
# AfterControlStatements: true
|
||||
# AfterForeachMacros: true
|
||||
# AfterFunctionDefinitionName: false
|
||||
# AfterFunctionDeclarationName: false
|
||||
# AfterIfMacros: true
|
||||
# AfterOverloadedOperator: false
|
||||
# BeforeNonEmptyParentheses: false
|
||||
# SpaceAroundPointerQualifiers: Default
|
||||
# SpaceBeforeRangeBasedForLoopColon: true
|
||||
# SpaceInEmptyBlock: false
|
||||
# SpaceInEmptyParentheses: false
|
||||
# SpacesBeforeTrailingComments: 1
|
||||
# SpacesInAngles: false
|
||||
# SpacesInAngles: Never
|
||||
# SpacesInConditionalStatement: false
|
||||
# SpacesInContainerLiterals: true
|
||||
# SpacesInCStyleCastParentheses: false
|
||||
## Godot TODO: We'll want to use a min of 1, but we need to see how to fix
|
||||
## our comment capitalization at the same time.
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 0
|
||||
Maximum: -1
|
||||
# SpacesInParentheses: false
|
||||
# SpacesInSquareBrackets: false
|
||||
# SpaceBeforeSquareBrackets: false
|
||||
# BitFieldColonSpacing: Both
|
||||
# StatementAttributeLikeMacros:
|
||||
# - Q_EMIT
|
||||
# StatementMacros:
|
||||
# - Q_UNUSED
|
||||
# - QT_REQUIRE_VERSION
|
||||
TabWidth: 4
|
||||
# UseCRLF: false
|
||||
UseTab: Always
|
||||
# WhitespaceSensitiveMacros:
|
||||
# - STRINGIZE
|
||||
# - PP_STRINGIZE
|
||||
# - BOOST_PP_STRINGIZE
|
||||
# - NS_SWIFT_NAME
|
||||
# - CF_SWIFT_NAME
|
||||
---
|
||||
### C++ specific config ###
|
||||
Language: Cpp
|
||||
Standard: Cpp11
|
||||
Standard: c++17
|
||||
---
|
||||
### ObjC specific config ###
|
||||
Language: ObjC
|
||||
Standard: Cpp11
|
||||
# ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 4
|
||||
# ObjCBreakBeforeNestedBlockParam: true
|
||||
# ObjCSpaceAfterProperty: false
|
||||
# ObjCSpaceBeforeProtocolList: true
|
||||
---
|
||||
|
||||
16
.editorconfig
Normal file
16
.editorconfig
Normal 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
8
.gitattributes
vendored
@@ -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
|
||||
|
||||
6
.github/CODEOWNERS
vendored
Normal file
6
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
# Lines starting with '#' are comments.
|
||||
# Each line is a file pattern followed by one or more owners.
|
||||
# Owners can be @users, @org/teams or emails
|
||||
|
||||
* @godotengine/gdextension
|
||||
.github/ @godotengine/buildsystem
|
||||
71
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
71
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
name: Bug report
|
||||
description: Report a bug in the godot-cpp GDExtension/GDNative integration
|
||||
body:
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
- When reporting bugs, you'll make our life simpler (and the fix will come sooner) if you follow the guidelines in this template.
|
||||
- Write a descriptive issue title above.
|
||||
- The golden rule is to **always open *one* issue for *one* bug**. If you notice several bugs and want to report them, make sure to create one new issue for each of them.
|
||||
- Search [open](https://github.com/godotengine/godot-cpp/issues) and [closed](https://github.com/godotengine/godot-cpp/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported. If you don't find a relevant match or if you're unsure, don't hesitate to **open a new issue**. The bugsquad will handle it from there if it's a duplicate.
|
||||
- Verify that you are using a [supported Godot version](https://docs.godotengine.org/en/latest/about/release_policy.html).
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: Godot version
|
||||
description: >
|
||||
Specify the Git commit hash if using a development or non-official build.
|
||||
If you use a custom build, please test if your issue is reproducible in official builds too.
|
||||
placeholder: 3.3.stable, 4.0.dev (3041becc6)
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: godot-cpp version
|
||||
description: >
|
||||
Specify the Git commit hash if using a development build.
|
||||
placeholder: 3.3.stable, 4.0.dev (3041becc6)
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: System information
|
||||
description: |
|
||||
- Specify the OS version, and when relevant hardware information.
|
||||
- For issues that are likely OS-specific and/or graphics-related, please specify the CPU model and architecture.
|
||||
- **Bug reports not including the required information may be closed at the maintainers' discretion.** If in doubt, always include all the requested information; it's better to include too much information than not enough information.
|
||||
placeholder: Windows 10, Intel Core i5-7200U
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Issue description
|
||||
description: |
|
||||
Describe your issue briefly. What doesn't work, and how do you expect it to work instead?
|
||||
You can include images or videos with drag and drop, and format code blocks or logs with <code>```</code> tags.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: |
|
||||
List of steps or sample code that reproduces the issue. Having reproducible issues is a prerequisite for contributors to be able to solve them.
|
||||
If you include a minimal reproduction project below, you can detail how to use it here.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Minimal reproduction project
|
||||
description: |
|
||||
- A small Godot project which reproduces the issue, with no unnecessary files included. Be sure to not include the `.godot` folder in the archive (but keep `project.godot`).
|
||||
- Required, unless the reproduction steps are trivial and don't require any project files to be followed. In this case, write "N/A" in the field.
|
||||
- Drag and drop a ZIP archive to upload it. **Do not select another field until the project is done uploading.**
|
||||
- **If you've been asked by a maintainer to upload a minimal reproduction project, you *must* do so within 7 days.** Otherwise, your bug report will be closed as it'll be considered too difficult to diagnose.
|
||||
validations:
|
||||
required: true
|
||||
14
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
14
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
blank_issues_enabled: false
|
||||
|
||||
contact_links:
|
||||
- name: Godot proposals
|
||||
url: https://github.com/godotengine/godot-proposals
|
||||
about: Please submit feature proposals on the Godot proposals repository, not here.
|
||||
|
||||
- name: Godot documentation repository
|
||||
url: https://github.com/godotengine/godot-docs
|
||||
about: Please report issues with documentation on the Godot documentation repository, not here.
|
||||
|
||||
- name: Godot community channels
|
||||
url: https://godotengine.org/community
|
||||
about: Please ask for technical support on one of the other community channels, not here.
|
||||
24
.github/actions/godot-cache-restore/action.yml
vendored
Normal file
24
.github/actions/godot-cache-restore/action.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
name: Restore Godot build cache
|
||||
description: Restore Godot build cache.
|
||||
inputs:
|
||||
cache-name:
|
||||
description: The cache base name (job name by default).
|
||||
default: ${{ github.job }}
|
||||
scons-cache:
|
||||
description: The SCons cache path.
|
||||
default: ${{ github.workspace }}/.scons-cache/
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Restore SCons cache directory
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: ${{ inputs.scons-cache }}
|
||||
key: ${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}-${{ github.sha }}
|
||||
|
||||
restore-keys: |
|
||||
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}-${{ github.sha }}
|
||||
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}
|
||||
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-refs/heads/${{ env.GODOT_BASE_BRANCH }}
|
||||
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}
|
||||
18
.github/actions/godot-cache-save/action.yml
vendored
Normal file
18
.github/actions/godot-cache-save/action.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
name: Save Godot build cache
|
||||
description: Save Godot build cache.
|
||||
inputs:
|
||||
cache-name:
|
||||
description: The cache base name (job name by default).
|
||||
default: ${{ github.job }}
|
||||
scons-cache:
|
||||
description: The SCons cache path.
|
||||
default: ${{ github.workspace }}/.scons-cache/
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Save SCons cache directory
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
path: ${{ inputs.scons-cache }}
|
||||
key: ${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}-${{ github.sha }}
|
||||
62
.github/actions/setup-godot-cpp/action.yml
vendored
Normal file
62
.github/actions/setup-godot-cpp/action.yml
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
name: Setup godot-cpp
|
||||
description: Setup build dependencies for godot-cpp.
|
||||
|
||||
inputs:
|
||||
platform:
|
||||
required: true
|
||||
description: Target platform.
|
||||
em-version:
|
||||
default: 3.1.62
|
||||
description: Emscripten version.
|
||||
windows-compiler:
|
||||
required: true
|
||||
description: The compiler toolchain to use on Windows ('mingw' or 'msvc').
|
||||
type: choice
|
||||
options:
|
||||
- mingw
|
||||
- msvc
|
||||
default: mingw
|
||||
mingw-version:
|
||||
default: 12.2.0
|
||||
description: MinGW version.
|
||||
ndk-version:
|
||||
default: r23c
|
||||
description: Android NDK version.
|
||||
scons-version:
|
||||
default: 4.4.0
|
||||
description: SCons version.
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Setup Python (for SCons)
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Setup Android dependencies
|
||||
if: inputs.platform == 'android'
|
||||
uses: nttld/setup-ndk@v1
|
||||
with:
|
||||
ndk-version: ${{ inputs.ndk-version }}
|
||||
link-to-sdk: true
|
||||
|
||||
- name: Setup Web dependencies
|
||||
if: inputs.platform == 'web'
|
||||
uses: mymindstorm/setup-emsdk@v14
|
||||
with:
|
||||
version: ${{ inputs.em-version }}
|
||||
no-cache: true
|
||||
|
||||
- name: Setup MinGW for Windows/MinGW build
|
||||
if: inputs.platform == 'windows' && inputs.windows-compiler == 'mingw'
|
||||
uses: egor-tensin/setup-mingw@v2
|
||||
with:
|
||||
version: ${{ inputs.mingw-version }}
|
||||
|
||||
- name: Setup SCons
|
||||
shell: bash
|
||||
run: |
|
||||
python -c "import sys; print(sys.version)"
|
||||
python -m pip install scons==${{ inputs.scons-version }}
|
||||
scons --version
|
||||
365
.github/workflows/ci.yml
vendored
365
.github/workflows/ci.yml
vendored
@@ -1,196 +1,249 @@
|
||||
name: Continuous integration
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
env:
|
||||
# Only used for the cache key. Increment version to force clean build.
|
||||
GODOT_BASE_BRANCH: master
|
||||
# Used to select the version of Godot to run the tests with.
|
||||
GODOT_TEST_VERSION: 4.3-stable
|
||||
|
||||
concurrency:
|
||||
group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
name: Build (Linux, GCC)
|
||||
runs-on: ubuntu-18.04
|
||||
build:
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: 🐧 Linux (GCC)
|
||||
os: ubuntu-22.04
|
||||
platform: linux
|
||||
artifact-name: godot-cpp-linux-glibc2.27-x86_64-release
|
||||
artifact-path: bin/libgodot-cpp.linux.template_release.x86_64.a
|
||||
run-tests: true
|
||||
cache-name: linux-x86_64
|
||||
|
||||
- name: 🐧 Linux (GCC, Double Precision)
|
||||
os: ubuntu-22.04
|
||||
platform: linux
|
||||
artifact-name: godot-cpp-linux-glibc2.27-x86_64-double-release
|
||||
artifact-path: bin/libgodot-cpp.linux.template_release.double.x86_64.a
|
||||
flags: precision=double
|
||||
run-tests: false
|
||||
cache-name: linux-x86_64-f64
|
||||
|
||||
- name: 🏁 Windows (x86_64, MSVC)
|
||||
os: windows-2022
|
||||
platform: windows
|
||||
artifact-name: godot-cpp-windows-msvc2019-x86_64-release
|
||||
artifact-path: bin/libgodot-cpp.windows.template_release.x86_64.lib
|
||||
run-tests: false
|
||||
cache-name: windows-x86_64-msvc
|
||||
|
||||
- name: 🏁 Windows (x86_64, MinGW)
|
||||
os: windows-2022
|
||||
platform: windows
|
||||
artifact-name: godot-cpp-linux-mingw-x86_64-release
|
||||
artifact-path: bin/libgodot-cpp.windows.template_release.x86_64.a
|
||||
flags: use_mingw=yes
|
||||
run-tests: false
|
||||
cache-name: windows-x86_64-mingw
|
||||
|
||||
- name: 🍎 macOS (universal)
|
||||
os: macos-latest
|
||||
platform: macos
|
||||
artifact-name: godot-cpp-macos-universal-release
|
||||
artifact-path: bin/libgodot-cpp.macos.template_release.universal.a
|
||||
flags: arch=universal
|
||||
run-tests: false
|
||||
cache-name: macos-universal
|
||||
|
||||
- name: 🤖 Android (arm64)
|
||||
os: ubuntu-22.04
|
||||
platform: android
|
||||
artifact-name: godot-cpp-android-arm64-release
|
||||
artifact-path: bin/libgodot-cpp.android.template_release.arm64.a
|
||||
flags: arch=arm64
|
||||
run-tests: false
|
||||
cache-name: android-arm64
|
||||
|
||||
- name: 🍏 iOS (arm64)
|
||||
os: macos-latest
|
||||
platform: ios
|
||||
artifact-name: godot-cpp-ios-arm64-release
|
||||
artifact-path: bin/libgodot-cpp.ios.template_release.arm64.a
|
||||
flags: arch=arm64
|
||||
run-tests: false
|
||||
cache-name: ios-arm64
|
||||
|
||||
- name: 🌐 Web (wasm32)
|
||||
os: ubuntu-22.04
|
||||
platform: web
|
||||
artifact-name: godot-cpp-web-wasm32-release
|
||||
artifact-path: bin/libgodot-cpp.web.template_release.wasm32.a
|
||||
run-tests: false
|
||||
cache-name: web-wasm32
|
||||
|
||||
env:
|
||||
SCONS_CACHE: ${{ github.workspace }}/.scons-cache/
|
||||
EM_VERSION: 3.1.39
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Python (for SCons)
|
||||
uses: actions/setup-python@v2
|
||||
- name: Restore Godot build cache
|
||||
uses: ./.github/actions/godot-cache-restore
|
||||
with:
|
||||
python-version: '3.x'
|
||||
cache-name: ${{ matrix.cache-name }}
|
||||
continue-on-error: true
|
||||
|
||||
- name: Setup godot-cpp
|
||||
uses: ./.github/actions/setup-godot-cpp
|
||||
with:
|
||||
platform: ${{ matrix.platform }}
|
||||
windows-compiler: ${{ contains(matrix.flags, 'use_mingw=yes') && 'mingw' || 'msvc' }}
|
||||
|
||||
- name: Generate godot-cpp sources only
|
||||
run: |
|
||||
scons platform=${{ matrix.platform }} verbose=yes build_library=no ${{ matrix.flags }}
|
||||
scons -c
|
||||
|
||||
- name: Build godot-cpp (debug)
|
||||
run: |
|
||||
scons platform=${{ matrix.platform }} verbose=yes target=template_debug ${{ matrix.flags }}
|
||||
|
||||
- name: Build test without rebuilding godot-cpp (debug)
|
||||
run: |
|
||||
cd test
|
||||
scons platform=${{ matrix.platform }} verbose=yes target=template_debug ${{ matrix.flags }} build_library=no
|
||||
|
||||
- name: Build test and godot-cpp (release)
|
||||
run: |
|
||||
cd test
|
||||
scons platform=${{ matrix.platform }} verbose=yes target=template_release ${{ matrix.flags }}
|
||||
|
||||
- name: Save Godot build cache
|
||||
uses: ./.github/actions/godot-cache-save
|
||||
with:
|
||||
cache-name: ${{ matrix.cache-name }}
|
||||
continue-on-error: true
|
||||
|
||||
- name: Download latest Godot artifacts
|
||||
uses: dsnopek/action-download-artifact@1322f74e2dac9feed2ee76a32d9ae1ca3b4cf4e9
|
||||
if: matrix.run-tests && env.GODOT_TEST_VERSION == 'master'
|
||||
with:
|
||||
repo: godotengine/godot
|
||||
branch: master
|
||||
event: push
|
||||
workflow: linux_builds.yml
|
||||
workflow_conclusion: success
|
||||
name: linux-editor-mono
|
||||
search_artifacts: true
|
||||
check_artifacts: true
|
||||
ensure_latest: true
|
||||
path: godot-artifacts
|
||||
|
||||
- name: Prepare Godot artifacts for testing
|
||||
if: matrix.run-tests && env.GODOT_TEST_VERSION == 'master'
|
||||
run: |
|
||||
chmod +x ./godot-artifacts/godot.linuxbsd.editor.x86_64.mono
|
||||
echo "GODOT=$(pwd)/godot-artifacts/godot.linuxbsd.editor.x86_64.mono" >> $GITHUB_ENV
|
||||
|
||||
- name: Download requested Godot version for testing
|
||||
if: matrix.run-tests && env.GODOT_TEST_VERSION != 'master'
|
||||
run: |
|
||||
wget "https://github.com/godotengine/godot-builds/releases/download/${GODOT_TEST_VERSION}/Godot_v${GODOT_TEST_VERSION}_linux.x86_64.zip" -O Godot.zip
|
||||
unzip -a Godot.zip
|
||||
chmod +x "Godot_v${GODOT_TEST_VERSION}_linux.x86_64"
|
||||
echo "GODOT=$(pwd)/Godot_v${GODOT_TEST_VERSION}_linux.x86_64" >> $GITHUB_ENV
|
||||
|
||||
- name: Run tests
|
||||
if: matrix.run-tests
|
||||
run: |
|
||||
$GODOT --headless --version
|
||||
cd test
|
||||
# Need to run the editor so .godot is generated... but it crashes! Ignore that :-)
|
||||
(cd project && (timeout 30 $GODOT --import --headless >/dev/null 2>&1 || true))
|
||||
./run-tests.sh
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.artifact-name }}
|
||||
path: ${{ matrix.artifact-path }}
|
||||
if-no-files-found: error
|
||||
|
||||
linux-cmake:
|
||||
name: 🐧 Build (Linux, GCC, CMake)
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -qqq build-essential pkg-config
|
||||
python -m pip install scons
|
||||
curl -LO https://downloads.tuxfamily.org/godotengine/3.3.3/Godot_v3.3.3-stable_linux_server.64.zip
|
||||
unzip Godot_v3.3.3-stable_linux_server.64.zip
|
||||
sudo apt-get install -qqq build-essential pkg-config cmake
|
||||
|
||||
- name: Build godot-cpp
|
||||
run: |
|
||||
scons target=release generate_bindings=yes -j $(nproc)
|
||||
cmake -DCMAKE_BUILD_TYPE=Release .
|
||||
make -j $(nproc) VERBOSE=1
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: godot-cpp-linux-glibc2.27-x86_64-release
|
||||
path: bin/libgodot-cpp.linux.release.64.a
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Build test GDNative library
|
||||
- name: Build test GDExtension library
|
||||
run: |
|
||||
scons target=release platform=linux bits=64 -j $(nproc) -C test
|
||||
cd test && cmake -DCMAKE_BUILD_TYPE=Release -DGODOT_HEADERS_PATH="../godot-headers" -DCPP_BINDINGS_PATH=".." .
|
||||
make -j $(nproc) VERBOSE=1
|
||||
|
||||
- name: Run test GDNative library
|
||||
run: |
|
||||
./Godot_v3.3.3-stable_linux_server.64 --path test -s script.gd
|
||||
|
||||
windows-msvc:
|
||||
name: Build (Windows, MSVC)
|
||||
runs-on: windows-2019
|
||||
linux-cmake-ninja:
|
||||
name: 🐧 Build (Linux, GCC, CMake Ninja)
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Python (for SCons)
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install scons
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -qqq build-essential pkg-config cmake ninja-build
|
||||
|
||||
- name: Build godot-cpp
|
||||
run: |
|
||||
scons target=release generate_bindings=yes -j $env:NUMBER_OF_PROCESSORS
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -GNinja .
|
||||
cmake --build . -j $(nproc) --verbose
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: godot-cpp-windows-msvc2019-x86_64-release
|
||||
path: bin/libgodot-cpp.windows.release.64.lib
|
||||
if-no-files-found: error
|
||||
- name: Build test GDExtension library
|
||||
run: |
|
||||
cd test && cmake -DCMAKE_BUILD_TYPE=Release -DGODOT_HEADERS_PATH="../godot-headers" -DCPP_BINDINGS_PATH=".." -GNinja .
|
||||
cmake --build . -j $(nproc) --verbose
|
||||
|
||||
windows-mingw:
|
||||
name: Build (Windows, MinGW)
|
||||
runs-on: windows-2019
|
||||
windows-msvc-cmake:
|
||||
name: 🏁 Build (Windows, MSVC, CMake)
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Python (for SCons)
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install scons
|
||||
|
||||
- name: Build godot-cpp
|
||||
# Install GCC from Scoop as the default supplied GCC doesn't work ("Error 1").
|
||||
run: |
|
||||
Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')
|
||||
scoop install gcc
|
||||
g++ --version
|
||||
gcc --version
|
||||
scons target=release generate_bindings=yes use_mingw=yes -j $env:NUMBER_OF_PROCESSORS
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: godot-cpp-linux-mingw-x86_64-release
|
||||
path: bin/libgodot-cpp.windows.release.64.a
|
||||
if-no-files-found: error
|
||||
|
||||
macos:
|
||||
name: Build (macOS, Clang)
|
||||
runs-on: macos-10.15
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Python (for SCons)
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install scons
|
||||
curl -LO https://downloads.tuxfamily.org/godotengine/3.3.3/Godot_v3.3.3-stable_osx.universal.zip
|
||||
unzip Godot_v3.3.3-stable_osx.universal.zip
|
||||
|
||||
- name: Build godot-cpp
|
||||
run: |
|
||||
scons target=release generate_bindings=yes -j $(sysctl -n hw.logicalcpu)
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -G"Visual Studio 17 2022" .
|
||||
cmake --build . --verbose --config Release
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: godot-cpp-macos-x86_64-release
|
||||
path: bin/libgodot-cpp.osx.release.64.a
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Build test GDNative library
|
||||
- name: Build test GDExtension library
|
||||
run: |
|
||||
scons target=release platform=osx bits=64 -j $(sysctl -n hw.logicalcpu) -C test
|
||||
|
||||
- name: Run test GDNative library
|
||||
run: |
|
||||
./Godot.app/Contents/MacOS/Godot --path test -s script.gd
|
||||
|
||||
macos-arm64:
|
||||
name: Build (macOS, Clang, cross-compile arm64)
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Python (for SCons)
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install scons
|
||||
|
||||
- name: Build godot-cpp
|
||||
run: |
|
||||
# The default SDK in github the actions environemnt seems to have problems compiling for arm64.
|
||||
# Use the latest 11.x SDK.
|
||||
SDK_BASE=/Library/Developer/CommandLineTools/SDKs
|
||||
SDK_VER=$(ls $SDK_BASE | grep "MacOSX11." | sort -r | head -n1)
|
||||
echo $SDK_BASE/$SDK_VER/
|
||||
scons target=release generate_bindings=yes macos_arch=arm64 macos_deployment_target=10.15 macos_sdk_path="$SDK_BASE/$SDK_VER/" -j $(sysctl -n hw.logicalcpu)
|
||||
|
||||
static-checks:
|
||||
name: Static Checks (clang-format)
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Make apt sources.list use the default Ubuntu repositories
|
||||
run: |
|
||||
sudo rm -f /etc/apt/sources.list.d/*
|
||||
sudo cp -f misc/ci/sources.list /etc/apt/sources.list
|
||||
sudo apt-get update
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get install -qq dos2unix recode clang-format-11
|
||||
sudo update-alternatives --remove-all clang-format
|
||||
sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-11 100
|
||||
|
||||
- name: Style checks via clang-format
|
||||
run: |
|
||||
bash ./misc/scripts/clang_format.sh
|
||||
cd test && cmake -DCMAKE_BUILD_TYPE=Release -DGODOT_HEADERS_PATH="../godot-headers" -DCPP_BINDINGS_PATH=".." -G"Visual Studio 17 2022" .
|
||||
cmake --build . --verbose --config Release
|
||||
|
||||
21
.github/workflows/runner.yml
vendored
Normal file
21
.github/workflows/runner.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
name: 🔗 GHA
|
||||
on: [push, pull_request, merge_group]
|
||||
|
||||
concurrency:
|
||||
group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-runner
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
# First stage: Only static checks, fast and prevent expensive builds from running.
|
||||
|
||||
static-checks:
|
||||
if: '!vars.DISABLE_GODOT_CI'
|
||||
name: 📊 Static Checks
|
||||
uses: ./.github/workflows/static_checks.yml
|
||||
|
||||
# Second stage: Run all the builds and some of the tests.
|
||||
|
||||
ci:
|
||||
name: 🛠️ Continuous Integration
|
||||
needs: static-checks
|
||||
uses: ./.github/workflows/ci.yml
|
||||
38
.github/workflows/static_checks.yml
vendored
Normal file
38
.github/workflows/static_checks.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
name: 📊 Static Checks
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
concurrency:
|
||||
group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-static
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
static-checks:
|
||||
name: Format (clang-format, ruff format, file format)
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: Get changed files
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
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: Style checks via pre-commit
|
||||
uses: pre-commit/action@v3.0.1
|
||||
with:
|
||||
extra_args: --verbose --hook-stage manual --files ${{ env.CHANGED_FILES }}
|
||||
|
||||
- name: Check generated files consistency
|
||||
run:
|
||||
python misc/scripts/check_get_file_list.py
|
||||
28
.gitignore
vendored
28
.gitignore
vendored
@@ -1,5 +1,22 @@
|
||||
# Godot auto generated files
|
||||
*.gen.*
|
||||
.import/
|
||||
.godot/
|
||||
/gen/
|
||||
|
||||
# Godot 3.x ignores
|
||||
include/gen
|
||||
src/gen
|
||||
|
||||
# Build configuration.
|
||||
/custom.py
|
||||
|
||||
# Misc
|
||||
logs/*
|
||||
*.log
|
||||
|
||||
# The default cache directory
|
||||
cache/
|
||||
|
||||
# Binaries
|
||||
*.o
|
||||
@@ -17,6 +34,7 @@ bin
|
||||
*.creator.user
|
||||
*.files
|
||||
*.includes
|
||||
*.idb
|
||||
|
||||
# Gprof output
|
||||
gmon.out
|
||||
@@ -82,7 +100,7 @@ AppPackages/
|
||||
|
||||
# Others
|
||||
sql/
|
||||
*.Cache
|
||||
*.[Cc]ache
|
||||
ClientBin/
|
||||
[Ss]tyle[Cc]op.*
|
||||
~$*
|
||||
@@ -173,3 +191,11 @@ godot.creator.*
|
||||
|
||||
# compile commands (https://clang.llvm.org/docs/JSONCompilationDatabase.html)
|
||||
compile_commands.json
|
||||
|
||||
# Python development
|
||||
.venv
|
||||
venv
|
||||
|
||||
# Clion Configuration
|
||||
.idea/
|
||||
cmake-build-*
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
||||
[submodule "godot-headers"]
|
||||
path = godot-headers
|
||||
url = https://github.com/godotengine/godot-headers
|
||||
|
||||
64
.pre-commit-config.yaml
Normal file
64
.pre-commit-config.yaml
Normal 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]
|
||||
224
CMakeLists.txt
224
CMakeLists.txt
@@ -1,212 +1,24 @@
|
||||
# cmake arguments
|
||||
# CMAKE_BUILD_TYPE: Compilation target (Debug or Release defaults to Debug)
|
||||
#
|
||||
# godot-cpp cmake arguments
|
||||
# GODOT_HEADERS_DIR: This is where the gdnative include folder is (godot_source/modules/gdnative/include)
|
||||
# GODOT_CUSTOM_API_FILE: This is if you have another path for the godot_api.json
|
||||
#
|
||||
# Android cmake arguments
|
||||
# CMAKE_TOOLCHAIN_FILE: The path to the android cmake toolchain ($ANDROID_NDK/build/cmake/android.toolchain.cmake)
|
||||
# ANDROID_NDK: The path to the android ndk root folder
|
||||
# ANDROID_TOOLCHAIN_NAME: The android toolchain (arm-linux-androideabi-4.9 or aarch64-linux-android-4.9 or x86-4.9 or x86_64-4.9)
|
||||
# ANDROID_PLATFORM: The android platform version (android-23)
|
||||
# More info here: https://godot.readthedocs.io/en/latest/development/compiling/compiling_for_android.html
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# Builds a debug version:
|
||||
# cmake .
|
||||
# cmake --build .
|
||||
#
|
||||
# Builds a release version with clang
|
||||
# CC=/usr/bin/clang CXX=/usr/bin/clang++ cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" .
|
||||
# cmake --build .
|
||||
#
|
||||
# Builds an android armeabi-v7a debug version:
|
||||
# cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake -DANDROID_NDK=$ANDROID_NDK \
|
||||
# -DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.9 -DANDROID_PLATFORM=android-23 -DCMAKE_BUILD_TYPE=Debug .
|
||||
# cmake --build .
|
||||
#
|
||||
# Protip
|
||||
# Generate the buildfiles in a sub directory to not clutter the root directory with build files:
|
||||
# mkdir build && cd build && cmake -G "Unix Makefiles" .. && cmake --build .
|
||||
#
|
||||
# Todo
|
||||
# Test build for Windows, Mac and mingw.
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(godot-cpp LANGUAGES CXX)
|
||||
|
||||
project(godot-cpp)
|
||||
cmake_minimum_required(VERSION 3.6)
|
||||
# Configure CMake
|
||||
# https://discourse.cmake.org/t/how-do-i-remove-compile-options-from-target/5965
|
||||
# https://stackoverflow.com/questions/74426638/how-to-remove-rtc1-from-specific-target-or-file-in-cmake
|
||||
if(${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)
|
||||
if(NOT CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
STRING(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
option(GENERATE_TEMPLATE_GET_NODE "Generate a template version of the Node class's get_node." ON)
|
||||
include( ${PROJECT_SOURCE_DIR}/cmake/godotcpp.cmake )
|
||||
|
||||
# Change the output directory to the bin directory
|
||||
set(BUILD_PATH ${CMAKE_SOURCE_DIR}/bin)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${BUILD_PATH}")
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${BUILD_PATH}")
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${BUILD_PATH}")
|
||||
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${BUILD_PATH}")
|
||||
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${BUILD_PATH}")
|
||||
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${BUILD_PATH}")
|
||||
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE "${BUILD_PATH}")
|
||||
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${BUILD_PATH}")
|
||||
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${BUILD_PATH}")
|
||||
# I know this doesn't look like a typical CMakeLists.txt, but as we are
|
||||
# attempting mostly feature parity with SCons, and easy maintenance, the closer
|
||||
# the two build systems look the easier they will be to keep in lockstep.
|
||||
|
||||
# Default build type is Debug in the SConstruct
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "")
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
endif()
|
||||
# The typical target definitions are in ${PROJECT_SOURCE_DIR}/cmake/godotcpp.cmake
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
add_definitions(-D_DEBUG)
|
||||
else()
|
||||
add_definitions(-DNDEBUG)
|
||||
endif(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
godotcpp_options()
|
||||
|
||||
# Set the c++ standard to c++14
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
# Input from user for godot headers and the api file
|
||||
set(GODOT_HEADERS_DIR "godot-headers" CACHE STRING "")
|
||||
set(GODOT_CUSTOM_API_FILE "godot-headers/api.json" CACHE STRING "")
|
||||
|
||||
set(GODOT_COMPILE_FLAGS )
|
||||
set(GODOT_LINKER_FLAGS )
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
# using Visual Studio C++
|
||||
set(GODOT_COMPILE_FLAGS "/EHsc /WX") # /GF /MP
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MDd") # /Od /RTC1 /Zi
|
||||
else()
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MD /O2") # /Oy /GL /Gy
|
||||
STRING(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
|
||||
endif(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
|
||||
# Disable conversion warning, trunkation, unreferenced var, signed missmatch
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /wd4244 /wd4305 /wd4101 /wd4018 /wd4267")
|
||||
|
||||
# Todo: Check if needed.
|
||||
add_definitions(-DWIN32_LEAN_AND_MEAN -D_CRT_SECURE_NO_WARNINGS)
|
||||
|
||||
# Unkomment for warning level 4
|
||||
#if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
|
||||
# string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
#endif()
|
||||
|
||||
else()
|
||||
|
||||
#elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
# using Clang
|
||||
#elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
# using GCC and maybe MinGW?
|
||||
|
||||
set(GODOT_LINKER_FLAGS "-static-libgcc -static-libstdc++ -Wl,-R,'$$ORIGIN'")
|
||||
|
||||
# Hmm.. maybe to strikt?
|
||||
set(GODOT_COMPILE_FLAGS "-fPIC -g -Wwrite-strings")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wchar-subscripts -Wcomment -Wdisabled-optimization")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wformat -Wformat=2 -Wformat-security -Wformat-y2k")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wimport -Winit-self -Winline -Winvalid-pch -Werror")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wmissing-braces -Wmissing-format-attribute")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wmissing-include-dirs -Wmissing-noreturn -Wpacked -Wpointer-arith")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wredundant-decls -Wreturn-type -Wsequence-point")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wswitch -Wswitch-enum -Wtrigraphs")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wuninitialized -Wunknown-pragmas -Wunreachable-code -Wunused-label")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wunused-value -Wvariadic-macros -Wvolatile-register-var -Wno-error=attributes")
|
||||
|
||||
# -Wshadow -Wextra -Wall -Weffc++ -Wfloat-equal -Wstack-protector -Wunused-parameter -Wsign-compare -Wunused-variable -Wcast-align
|
||||
# -Wunused-function -Wstrict-aliasing -Wstrict-aliasing=2 -Wmissing-field-initializers
|
||||
|
||||
if(NOT CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wno-ignored-attributes")
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0")
|
||||
else()
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -O3")
|
||||
endif(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
endif()
|
||||
|
||||
# Generate source from the bindings file
|
||||
find_package(PythonInterp REQUIRED)
|
||||
if(GENERATE_TEMPLATE_GET_NODE)
|
||||
set(GENERATE_BINDING_PARAMETERS "True")
|
||||
else()
|
||||
set(GENERATE_BINDING_PARAMETERS "False")
|
||||
endif()
|
||||
|
||||
message(STATUS "Generating Bindings")
|
||||
execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c" "import binding_generator; binding_generator.print_file_list(\"${GODOT_CUSTOM_API_FILE}\", \"${CMAKE_CURRENT_BINARY_DIR}\", headers=True)"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
RESULT_VARIABLE HEADERS_FILE_LIST_RESULT
|
||||
OUTPUT_VARIABLE HEADERS_FILE_LIST
|
||||
)
|
||||
set(HEADERS_FILE_LIST ${HEADERS_FILE_LIST})
|
||||
|
||||
execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c" "import binding_generator; binding_generator.print_file_list(\"${GODOT_CUSTOM_API_FILE}\", \"${CMAKE_CURRENT_BINARY_DIR}\", sources=True)"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
RESULT_VARIABLE SOURCES_FILE_LIST_RESULT
|
||||
OUTPUT_VARIABLE SOURCES_FILE_LIST
|
||||
)
|
||||
set(SOURCES_FILE_LIST ${SOURCES_FILE_LIST})
|
||||
|
||||
add_custom_command(OUTPUT ${HEADERS_FILE_LIST} ${SOURCES_FILE_LIST}
|
||||
COMMAND "${PYTHON_EXECUTABLE}" "-c" "import binding_generator; binding_generator.generate_bindings(\"${GODOT_CUSTOM_API_FILE}\", \"${GENERATE_BINDING_PARAMETERS}\", \"${CMAKE_CURRENT_BINARY_DIR}\")"
|
||||
VERBATIM
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
MAIN_DEPENDENCY ${GODOT_CUSTOM_API_FILE}
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/binding_generator.py
|
||||
COMMENT Generating Bindings
|
||||
)
|
||||
|
||||
# Get Sources
|
||||
file(GLOB_RECURSE SOURCES src/*.c**)
|
||||
file(GLOB_RECURSE HEADERS include/*.h**)
|
||||
|
||||
# Define our godot-cpp library
|
||||
add_library(${PROJECT_NAME}
|
||||
${SOURCES}
|
||||
${SOURCES_FILE_LIST}
|
||||
${HEADERS}
|
||||
${HEADERS_FILE_LIST}
|
||||
)
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PUBLIC
|
||||
include
|
||||
include/core
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/gen/
|
||||
)
|
||||
|
||||
# Put godot headers as SYSTEM PUBLIC to exclude warnings from irrelevant headers
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
SYSTEM PUBLIC
|
||||
${GODOT_HEADERS_DIR}
|
||||
)
|
||||
|
||||
# Add the compile flags
|
||||
set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY COMPILE_FLAGS ${GODOT_COMPILE_FLAGS})
|
||||
set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY LINK_FLAGS ${GODOT_LINKER_FLAGS})
|
||||
|
||||
# Create the correct name (godot.os.build_type.system_bits)
|
||||
|
||||
set(BITS 32)
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(BITS 64)
|
||||
endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
|
||||
string(TOLOWER "${CMAKE_SYSTEM_NAME}" SYSTEM_NAME)
|
||||
string(TOLOWER "${CMAKE_BUILD_TYPE}" BUILD_TYPE)
|
||||
|
||||
if(ANDROID)
|
||||
# Added the android abi after system name
|
||||
set(SYSTEM_NAME ${SYSTEM_NAME}.${ANDROID_ABI})
|
||||
# Android does not have the bits at the end if you look at the main godot repo build
|
||||
set_property(TARGET ${PROJECT_NAME} PROPERTY OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}")
|
||||
else()
|
||||
set_property(TARGET ${PROJECT_NAME} PROPERTY OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}.${BITS}")
|
||||
endif()
|
||||
godotcpp_generate()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# MIT License
|
||||
|
||||
Copyright (c) 2017-2021 Godot Engine contributors.
|
||||
Copyright (c) 2017-present Godot Engine contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
37
Makefile
37
Makefile
@@ -1,17 +1,17 @@
|
||||
GENERATE_BINDINGS = no
|
||||
HEADERS = godot-headers
|
||||
TARGET = debug
|
||||
USE_CLANG = no
|
||||
TARGET = template_debug
|
||||
|
||||
BASE = scons use_llvm=$(USE_CLANG) generate_bindings=$(GENERATE_BINDINGS) target=$(TARGET) headers=$(HEADERS) -j4
|
||||
BASE = scons target=$(TARGET) $(EXTRA_ARGS)
|
||||
LINUX = $(BASE) platform=linux
|
||||
WINDOWS = $(BASE) platform=windows
|
||||
OSX = $(BASE) platform=osx
|
||||
MACOS = $(BASE) platform=macos
|
||||
|
||||
|
||||
all:
|
||||
make linux
|
||||
make windows
|
||||
.PHONY: usage
|
||||
usage:
|
||||
@echo -e "Specify one of the available targets:\n"
|
||||
# https://stackoverflow.com/a/26339924
|
||||
@LC_ALL=C $(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/(^|\n)# Files(\n|$$)/,/(^|\n)# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | grep -E -v -e '^[^[:alnum:]]' -e '^$@$$'
|
||||
@echo -e "\nDefine the SCons target with TARGET, and pass extra SCons arguments with EXTRA_ARGS."
|
||||
|
||||
|
||||
linux:
|
||||
@@ -19,10 +19,10 @@ linux:
|
||||
make linux64
|
||||
|
||||
linux32: SConstruct
|
||||
$(LINUX) bits=32
|
||||
$(LINUX) arch=x86_32
|
||||
|
||||
linux64: SConstruct
|
||||
$(LINUX) bits=64
|
||||
$(LINUX) arch=x86_64
|
||||
|
||||
|
||||
windows:
|
||||
@@ -30,18 +30,11 @@ windows:
|
||||
make windows64
|
||||
|
||||
windows32: SConstruct
|
||||
$(WINDOWS) bits=32
|
||||
$(WINDOWS) arch=x86_32
|
||||
|
||||
windows64: SConstruct
|
||||
$(WINDOWS) bits=64
|
||||
$(WINDOWS) arch=x86_64
|
||||
|
||||
|
||||
osx:
|
||||
make osx32
|
||||
make osx64
|
||||
|
||||
osx32: SConstruct
|
||||
$(OSX) bits=32
|
||||
|
||||
osx64: SConstruct
|
||||
$(OSX) bits=64
|
||||
macos: SConstruct
|
||||
$(MACOS)
|
||||
|
||||
445
README.md
445
README.md
@@ -1,358 +1,143 @@
|
||||
# godot-cpp
|
||||
|
||||
**C++ bindings for the Godot script API.**
|
||||
> [!WARNING]
|
||||
>
|
||||
> This repository's `master` branch is only usable with
|
||||
> [GDExtension](https://godotengine.org/article/introducing-gd-extensions)
|
||||
> from Godot's `master` branch.
|
||||
>
|
||||
> For users of stable branches, switch to the branch matching your target Godot version:
|
||||
> - [`4.4`](https://github.com/godotengine/godot-cpp/tree/4.4)
|
||||
> - [`4.3`](https://github.com/godotengine/godot-cpp/tree/4.3)
|
||||
> - [`4.2`](https://github.com/godotengine/godot-cpp/tree/4.2)
|
||||
> - [`4.1`](https://github.com/godotengine/godot-cpp/tree/4.1)
|
||||
> - [`4.0`](https://github.com/godotengine/godot-cpp/tree/4.0)
|
||||
>
|
||||
> Or check out the Git tag matching your Godot version (e.g. `godot-4.1.1-stable`).
|
||||
>
|
||||
> For GDNative users (Godot 3.x), switch to the [`3.x`](https://github.com/godotengine/godot-cpp/tree/3.x)
|
||||
> or the [`3.5`](https://github.com/godotengine/godot-cpp/tree/3.5) branch.
|
||||
|
||||
The instructions below feature the new NativeScript 1.1 class structure and will only work for modules created for Godot 3.1 and later. Use the following branches for older implementations:
|
||||
|
||||
Version | Branch
|
||||
--- | ---
|
||||
**Godot 3.0 Nativescript 1.0** | [3.0](https://github.com/godotengine/godot-cpp/tree/3.0)
|
||||
**Godot 3.1 Nativescript 1.0** | [nativescript-1.0](https://github.com/godotengine/godot-cpp/tree/nativescript-1.0)
|
||||
|
||||
## Table of contents
|
||||
This repository contains the *C++ bindings* for the [**Godot Engine**](https://github.com/godotengine/godot)'s GDExtensions API.
|
||||
|
||||
- [**Versioning**](#versioning)
|
||||
- [**Compatibility**](#compatibility)
|
||||
- [**Contributing**](#contributing)
|
||||
- [**Getting Started**](#getting-started)
|
||||
- [**Creating a simple class**](#creating-a-simple-class)
|
||||
- [**Getting started**](#getting-started)
|
||||
- [**Examples and templates**](#examples-and-templates)
|
||||
|
||||
## Versioning
|
||||
|
||||
This repositories follows the same branch versioning as the main [Godot Engine
|
||||
repository](https://github.com/godotengine/godot):
|
||||
|
||||
- `master` tracks the current GDExtension development branch for the next Godot
|
||||
4.x minor release.
|
||||
- `3.x` tracks the development of the GDNative plugin for the next 3.x minor
|
||||
release.
|
||||
- Other versioned branches (e.g. `4.0`, `3.5`) track the latest stable release
|
||||
in the corresponding branch.
|
||||
|
||||
Stable releases are also tagged on this repository:
|
||||
[**Tags**](https://github.com/godotengine/godot-cpp/tags).
|
||||
|
||||
**For any project built against a stable release of Godot, we recommend using
|
||||
this repository as a Git submodule, checking out the specific tag matching your
|
||||
Godot version.**
|
||||
|
||||
> As the `master` branch of Godot is constantly getting updated, if you are
|
||||
> using `godot-cpp` against a more current version of Godot, see the instructions
|
||||
> in the `gdextension` folder to update the relevant files.
|
||||
|
||||
## Compatibility
|
||||
|
||||
GDExtensions targeting an earlier version of Godot should work in later minor versions,
|
||||
but not vice-versa. For example, a GDExtension targeting Godot 4.2 should work just fine
|
||||
in Godot 4.3, but one targeting Godot 4.3 won't work in Godot 4.2.
|
||||
|
||||
There is one exception to this: extensions targeting Godot 4.0 will _not_ work with
|
||||
Godot 4.1 and later.
|
||||
See [Updating your GDExtension for 4.1](https://docs.godotengine.org/en/latest/tutorials/migrating/upgrading_to_godot_4.1.html#updating-your-gdextension-for-godot-4-1).
|
||||
|
||||
## Contributing
|
||||
|
||||
We greatly appreciate help in maintaining and extending this project. If you
|
||||
wish to help out, ensure you have an account on GitHub and create a "fork" of
|
||||
this repository. Rémi "Akien" Verschelde wrote an excellent bit of documentation
|
||||
for the main Godot project on this:
|
||||
[Pull request workflow](https://docs.godotengine.org/en/3.0/community/contributing/pr_workflow.html)
|
||||
this repository. See [Pull request workflow](https://docs.godotengine.org/en/stable/community/contributing/pr_workflow.html)
|
||||
for instructions.
|
||||
|
||||
Please install clang-format and copy the files in `misc/hooks` into `.git/hooks`
|
||||
so formatting is done before your changes are submitted.
|
||||
Please install clang-format and the [pre-commit](https://pre-commit.com/) Python framework so formatting is done before your changes are submitted. See the [code style guidelines](https://docs.godotengine.org/en/latest/contributing/development/code_style_guidelines.html#pre-commit-hook) for instructions.
|
||||
|
||||
## Getting Started
|
||||
## Getting started
|
||||
|
||||
| **Build latest version of Godot** | [**GitHub**](https://github.com/godotengine/godot) | [**Docs**](https://godot.readthedocs.io/en/latest/development/compiling/index.html) |
|
||||
| --- | --- | --- |
|
||||
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).
|
||||
|
||||
### Setting up a new project
|
||||
Getting started with GDExtensions is a bit similar to what it was for 3.x but also a bit different.
|
||||
|
||||
We recommend using Git for managing your project. The instructions below assume
|
||||
you're using Git. Alternatively, you can download the source code directly from
|
||||
GitHub. In this case, you need to download both
|
||||
[godot-cpp](https://github.com/godotengine/godot-cpp) and
|
||||
[godot-headers](https://github.com/godotengine/godot-headers).
|
||||
This new approach is much more akin to how core Godot modules are structured.
|
||||
|
||||
```bash
|
||||
mkdir SimpleLibrary
|
||||
cd SimpleLibrary
|
||||
mkdir bin
|
||||
mkdir src
|
||||
git clone --recursive https://github.com/godotengine/godot-cpp
|
||||
Compiling this repository generates a static library to be linked with your shared lib,
|
||||
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.
|
||||
See [example.gdextension](test/project/example.gdextension) used in the test project:
|
||||
|
||||
```ini
|
||||
[configuration]
|
||||
|
||||
entry_symbol = "example_library_init"
|
||||
compatibility_minimum = "4.1"
|
||||
|
||||
[libraries]
|
||||
|
||||
macos.debug = "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.
|
||||
```
|
||||
|
||||
If you wish to use a specific branch, add the -b option to the clone command:
|
||||
|
||||
```bash
|
||||
git clone --recursive https://github.com/godotengine/godot-cpp -b 3.0
|
||||
```
|
||||
|
||||
If your project is an existing repository, use a Git submodule instead:
|
||||
|
||||
```bash
|
||||
git submodule add https://github.com/godotengine/godot-cpp
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
Right now, our directory structure should look like this:
|
||||
|
||||
```text
|
||||
SimpleLibrary/
|
||||
├─godot-cpp/
|
||||
| └─godot-headers/
|
||||
├─bin/
|
||||
└─src/
|
||||
```
|
||||
|
||||
### Updating the `api.json` file
|
||||
|
||||
Our `api.json` file contains metadata for all the classes that are part of the
|
||||
Godot core. This metadata is required to generate the C++ binding classes for
|
||||
use in GDNative modules.
|
||||
|
||||
This file is supplied with our
|
||||
[godot-headers](https://github.com/godotengine/godot-headers) repository
|
||||
for your convenience. However, if you're running a custom build of Godot and
|
||||
need access to classes that have recent changes, you must generate a new
|
||||
`api.json` file. You do this by starting your Godot executable with the
|
||||
following parameters:
|
||||
|
||||
```bash
|
||||
godot --gdnative-generate-json-api api.json
|
||||
```
|
||||
|
||||
Now copy the `api.json` file into your folder structure to make it easier to
|
||||
access.
|
||||
|
||||
See the remark below for the extra ```custom_api_file``` SCons argument, which
|
||||
is required to tell SCons where to find your file.
|
||||
|
||||
### Compiling the C++ bindings library
|
||||
|
||||
The final step is to compile our C++ bindings library:
|
||||
|
||||
```bash
|
||||
cd godot-cpp
|
||||
scons platform=<your platform> generate_bindings=yes
|
||||
cd ..
|
||||
```
|
||||
|
||||
Replace `<your platform>` with either `windows`, `linux`, `osx` or `android`. If
|
||||
you leave out `platform`, the target platform will automatically be detected
|
||||
from the host platform.
|
||||
|
||||
The resulting library will be created in `godot-cpp/bin/`, take note of its name
|
||||
as it'll differ depending on the target platform.
|
||||
|
||||
#### Compiling for Android
|
||||
|
||||
Download the latest [Android NDK](https://developer.android.com/ndk/downloads)
|
||||
and set the NDK path.
|
||||
|
||||
```bash
|
||||
scons platform=android generate_bindings=yes ANDROID_NDK_ROOT="/PATH-TO-ANDROID-NDK/" android_arch=<arch>
|
||||
```
|
||||
|
||||
The value of `android_arch` can be `armv7, arm64v8, x86, x86_64`. Most Android
|
||||
devices in use nowadays use an ARM architecture, so compiling for `armv7` and
|
||||
`arm64v8` is often enough when distributing an application.
|
||||
|
||||
`ANDROID_NDK_ROOT` can also be set in the environment variables of your PC if
|
||||
you don't want to include it in your SCons call.
|
||||
|
||||
#### Compilation options
|
||||
|
||||
You can optionally add the following options to the SCons command line:
|
||||
|
||||
- When targeting Linux, add `use_llvm=yes` to use Clang instead of GCC.
|
||||
- When targeting Windows, add `use_mingw=yes` to use MinGW instead of MSVC.
|
||||
- When targeting Windows, include `target=runtime` to build a runtime build.
|
||||
- To use an alternative `api.json` file, add `use_custom_api_file=yes
|
||||
custom_api_file=../api.json`. Be sure to specify the correct location where
|
||||
you placed your file (it can be a relative or absolute path).
|
||||
|
||||
## Creating a simple class
|
||||
|
||||
Create `init.cpp` under `SimpleLibrary/src/` and add the following code:
|
||||
The `entry_symbol` is the name of the function that initializes
|
||||
your library. It should be similar to following layout:
|
||||
|
||||
```cpp
|
||||
#include <Godot.hpp>
|
||||
#include <Reference.hpp>
|
||||
extern "C" {
|
||||
|
||||
// Initialization.
|
||||
|
||||
GDExtensionBool GDE_EXPORT example_library_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
|
||||
godot::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization);
|
||||
|
||||
init_obj.register_initializer(initialize_example_module);
|
||||
init_obj.register_terminator(uninitialize_example_module);
|
||||
init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);
|
||||
|
||||
return init_obj.init();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `initialize_example_module()` should register the classes in ClassDB, very like a Godot module would do.
|
||||
|
||||
```cpp
|
||||
using namespace godot;
|
||||
|
||||
class SimpleClass : public Reference {
|
||||
GODOT_CLASS(SimpleClass, Reference);
|
||||
public:
|
||||
SimpleClass() { }
|
||||
|
||||
/** `_init` must exist as it is called by Godot. */
|
||||
void _init() { }
|
||||
|
||||
void test_void_method() {
|
||||
Godot::print("This is test");
|
||||
}
|
||||
|
||||
Variant method(Variant arg) {
|
||||
Variant ret;
|
||||
ret = arg;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void _register_methods() {
|
||||
register_method("method", &SimpleClass::method);
|
||||
|
||||
/**
|
||||
* The line below is equivalent to the following GDScript export:
|
||||
* export var _name = "SimpleClass"
|
||||
**/
|
||||
register_property<SimpleClass, String>("base/name", &SimpleClass::_name, String("SimpleClass"));
|
||||
|
||||
/** Alternatively, with getter and setter methods: */
|
||||
register_property<SimpleClass, int>("base/value", &SimpleClass::set_value, &SimpleClass::get_value, 0);
|
||||
|
||||
/** Registering a signal: **/
|
||||
// register_signal<SimpleClass>("signal_name");
|
||||
// register_signal<SimpleClass>("signal_name", "string_argument", GODOT_VARIANT_TYPE_STRING)
|
||||
}
|
||||
|
||||
String _name;
|
||||
int _value;
|
||||
|
||||
void set_value(int p_value) {
|
||||
_value = p_value;
|
||||
}
|
||||
|
||||
int get_value() const {
|
||||
return _value;
|
||||
}
|
||||
};
|
||||
|
||||
/** GDNative Initialize **/
|
||||
extern "C" void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o) {
|
||||
godot::Godot::gdnative_init(o);
|
||||
}
|
||||
|
||||
/** GDNative Terminate **/
|
||||
extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *o) {
|
||||
godot::Godot::gdnative_terminate(o);
|
||||
}
|
||||
|
||||
/** NativeScript Initialize **/
|
||||
extern "C" void GDN_EXPORT godot_nativescript_init(void *handle) {
|
||||
godot::Godot::nativescript_init(handle);
|
||||
|
||||
godot::register_class<SimpleClass>();
|
||||
void initialize_example_module(ModuleInitializationLevel p_level) {
|
||||
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
|
||||
return;
|
||||
}
|
||||
GDREGISTER_CLASS(Example);
|
||||
}
|
||||
```
|
||||
|
||||
### Compiling the GDNative library
|
||||
Any node and resource you register will be available in the corresponding `Create...` dialog. Any class will be available to scripting as well.
|
||||
|
||||
Once you've compiled the GDNative C++ bindings (see above), you can compile the GDNative library we've just created.
|
||||
## Examples and templates
|
||||
|
||||
#### Linux
|
||||
See the [godot-cpp-template](https://github.com/godotengine/godot-cpp-template) project for a
|
||||
generic reusable template.
|
||||
|
||||
```bash
|
||||
cd SimpleLibrary
|
||||
clang++ -fPIC -o src/init.o -c src/init.cpp -g -O3 -std=c++14 -Igodot-cpp/include -Igodot-cpp/include/core -Igodot-cpp/include/gen -Igodot-cpp/godot-headers
|
||||
clang++ -o bin/libtest.so -shared src/init.o -Lgodot-cpp/bin -l<name of the godot-cpp>
|
||||
```
|
||||
|
||||
You'll need to replace `<name of the godot-cpp>` with the file that was created in [**Compiling the cpp bindings library**](#compiling-the-cpp-bindings-library).
|
||||
|
||||
This creates the file `libtest.so` in your `SimpleLibrary/bin` directory.
|
||||
|
||||
#### Windows
|
||||
|
||||
```bash
|
||||
cd SimpleLibrary
|
||||
cl /Fosrc/init.obj /c src/init.cpp /nologo -EHsc -DNDEBUG /MDd /Igodot-cpp\include /Igodot-cpp\include\core /Igodot-cpp\include\gen /Igodot-cpp\godot-headers
|
||||
link /nologo /dll /out:bin\libtest.dll /implib:bin\libsimple.lib src\init.obj godot-cpp\bin\<name of the godot-cpp>
|
||||
```
|
||||
|
||||
You'll need to replace `<name of the godot-cpp>` with the file that was created
|
||||
in [**Compiling the cpp bindingslibrary**](#compiling-the-cpp-bindings-library).
|
||||
Replace `/MDd` with `/MD` to create a release build, which will run faster and
|
||||
be smaller.
|
||||
|
||||
This creates the file `libtest.dll` in your `SimpleLibrary/bin` directory.
|
||||
|
||||
#### macOS
|
||||
|
||||
For macOS, you'll need to find out which compiler flags need to be used. These
|
||||
are likely similar to Linux when using Clang, but may not be identical.
|
||||
|
||||
If you find suitable compiler flags for this example library, feel free to
|
||||
submit a pull request :slightly_smiling_face:
|
||||
|
||||
#### Android
|
||||
|
||||
```bash
|
||||
cd SimpleLibrary
|
||||
aarch64-linux-android29-clang++ -fPIC -o src/init.o -c src/init.cpp -g -O3 -std=c++14 -Igodot-cpp/include -Igodot-cpp/include/core -Igodot-cpp/include/gen -Igodot-cpp/godot-headers
|
||||
aarch64-linux-android29-clang++ -o bin/libtest.so -shared src/init.o -Lgodot-cpp/bin -l<name of the godot-cpp>
|
||||
```
|
||||
|
||||
You'll need to replace `<name of the godot-cpp>` with the file that was created in [**Compiling the cpp bindings library**](#compiling-the-cpp-bindings-library). The command above targets `arm64v8`. To target `armv7`, use `armv7a-linux-androideabi29-clang++` instead of `aarch64-linux-android29-clang++`.
|
||||
|
||||
This creates the file `libtest.so` in your `SimpleLibrary/bin` directory.
|
||||
|
||||
#### iOS
|
||||
|
||||
GDNative isn't supported on iOS yet. This is because iOS only allows linking
|
||||
static libraries, not dynamic libraries. In theory, it would be possible to link
|
||||
a GDNative library statically, but some of GDNative's convenience would be lost
|
||||
in the process as one would have to recompile the engine on every change. See
|
||||
[issue #30](https://github.com/godotengine/godot-headers/issues/30) in the
|
||||
Godot headers repository for more information.
|
||||
|
||||
#### HTML5
|
||||
|
||||
GDNative is supported on [specific exports](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_web.html#export-options) for the HTML5 platform since Godot `3.2.4`. Linking webassembly modules is currently underspecified in the standard, but [emscripten](https://emscripten.org/), which Godot uses to build the HTML5 version, implements its own linking system.
|
||||
|
||||
To build GDNative libraries, you will need a recent version of [Emscripten](https://emscripten.org/).
|
||||
|
||||
```bash
|
||||
cd SimpleLibrary
|
||||
emcc -o bin/libtest.wasm -g -O3 -s SIDE_MODULE=1 src/init.cpp godot-cpp/bin/<name of the godot-cpp> -Igodot-cpp/include -Igodot-cpp/include/core -Igodot-cpp/include/gen -Igodot-cpp/godot-headers
|
||||
```
|
||||
|
||||
You'll need to replace `<name of the godot-cpp>` with the file that was created in [**Compiling the cpp bindings library**](#compiling-the-cpp-bindings-library).
|
||||
|
||||
This creates the file `libtest.so` in your `SimpleLibrary/bin` directory.
|
||||
|
||||
### Creating `.gdnlib` and `.gdns` files
|
||||
|
||||
Follow the instructions in
|
||||
[godot-headers/README.md](https://github.com/godotengine/godot-headers/blob/master/README.md#how-do-i-use-native-scripts-from-the-editor)
|
||||
to create the `.gdns` file. This file contains paths to GDNative libraries for
|
||||
various platforms. This makes the library usable from Godot in a
|
||||
platform-independent manner.
|
||||
|
||||
### Implementing with GDScript
|
||||
|
||||
Once your GDNative library is compiled and referenced in a `.gdns` file, you can use it in GDScript or C#. Here's an example with GDScript:
|
||||
|
||||
```gdscript
|
||||
var simpleclass = load("res://simpleclass.gdns").new()
|
||||
simpleclass.method("Test argument")
|
||||
```
|
||||
|
||||
### Using Godot classes in C++
|
||||
|
||||
Godot expects you to manage its classes the same way the engine does. These rules apply to all Godot classes, including your NativeScripts, but not to any normal C++ classes used in your library.
|
||||
|
||||
- Instantiate Objects using `_new()`, not C++'s `new` operator.
|
||||
|
||||
```cpp
|
||||
Sprite *sprite = Sprite::_new();
|
||||
```
|
||||
|
||||
- Destroy Nodes using `queue_free()`, not C++'s `delete` operator.
|
||||
|
||||
```cpp
|
||||
some_old_node->queue_free();
|
||||
```
|
||||
|
||||
- Wrap References in `Ref` instead of passing around raw pointers. They are reference-counted and don't need to be freed manually.
|
||||
|
||||
```cpp
|
||||
Ref<Texture> texture = resource_loader->load("res://icon.png");
|
||||
```
|
||||
|
||||
- Pass core types that do *not* inherit Object by value. The containers (Array, Dictionary, PoolArray, String) manage their own memory and do not need to be explicitly initialized or freed.
|
||||
|
||||
```cpp
|
||||
Array ints;
|
||||
ints.append(123);
|
||||
return ints;
|
||||
```
|
||||
|
||||
- Initialize your NativeScript classes in their `_init()` method, not their constructor. The constructor can't access the base class's methods.
|
||||
|
||||
- Cast objects using `Object::cast_to`, not unsafe C-style casts or `static_cast`.
|
||||
|
||||
```cpp
|
||||
MeshInstance *m = Object::cast_to<MeshInstance>(get_node("ChildNode"));
|
||||
// `m` will be null if it's not a MeshInstance
|
||||
if (m) { ... }
|
||||
```
|
||||
|
||||
- **Never** use Godot types in static or global variables. The Godot API isn't loaded until after their constructors are called.
|
||||
|
||||
```cpp
|
||||
String s; // crashes
|
||||
class SomeClass {
|
||||
static Dictionary d; // crashes
|
||||
|
||||
static Node *node_a = NULL; // fine, it's just a pointer
|
||||
static Node *node_b = Node::_new(); // crashes
|
||||
};
|
||||
```
|
||||
Or checkout the code for the [Summator example](https://github.com/paddy-exe/GDExtensionSummator)
|
||||
as shown in the [official documentation](https://docs.godotengine.org/en/latest/tutorials/scripting/cpp/gdextension_cpp_example.html).
|
||||
|
||||
504
SConstruct
504
SConstruct
@@ -1,481 +1,51 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
if sys.version_info < (3,):
|
||||
def decode_utf8(x):
|
||||
return x
|
||||
else:
|
||||
import codecs
|
||||
def decode_utf8(x):
|
||||
return codecs.utf_8_decode(x)[0]
|
||||
|
||||
# Workaround for MinGW. See:
|
||||
# http://www.scons.org/wiki/LongCmdLinesOnWin32
|
||||
if (os.name=="nt"):
|
||||
import subprocess
|
||||
|
||||
def mySubProcess(cmdline,env):
|
||||
#print "SPAWNED : " + cmdline
|
||||
startupinfo = subprocess.STARTUPINFO()
|
||||
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||
proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, startupinfo=startupinfo, shell = False, env = env)
|
||||
data, err = proc.communicate()
|
||||
rv = proc.wait()
|
||||
if rv:
|
||||
print("=====")
|
||||
print(err.decode("utf-8"))
|
||||
print("=====")
|
||||
return rv
|
||||
|
||||
def mySpawn(sh, escape, cmd, args, env):
|
||||
|
||||
newargs = ' '.join(args[1:])
|
||||
cmdline = cmd + " " + newargs
|
||||
|
||||
rv=0
|
||||
if len(cmdline) > 32000 and cmd.endswith("ar") :
|
||||
cmdline = cmd + " " + args[1] + " " + args[2] + " "
|
||||
for i in range(3,len(args)) :
|
||||
rv = mySubProcess( cmdline + args[i], env )
|
||||
if rv :
|
||||
break
|
||||
else:
|
||||
rv = mySubProcess( cmdline, env )
|
||||
|
||||
return rv
|
||||
|
||||
def add_sources(sources, dir, extension):
|
||||
for f in os.listdir(dir):
|
||||
if f.endswith('.' + extension):
|
||||
sources.append(dir + '/' + f)
|
||||
EnsureSConsVersion(4, 0)
|
||||
|
||||
|
||||
# Try to detect the host platform automatically.
|
||||
# This is used if no `platform` argument is passed
|
||||
if sys.platform.startswith('linux'):
|
||||
host_platform = 'linux'
|
||||
elif sys.platform.startswith('freebsd'):
|
||||
host_platform = 'freebsd'
|
||||
elif sys.platform == 'darwin':
|
||||
host_platform = 'osx'
|
||||
elif sys.platform == 'win32' or sys.platform == 'msys':
|
||||
host_platform = 'windows'
|
||||
else:
|
||||
raise ValueError(
|
||||
'Could not detect platform automatically, please specify with '
|
||||
'platform=<platform>'
|
||||
)
|
||||
try:
|
||||
Import("env")
|
||||
except Exception:
|
||||
# Default tools with no platform defaults to gnu toolchain.
|
||||
# We apply platform specific toolchains via our custom tools.
|
||||
env = Environment(tools=["default"], PLATFORM="")
|
||||
|
||||
env = Environment(ENV = os.environ)
|
||||
|
||||
is64 = sys.maxsize > 2**32
|
||||
if (
|
||||
env['TARGET_ARCH'] == 'amd64' or
|
||||
env['TARGET_ARCH'] == 'emt64' or
|
||||
env['TARGET_ARCH'] == 'x86_64' or
|
||||
env['TARGET_ARCH'] == 'arm64-v8a'
|
||||
):
|
||||
is64 = True
|
||||
|
||||
opts = Variables([], ARGUMENTS)
|
||||
opts.Add(EnumVariable(
|
||||
'platform',
|
||||
'Target platform',
|
||||
host_platform,
|
||||
allowed_values=('linux', 'freebsd', 'osx', 'windows', 'android', 'ios', 'javascript'),
|
||||
ignorecase=2
|
||||
))
|
||||
opts.Add(EnumVariable(
|
||||
'bits',
|
||||
'Target platform bits',
|
||||
'64' if is64 else '32',
|
||||
('32', '64')
|
||||
))
|
||||
opts.Add(BoolVariable(
|
||||
'use_llvm',
|
||||
'Use the LLVM compiler - only effective when targeting Linux or FreeBSD',
|
||||
False
|
||||
))
|
||||
opts.Add(BoolVariable(
|
||||
'use_mingw',
|
||||
'Use the MinGW compiler instead of MSVC - only effective on Windows',
|
||||
False
|
||||
))
|
||||
# Must be the same setting as used for cpp_bindings
|
||||
opts.Add(EnumVariable(
|
||||
'target',
|
||||
'Compilation target',
|
||||
'debug',
|
||||
allowed_values=('debug', 'release'),
|
||||
ignorecase=2
|
||||
))
|
||||
opts.Add(PathVariable(
|
||||
'headers_dir',
|
||||
'Path to the directory containing Godot headers',
|
||||
'godot-headers',
|
||||
PathVariable.PathIsDir
|
||||
))
|
||||
opts.Add(PathVariable(
|
||||
'custom_api_file',
|
||||
'Path to a custom JSON API file',
|
||||
None,
|
||||
PathVariable.PathIsFile
|
||||
))
|
||||
opts.Add(EnumVariable(
|
||||
'generate_bindings',
|
||||
'Generate GDNative API bindings',
|
||||
'auto',
|
||||
allowed_values = ['yes', 'no', 'auto', 'true'],
|
||||
ignorecase = 2
|
||||
))
|
||||
opts.Add(EnumVariable(
|
||||
'android_arch',
|
||||
'Target Android architecture',
|
||||
'armv7',
|
||||
['armv7','arm64v8','x86','x86_64']
|
||||
))
|
||||
opts.Add(
|
||||
'macos_deployment_target',
|
||||
'macOS deployment target',
|
||||
'default'
|
||||
)
|
||||
opts.Add(
|
||||
'macos_sdk_path',
|
||||
'macOS SDK path',
|
||||
''
|
||||
)
|
||||
opts.Add(EnumVariable(
|
||||
'macos_arch',
|
||||
'Target macOS architecture',
|
||||
'x86_64',
|
||||
['x86_64', 'arm64']
|
||||
))
|
||||
opts.Add(EnumVariable(
|
||||
'ios_arch',
|
||||
'Target iOS architecture',
|
||||
'arm64',
|
||||
['armv7', 'arm64', 'x86_64']
|
||||
))
|
||||
opts.Add(BoolVariable(
|
||||
'ios_simulator',
|
||||
'Target iOS Simulator',
|
||||
False
|
||||
))
|
||||
opts.Add(
|
||||
'IPHONEPATH',
|
||||
'Path to iPhone toolchain',
|
||||
'/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain',
|
||||
)
|
||||
opts.Add(
|
||||
'android_api_level',
|
||||
'Target Android API level',
|
||||
'18' if ARGUMENTS.get("android_arch", 'armv7') in ['armv7', 'x86'] else '21'
|
||||
)
|
||||
opts.Add(
|
||||
'ANDROID_NDK_ROOT',
|
||||
'Path to your Android NDK installation. By default, uses ANDROID_NDK_ROOT from your defined environment variables.',
|
||||
os.environ.get("ANDROID_NDK_ROOT", None)
|
||||
)
|
||||
opts.Add(BoolVariable(
|
||||
'generate_template_get_node',
|
||||
"Generate a template version of the Node class's get_node.",
|
||||
True
|
||||
))
|
||||
env.PrependENVPath("PATH", os.getenv("PATH"))
|
||||
|
||||
# Custom options and profile flags.
|
||||
customs = ["custom.py"]
|
||||
try:
|
||||
customs += Import("customs")
|
||||
except Exception:
|
||||
pass
|
||||
profile = ARGUMENTS.get("profile", "")
|
||||
if profile:
|
||||
if os.path.isfile(profile):
|
||||
customs.append(profile)
|
||||
elif os.path.isfile(profile + ".py"):
|
||||
customs.append(profile + ".py")
|
||||
opts = Variables(customs, ARGUMENTS)
|
||||
cpp_tool = Tool("godotcpp", toolpath=["tools"])
|
||||
cpp_tool.options(opts, env)
|
||||
opts.Update(env)
|
||||
|
||||
Help(opts.GenerateHelpText(env))
|
||||
|
||||
# This makes sure to keep the session environment variables on Windows.
|
||||
# This way, you can run SCons in a Visual Studio 2017 prompt and it will find
|
||||
# all the required tools
|
||||
if host_platform == 'windows' and env['platform'] != 'android':
|
||||
if env['bits'] == '64':
|
||||
env = Environment(TARGET_ARCH='amd64')
|
||||
elif env['bits'] == '32':
|
||||
env = Environment(TARGET_ARCH='x86')
|
||||
# Detect and print a warning listing unknown SCons variables to ease troubleshooting.
|
||||
unknown = opts.UnknownVariables()
|
||||
if unknown:
|
||||
print("WARNING: Unknown SCons variables were passed and will be ignored:")
|
||||
for item in unknown.items():
|
||||
print(" " + item[0] + "=" + item[1])
|
||||
|
||||
opts.Update(env)
|
||||
scons_cache_path = os.environ.get("SCONS_CACHE")
|
||||
if scons_cache_path is not None:
|
||||
CacheDir(scons_cache_path)
|
||||
Decider("MD5")
|
||||
|
||||
if env['platform'] == 'linux' or env['platform'] == 'freebsd':
|
||||
if env['use_llvm']:
|
||||
env['CXX'] = 'clang++'
|
||||
cpp_tool.generate(env)
|
||||
library = env.GodotCPP()
|
||||
|
||||
env.Append(CCFLAGS=['-fPIC', '-std=c++14', '-Wwrite-strings'])
|
||||
env.Append(LINKFLAGS=["-Wl,-R,'$$ORIGIN'"])
|
||||
|
||||
if env['target'] == 'debug':
|
||||
env.Append(CCFLAGS=['-Og', '-g'])
|
||||
elif env['target'] == 'release':
|
||||
env.Append(CCFLAGS=['-O3'])
|
||||
|
||||
if env['bits'] == '64':
|
||||
env.Append(CCFLAGS=['-m64'])
|
||||
env.Append(LINKFLAGS=['-m64'])
|
||||
elif env['bits'] == '32':
|
||||
env.Append(CCFLAGS=['-m32'])
|
||||
env.Append(LINKFLAGS=['-m32'])
|
||||
|
||||
elif env['platform'] == 'osx':
|
||||
# Use Clang on macOS by default
|
||||
env['CXX'] = 'clang++'
|
||||
|
||||
if env['bits'] == '32':
|
||||
raise ValueError(
|
||||
'Only 64-bit builds are supported for the macOS target.'
|
||||
)
|
||||
|
||||
env.Append(CCFLAGS=['-std=c++14', '-arch', env['macos_arch']])
|
||||
|
||||
if env['macos_deployment_target'] != 'default':
|
||||
env.Append(CCFLAGS=['-mmacosx-version-min=' + env['macos_deployment_target']])
|
||||
env.Append(LINKFLAGS=['-mmacosx-version-min=' + env['macos_deployment_target']])
|
||||
|
||||
if env['macos_sdk_path']:
|
||||
env.Append(CCFLAGS=['-isysroot', env['macos_sdk_path']])
|
||||
env.Append(LINKFLAGS=['-isysroot', env['macos_sdk_path']])
|
||||
|
||||
env.Append(LINKFLAGS=[
|
||||
'-arch',
|
||||
env['macos_arch'],
|
||||
'-framework',
|
||||
'Cocoa',
|
||||
'-Wl,-undefined,dynamic_lookup',
|
||||
])
|
||||
|
||||
if env['target'] == 'debug':
|
||||
env.Append(CCFLAGS=['-Og', '-g'])
|
||||
elif env['target'] == 'release':
|
||||
env.Append(CCFLAGS=['-O3'])
|
||||
|
||||
elif env['platform'] == 'ios':
|
||||
if env['ios_simulator']:
|
||||
sdk_name = 'iphonesimulator'
|
||||
env.Append(CCFLAGS=['-mios-simulator-version-min=10.0'])
|
||||
env['LIBSUFFIX'] = ".simulator" + env['LIBSUFFIX']
|
||||
else:
|
||||
sdk_name = 'iphoneos'
|
||||
env.Append(CCFLAGS=['-miphoneos-version-min=10.0'])
|
||||
|
||||
try:
|
||||
sdk_path = decode_utf8(subprocess.check_output(['xcrun', '--sdk', sdk_name, '--show-sdk-path']).strip())
|
||||
except (subprocess.CalledProcessError, OSError):
|
||||
raise ValueError("Failed to find SDK path while running xcrun --sdk {} --show-sdk-path.".format(sdk_name))
|
||||
|
||||
compiler_path = env['IPHONEPATH'] + '/usr/bin/'
|
||||
env['ENV']['PATH'] = env['IPHONEPATH'] + "/Developer/usr/bin/:" + env['ENV']['PATH']
|
||||
|
||||
env['CC'] = compiler_path + 'clang'
|
||||
env['CXX'] = compiler_path + 'clang++'
|
||||
env['AR'] = compiler_path + 'ar'
|
||||
env['RANLIB'] = compiler_path + 'ranlib'
|
||||
|
||||
env.Append(CCFLAGS=['-std=c++14', '-arch', env['ios_arch'], '-isysroot', sdk_path])
|
||||
env.Append(LINKFLAGS=[
|
||||
'-arch',
|
||||
env['ios_arch'],
|
||||
'-framework',
|
||||
'Cocoa',
|
||||
'-Wl,-undefined,dynamic_lookup',
|
||||
'-isysroot', sdk_path,
|
||||
'-F' + sdk_path
|
||||
])
|
||||
|
||||
if env['target'] == 'debug':
|
||||
env.Append(CCFLAGS=['-Og', '-g'])
|
||||
elif env['target'] == 'release':
|
||||
env.Append(CCFLAGS=['-O3'])
|
||||
|
||||
elif env['platform'] == 'windows':
|
||||
if host_platform == 'windows' and not env['use_mingw']:
|
||||
# MSVC
|
||||
env.Append(LINKFLAGS=['/WX'])
|
||||
if env['target'] == 'debug':
|
||||
env.Append(CCFLAGS=['/Z7', '/Od', '/EHsc', '/D_DEBUG', '/MDd'])
|
||||
elif env['target'] == 'release':
|
||||
env.Append(CCFLAGS=['/O2', '/EHsc', '/DNDEBUG', '/MD'])
|
||||
|
||||
elif host_platform == 'linux' or host_platform == 'freebsd' or host_platform == 'osx':
|
||||
# Cross-compilation using MinGW
|
||||
if env['bits'] == '64':
|
||||
env['CXX'] = 'x86_64-w64-mingw32-g++'
|
||||
env['AR'] = "x86_64-w64-mingw32-ar"
|
||||
env['RANLIB'] = "x86_64-w64-mingw32-ranlib"
|
||||
env['LINK'] = "x86_64-w64-mingw32-g++"
|
||||
elif env['bits'] == '32':
|
||||
env['CXX'] = 'i686-w64-mingw32-g++'
|
||||
env['AR'] = "i686-w64-mingw32-ar"
|
||||
env['RANLIB'] = "i686-w64-mingw32-ranlib"
|
||||
env['LINK'] = "i686-w64-mingw32-g++"
|
||||
|
||||
elif host_platform == 'windows' and env['use_mingw']:
|
||||
# Don't Clone the environment. Because otherwise, SCons will pick up msvc stuff.
|
||||
env = Environment(ENV = os.environ, tools=["mingw"])
|
||||
opts.Update(env)
|
||||
#env = env.Clone(tools=['mingw'])
|
||||
|
||||
env["SPAWN"] = mySpawn
|
||||
|
||||
# Native or cross-compilation using MinGW
|
||||
if host_platform == 'linux' or host_platform == 'freebsd' or host_platform == 'osx' or env['use_mingw']:
|
||||
# These options are for a release build even using target=debug
|
||||
env.Append(CCFLAGS=['-O3', '-std=c++14', '-Wwrite-strings'])
|
||||
env.Append(LINKFLAGS=[
|
||||
'--static',
|
||||
'-Wl,--no-undefined',
|
||||
'-static-libgcc',
|
||||
'-static-libstdc++',
|
||||
])
|
||||
|
||||
elif env['platform'] == 'android':
|
||||
if host_platform == 'windows':
|
||||
# Don't Clone the environment. Because otherwise, SCons will pick up msvc stuff.
|
||||
env = Environment(ENV = os.environ, tools=["mingw"])
|
||||
opts.Update(env)
|
||||
#env = env.Clone(tools=['mingw'])
|
||||
|
||||
env["SPAWN"] = mySpawn
|
||||
|
||||
# Verify NDK root
|
||||
if not 'ANDROID_NDK_ROOT' in env:
|
||||
raise ValueError("To build for Android, ANDROID_NDK_ROOT must be defined. Please set ANDROID_NDK_ROOT to the root folder of your Android NDK installation.")
|
||||
|
||||
# Validate API level
|
||||
api_level = int(env['android_api_level'])
|
||||
if env['android_arch'] in ['x86_64', 'arm64v8'] and api_level < 21:
|
||||
print("WARN: 64-bit Android architectures require an API level of at least 21; setting android_api_level=21")
|
||||
env['android_api_level'] = '21'
|
||||
api_level = 21
|
||||
|
||||
# Setup toolchain
|
||||
toolchain = env['ANDROID_NDK_ROOT'] + "/toolchains/llvm/prebuilt/"
|
||||
if host_platform == "windows":
|
||||
toolchain += "windows"
|
||||
import platform as pltfm
|
||||
if pltfm.machine().endswith("64"):
|
||||
toolchain += "-x86_64"
|
||||
elif host_platform == "linux":
|
||||
toolchain += "linux-x86_64"
|
||||
elif host_platform == "osx":
|
||||
toolchain += "darwin-x86_64"
|
||||
env.PrependENVPath('PATH', toolchain + "/bin") # This does nothing half of the time, but we'll put it here anyways
|
||||
|
||||
# Get architecture info
|
||||
arch_info_table = {
|
||||
"armv7" : {
|
||||
"march":"armv7-a", "target":"armv7a-linux-androideabi", "tool_path":"arm-linux-androideabi", "compiler_path":"armv7a-linux-androideabi",
|
||||
"ccflags" : ['-mfpu=neon']
|
||||
},
|
||||
"arm64v8" : {
|
||||
"march":"armv8-a", "target":"aarch64-linux-android", "tool_path":"aarch64-linux-android", "compiler_path":"aarch64-linux-android",
|
||||
"ccflags" : []
|
||||
},
|
||||
"x86" : {
|
||||
"march":"i686", "target":"i686-linux-android", "tool_path":"i686-linux-android", "compiler_path":"i686-linux-android",
|
||||
"ccflags" : ['-mstackrealign']
|
||||
},
|
||||
"x86_64" : {"march":"x86-64", "target":"x86_64-linux-android", "tool_path":"x86_64-linux-android", "compiler_path":"x86_64-linux-android",
|
||||
"ccflags" : []
|
||||
}
|
||||
}
|
||||
arch_info = arch_info_table[env['android_arch']]
|
||||
|
||||
# Setup tools
|
||||
env['CC'] = toolchain + "/bin/clang"
|
||||
env['CXX'] = toolchain + "/bin/clang++"
|
||||
env['AR'] = toolchain + "/bin/" + arch_info['tool_path'] + "-ar"
|
||||
|
||||
env.Append(CCFLAGS=['--target=' + arch_info['target'] + env['android_api_level'], '-march=' + arch_info['march'], '-fPIC'])#, '-fPIE', '-fno-addrsig', '-Oz'])
|
||||
env.Append(CCFLAGS=arch_info['ccflags'])
|
||||
|
||||
if env['target'] == 'debug':
|
||||
env.Append(CCFLAGS=['-Og', '-g'])
|
||||
elif env['target'] == 'release':
|
||||
env.Append(CCFLAGS=['-O3'])
|
||||
|
||||
elif env["platform"] == "javascript":
|
||||
env["ENV"] = os.environ
|
||||
env["CC"] = "emcc"
|
||||
env["CXX"] = "em++"
|
||||
env["AR"] = "emar"
|
||||
env["RANLIB"] = "emranlib"
|
||||
env.Append(CPPFLAGS=["-s", "SIDE_MODULE=1"])
|
||||
env.Append(LINKFLAGS=["-s", "SIDE_MODULE=1"])
|
||||
env["SHOBJSUFFIX"] = ".bc"
|
||||
env["SHLIBSUFFIX"] = ".wasm"
|
||||
# Use TempFileMunge since some AR invocations are too long for cmd.exe.
|
||||
# Use POSIX-style paths, required with TempFileMunge.
|
||||
env["ARCOM_POSIX"] = env["ARCOM"].replace("$TARGET", "$TARGET.posix").replace("$SOURCES", "$SOURCES.posix")
|
||||
env["ARCOM"] = "${TEMPFILE(ARCOM_POSIX)}"
|
||||
|
||||
# All intermediate files are just LLVM bitcode.
|
||||
env["OBJPREFIX"] = ""
|
||||
env["OBJSUFFIX"] = ".bc"
|
||||
env["PROGPREFIX"] = ""
|
||||
# Program() output consists of multiple files, so specify suffixes manually at builder.
|
||||
env["PROGSUFFIX"] = ""
|
||||
env["LIBPREFIX"] = "lib"
|
||||
env["LIBSUFFIX"] = ".a"
|
||||
env["LIBPREFIXES"] = ["$LIBPREFIX"]
|
||||
env["LIBSUFFIXES"] = ["$LIBSUFFIX"]
|
||||
env.Replace(SHLINKFLAGS='$LINKFLAGS')
|
||||
env.Replace(SHLINKFLAGS='$LINKFLAGS')
|
||||
|
||||
if env['target'] == 'debug':
|
||||
env.Append(CCFLAGS=['-O0', '-g'])
|
||||
elif env['target'] == 'release':
|
||||
env.Append(CCFLAGS=['-O3'])
|
||||
|
||||
env.Append(CPPPATH=[
|
||||
'.',
|
||||
env['headers_dir'],
|
||||
'include',
|
||||
'include/gen',
|
||||
'include/core',
|
||||
])
|
||||
|
||||
# Generate bindings?
|
||||
json_api_file = ''
|
||||
|
||||
if 'custom_api_file' in env:
|
||||
json_api_file = env['custom_api_file']
|
||||
else:
|
||||
json_api_file = os.path.join(os.getcwd(), env['headers_dir'], 'api.json')
|
||||
|
||||
if env['generate_bindings'] == 'auto':
|
||||
# Check if generated files exist
|
||||
should_generate_bindings = not os.path.isfile(os.path.join(os.getcwd(), 'src', 'gen', 'Object.cpp'))
|
||||
else:
|
||||
should_generate_bindings = env['generate_bindings'] in ['yes', 'true']
|
||||
|
||||
if should_generate_bindings:
|
||||
# Actually create the bindings here
|
||||
import binding_generator
|
||||
|
||||
binding_generator.generate_bindings(json_api_file, env['generate_template_get_node'])
|
||||
|
||||
# Sources to compile
|
||||
sources = []
|
||||
add_sources(sources, 'src/core', 'cpp')
|
||||
add_sources(sources, 'src/gen', 'cpp')
|
||||
|
||||
arch_suffix = env['bits']
|
||||
if env['platform'] == 'android':
|
||||
arch_suffix = env['android_arch']
|
||||
if env['platform'] == 'ios':
|
||||
arch_suffix = env['ios_arch']
|
||||
if env['platform'] == 'javascript':
|
||||
arch_suffix = 'wasm'
|
||||
|
||||
library = env.StaticLibrary(
|
||||
target='bin/' + 'libgodot-cpp.{}.{}.{}{}'.format(
|
||||
env['platform'],
|
||||
env['target'],
|
||||
arch_suffix,
|
||||
env['LIBSUFFIX']
|
||||
), source=sources
|
||||
)
|
||||
Default(library)
|
||||
Return("env")
|
||||
|
||||
3446
binding_generator.py
3446
binding_generator.py
File diff suppressed because it is too large
Load Diff
183
build_profile.py
Normal file
183
build_profile.py
Normal file
@@ -0,0 +1,183 @@
|
||||
import json
|
||||
import sys
|
||||
|
||||
|
||||
def parse_build_profile(profile_filepath, api):
|
||||
if profile_filepath == "":
|
||||
return {}
|
||||
|
||||
with open(profile_filepath, encoding="utf-8") as profile_file:
|
||||
profile = json.load(profile_file)
|
||||
|
||||
api_dict = {}
|
||||
parents = {}
|
||||
children = {}
|
||||
for engine_class in api["classes"]:
|
||||
api_dict[engine_class["name"]] = engine_class
|
||||
parent = engine_class.get("inherits", "")
|
||||
child = engine_class["name"]
|
||||
parents[child] = parent
|
||||
if parent == "":
|
||||
continue
|
||||
children[parent] = children.get(parent, [])
|
||||
children[parent].append(child)
|
||||
|
||||
included = []
|
||||
front = list(profile.get("enabled_classes", []))
|
||||
if front:
|
||||
# These must always be included
|
||||
front.append("WorkerThreadPool")
|
||||
front.append("ClassDB")
|
||||
front.append("ClassDBSingleton")
|
||||
# In src/classes/low_level.cpp
|
||||
front.append("FileAccess")
|
||||
front.append("Image")
|
||||
front.append("XMLParser")
|
||||
# In include/godot_cpp/templates/thread_work_pool.hpp
|
||||
front.append("Semaphore")
|
||||
while front:
|
||||
cls = front.pop()
|
||||
if cls in included:
|
||||
continue
|
||||
included.append(cls)
|
||||
parent = parents.get(cls, "")
|
||||
if parent:
|
||||
front.append(parent)
|
||||
|
||||
excluded = []
|
||||
front = list(profile.get("disabled_classes", []))
|
||||
while front:
|
||||
cls = front.pop()
|
||||
if cls in excluded:
|
||||
continue
|
||||
excluded.append(cls)
|
||||
front += children.get(cls, [])
|
||||
|
||||
if included and excluded:
|
||||
print(
|
||||
"WARNING: Cannot specify both 'enabled_classes' and 'disabled_classes' in build profile. 'disabled_classes' will be ignored."
|
||||
)
|
||||
|
||||
return {
|
||||
"enabled_classes": included,
|
||||
"disabled_classes": excluded,
|
||||
}
|
||||
|
||||
|
||||
def generate_trimmed_api(source_api_filepath, profile_filepath):
|
||||
with open(source_api_filepath, encoding="utf-8") as api_file:
|
||||
api = json.load(api_file)
|
||||
|
||||
if profile_filepath == "":
|
||||
return api
|
||||
|
||||
build_profile = parse_build_profile(profile_filepath, api)
|
||||
|
||||
engine_classes = {}
|
||||
for class_api in api["classes"]:
|
||||
engine_classes[class_api["name"]] = class_api["is_refcounted"]
|
||||
for native_struct in api["native_structures"]:
|
||||
if native_struct["name"] == "ObjectID":
|
||||
continue
|
||||
engine_classes[native_struct["name"]] = False
|
||||
|
||||
classes = []
|
||||
for class_api in api["classes"]:
|
||||
if not is_class_included(class_api["name"], build_profile):
|
||||
continue
|
||||
if "methods" in class_api:
|
||||
methods = []
|
||||
for method in class_api["methods"]:
|
||||
if not is_method_included(method, build_profile, engine_classes):
|
||||
continue
|
||||
methods.append(method)
|
||||
class_api["methods"] = methods
|
||||
classes.append(class_api)
|
||||
api["classes"] = classes
|
||||
|
||||
return api
|
||||
|
||||
|
||||
def is_class_included(class_name, build_profile):
|
||||
"""
|
||||
Check if an engine class should be included.
|
||||
This removes classes according to a build profile of enabled or disabled classes.
|
||||
"""
|
||||
included = build_profile.get("enabled_classes", [])
|
||||
excluded = build_profile.get("disabled_classes", [])
|
||||
if included:
|
||||
return class_name in included
|
||||
if excluded:
|
||||
return class_name not in excluded
|
||||
return True
|
||||
|
||||
|
||||
def is_method_included(method, build_profile, engine_classes):
|
||||
"""
|
||||
Check if an engine class method should be included.
|
||||
This removes methods according to a build profile of enabled or disabled classes.
|
||||
"""
|
||||
included = build_profile.get("enabled_classes", [])
|
||||
excluded = build_profile.get("disabled_classes", [])
|
||||
ref_cls = set()
|
||||
rtype = get_base_type(method.get("return_value", {}).get("type", ""))
|
||||
args = [get_base_type(a["type"]) for a in method.get("arguments", [])]
|
||||
if rtype in engine_classes:
|
||||
ref_cls.add(rtype)
|
||||
elif is_enum(rtype) and get_enum_class(rtype) in engine_classes:
|
||||
ref_cls.add(get_enum_class(rtype))
|
||||
for arg in args:
|
||||
if arg in engine_classes:
|
||||
ref_cls.add(arg)
|
||||
elif is_enum(arg) and get_enum_class(arg) in engine_classes:
|
||||
ref_cls.add(get_enum_class(arg))
|
||||
for acls in ref_cls:
|
||||
if len(included) > 0 and acls not in included:
|
||||
return False
|
||||
elif len(excluded) > 0 and acls in excluded:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def is_enum(type_name):
|
||||
return type_name.startswith("enum::") or type_name.startswith("bitfield::")
|
||||
|
||||
|
||||
def get_enum_class(enum_name: str):
|
||||
if "." in enum_name:
|
||||
if is_bitfield(enum_name):
|
||||
return enum_name.replace("bitfield::", "").split(".")[0]
|
||||
else:
|
||||
return enum_name.replace("enum::", "").split(".")[0]
|
||||
else:
|
||||
return "GlobalConstants"
|
||||
|
||||
|
||||
def get_base_type(type_name):
|
||||
if type_name.startswith("const "):
|
||||
type_name = type_name[6:]
|
||||
if type_name.endswith("*"):
|
||||
type_name = type_name[:-1]
|
||||
if type_name.startswith("typedarray::"):
|
||||
type_name = type_name.replace("typedarray::", "")
|
||||
return type_name
|
||||
|
||||
|
||||
def is_bitfield(type_name):
|
||||
return type_name.startswith("bitfield::")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 3 or len(sys.argv) > 4:
|
||||
print("Usage: %s BUILD_PROFILE INPUT_JSON [OUTPUT_JSON]" % (sys.argv[0]))
|
||||
sys.exit(1)
|
||||
profile = sys.argv[1]
|
||||
infile = sys.argv[2]
|
||||
outfile = sys.argv[3] if len(sys.argv) > 3 else ""
|
||||
api = generate_trimmed_api(infile, profile)
|
||||
|
||||
if outfile:
|
||||
with open(outfile, "w", encoding="utf-8") as f:
|
||||
json.dump(api, f)
|
||||
else:
|
||||
json.dump(api, sys.stdout)
|
||||
94
cmake/common_compiler_flags.cmake
Normal file
94
cmake/common_compiler_flags.cmake
Normal file
@@ -0,0 +1,94 @@
|
||||
# Add warnings based on compiler & version
|
||||
# Set some helper variables for readability
|
||||
set( compiler_less_than_v8 "$<VERSION_LESS:$<CXX_COMPILER_VERSION>,8>" )
|
||||
set( compiler_greater_than_or_equal_v9 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,9>" )
|
||||
set( compiler_greater_than_or_equal_v11 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,11>" )
|
||||
set( compiler_less_than_v11 "$<VERSION_LESS:$<CXX_COMPILER_VERSION>,11>" )
|
||||
set( compiler_greater_than_or_equal_v12 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,12>" )
|
||||
|
||||
# These compiler options reflect what is in godot/SConstruct.
|
||||
target_compile_options( ${PROJECT_NAME} PRIVATE
|
||||
# MSVC only
|
||||
$<${compiler_is_msvc}:
|
||||
/W4
|
||||
|
||||
# Disable warnings which we don't plan to fix.
|
||||
/wd4100 # C4100 (unreferenced formal parameter): Doesn't play nice with polymorphism.
|
||||
/wd4127 # C4127 (conditional expression is constant)
|
||||
/wd4201 # C4201 (non-standard nameless struct/union): Only relevant for C89.
|
||||
/wd4244 # C4244 C4245 C4267 (narrowing conversions): Unavoidable at this scale.
|
||||
/wd4245
|
||||
/wd4267
|
||||
/wd4305 # C4305 (truncation): double to float or real_t, too hard to avoid.
|
||||
/wd4514 # C4514 (unreferenced inline function has been removed)
|
||||
/wd4714 # C4714 (function marked as __forceinline not inlined)
|
||||
/wd4820 # C4820 (padding added after construct)
|
||||
>
|
||||
|
||||
# Clang and GNU common options
|
||||
$<$<OR:${compiler_is_clang},${compiler_is_gnu}>:
|
||||
-Wall
|
||||
-Wctor-dtor-privacy
|
||||
-Wextra
|
||||
-Wno-unused-parameter
|
||||
-Wnon-virtual-dtor
|
||||
-Wwrite-strings
|
||||
>
|
||||
|
||||
# Clang only
|
||||
$<${compiler_is_clang}:
|
||||
-Wimplicit-fallthrough
|
||||
-Wno-ordered-compare-function-pointers
|
||||
>
|
||||
|
||||
# GNU only
|
||||
$<${compiler_is_gnu}:
|
||||
-Walloc-zero
|
||||
-Wduplicated-branches
|
||||
-Wduplicated-cond
|
||||
-Wno-misleading-indentation
|
||||
-Wplacement-new=1
|
||||
-Wshadow-local
|
||||
-Wstringop-overflow=4
|
||||
>
|
||||
$<$<AND:${compiler_is_gnu},${compiler_less_than_v8}>:
|
||||
# Bogus warning fixed in 8+.
|
||||
-Wno-strict-overflow
|
||||
>
|
||||
$<$<AND:${compiler_is_gnu},${compiler_greater_than_or_equal_v9}>:
|
||||
-Wattribute-alias=2
|
||||
>
|
||||
$<$<AND:${compiler_is_gnu},${compiler_greater_than_or_equal_v11}>:
|
||||
# Broke on MethodBind templates before GCC 11.
|
||||
-Wlogical-op
|
||||
>
|
||||
$<$<AND:${compiler_is_gnu},${compiler_less_than_v11}>:
|
||||
# Regression in GCC 9/10, spams so much in our variadic templates that we need to outright disable it.
|
||||
-Wno-type-limits
|
||||
>
|
||||
$<$<AND:${compiler_is_gnu},${compiler_greater_than_or_equal_v12}>:
|
||||
# False positives in our error macros, see GH-58747.
|
||||
-Wno-return-type
|
||||
>
|
||||
)
|
||||
|
||||
# Treat warnings as errors
|
||||
function( set_warning_as_error )
|
||||
message( STATUS "[${PROJECT_NAME}] Treating warnings as errors")
|
||||
if ( CMAKE_VERSION VERSION_GREATER_EQUAL "3.24" )
|
||||
set_target_properties( ${PROJECT_NAME}
|
||||
PROPERTIES
|
||||
COMPILE_WARNING_AS_ERROR ON
|
||||
)
|
||||
else()
|
||||
target_compile_options( ${PROJECT_NAME}
|
||||
PRIVATE
|
||||
$<${compiler_is_msvc}:/WX>
|
||||
$<$<OR:${compiler_is_clang},${compiler_is_gnu}>:-Werror>
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
if ( GODOT_WARNING_AS_ERROR )
|
||||
set_warning_as_error()
|
||||
endif()
|
||||
240
cmake/godotcpp.cmake
Normal file
240
cmake/godotcpp.cmake
Normal file
@@ -0,0 +1,240 @@
|
||||
function( godotcpp_options )
|
||||
|
||||
#TODO platform
|
||||
#TODO target
|
||||
|
||||
# Input from user for GDExtension interface header and the API JSON file
|
||||
set(GODOT_GDEXTENSION_DIR "gdextension" CACHE PATH
|
||||
"Path to a custom directory containing GDExtension interface header and API JSON file ( /path/to/gdextension_dir )" )
|
||||
set(GODOT_CUSTOM_API_FILE "" CACHE FILEPATH
|
||||
"Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`) ( /path/to/custom_api_file )")
|
||||
|
||||
#TODO generate_bindings
|
||||
|
||||
option(GODOT_GENERATE_TEMPLATE_GET_NODE
|
||||
"Generate a template version of the Node class's get_node. (ON|OFF)" ON)
|
||||
|
||||
#TODO build_library
|
||||
|
||||
set(GODOT_PRECISION "single" CACHE STRING
|
||||
"Set the floating-point precision level (single|double)")
|
||||
|
||||
#TODO arch
|
||||
#TODO threads
|
||||
#TODO compiledb
|
||||
#TODO compiledb_file
|
||||
#TODO build_profile aka cmake preset
|
||||
|
||||
set(GODOT_USE_HOT_RELOAD "" CACHE BOOL
|
||||
"Enable the extra accounting required to support hot reload. (ON|OFF)")
|
||||
|
||||
option(GODOT_DISABLE_EXCEPTIONS "Force disabling exception handling code (ON|OFF)" ON )
|
||||
|
||||
set( GODOT_SYMBOL_VISIBILITY "hidden" CACHE STRING
|
||||
"Symbols visibility on GNU platforms. Use 'auto' to apply the default value. (auto|visible|hidden)")
|
||||
set_property( CACHE GODOT_SYMBOL_VISIBILITY PROPERTY STRINGS "auto;visible;hidden" )
|
||||
|
||||
#TODO optimize
|
||||
#TODO debug_symbols
|
||||
#TODO dev_build
|
||||
|
||||
# FIXME These options are not present in SCons, and perhaps should be added there.
|
||||
option(GODOT_SYSTEM_HEADERS "Expose headers as SYSTEM." ON)
|
||||
option(GODOT_WARNING_AS_ERROR "Treat warnings as errors" OFF)
|
||||
|
||||
# Run options commands on the following to populate cache for all platforms.
|
||||
# This type of thing is typically done conditionally
|
||||
# But as scons shows all options so shall we.
|
||||
#TODO ios_options()
|
||||
#TODO linux_options()
|
||||
#TODO macos_options()
|
||||
#TODO web_options()
|
||||
#TODO windows_options()
|
||||
endfunction()
|
||||
|
||||
|
||||
function( godotcpp_generate )
|
||||
# Set some helper variables for readability
|
||||
set( compiler_is_clang "$<OR:$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:Clang>>" )
|
||||
set( compiler_is_gnu "$<CXX_COMPILER_ID:GNU>" )
|
||||
set( compiler_is_msvc "$<CXX_COMPILER_ID:MSVC>" )
|
||||
|
||||
# CXX_VISIBILITY_PRESET supported values are: default, hidden, protected, and internal
|
||||
# which is inline with the gcc -fvisibility=
|
||||
# https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html
|
||||
# To match the scons options we need to change the text to match the -fvisibility flag
|
||||
# it is probably worth another PR which changes both to use the flag options
|
||||
if( ${GODOT_SYMBOL_VISIBILITY} STREQUAL "auto" OR ${GODOT_SYMBOL_VISIBILITY} STREQUAL "visible" )
|
||||
set( GODOT_SYMBOL_VISIBILITY "default" )
|
||||
endif ()
|
||||
|
||||
# Default build type is Debug in the SConstruct
|
||||
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
endif()
|
||||
|
||||
# Hot reload is enabled by default in Debug-builds
|
||||
if( GODOT_USE_HOT_RELOAD STREQUAL "" AND NOT CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
set(GODOT_USE_HOT_RELOAD ON)
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED BITS)
|
||||
set(BITS 32)
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(BITS 64)
|
||||
endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
endif()
|
||||
|
||||
|
||||
set(GODOT_GDEXTENSION_API_FILE "${GODOT_GDEXTENSION_DIR}/extension_api.json")
|
||||
if (NOT "${GODOT_CUSTOM_API_FILE}" STREQUAL "") # User-defined override.
|
||||
set(GODOT_GDEXTENSION_API_FILE "${GODOT_CUSTOM_API_FILE}")
|
||||
endif()
|
||||
|
||||
if ("${GODOT_PRECISION}" STREQUAL "double")
|
||||
add_definitions(-DREAL_T_IS_DOUBLE)
|
||||
endif()
|
||||
|
||||
set( GODOT_COMPILE_FLAGS )
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
# using Visual Studio C++
|
||||
set(GODOT_COMPILE_FLAGS "/utf-8") # /GF /MP
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MDd") # /Od /RTC1 /Zi
|
||||
else()
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MD /O2") # /Oy /GL /Gy
|
||||
endif(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
|
||||
add_definitions(-DNOMINMAX)
|
||||
else() # GCC/Clang
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0 -g")
|
||||
else()
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -O3")
|
||||
endif(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
endif()
|
||||
|
||||
# Disable exception handling. Godot doesn't use exceptions anywhere, and this
|
||||
# saves around 20% of binary size and very significant build time (GH-80513).
|
||||
if (GODOT_DISABLE_EXCEPTIONS)
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -D_HAS_EXCEPTIONS=0")
|
||||
else()
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-exceptions")
|
||||
endif()
|
||||
else()
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /EHsc")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Generate source from the bindings file
|
||||
find_package(Python3 3.4 REQUIRED) # pathlib should be present
|
||||
if(GODOT_GENERATE_TEMPLATE_GET_NODE)
|
||||
set(GENERATE_BINDING_PARAMETERS "True")
|
||||
else()
|
||||
set(GENERATE_BINDING_PARAMETERS "False")
|
||||
endif()
|
||||
|
||||
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}
|
||||
COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.generate_bindings(\"${GODOT_GDEXTENSION_API_FILE}\", \"${GENERATE_BINDING_PARAMETERS}\", \"${BITS}\", \"${GODOT_PRECISION}\", \"${CMAKE_CURRENT_BINARY_DIR}\")"
|
||||
VERBATIM
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
MAIN_DEPENDENCY ${GODOT_GDEXTENSION_API_FILE}
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/binding_generator.py
|
||||
COMMENT "Generating bindings"
|
||||
)
|
||||
|
||||
# Get Sources
|
||||
# As this cmake file was added using 'include(godotcpp)' from the root CMakeLists.txt,
|
||||
# the ${CMAKE_CURRENT_SOURCE_DIR} is still the root dir.
|
||||
file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS src/*.c**)
|
||||
file(GLOB_RECURSE HEADERS CONFIGURE_DEPENDS include/*.h**)
|
||||
|
||||
# Define our godot-cpp library
|
||||
add_library(${PROJECT_NAME} STATIC
|
||||
${SOURCES}
|
||||
${HEADERS}
|
||||
${GENERATED_FILES_LIST}
|
||||
)
|
||||
add_library(godot::cpp ALIAS ${PROJECT_NAME})
|
||||
|
||||
include(${PROJECT_SOURCE_DIR}/cmake/common_compiler_flags.cmake)
|
||||
|
||||
target_compile_features(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
cxx_std_17
|
||||
)
|
||||
|
||||
if(GODOT_USE_HOT_RELOAD)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC HOT_RELOAD_ENABLED)
|
||||
target_compile_options(${PROJECT_NAME} PUBLIC $<${compiler_is_gnu}:-fno-gnu-unique>)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC
|
||||
$<$<CONFIG:Debug>:
|
||||
DEBUG_ENABLED
|
||||
DEBUG_METHODS_ENABLED
|
||||
>
|
||||
$<${compiler_is_msvc}:
|
||||
TYPED_METHOD_BIND
|
||||
>
|
||||
)
|
||||
|
||||
target_link_options(${PROJECT_NAME} PRIVATE
|
||||
$<$<NOT:${compiler_is_msvc}>:
|
||||
-static-libgcc
|
||||
-static-libstdc++
|
||||
-Wl,-R,'$$ORIGIN'
|
||||
>
|
||||
)
|
||||
|
||||
# Optionally mark headers as SYSTEM
|
||||
set(GODOT_SYSTEM_HEADERS_ATTRIBUTE "")
|
||||
if (GODOT_SYSTEM_HEADERS)
|
||||
set(GODOT_SYSTEM_HEADERS_ATTRIBUTE SYSTEM)
|
||||
endif ()
|
||||
|
||||
target_include_directories(${PROJECT_NAME} ${GODOT_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC
|
||||
include
|
||||
${CMAKE_CURRENT_BINARY_DIR}/gen/include
|
||||
${GODOT_GDEXTENSION_DIR}
|
||||
)
|
||||
|
||||
# Add the compile flags
|
||||
set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY COMPILE_FLAGS ${GODOT_COMPILE_FLAGS})
|
||||
|
||||
# Create the correct name (godot.os.build_type.system_bits)
|
||||
string(TOLOWER "${CMAKE_SYSTEM_NAME}" SYSTEM_NAME)
|
||||
string(TOLOWER "${CMAKE_BUILD_TYPE}" BUILD_TYPE)
|
||||
|
||||
if(ANDROID)
|
||||
# Added the android abi after system name
|
||||
set(SYSTEM_NAME ${SYSTEM_NAME}.${ANDROID_ABI})
|
||||
|
||||
# Android does not have the bits at the end if you look at the main godot repo build
|
||||
set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}")
|
||||
else()
|
||||
set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}.${BITS}")
|
||||
endif()
|
||||
|
||||
set_target_properties(${PROJECT_NAME}
|
||||
PROPERTIES
|
||||
CXX_EXTENSIONS OFF
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
CXX_VISIBILITY_PRESET ${GODOT_SYMBOL_VISIBILITY}
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin"
|
||||
OUTPUT_NAME "${OUTPUT_NAME}"
|
||||
)
|
||||
|
||||
endfunction()
|
||||
57
doc/cmake.md
Normal file
57
doc/cmake.md
Normal file
@@ -0,0 +1,57 @@
|
||||
## CMake
|
||||
|
||||
### cmake arguments
|
||||
|
||||
`CMAKE_BUILD_TYPE`: Compilation target (Debug or Release defaults to Debug)
|
||||
|
||||
### godot-cpp cmake arguments
|
||||
- `GODOT_GDEXTENSION_DIR`: Path to the directory containing GDExtension interface header and API JSON file
|
||||
- `GODOT_SYSTEM_HEADERS`: Mark the header files as SYSTEM. This may be useful to suppress warnings in projects including this one.
|
||||
- `GODOT_WARNING_AS_ERROR`: Treat any warnings as errors
|
||||
- `GODOT_USE_HOT_RELOAD`: Build with hot reload support. Defaults to YES for Debug-builds and NO for Release-builds.
|
||||
- `GODOT_CUSTOM_API_FILE`: Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`)
|
||||
- `GODOT_PRECISION`: Floating-point precision level ("single", "double")
|
||||
|
||||
### Android cmake arguments
|
||||
- `CMAKE_TOOLCHAIN_FILE`: The path to the android cmake toolchain ($ANDROID_NDK/build/cmake/android.toolchain.cmake)
|
||||
- `ANDROID_NDK`: The path to the android ndk root folder
|
||||
- `ANDROID_TOOLCHAIN_NAME`: The android toolchain (arm-linux-androideabi-4.9 or aarch64-linux-android-4.9 or x86-4.9 or x86_64-4.9)
|
||||
- `ANDROID_PLATFORM`: The android platform version (android-23)
|
||||
|
||||
- More info [here](https://godot.readthedocs.io/en/latest/development/compiling/compiling_for_android.html)
|
||||
|
||||
## Examples
|
||||
```shell
|
||||
Builds a debug version:
|
||||
cmake .
|
||||
cmake --build .
|
||||
```
|
||||
Builds a release version with clang
|
||||
|
||||
```shell
|
||||
CC=/usr/bin/clang CXX=/usr/bin/clang++ cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" .
|
||||
cmake --build .
|
||||
```
|
||||
Builds an android armeabi-v7a debug version:
|
||||
|
||||
``` shell
|
||||
cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake -DANDROID_NDK=$ANDROID_NDK \
|
||||
-DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.9 -DANDROID_PLATFORM=android-23 -DCMAKE_BUILD_TYPE=Debug .
|
||||
cmake --build .
|
||||
```
|
||||
|
||||
## Protip
|
||||
Generate the buildfiles in a sub directory to not clutter the root directory with build files:
|
||||
|
||||
```shell
|
||||
mkdir build && cd build && cmake -G "Unix Makefiles" .. && cmake --build .
|
||||
```
|
||||
|
||||
Ensure that you avoid exposing godot-cpp symbols - this might lead to hard to debug errors if you ever load multiple
|
||||
plugins using difference godot-cpp versions. Use visibility hidden whenever possible:
|
||||
```cmake
|
||||
set_target_properties(<all-my-plugin-related-targets> PROPERTIES CXX_VISIBILITY_PRESET hidden)
|
||||
```
|
||||
|
||||
## Todo
|
||||
Test build for Windows, Mac and mingw.
|
||||
20
gdextension/README.md
Normal file
20
gdextension/README.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# GDExtension header and API
|
||||
|
||||
This repository contains the C header and API JSON for
|
||||
[**Godot Engine**](https://github.com/godotengine/godot)'s *GDExtensions* API.
|
||||
|
||||
## Updating header and API
|
||||
|
||||
If the current branch is not up-to-date for your needs, or if you want to sync
|
||||
the header and API JSON with your own modified version of Godot, here is the
|
||||
update procedure used to sync this repository with upstream releases:
|
||||
|
||||
- Compile [Godot Engine](https://github.com/godotengine/godot) at the specific
|
||||
version/commit which you are using.
|
||||
* Or if you use an official release, download that version of the Godot editor.
|
||||
- Use the compiled or downloaded executable to generate the `extension_api.json`
|
||||
and `gdextension_interface.h` files with:
|
||||
|
||||
```
|
||||
godot --dump-extension-api --dump-gdextension-interface
|
||||
```
|
||||
304401
gdextension/extension_api.json
Normal file
304401
gdextension/extension_api.json
Normal file
File diff suppressed because it is too large
Load Diff
2964
gdextension/gdextension_interface.h
Normal file
2964
gdextension/gdextension_interface.h
Normal file
File diff suppressed because it is too large
Load Diff
Submodule godot-headers deleted from 68174528c9
@@ -1,80 +0,0 @@
|
||||
#ifndef AABB_H
|
||||
#define AABB_H
|
||||
|
||||
#include "Vector3.hpp"
|
||||
|
||||
#include "Plane.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class AABB {
|
||||
public:
|
||||
Vector3 position;
|
||||
Vector3 size;
|
||||
|
||||
real_t get_area() const; /// get area
|
||||
inline bool has_no_area() const {
|
||||
return (size.x <= CMP_EPSILON || size.y <= CMP_EPSILON || size.z <= CMP_EPSILON);
|
||||
}
|
||||
|
||||
inline bool has_no_surface() const {
|
||||
return (size.x <= CMP_EPSILON && size.y <= CMP_EPSILON && size.z <= CMP_EPSILON);
|
||||
}
|
||||
|
||||
inline const Vector3 &get_position() const { return position; }
|
||||
inline void set_position(const Vector3 &p_position) { position = p_position; }
|
||||
inline const Vector3 &get_size() const { return size; }
|
||||
inline void set_size(const Vector3 &p_size) { size = p_size; }
|
||||
|
||||
bool operator==(const AABB &p_rval) const;
|
||||
bool operator!=(const AABB &p_rval) const;
|
||||
|
||||
bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap
|
||||
bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap
|
||||
bool encloses(const AABB &p_aabb) const; /// p_aabb is completely inside this
|
||||
|
||||
AABB merge(const AABB &p_with) const;
|
||||
void merge_with(const AABB &p_aabb); ///merge with another AABB
|
||||
AABB intersection(const AABB &p_aabb) const; ///get box where two intersect, empty if no intersection occurs
|
||||
bool intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector3 *r_clip = nullptr, Vector3 *r_normal = nullptr) const;
|
||||
bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *r_clip = nullptr, Vector3 *r_normal = nullptr) const;
|
||||
bool smits_intersect_ray(const Vector3 &from, const Vector3 &p_dir, real_t t0, real_t t1) const;
|
||||
|
||||
bool intersects_convex_shape(const Plane *p_plane, int p_plane_count) const;
|
||||
bool intersects_plane(const Plane &p_plane) const;
|
||||
|
||||
bool has_point(const Vector3 &p_point) const;
|
||||
Vector3 get_support(const Vector3 &p_normal) const;
|
||||
|
||||
Vector3 get_longest_axis() const;
|
||||
int get_longest_axis_index() const;
|
||||
real_t get_longest_axis_size() const;
|
||||
|
||||
Vector3 get_shortest_axis() const;
|
||||
int get_shortest_axis_index() const;
|
||||
real_t get_shortest_axis_size() const;
|
||||
|
||||
AABB grow(real_t p_by) const;
|
||||
void grow_by(real_t p_amount);
|
||||
|
||||
void get_edge(int p_edge, Vector3 &r_from, Vector3 &r_to) const;
|
||||
Vector3 get_endpoint(int p_point) const;
|
||||
|
||||
AABB expand(const Vector3 &p_vector) const;
|
||||
void project_range_in_plane(const Plane &p_plane, real_t &r_min, real_t &r_max) const;
|
||||
void expand_to(const Vector3 &p_vector); /** expand to contain a point if necesary */
|
||||
|
||||
operator String() const;
|
||||
|
||||
inline AABB() {}
|
||||
inline AABB(const Vector3 &p_pos, const Vector3 &p_size) {
|
||||
position = p_pos;
|
||||
size = p_size;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // RECT3_H
|
||||
@@ -1,161 +0,0 @@
|
||||
#ifndef ARRAY_H
|
||||
#define ARRAY_H
|
||||
|
||||
#include <gdnative/array.h>
|
||||
|
||||
#include "String.hpp"
|
||||
|
||||
namespace godot {
|
||||
|
||||
namespace helpers {
|
||||
template <typename T, typename ValueT>
|
||||
T append_all(T appendable, ValueT value) {
|
||||
appendable.append(value);
|
||||
return appendable;
|
||||
}
|
||||
|
||||
template <typename T, typename ValueT, typename... Args>
|
||||
T append_all(T appendable, ValueT value, Args... args) {
|
||||
appendable.append(value);
|
||||
return append_all(appendable, args...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T append_all(T appendable) {
|
||||
return appendable;
|
||||
}
|
||||
|
||||
template <typename KV, typename KeyT, typename ValueT>
|
||||
KV add_all(KV kv, KeyT key, ValueT value) {
|
||||
kv[key] = value;
|
||||
return kv;
|
||||
}
|
||||
|
||||
template <typename KV, typename KeyT, typename ValueT, typename... Args>
|
||||
KV add_all(KV kv, KeyT key, ValueT value, Args... args) {
|
||||
kv[key] = value;
|
||||
return add_all(kv, args...);
|
||||
}
|
||||
|
||||
template <typename KV>
|
||||
KV add_all(KV kv) {
|
||||
return kv;
|
||||
}
|
||||
} // namespace helpers
|
||||
|
||||
class Variant;
|
||||
class PoolByteArray;
|
||||
class PoolIntArray;
|
||||
class PoolRealArray;
|
||||
class PoolStringArray;
|
||||
class PoolVector2Array;
|
||||
class PoolVector3Array;
|
||||
class PoolColorArray;
|
||||
|
||||
class Object;
|
||||
|
||||
class Array {
|
||||
godot_array _godot_array;
|
||||
|
||||
friend class Variant;
|
||||
friend class Dictionary;
|
||||
friend class String;
|
||||
inline explicit Array(const godot_array &other) {
|
||||
_godot_array = other;
|
||||
}
|
||||
|
||||
public:
|
||||
Array();
|
||||
Array(const Array &other);
|
||||
Array &operator=(const Array &other);
|
||||
|
||||
Array(const PoolByteArray &a);
|
||||
|
||||
Array(const PoolIntArray &a);
|
||||
|
||||
Array(const PoolRealArray &a);
|
||||
|
||||
Array(const PoolStringArray &a);
|
||||
|
||||
Array(const PoolVector2Array &a);
|
||||
|
||||
Array(const PoolVector3Array &a);
|
||||
|
||||
Array(const PoolColorArray &a);
|
||||
|
||||
template <class... Args>
|
||||
static Array make(Args... args) {
|
||||
return helpers::append_all(Array(), args...);
|
||||
}
|
||||
|
||||
Variant &operator[](const int idx);
|
||||
|
||||
const Variant &operator[](const int idx) const;
|
||||
|
||||
void append(const Variant &v);
|
||||
|
||||
void clear();
|
||||
|
||||
int count(const Variant &v);
|
||||
|
||||
bool empty() const;
|
||||
|
||||
void erase(const Variant &v);
|
||||
|
||||
Variant front() const;
|
||||
|
||||
Variant back() const;
|
||||
|
||||
int find(const Variant &what, const int from = 0) const;
|
||||
|
||||
int find_last(const Variant &what) const;
|
||||
|
||||
bool has(const Variant &what) const;
|
||||
|
||||
uint32_t hash() const;
|
||||
|
||||
void insert(const int pos, const Variant &value);
|
||||
|
||||
void invert();
|
||||
|
||||
bool is_shared() const;
|
||||
|
||||
Variant pop_back();
|
||||
|
||||
Variant pop_front();
|
||||
|
||||
void push_back(const Variant &v);
|
||||
|
||||
void push_front(const Variant &v);
|
||||
|
||||
void remove(const int idx);
|
||||
|
||||
int size() const;
|
||||
|
||||
void resize(const int size);
|
||||
|
||||
int rfind(const Variant &what, const int from = -1) const;
|
||||
|
||||
void sort();
|
||||
|
||||
void sort_custom(Object *obj, const String &func);
|
||||
|
||||
int bsearch(const Variant &value, const bool before = true);
|
||||
|
||||
int bsearch_custom(const Variant &value, const Object *obj,
|
||||
const String &func, const bool before = true);
|
||||
|
||||
Array duplicate(const bool deep = false) const;
|
||||
|
||||
Variant max() const;
|
||||
|
||||
Variant min() const;
|
||||
|
||||
void shuffle();
|
||||
|
||||
~Array();
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // ARRAY_H
|
||||
@@ -1,428 +0,0 @@
|
||||
#ifndef BASIS_H
|
||||
#define BASIS_H
|
||||
|
||||
#include <gdnative/basis.h>
|
||||
|
||||
#include "Defs.hpp"
|
||||
|
||||
#include "Vector3.hpp"
|
||||
|
||||
namespace godot {
|
||||
|
||||
class Quat;
|
||||
|
||||
class Basis {
|
||||
private:
|
||||
static const Basis IDENTITY;
|
||||
static const Basis FLIP_X;
|
||||
static const Basis FLIP_Y;
|
||||
static const Basis FLIP_Z;
|
||||
|
||||
// This helper template is for mimicking the behavior difference between the engine
|
||||
// and script interfaces that logically script sees matrices as column major, while
|
||||
// the engine stores them in row major to efficiently take advantage of SIMD
|
||||
// instructions in case of matrix-vector multiplications.
|
||||
// With this helper template native scripts see the data as if it was column major
|
||||
// without actually transposing the basis matrix at the script-engine boundary.
|
||||
template <int column>
|
||||
class ColumnVector3 {
|
||||
private:
|
||||
template <int column1, int component>
|
||||
class ColumnVectorComponent {
|
||||
private:
|
||||
Vector3 elements[3];
|
||||
|
||||
protected:
|
||||
inline ColumnVectorComponent<column1, component> &operator=(const ColumnVectorComponent<column1, component> &p_value) {
|
||||
return *this = real_t(p_value);
|
||||
}
|
||||
|
||||
inline ColumnVectorComponent(const ColumnVectorComponent<column1, component> &p_value) {
|
||||
*this = real_t(p_value);
|
||||
}
|
||||
|
||||
inline ColumnVectorComponent<column1, component> &operator=(const real_t &p_value) {
|
||||
elements[component][column1] = p_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline operator real_t() const {
|
||||
return elements[component][column1];
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
enum Axis {
|
||||
AXIS_X,
|
||||
AXIS_Y,
|
||||
AXIS_Z,
|
||||
};
|
||||
|
||||
union {
|
||||
ColumnVectorComponent<column, 0> x;
|
||||
ColumnVectorComponent<column, 1> y;
|
||||
ColumnVectorComponent<column, 2> z;
|
||||
|
||||
Vector3 elements[3]; // Not for direct access, use [] operator instead
|
||||
};
|
||||
|
||||
inline ColumnVector3<column> &operator=(const ColumnVector3<column> &p_value) {
|
||||
return *this = Vector3(p_value);
|
||||
}
|
||||
|
||||
inline ColumnVector3(const ColumnVector3<column> &p_value) {
|
||||
*this = Vector3(p_value);
|
||||
}
|
||||
|
||||
inline ColumnVector3<column> &operator=(const Vector3 &p_value) {
|
||||
elements[0][column] = p_value.x;
|
||||
elements[1][column] = p_value.y;
|
||||
elements[2][column] = p_value.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline operator Vector3() const {
|
||||
return Vector3(elements[0][column], elements[1][column], elements[2][column]);
|
||||
}
|
||||
|
||||
// Unfortunately, we also need to replicate the other interfaces of Vector3 in
|
||||
// order for being able to directly operate on these "meta-Vector3" objects without
|
||||
// an explicit cast or an intermediate assignment to a real Vector3 object.
|
||||
|
||||
inline const real_t &operator[](int p_axis) const {
|
||||
return elements[p_axis][column];
|
||||
}
|
||||
|
||||
inline real_t &operator[](int p_axis) {
|
||||
return elements[p_axis][column];
|
||||
}
|
||||
|
||||
inline ColumnVector3<column> &operator+=(const Vector3 &p_v) {
|
||||
return *this = *this + p_v;
|
||||
}
|
||||
|
||||
inline Vector3 operator+(const Vector3 &p_v) const {
|
||||
return Vector3(*this) + p_v;
|
||||
}
|
||||
|
||||
inline ColumnVector3<column> &operator-=(const Vector3 &p_v) {
|
||||
return *this = *this - p_v;
|
||||
}
|
||||
|
||||
inline Vector3 operator-(const Vector3 &p_v) const {
|
||||
return Vector3(*this) - p_v;
|
||||
}
|
||||
|
||||
inline ColumnVector3<column> &operator*=(const Vector3 &p_v) {
|
||||
return *this = *this * p_v;
|
||||
}
|
||||
|
||||
inline Vector3 operator*(const Vector3 &p_v) const {
|
||||
return Vector3(*this) * p_v;
|
||||
}
|
||||
|
||||
inline ColumnVector3<column> &operator/=(const Vector3 &p_v) {
|
||||
return *this = *this / p_v;
|
||||
}
|
||||
|
||||
inline Vector3 operator/(const Vector3 &p_v) const {
|
||||
return Vector3(*this) / p_v;
|
||||
}
|
||||
|
||||
inline ColumnVector3<column> &operator*=(real_t p_scalar) {
|
||||
return *this = *this * p_scalar;
|
||||
}
|
||||
|
||||
inline Vector3 operator*(real_t p_scalar) const {
|
||||
return Vector3(*this) * p_scalar;
|
||||
}
|
||||
|
||||
inline ColumnVector3<column> &operator/=(real_t p_scalar) {
|
||||
return *this = *this / p_scalar;
|
||||
}
|
||||
|
||||
inline Vector3 operator/(real_t p_scalar) const {
|
||||
return Vector3(*this) / p_scalar;
|
||||
}
|
||||
|
||||
inline Vector3 operator-() const {
|
||||
return -Vector3(*this);
|
||||
}
|
||||
|
||||
inline bool operator==(const Vector3 &p_v) const {
|
||||
return Vector3(*this) == p_v;
|
||||
}
|
||||
|
||||
inline bool operator!=(const Vector3 &p_v) const {
|
||||
return Vector3(*this) != p_v;
|
||||
}
|
||||
|
||||
inline bool operator<(const Vector3 &p_v) const {
|
||||
return Vector3(*this) < p_v;
|
||||
}
|
||||
|
||||
inline bool operator<=(const Vector3 &p_v) const {
|
||||
return Vector3(*this) <= p_v;
|
||||
}
|
||||
|
||||
inline Vector3 abs() const {
|
||||
return Vector3(*this).abs();
|
||||
}
|
||||
|
||||
inline Vector3 ceil() const {
|
||||
return Vector3(*this).ceil();
|
||||
}
|
||||
|
||||
inline Vector3 cross(const Vector3 &b) const {
|
||||
return Vector3(*this).cross(b);
|
||||
}
|
||||
|
||||
inline Vector3 linear_interpolate(const Vector3 &p_b, real_t p_t) const {
|
||||
return Vector3(*this).linear_interpolate(p_b, p_t);
|
||||
}
|
||||
|
||||
inline Vector3 cubic_interpolate(const Vector3 &b, const Vector3 &pre_a, const Vector3 &post_b, const real_t t) const {
|
||||
return Vector3(*this).cubic_interpolate(b, pre_a, post_b, t);
|
||||
}
|
||||
|
||||
inline Vector3 bounce(const Vector3 &p_normal) const {
|
||||
return Vector3(*this).bounce(p_normal);
|
||||
}
|
||||
|
||||
inline real_t length() const {
|
||||
return Vector3(*this).length();
|
||||
}
|
||||
|
||||
inline real_t length_squared() const {
|
||||
return Vector3(*this).length_squared();
|
||||
}
|
||||
|
||||
inline real_t distance_squared_to(const Vector3 &b) const {
|
||||
return Vector3(*this).distance_squared_to(b);
|
||||
}
|
||||
|
||||
inline real_t distance_to(const Vector3 &b) const {
|
||||
return Vector3(*this).distance_to(b);
|
||||
}
|
||||
|
||||
inline real_t dot(const Vector3 &b) const {
|
||||
return Vector3(*this).dot(b);
|
||||
}
|
||||
|
||||
inline real_t angle_to(const Vector3 &b) const {
|
||||
return Vector3(*this).angle_to(b);
|
||||
}
|
||||
|
||||
inline Vector3 floor() const {
|
||||
return Vector3(*this).floor();
|
||||
}
|
||||
|
||||
inline Vector3 inverse() const {
|
||||
return Vector3(*this).inverse();
|
||||
}
|
||||
|
||||
inline bool is_normalized() const {
|
||||
return Vector3(*this).is_normalized();
|
||||
}
|
||||
|
||||
inline Basis outer(const Vector3 &b) const {
|
||||
return Vector3(*this).outer(b);
|
||||
}
|
||||
|
||||
inline int max_axis() const {
|
||||
return Vector3(*this).max_axis();
|
||||
}
|
||||
|
||||
inline int min_axis() const {
|
||||
return Vector3(*this).min_axis();
|
||||
}
|
||||
|
||||
inline void normalize() {
|
||||
Vector3 v = *this;
|
||||
v.normalize();
|
||||
*this = v;
|
||||
}
|
||||
|
||||
inline Vector3 normalized() const {
|
||||
return Vector3(*this).normalized();
|
||||
}
|
||||
|
||||
inline Vector3 reflect(const Vector3 &by) const {
|
||||
return Vector3(*this).reflect(by);
|
||||
}
|
||||
|
||||
inline Vector3 rotated(const Vector3 &axis, const real_t phi) const {
|
||||
return Vector3(*this).rotated(axis, phi);
|
||||
}
|
||||
|
||||
inline void rotate(const Vector3 &p_axis, real_t p_phi) {
|
||||
Vector3 v = *this;
|
||||
v.rotate(p_axis, p_phi);
|
||||
*this = v;
|
||||
}
|
||||
|
||||
inline Vector3 slide(const Vector3 &by) const {
|
||||
return Vector3(*this).slide(by);
|
||||
}
|
||||
|
||||
inline void snap(real_t p_val) {
|
||||
Vector3 v = *this;
|
||||
v.snap(p_val);
|
||||
*this = v;
|
||||
}
|
||||
|
||||
inline Vector3 snapped(const float by) {
|
||||
return Vector3(*this).snapped(by);
|
||||
}
|
||||
|
||||
inline operator String() const {
|
||||
return String(Vector3(*this));
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
union {
|
||||
ColumnVector3<0> x;
|
||||
ColumnVector3<1> y;
|
||||
ColumnVector3<2> z;
|
||||
|
||||
Vector3 elements[3]; // Not for direct access, use [] operator instead
|
||||
};
|
||||
|
||||
inline Basis(const Basis &p_basis) {
|
||||
elements[0] = p_basis.elements[0];
|
||||
elements[1] = p_basis.elements[1];
|
||||
elements[2] = p_basis.elements[2];
|
||||
}
|
||||
|
||||
inline Basis &operator=(const Basis &p_basis) {
|
||||
elements[0] = p_basis.elements[0];
|
||||
elements[1] = p_basis.elements[1];
|
||||
elements[2] = p_basis.elements[2];
|
||||
return *this;
|
||||
}
|
||||
|
||||
Basis(const Quat &p_quat); // euler
|
||||
Basis(const Vector3 &p_euler); // euler
|
||||
Basis(const Vector3 &p_axis, real_t p_phi);
|
||||
|
||||
Basis(const Vector3 &row0, const Vector3 &row1, const Vector3 &row2);
|
||||
|
||||
Basis(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz);
|
||||
|
||||
Basis();
|
||||
|
||||
const Vector3 operator[](int axis) const {
|
||||
return get_axis(axis);
|
||||
}
|
||||
|
||||
ColumnVector3<0> &operator[](int axis) {
|
||||
// We need to do a little pointer magic to get this to work, because the
|
||||
// ColumnVector3 template takes the axis as a template parameter.
|
||||
// Don't touch this unless you're sure what you're doing!
|
||||
return (reinterpret_cast<Basis *>(reinterpret_cast<real_t *>(this) + axis))->x;
|
||||
}
|
||||
|
||||
void invert();
|
||||
|
||||
bool isequal_approx(const Basis &a, const Basis &b) const;
|
||||
|
||||
bool is_orthogonal() const;
|
||||
|
||||
bool is_rotation() const;
|
||||
|
||||
void transpose();
|
||||
|
||||
Basis inverse() const;
|
||||
|
||||
Basis transposed() const;
|
||||
|
||||
real_t determinant() const;
|
||||
|
||||
Vector3 get_axis(int p_axis) const;
|
||||
|
||||
void set_axis(int p_axis, const Vector3 &p_value);
|
||||
|
||||
void rotate(const Vector3 &p_axis, real_t p_phi);
|
||||
|
||||
Basis rotated(const Vector3 &p_axis, real_t p_phi) const;
|
||||
|
||||
void scale(const Vector3 &p_scale);
|
||||
|
||||
Basis scaled(const Vector3 &p_scale) const;
|
||||
|
||||
Vector3 get_scale() const;
|
||||
|
||||
Basis slerp(Basis b, float t) const;
|
||||
|
||||
Vector3 get_euler_xyz() const;
|
||||
void set_euler_xyz(const Vector3 &p_euler);
|
||||
Vector3 get_euler_yxz() const;
|
||||
void set_euler_yxz(const Vector3 &p_euler);
|
||||
|
||||
inline Vector3 get_euler() const { return get_euler_yxz(); }
|
||||
inline void set_euler(const Vector3 &p_euler) { set_euler_yxz(p_euler); }
|
||||
|
||||
// transposed dot products
|
||||
real_t tdotx(const Vector3 &v) const;
|
||||
real_t tdoty(const Vector3 &v) const;
|
||||
real_t tdotz(const Vector3 &v) const;
|
||||
|
||||
bool operator==(const Basis &p_matrix) const;
|
||||
|
||||
bool operator!=(const Basis &p_matrix) const;
|
||||
|
||||
Vector3 xform(const Vector3 &p_vector) const;
|
||||
|
||||
Vector3 xform_inv(const Vector3 &p_vector) const;
|
||||
void operator*=(const Basis &p_matrix);
|
||||
|
||||
Basis operator*(const Basis &p_matrix) const;
|
||||
|
||||
void operator+=(const Basis &p_matrix);
|
||||
|
||||
Basis operator+(const Basis &p_matrix) const;
|
||||
|
||||
void operator-=(const Basis &p_matrix);
|
||||
|
||||
Basis operator-(const Basis &p_matrix) const;
|
||||
|
||||
void operator*=(real_t p_val);
|
||||
|
||||
Basis operator*(real_t p_val) const;
|
||||
|
||||
int get_orthogonal_index() const; // down below
|
||||
|
||||
void set_orthogonal_index(int p_index); // down below
|
||||
|
||||
operator String() const;
|
||||
|
||||
void get_axis_and_angle(Vector3 &r_axis, real_t &r_angle) const;
|
||||
|
||||
/* create / set */
|
||||
|
||||
void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz);
|
||||
|
||||
Vector3 get_column(int i) const;
|
||||
|
||||
Vector3 get_row(int i) const;
|
||||
Vector3 get_main_diagonal() const;
|
||||
|
||||
void set_row(int i, const Vector3 &p_row);
|
||||
|
||||
Basis transpose_xform(const Basis &m) const;
|
||||
|
||||
void orthonormalize();
|
||||
|
||||
Basis orthonormalized() const;
|
||||
|
||||
bool is_symmetric() const;
|
||||
|
||||
Basis diagonalize();
|
||||
|
||||
operator Quat() const;
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // BASIS_H
|
||||
@@ -1,94 +0,0 @@
|
||||
#ifndef CAMERA_MATRIX_H
|
||||
#define CAMERA_MATRIX_H
|
||||
|
||||
#include "Defs.hpp"
|
||||
#include "Math.hpp"
|
||||
#include "Plane.hpp"
|
||||
#include "Rect2.hpp"
|
||||
#include "Transform.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
using namespace godot;
|
||||
} // namespace
|
||||
|
||||
struct CameraMatrix {
|
||||
enum Planes {
|
||||
PLANE_NEAR,
|
||||
PLANE_FAR,
|
||||
PLANE_LEFT,
|
||||
PLANE_TOP,
|
||||
PLANE_RIGHT,
|
||||
PLANE_BOTTOM
|
||||
};
|
||||
|
||||
real_t matrix[4][4];
|
||||
|
||||
void set_identity();
|
||||
void set_zero();
|
||||
void set_light_bias();
|
||||
void set_light_atlas_rect(const Rect2 &p_rect);
|
||||
void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false);
|
||||
void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist);
|
||||
void set_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_dist, real_t p_display_width, real_t p_display_to_lens, real_t p_oversample, real_t p_z_near, real_t p_z_far);
|
||||
void set_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);
|
||||
void set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov = false);
|
||||
void set_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far);
|
||||
void set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov = false);
|
||||
|
||||
static real_t get_fovy(real_t p_fovx, real_t p_aspect) {
|
||||
return Math::rad2deg(atan(p_aspect * tan(Math::deg2rad(p_fovx) * 0.5)) * 2.0);
|
||||
}
|
||||
|
||||
static inline double absd(double g) {
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
u.d = g;
|
||||
u.i &= (uint64_t)9223372036854775807ll;
|
||||
return u.d;
|
||||
}
|
||||
|
||||
real_t get_z_far() const;
|
||||
real_t get_z_near() const;
|
||||
real_t get_aspect() const;
|
||||
real_t get_fov() const;
|
||||
bool is_orthogonal() const;
|
||||
|
||||
std::vector<Plane> get_projection_planes(const Transform &p_transform) const;
|
||||
|
||||
bool get_endpoints(const Transform &p_transform, Vector3 *p_8points) const;
|
||||
Vector2 get_viewport_half_extents() const;
|
||||
|
||||
void invert();
|
||||
CameraMatrix inverse() const;
|
||||
|
||||
CameraMatrix operator*(const CameraMatrix &p_matrix) const;
|
||||
|
||||
Plane xform4(const Plane &p_vec4) const;
|
||||
inline Vector3 xform(const Vector3 &p_vec3) const;
|
||||
|
||||
operator String() const;
|
||||
|
||||
void scale_translate_to_fit(const AABB &p_aabb);
|
||||
void make_scale(const Vector3 &p_scale);
|
||||
int get_pixels_per_meter(int p_for_pixel_width) const;
|
||||
operator Transform() const;
|
||||
|
||||
CameraMatrix();
|
||||
CameraMatrix(const Transform &p_transform);
|
||||
~CameraMatrix();
|
||||
};
|
||||
|
||||
Vector3 CameraMatrix::xform(const Vector3 &p_vec3) const {
|
||||
Vector3 ret;
|
||||
ret.x = matrix[0][0] * p_vec3.x + matrix[1][0] * p_vec3.y + matrix[2][0] * p_vec3.z + matrix[3][0];
|
||||
ret.y = matrix[0][1] * p_vec3.x + matrix[1][1] * p_vec3.y + matrix[2][1] * p_vec3.z + matrix[3][1];
|
||||
ret.z = matrix[0][2] * p_vec3.x + matrix[1][2] * p_vec3.y + matrix[2][2] * p_vec3.z + matrix[3][2];
|
||||
real_t w = matrix[0][3] * p_vec3.x + matrix[1][3] * p_vec3.y + matrix[2][3] * p_vec3.z + matrix[3][3];
|
||||
return ret / w;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,141 +0,0 @@
|
||||
#ifndef COLOR_H
|
||||
#define COLOR_H
|
||||
|
||||
#include <gdnative/color.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "Defs.hpp"
|
||||
#include "String.hpp"
|
||||
|
||||
namespace godot {
|
||||
|
||||
struct Color {
|
||||
private:
|
||||
// static float _parse_col(const String& p_str, int p_ofs);
|
||||
public:
|
||||
union {
|
||||
struct {
|
||||
float r;
|
||||
float g;
|
||||
float b;
|
||||
float a;
|
||||
};
|
||||
float components[4];
|
||||
};
|
||||
|
||||
inline bool operator==(const Color &p_color) const { return (r == p_color.r && g == p_color.g && b == p_color.b && a == p_color.a); }
|
||||
inline bool operator!=(const Color &p_color) const { return (r != p_color.r || g != p_color.g || b != p_color.b || a != p_color.a); }
|
||||
|
||||
uint32_t to_32() const;
|
||||
|
||||
uint32_t to_ARGB32() const;
|
||||
|
||||
uint32_t to_ABGR32() const;
|
||||
|
||||
uint64_t to_ABGR64() const;
|
||||
|
||||
uint64_t to_ARGB64() const;
|
||||
|
||||
uint32_t to_RGBA32() const;
|
||||
|
||||
uint64_t to_RGBA64() const;
|
||||
|
||||
float gray() const;
|
||||
|
||||
uint8_t get_r8() const;
|
||||
|
||||
uint8_t get_g8() const;
|
||||
|
||||
uint8_t get_b8() const;
|
||||
|
||||
uint8_t get_a8() const;
|
||||
|
||||
float get_h() const;
|
||||
|
||||
float get_s() const;
|
||||
|
||||
float get_v() const;
|
||||
|
||||
void set_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0);
|
||||
|
||||
Color darkened(const float amount) const;
|
||||
|
||||
Color lightened(const float amount) const;
|
||||
|
||||
Color from_hsv(float p_h, float p_s, float p_v, float p_a = 1.0) const;
|
||||
|
||||
inline float &operator[](int idx) {
|
||||
return components[idx];
|
||||
}
|
||||
inline const float &operator[](int idx) const {
|
||||
return components[idx];
|
||||
}
|
||||
|
||||
Color operator+(const Color &p_color) const;
|
||||
void operator+=(const Color &p_color);
|
||||
|
||||
Color operator-() const;
|
||||
Color operator-(const Color &p_color) const;
|
||||
void operator-=(const Color &p_color);
|
||||
|
||||
Color operator*(const Color &p_color) const;
|
||||
Color operator*(const real_t &rvalue) const;
|
||||
void operator*=(const Color &p_color);
|
||||
void operator*=(const real_t &rvalue);
|
||||
|
||||
Color operator/(const Color &p_color) const;
|
||||
Color operator/(const real_t &rvalue) const;
|
||||
void operator/=(const Color &p_color);
|
||||
void operator/=(const real_t &rvalue);
|
||||
|
||||
void invert();
|
||||
|
||||
void contrast();
|
||||
|
||||
Color inverted() const;
|
||||
|
||||
Color contrasted() const;
|
||||
|
||||
Color linear_interpolate(const Color &p_b, float p_t) const;
|
||||
|
||||
Color blend(const Color &p_over) const;
|
||||
|
||||
Color to_linear() const;
|
||||
|
||||
static Color hex(uint32_t p_hex);
|
||||
|
||||
static Color html(const String &p_color);
|
||||
|
||||
static bool html_is_valid(const String &p_color);
|
||||
|
||||
String to_html(bool p_alpha = true) const;
|
||||
|
||||
bool operator<(const Color &p_color) const; //used in set keys
|
||||
|
||||
operator String() const;
|
||||
|
||||
/**
|
||||
* No construct parameters, r=0, g=0, b=0. a=255
|
||||
*/
|
||||
inline Color() {
|
||||
r = 0;
|
||||
g = 0;
|
||||
b = 0;
|
||||
a = 1.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB / RGBA construct parameters. Alpha is optional, but defaults to 1.0
|
||||
*/
|
||||
inline Color(float p_r, float p_g, float p_b, float p_a = 1.0) {
|
||||
r = p_r;
|
||||
g = p_g;
|
||||
b = p_b;
|
||||
a = p_a;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // COLOR_H
|
||||
@@ -1,26 +0,0 @@
|
||||
#ifndef CORETYPES_H
|
||||
#define CORETYPES_H
|
||||
|
||||
#include "Defs.hpp"
|
||||
|
||||
#include "AABB.hpp"
|
||||
#include "Array.hpp"
|
||||
#include "Basis.hpp"
|
||||
#include "Color.hpp"
|
||||
#include "Dictionary.hpp"
|
||||
#include "NodePath.hpp"
|
||||
#include "Plane.hpp"
|
||||
#include "PoolArrays.hpp"
|
||||
#include "Quat.hpp"
|
||||
#include "RID.hpp"
|
||||
#include "Rect2.hpp"
|
||||
#include "String.hpp"
|
||||
#include "Transform.hpp"
|
||||
#include "Transform2D.hpp"
|
||||
#include "Variant.hpp"
|
||||
#include "Vector2.hpp"
|
||||
#include "Vector3.hpp"
|
||||
|
||||
#include "Wrapped.hpp"
|
||||
|
||||
#endif // CORETYPES_H
|
||||
@@ -1,268 +0,0 @@
|
||||
#ifndef DEFS_H
|
||||
#define DEFS_H
|
||||
|
||||
namespace godot {
|
||||
|
||||
enum class Error {
|
||||
OK,
|
||||
FAILED, ///< Generic fail error
|
||||
ERR_UNAVAILABLE, ///< What is requested is unsupported/unavailable
|
||||
ERR_UNCONFIGURED, ///< The object being used hasnt been properly set up yet
|
||||
ERR_UNAUTHORIZED, ///< Missing credentials for requested resource
|
||||
ERR_PARAMETER_RANGE_ERROR, ///< Parameter given out of range (5)
|
||||
ERR_OUT_OF_MEMORY, ///< Out of memory
|
||||
ERR_FILE_NOT_FOUND,
|
||||
ERR_FILE_BAD_DRIVE,
|
||||
ERR_FILE_BAD_PATH,
|
||||
ERR_FILE_NO_PERMISSION, // (10)
|
||||
ERR_FILE_ALREADY_IN_USE,
|
||||
ERR_FILE_CANT_OPEN,
|
||||
ERR_FILE_CANT_WRITE,
|
||||
ERR_FILE_CANT_READ,
|
||||
ERR_FILE_UNRECOGNIZED, // (15)
|
||||
ERR_FILE_CORRUPT,
|
||||
ERR_FILE_MISSING_DEPENDENCIES,
|
||||
ERR_FILE_EOF,
|
||||
ERR_CANT_OPEN, ///< Can't open a resource/socket/file
|
||||
ERR_CANT_CREATE, // (20)
|
||||
ERR_QUERY_FAILED,
|
||||
ERR_ALREADY_IN_USE,
|
||||
ERR_LOCKED, ///< resource is locked
|
||||
ERR_TIMEOUT,
|
||||
ERR_CANT_CONNECT, // (25)
|
||||
ERR_CANT_RESOLVE,
|
||||
ERR_CONNECTION_ERROR,
|
||||
ERR_CANT_AQUIRE_RESOURCE,
|
||||
ERR_CANT_FORK,
|
||||
ERR_INVALID_DATA, ///< Data passed is invalid (30)
|
||||
ERR_INVALID_PARAMETER, ///< Parameter passed is invalid
|
||||
ERR_ALREADY_EXISTS, ///< When adding, item already exists
|
||||
ERR_DOES_NOT_EXIST, ///< When retrieving/erasing, it item does not exist
|
||||
ERR_DATABASE_CANT_READ, ///< database is full
|
||||
ERR_DATABASE_CANT_WRITE, ///< database is full (35)
|
||||
ERR_COMPILATION_FAILED,
|
||||
ERR_METHOD_NOT_FOUND,
|
||||
ERR_LINK_FAILED,
|
||||
ERR_SCRIPT_FAILED,
|
||||
ERR_CYCLIC_LINK, // (40)
|
||||
ERR_INVALID_DECLARATION,
|
||||
ERR_DUPLICATE_SYMBOL,
|
||||
ERR_PARSE_ERROR,
|
||||
ERR_BUSY,
|
||||
ERR_SKIP, // (45)
|
||||
ERR_HELP, ///< user requested help!!
|
||||
ERR_BUG, ///< a bug in the software certainly happened, due to a double check failing or unexpected behavior.
|
||||
ERR_PRINTER_ON_FIRE, /// the parallel port printer is engulfed in flames
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#include <GodotGlobal.hpp>
|
||||
|
||||
// alloca() is non-standard. When using MSVC, it's in malloc.h.
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#include <alloca.h>
|
||||
#else
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
typedef float real_t;
|
||||
|
||||
// This epsilon should match the one used by Godot for consistency.
|
||||
// Using `f` when `real_t` is float.
|
||||
#define CMP_EPSILON 0.00001f
|
||||
#define CMP_EPSILON2 (CMP_EPSILON * CMP_EPSILON)
|
||||
|
||||
#define Math_PI 3.1415926535897932384626433833
|
||||
#define Math_TAU 6.2831853071795864769252867666
|
||||
|
||||
#define _PLANE_EQ_DOT_EPSILON 0.999
|
||||
#define _PLANE_EQ_D_EPSILON 0.0001
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define likely(x) x
|
||||
#define unlikely(x) x
|
||||
#endif
|
||||
|
||||
// Don't use this directly; instead, use any of the CRASH_* macros
|
||||
#ifdef _MSC_VER
|
||||
#define GENERATE_TRAP \
|
||||
__debugbreak(); \
|
||||
/* Avoid warning about control paths */ \
|
||||
for (;;) { \
|
||||
}
|
||||
#else
|
||||
#define GENERATE_TRAP __builtin_trap();
|
||||
#endif
|
||||
|
||||
// ERR/WARN macros
|
||||
#ifndef WARN_PRINT
|
||||
#define WARN_PRINT(msg) godot::Godot::print_warning(msg, __func__, __FILE__, __LINE__)
|
||||
#endif
|
||||
|
||||
#ifndef WARN_PRINTS
|
||||
#define WARN_PRINTS(msg) WARN_PRINT((msg).utf8().get_data())
|
||||
#endif
|
||||
|
||||
#ifndef ERR_PRINT
|
||||
#define ERR_PRINT(msg) godot::Godot::print_error(msg, __func__, __FILE__, __LINE__)
|
||||
#endif
|
||||
|
||||
#ifndef ERR_PRINTS
|
||||
#define ERR_PRINTS(msg) ERR_PRINT((msg).utf8().get_data())
|
||||
#endif
|
||||
|
||||
#ifndef FATAL_PRINT
|
||||
#define FATAL_PRINT(msg) ERR_PRINT(godot::String("FATAL: ") + (msg))
|
||||
#endif
|
||||
|
||||
#ifndef ERR_MSG_INDEX
|
||||
#define ERR_MSG_INDEX(index, size) (godot::String("Index ") + #index + "=" + godot::String::num_int64(index) + " out of size (" + #size + "=" + godot::String::num_int64(size) + ")")
|
||||
#endif
|
||||
|
||||
#ifndef ERR_MSG_NULL
|
||||
#define ERR_MSG_NULL(param) (godot::String("Parameter '") + #param + "' is null.")
|
||||
#endif
|
||||
|
||||
#ifndef ERR_MSG_COND
|
||||
#define ERR_MSG_COND(cond) (godot::String("Condition '") + #cond + "' is true.")
|
||||
#endif
|
||||
|
||||
#ifndef ERR_FAIL_INDEX
|
||||
#define ERR_FAIL_INDEX(index, size) \
|
||||
do { \
|
||||
if (unlikely((index) < 0 || (index) >= (size))) { \
|
||||
ERR_PRINT(ERR_MSG_INDEX(index, size)); \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef ERR_FAIL_INDEX_V
|
||||
#define ERR_FAIL_INDEX_V(index, size, ret) \
|
||||
do { \
|
||||
if (unlikely((index) < 0 || (index) >= (size))) { \
|
||||
ERR_PRINT(ERR_MSG_INDEX(index, size)); \
|
||||
return ret; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef ERR_FAIL_UNSIGNED_INDEX_V
|
||||
#define ERR_FAIL_UNSIGNED_INDEX_V(index, size, ret) \
|
||||
do { \
|
||||
if (unlikely((index) >= (size))) { \
|
||||
ERR_PRINT(ERR_MSG_INDEX(index, size)); \
|
||||
return ret; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef CRASH_BAD_INDEX
|
||||
#define CRASH_BAD_INDEX(index, size) \
|
||||
do { \
|
||||
if (unlikely((index) < 0 || (index) >= (size))) { \
|
||||
FATAL_PRINT(ERR_MSG_INDEX(index, size)); \
|
||||
GENERATE_TRAP; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef ERR_FAIL_NULL
|
||||
#define ERR_FAIL_NULL(param) \
|
||||
do { \
|
||||
if (unlikely(!param)) { \
|
||||
ERR_PRINT(ERR_MSG_NULL(param)); \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef ERR_FAIL_NULL_V
|
||||
#define ERR_FAIL_NULL_V(param, ret) \
|
||||
do { \
|
||||
if (unlikely(!param)) { \
|
||||
ERR_PRINT(ERR_MSG_NULL(param)); \
|
||||
return ret; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef ERR_FAIL_COND
|
||||
#define ERR_FAIL_COND(cond) \
|
||||
do { \
|
||||
if (unlikely(cond)) { \
|
||||
ERR_PRINT(ERR_MSG_COND(cond)); \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef CRASH_COND
|
||||
#define CRASH_COND(cond) \
|
||||
do { \
|
||||
if (unlikely(cond)) { \
|
||||
FATAL_PRINT(ERR_MSG_COND(cond)); \
|
||||
GENERATE_TRAP; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef ERR_FAIL_COND_V
|
||||
#define ERR_FAIL_COND_V(cond, ret) \
|
||||
do { \
|
||||
if (unlikely(cond)) { \
|
||||
ERR_PRINT(ERR_MSG_COND(cond)); \
|
||||
return ret; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef ERR_CONTINUE
|
||||
#define ERR_CONTINUE(cond) \
|
||||
{ \
|
||||
if (unlikely(cond)) { \
|
||||
ERR_PRINT(ERR_MSG_COND(cond)); \
|
||||
continue; \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ERR_BREAK
|
||||
#define ERR_BREAK(cond) \
|
||||
{ \
|
||||
if (unlikely(cond)) { \
|
||||
ERR_PRINT(ERR_MSG_COND(cond)); \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ERR_FAIL
|
||||
#define ERR_FAIL() \
|
||||
do { \
|
||||
ERR_PRINT("Method/Function Failed."); \
|
||||
return; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef ERR_FAIL_V
|
||||
#define ERR_FAIL_V(ret) \
|
||||
do { \
|
||||
ERR_PRINT("Method/Function Failed."); \
|
||||
return ret; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef CRASH_NOW
|
||||
#define CRASH_NOW() \
|
||||
do { \
|
||||
FATAL_PRINT("Method/Function Failed."); \
|
||||
GENERATE_TRAP; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#endif // DEFS_H
|
||||
@@ -1,59 +0,0 @@
|
||||
#ifndef DICTIONARY_H
|
||||
#define DICTIONARY_H
|
||||
|
||||
#include "Variant.hpp"
|
||||
|
||||
#include "Array.hpp"
|
||||
|
||||
#include <gdnative/dictionary.h>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class Dictionary {
|
||||
godot_dictionary _godot_dictionary;
|
||||
|
||||
friend Variant::operator Dictionary() const;
|
||||
inline explicit Dictionary(const godot_dictionary &other) {
|
||||
_godot_dictionary = other;
|
||||
}
|
||||
|
||||
public:
|
||||
Dictionary();
|
||||
Dictionary(const Dictionary &other);
|
||||
Dictionary &operator=(const Dictionary &other);
|
||||
|
||||
template <class... Args>
|
||||
static Dictionary make(Args... args) {
|
||||
return helpers::add_all(Dictionary(), args...);
|
||||
}
|
||||
|
||||
void clear();
|
||||
|
||||
bool empty() const;
|
||||
|
||||
void erase(const Variant &key);
|
||||
|
||||
bool has(const Variant &key) const;
|
||||
|
||||
bool has_all(const Array &keys) const;
|
||||
|
||||
uint32_t hash() const;
|
||||
|
||||
Array keys() const;
|
||||
|
||||
Variant &operator[](const Variant &key);
|
||||
|
||||
const Variant &operator[](const Variant &key) const;
|
||||
|
||||
int size() const;
|
||||
|
||||
String to_json() const;
|
||||
|
||||
Array values() const;
|
||||
|
||||
~Dictionary();
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // DICTIONARY_H
|
||||
@@ -1,576 +0,0 @@
|
||||
#ifndef GODOT_HPP
|
||||
#define GODOT_HPP
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include <gdnative_api_struct.gen.h>
|
||||
#include <nativescript/godot_nativescript.h>
|
||||
#include <typeinfo>
|
||||
|
||||
#include "CoreTypes.hpp"
|
||||
#include "Ref.hpp"
|
||||
#include "TagDB.hpp"
|
||||
#include "Variant.hpp"
|
||||
|
||||
#include "Object.hpp"
|
||||
|
||||
#include "GodotGlobal.hpp"
|
||||
|
||||
namespace godot {
|
||||
namespace detail {
|
||||
|
||||
// Godot classes are wrapped by heap-allocated instances mimicking them through the C API.
|
||||
// They all inherit `_Wrapped`.
|
||||
template <class T>
|
||||
T *get_wrapper(godot_object *obj) {
|
||||
return (T *)godot::nativescript_1_1_api->godot_nativescript_get_instance_binding_data(godot::_RegisterState::language_index, obj);
|
||||
}
|
||||
|
||||
// Custom class instances are not obtainable by just casting the pointer to the base class they inherit,
|
||||
// partly because in Godot, scripts are not instances of the classes themselves, they are only attached to them.
|
||||
// Yet we want to "fake" it as if they were the same entity.
|
||||
template <class T>
|
||||
T *get_custom_class_instance(const Object *obj) {
|
||||
return (obj) ? (T *)godot::nativescript_api->godot_nativescript_get_userdata(obj->_owner) : nullptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T *create_custom_class_instance() {
|
||||
// Usually, script instances hold a reference to their NativeScript resource.
|
||||
// that resource is obtained from a `.gdns` file, which in turn exists because
|
||||
// of the resource system of Godot. We can't cleanly hardcode that here,
|
||||
// so the easiest for now (though not really clean) is to create new resource instances,
|
||||
// individually attached to the script instances.
|
||||
|
||||
// We cannot use wrappers because of https://github.com/godotengine/godot/issues/39181
|
||||
// godot::NativeScript *script = godot::NativeScript::_new();
|
||||
// script->set_library(get_wrapper<godot::GDNativeLibrary>((godot_object *)godot::gdnlib));
|
||||
// script->set_class_name(T::___get_class_name());
|
||||
|
||||
static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes");
|
||||
|
||||
// So we use the C API directly.
|
||||
static godot_class_constructor script_constructor = godot::api->godot_get_class_constructor("NativeScript");
|
||||
static godot_method_bind *mb_set_library = godot::api->godot_method_bind_get_method("NativeScript", "set_library");
|
||||
static godot_method_bind *mb_set_class_name = godot::api->godot_method_bind_get_method("NativeScript", "set_class_name");
|
||||
godot_object *script = script_constructor();
|
||||
{
|
||||
const void *args[] = { godot::gdnlib };
|
||||
godot::api->godot_method_bind_ptrcall(mb_set_library, script, args, nullptr);
|
||||
}
|
||||
{
|
||||
const String class_name = T::___get_class_name();
|
||||
const void *args[] = { &class_name };
|
||||
godot::api->godot_method_bind_ptrcall(mb_set_class_name, script, args, nullptr);
|
||||
}
|
||||
|
||||
// Now to instanciate T, we initially did this, however in case of Reference it returns a variant with refcount
|
||||
// already initialized, which woud cause inconsistent behavior compared to other classes (we still have to return a pointer).
|
||||
//Variant instance_variant = script->new_();
|
||||
//T *instance = godot::get_custom_class_instance<T>(instance_variant);
|
||||
|
||||
// So we should do this instead, however while convenient, it uses unnecessary wrapper objects.
|
||||
// Object *base_obj = T::___new_godot_base();
|
||||
// base_obj->set_script(script);
|
||||
// return get_custom_class_instance<T>(base_obj);
|
||||
|
||||
// Again using the C API to do exactly what we have to do.
|
||||
static godot_class_constructor base_constructor = godot::api->godot_get_class_constructor(T::___get_godot_class_name());
|
||||
static godot_method_bind *mb_set_script = godot::api->godot_method_bind_get_method("Object", "set_script");
|
||||
godot_object *base_obj = base_constructor();
|
||||
{
|
||||
const void *args[] = { script };
|
||||
godot::api->godot_method_bind_ptrcall(mb_set_script, base_obj, args, nullptr);
|
||||
}
|
||||
|
||||
return (T *)godot::nativescript_api->godot_nativescript_get_userdata(base_obj);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// Used in the definition of a custom class.
|
||||
//
|
||||
// Name: Name of your class, without namespace
|
||||
// Base: Name of the direct base class, with namespace if necessary
|
||||
//
|
||||
// ___get_class_name: Name of the class
|
||||
// ___get_godot_class_name: Name of the Godot base class this class inherits from (i.e not direct)
|
||||
// _new: Creates a new instance of the class
|
||||
// ___get_id: Gets the unique ID of the class. Godot and custom classes are both within that set.
|
||||
// ___get_base_id: Gets the ID of the direct base class, as returned by ___get_id
|
||||
// ___get_base_class_name: Name of the direct base class
|
||||
// ___get_from_variant: Converts a Variant into an Object*. Will be non-null if the class matches.
|
||||
#define GODOT_CLASS(Name, Base) \
|
||||
\
|
||||
public: \
|
||||
inline static const char *___get_class_name() { return #Name; } \
|
||||
enum { ___CLASS_IS_SCRIPT = 1 }; \
|
||||
inline static const char *___get_godot_class_name() { \
|
||||
return Base::___get_godot_class_name(); \
|
||||
} \
|
||||
inline static Name *_new() { \
|
||||
return godot::detail::create_custom_class_instance<Name>(); \
|
||||
} \
|
||||
inline static size_t ___get_id() { return typeid(Name).hash_code(); } \
|
||||
inline static size_t ___get_base_id() { return Base::___get_id(); } \
|
||||
inline static const char *___get_base_class_name() { return Base::___get_class_name(); } \
|
||||
inline static godot::Object *___get_from_variant(godot::Variant a) { \
|
||||
return (godot::Object *)godot::detail::get_custom_class_instance<Name>( \
|
||||
godot::Object::___get_from_variant(a)); \
|
||||
} \
|
||||
\
|
||||
private:
|
||||
|
||||
// Legacy compatibility
|
||||
#define GODOT_SUBCLASS(Name, Base) GODOT_CLASS(Name, Base)
|
||||
|
||||
template <class T>
|
||||
struct _ArgCast {
|
||||
static T _arg_cast(Variant a) {
|
||||
return a;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct _ArgCast<T *> {
|
||||
static T *_arg_cast(Variant a) {
|
||||
return (T *)T::___get_from_variant(a);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct _ArgCast<Variant> {
|
||||
static Variant _arg_cast(Variant a) {
|
||||
return a;
|
||||
}
|
||||
};
|
||||
|
||||
// instance and destroy funcs
|
||||
|
||||
template <class T>
|
||||
void *_godot_class_instance_func(godot_object *p, void * /*method_data*/) {
|
||||
T *d = new T();
|
||||
d->_owner = p;
|
||||
d->_type_tag = typeid(T).hash_code();
|
||||
d->_init();
|
||||
return d;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void _godot_class_destroy_func(godot_object * /*p*/, void * /*method_data*/, void *data) {
|
||||
T *d = (T *)data;
|
||||
delete d;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void register_class() {
|
||||
static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes");
|
||||
|
||||
godot_instance_create_func create = {};
|
||||
create.create_func = _godot_class_instance_func<T>;
|
||||
|
||||
godot_instance_destroy_func destroy = {};
|
||||
destroy.destroy_func = _godot_class_destroy_func<T>;
|
||||
|
||||
_TagDB::register_type(T::___get_id(), T::___get_base_id());
|
||||
|
||||
godot::nativescript_api->godot_nativescript_register_class(godot::_RegisterState::nativescript_handle,
|
||||
T::___get_class_name(), T::___get_base_class_name(), create, destroy);
|
||||
|
||||
godot::nativescript_1_1_api->godot_nativescript_set_type_tag(godot::_RegisterState::nativescript_handle,
|
||||
T::___get_class_name(), (const void *)T::___get_id());
|
||||
|
||||
T::_register_methods();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void register_tool_class() {
|
||||
static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes");
|
||||
|
||||
godot_instance_create_func create = {};
|
||||
create.create_func = _godot_class_instance_func<T>;
|
||||
|
||||
godot_instance_destroy_func destroy = {};
|
||||
destroy.destroy_func = _godot_class_destroy_func<T>;
|
||||
|
||||
_TagDB::register_type(T::___get_id(), T::___get_base_id());
|
||||
|
||||
godot::nativescript_api->godot_nativescript_register_tool_class(godot::_RegisterState::nativescript_handle,
|
||||
T::___get_class_name(), T::___get_base_class_name(), create, destroy);
|
||||
|
||||
godot::nativescript_1_1_api->godot_nativescript_set_type_tag(godot::_RegisterState::nativescript_handle,
|
||||
T::___get_class_name(), (const void *)T::___get_id());
|
||||
|
||||
T::_register_methods();
|
||||
}
|
||||
|
||||
// method registering
|
||||
|
||||
typedef godot_variant (*__godot_wrapper_method)(godot_object *, void *, void *, int, godot_variant **);
|
||||
|
||||
template <class T, class R, class... args>
|
||||
const char *___get_method_class_name(R (T::*p)(args... a)) {
|
||||
static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes");
|
||||
(void)p; // To avoid "unused parameter" warnings. `p` is required for template matching.
|
||||
return T::___get_class_name();
|
||||
}
|
||||
|
||||
// This second version is also required to match constant functions
|
||||
template <class T, class R, class... args>
|
||||
const char *___get_method_class_name(R (T::*p)(args... a) const) {
|
||||
static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes");
|
||||
(void)p; // To avoid "unused parameter" warnings. `p` is required for template matching.
|
||||
return T::___get_class_name();
|
||||
}
|
||||
|
||||
// Okay, time for some template magic.
|
||||
// Many thanks to manpat from the GDL Discord Server.
|
||||
|
||||
// This is stuff that's available in C++14 I think, but whatever.
|
||||
|
||||
template <int... I>
|
||||
struct __Sequence {};
|
||||
|
||||
template <int N, int... I>
|
||||
struct __construct_sequence {
|
||||
using type = typename __construct_sequence<N - 1, N - 1, I...>::type;
|
||||
};
|
||||
|
||||
template <int... I>
|
||||
struct __construct_sequence<0, I...> {
|
||||
using type = __Sequence<I...>;
|
||||
};
|
||||
|
||||
// Now the wrapping part.
|
||||
template <class T, class R, class... As>
|
||||
struct _WrappedMethod {
|
||||
R(T::*f)
|
||||
(As...);
|
||||
|
||||
template <int... I>
|
||||
void apply(Variant *ret, T *obj, Variant **args, __Sequence<I...>) {
|
||||
*ret = (obj->*f)(_ArgCast<As>::_arg_cast(*args[I])...);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class... As>
|
||||
struct _WrappedMethod<T, void, As...> {
|
||||
void (T::*f)(As...);
|
||||
|
||||
template <int... I>
|
||||
void apply(Variant * /*ret*/, T *obj, Variant **args, __Sequence<I...>) {
|
||||
(obj->*f)(_ArgCast<As>::_arg_cast(*args[I])...);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class R, class... As>
|
||||
godot_variant __wrapped_method(godot_object *, void *method_data, void *user_data, int /*num_args*/, godot_variant **args) {
|
||||
godot_variant v;
|
||||
godot::api->godot_variant_new_nil(&v);
|
||||
|
||||
T *obj = (T *)user_data;
|
||||
_WrappedMethod<T, R, As...> *method = (_WrappedMethod<T, R, As...> *)method_data;
|
||||
|
||||
Variant *var = (Variant *)&v;
|
||||
Variant **arg = (Variant **)args;
|
||||
|
||||
method->apply(var, obj, arg, typename __construct_sequence<sizeof...(As)>::type{});
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
template <class T, class R, class... As>
|
||||
void *___make_wrapper_function(R (T::*f)(As...)) {
|
||||
using MethodType = _WrappedMethod<T, R, As...>;
|
||||
MethodType *p = (MethodType *)godot::api->godot_alloc(sizeof(MethodType));
|
||||
p->f = f;
|
||||
return (void *)p;
|
||||
}
|
||||
|
||||
template <class T, class R, class... As>
|
||||
__godot_wrapper_method ___get_wrapper_function(R (T::* /*f*/)(As...)) {
|
||||
return (__godot_wrapper_method)&__wrapped_method<T, R, As...>;
|
||||
}
|
||||
|
||||
template <class T, class R, class... A>
|
||||
void *___make_wrapper_function(R (T::*f)(A...) const) {
|
||||
return ___make_wrapper_function((R(T::*)(A...))f);
|
||||
}
|
||||
|
||||
template <class T, class R, class... A>
|
||||
__godot_wrapper_method ___get_wrapper_function(R (T::*f)(A...) const) {
|
||||
return ___get_wrapper_function((R(T::*)(A...))f);
|
||||
}
|
||||
|
||||
template <class M>
|
||||
void register_method(const char *name, M method_ptr, godot_method_rpc_mode rpc_type = GODOT_METHOD_RPC_MODE_DISABLED) {
|
||||
godot_instance_method method = {};
|
||||
method.method_data = ___make_wrapper_function(method_ptr);
|
||||
method.free_func = godot::api->godot_free;
|
||||
method.method = (__godot_wrapper_method)___get_wrapper_function(method_ptr);
|
||||
|
||||
godot_method_attributes attr = {};
|
||||
attr.rpc_type = rpc_type;
|
||||
|
||||
godot::nativescript_api->godot_nativescript_register_method(godot::_RegisterState::nativescript_handle,
|
||||
___get_method_class_name(method_ptr), name, attr, method);
|
||||
}
|
||||
|
||||
// User can specify a derived class D to register the method for, instead of it being inferred.
|
||||
template <class D, class B, class R, class... As>
|
||||
void register_method_explicit(const char *name, R (B::*method_ptr)(As...),
|
||||
godot_method_rpc_mode rpc_type = GODOT_METHOD_RPC_MODE_DISABLED) {
|
||||
static_assert(std::is_base_of<B, D>::value, "Explicit class must derive from method class");
|
||||
register_method(name, static_cast<R (D::*)(As...)>(method_ptr), rpc_type);
|
||||
}
|
||||
|
||||
template <class T, class P>
|
||||
struct _PropertySetFunc {
|
||||
void (T::*f)(P);
|
||||
static void _wrapped_setter(godot_object * /*object*/, void *method_data, void *user_data, godot_variant *value) {
|
||||
_PropertySetFunc<T, P> *set_func = (_PropertySetFunc<T, P> *)method_data;
|
||||
T *obj = (T *)user_data;
|
||||
|
||||
Variant *v = (Variant *)value;
|
||||
|
||||
(obj->*(set_func->f))(_ArgCast<P>::_arg_cast(*v));
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class P>
|
||||
struct _PropertyGetFunc {
|
||||
P(T::*f)
|
||||
();
|
||||
static godot_variant _wrapped_getter(godot_object * /*object*/, void *method_data, void *user_data) {
|
||||
_PropertyGetFunc<T, P> *get_func = (_PropertyGetFunc<T, P> *)method_data;
|
||||
T *obj = (T *)user_data;
|
||||
|
||||
godot_variant var;
|
||||
godot::api->godot_variant_new_nil(&var);
|
||||
|
||||
Variant *v = (Variant *)&var;
|
||||
|
||||
*v = (obj->*(get_func->f))();
|
||||
|
||||
return var;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class P>
|
||||
struct _PropertyDefaultSetFunc {
|
||||
P(T::*f);
|
||||
static void _wrapped_setter(godot_object * /*object*/, void *method_data, void *user_data, godot_variant *value) {
|
||||
_PropertyDefaultSetFunc<T, P> *set_func = (_PropertyDefaultSetFunc<T, P> *)method_data;
|
||||
T *obj = (T *)user_data;
|
||||
|
||||
Variant *v = (Variant *)value;
|
||||
|
||||
(obj->*(set_func->f)) = _ArgCast<P>::_arg_cast(*v);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class P>
|
||||
struct _PropertyDefaultGetFunc {
|
||||
P(T::*f);
|
||||
static godot_variant _wrapped_getter(godot_object * /*object*/, void *method_data, void *user_data) {
|
||||
_PropertyDefaultGetFunc<T, P> *get_func = (_PropertyDefaultGetFunc<T, P> *)method_data;
|
||||
T *obj = (T *)user_data;
|
||||
|
||||
godot_variant var;
|
||||
godot::api->godot_variant_new_nil(&var);
|
||||
|
||||
Variant *v = (Variant *)&var;
|
||||
|
||||
*v = (obj->*(get_func->f));
|
||||
|
||||
return var;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class P>
|
||||
void register_property(const char *name, P(T::*var), P default_value,
|
||||
godot_method_rpc_mode rpc_mode = GODOT_METHOD_RPC_MODE_DISABLED,
|
||||
godot_property_usage_flags usage = GODOT_PROPERTY_USAGE_DEFAULT,
|
||||
godot_property_hint hint = GODOT_PROPERTY_HINT_NONE, String hint_string = "") {
|
||||
static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes");
|
||||
|
||||
Variant def_val = default_value;
|
||||
|
||||
usage = (godot_property_usage_flags)((int)usage | GODOT_PROPERTY_USAGE_SCRIPT_VARIABLE);
|
||||
|
||||
if (def_val.get_type() == Variant::OBJECT) {
|
||||
Object *o = detail::get_wrapper<Object>(def_val.operator godot_object *());
|
||||
if (o && o->is_class("Resource")) {
|
||||
hint = (godot_property_hint)((int)hint | GODOT_PROPERTY_HINT_RESOURCE_TYPE);
|
||||
hint_string = o->get_class();
|
||||
}
|
||||
}
|
||||
|
||||
godot_string *_hint_string = (godot_string *)&hint_string;
|
||||
|
||||
godot_property_attributes attr = {};
|
||||
if (def_val.get_type() == Variant::NIL) {
|
||||
attr.type = Variant::OBJECT;
|
||||
} else {
|
||||
attr.type = def_val.get_type();
|
||||
attr.default_value = *(godot_variant *)&def_val;
|
||||
}
|
||||
|
||||
attr.hint = hint;
|
||||
attr.rset_type = rpc_mode;
|
||||
attr.usage = usage;
|
||||
attr.hint_string = *_hint_string;
|
||||
|
||||
_PropertyDefaultSetFunc<T, P> *wrapped_set =
|
||||
(_PropertyDefaultSetFunc<T, P> *)godot::api->godot_alloc(sizeof(_PropertyDefaultSetFunc<T, P>));
|
||||
wrapped_set->f = var;
|
||||
|
||||
_PropertyDefaultGetFunc<T, P> *wrapped_get =
|
||||
(_PropertyDefaultGetFunc<T, P> *)godot::api->godot_alloc(sizeof(_PropertyDefaultGetFunc<T, P>));
|
||||
wrapped_get->f = var;
|
||||
|
||||
godot_property_set_func set_func = {};
|
||||
set_func.method_data = (void *)wrapped_set;
|
||||
set_func.free_func = godot::api->godot_free;
|
||||
set_func.set_func = &_PropertyDefaultSetFunc<T, P>::_wrapped_setter;
|
||||
|
||||
godot_property_get_func get_func = {};
|
||||
get_func.method_data = (void *)wrapped_get;
|
||||
get_func.free_func = godot::api->godot_free;
|
||||
get_func.get_func = &_PropertyDefaultGetFunc<T, P>::_wrapped_getter;
|
||||
|
||||
godot::nativescript_api->godot_nativescript_register_property(godot::_RegisterState::nativescript_handle,
|
||||
T::___get_class_name(), name, &attr, set_func, get_func);
|
||||
}
|
||||
|
||||
template <class T, class P>
|
||||
void register_property(const char *name, void (T::*setter)(P), P (T::*getter)(), P default_value,
|
||||
godot_method_rpc_mode rpc_mode = GODOT_METHOD_RPC_MODE_DISABLED,
|
||||
godot_property_usage_flags usage = GODOT_PROPERTY_USAGE_DEFAULT,
|
||||
godot_property_hint hint = GODOT_PROPERTY_HINT_NONE, String hint_string = "") {
|
||||
static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes");
|
||||
|
||||
Variant def_val = default_value;
|
||||
|
||||
godot_string *_hint_string = (godot_string *)&hint_string;
|
||||
|
||||
godot_property_attributes attr = {};
|
||||
if (def_val.get_type() == Variant::NIL) {
|
||||
attr.type = Variant::OBJECT;
|
||||
} else {
|
||||
attr.type = def_val.get_type();
|
||||
attr.default_value = *(godot_variant *)&def_val;
|
||||
}
|
||||
attr.hint = hint;
|
||||
attr.rset_type = rpc_mode;
|
||||
attr.usage = usage;
|
||||
attr.hint_string = *_hint_string;
|
||||
|
||||
_PropertySetFunc<T, P> *wrapped_set = (_PropertySetFunc<T, P> *)godot::api->godot_alloc(sizeof(_PropertySetFunc<T, P>));
|
||||
wrapped_set->f = setter;
|
||||
|
||||
_PropertyGetFunc<T, P> *wrapped_get = (_PropertyGetFunc<T, P> *)godot::api->godot_alloc(sizeof(_PropertyGetFunc<T, P>));
|
||||
wrapped_get->f = getter;
|
||||
|
||||
godot_property_set_func set_func = {};
|
||||
set_func.method_data = (void *)wrapped_set;
|
||||
set_func.free_func = godot::api->godot_free;
|
||||
set_func.set_func = &_PropertySetFunc<T, P>::_wrapped_setter;
|
||||
|
||||
godot_property_get_func get_func = {};
|
||||
get_func.method_data = (void *)wrapped_get;
|
||||
get_func.free_func = godot::api->godot_free;
|
||||
get_func.get_func = &_PropertyGetFunc<T, P>::_wrapped_getter;
|
||||
|
||||
godot::nativescript_api->godot_nativescript_register_property(godot::_RegisterState::nativescript_handle,
|
||||
T::___get_class_name(), name, &attr, set_func, get_func);
|
||||
}
|
||||
|
||||
template <class T, class P>
|
||||
void register_property(const char *name, void (T::*setter)(P), P (T::*getter)() const, P default_value,
|
||||
godot_method_rpc_mode rpc_mode = GODOT_METHOD_RPC_MODE_DISABLED,
|
||||
godot_property_usage_flags usage = GODOT_PROPERTY_USAGE_DEFAULT,
|
||||
godot_property_hint hint = GODOT_PROPERTY_HINT_NONE, String hint_string = "") {
|
||||
register_property(name, setter, (P(T::*)())getter, default_value, rpc_mode, usage, hint, hint_string);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void register_signal(String name, Dictionary args = Dictionary()) {
|
||||
static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes");
|
||||
|
||||
godot_signal signal = {};
|
||||
signal.name = *(godot_string *)&name;
|
||||
signal.num_args = args.size();
|
||||
signal.num_default_args = 0;
|
||||
|
||||
// Need to check because malloc(0) is platform-dependent. Zero arguments will leave args to nullptr.
|
||||
if (signal.num_args != 0) {
|
||||
signal.args = (godot_signal_argument *)godot::api->godot_alloc(sizeof(godot_signal_argument) * signal.num_args);
|
||||
memset((void *)signal.args, 0, sizeof(godot_signal_argument) * signal.num_args);
|
||||
}
|
||||
|
||||
for (int i = 0; i < signal.num_args; i++) {
|
||||
// Array entry = args[i];
|
||||
// String name = entry[0];
|
||||
String name = args.keys()[i];
|
||||
godot_string *_key = (godot_string *)&name;
|
||||
godot::api->godot_string_new_copy(&signal.args[i].name, _key);
|
||||
|
||||
// if (entry.size() > 1) {
|
||||
// signal.args[i].type = entry[1];
|
||||
// }
|
||||
signal.args[i].type = args.values()[i];
|
||||
}
|
||||
|
||||
godot::nativescript_api->godot_nativescript_register_signal(godot::_RegisterState::nativescript_handle,
|
||||
T::___get_class_name(), &signal);
|
||||
|
||||
for (int i = 0; i < signal.num_args; i++) {
|
||||
godot::api->godot_string_destroy(&signal.args[i].name);
|
||||
}
|
||||
|
||||
if (signal.args) {
|
||||
godot::api->godot_free(signal.args);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, class... Args>
|
||||
void register_signal(String name, Args... varargs) {
|
||||
register_signal<T>(name, Dictionary::make(varargs...));
|
||||
}
|
||||
|
||||
#ifndef GODOT_CPP_NO_OBJECT_CAST
|
||||
template <class T>
|
||||
T *Object::cast_to(const Object *obj) {
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
if (T::___CLASS_IS_SCRIPT) {
|
||||
size_t have_tag = (size_t)godot::nativescript_1_1_api->godot_nativescript_get_type_tag(obj->_owner);
|
||||
if (have_tag) {
|
||||
if (!godot::_TagDB::is_type_known((size_t)have_tag)) {
|
||||
have_tag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!have_tag) {
|
||||
have_tag = obj->_type_tag;
|
||||
}
|
||||
|
||||
if (godot::_TagDB::is_type_compatible(T::___get_id(), have_tag)) {
|
||||
return detail::get_custom_class_instance<T>(obj);
|
||||
}
|
||||
} else {
|
||||
if (godot::core_1_2_api->godot_object_cast_to(obj->_owner, (void *)T::___get_id())) {
|
||||
return (T *)obj;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_HPP
|
||||
@@ -1,51 +0,0 @@
|
||||
#ifndef GODOT_GLOBAL_HPP
|
||||
#define GODOT_GLOBAL_HPP
|
||||
|
||||
#include "Array.hpp"
|
||||
#include "String.hpp"
|
||||
#include <gdnative_api_struct.gen.h>
|
||||
|
||||
namespace godot {
|
||||
|
||||
extern "C" const godot_gdnative_core_api_struct *api;
|
||||
extern "C" const godot_gdnative_core_1_1_api_struct *core_1_1_api;
|
||||
extern "C" const godot_gdnative_core_1_2_api_struct *core_1_2_api;
|
||||
|
||||
extern "C" const godot_gdnative_ext_nativescript_api_struct *nativescript_api;
|
||||
extern "C" const godot_gdnative_ext_nativescript_1_1_api_struct *nativescript_1_1_api;
|
||||
extern "C" const godot_gdnative_ext_pluginscript_api_struct *pluginscript_api;
|
||||
extern "C" const godot_gdnative_ext_android_api_struct *android_api;
|
||||
extern "C" const godot_gdnative_ext_arvr_api_struct *arvr_api;
|
||||
extern "C" const godot_gdnative_ext_videodecoder_api_struct *videodecoder_api;
|
||||
extern "C" const godot_gdnative_ext_net_api_struct *net_api;
|
||||
extern "C" const godot_gdnative_ext_net_3_2_api_struct *net_3_2_api;
|
||||
|
||||
extern "C" const void *gdnlib;
|
||||
|
||||
class Godot {
|
||||
public:
|
||||
static void print(const String &message);
|
||||
static void print_warning(const String &description, const String &function, const String &file, int line);
|
||||
static void print_error(const String &description, const String &function, const String &file, int line);
|
||||
|
||||
static void gdnative_init(godot_gdnative_init_options *o);
|
||||
static void gdnative_terminate(godot_gdnative_terminate_options *o);
|
||||
static void nativescript_init(void *handle);
|
||||
static void nativescript_terminate(void *handle);
|
||||
|
||||
static void gdnative_profiling_add_data(const char *p_signature, uint64_t p_time);
|
||||
|
||||
template <class... Args>
|
||||
static void print(const String &fmt, Args... values) {
|
||||
print(fmt.format(Array::make(values...)));
|
||||
}
|
||||
};
|
||||
|
||||
struct _RegisterState {
|
||||
static void *nativescript_handle;
|
||||
static int language_index;
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef GODOT_PROFILING_HPP
|
||||
#define GODOT_PROFILING_HPP
|
||||
|
||||
#include "OS.hpp"
|
||||
|
||||
namespace godot {
|
||||
|
||||
class FunctionProfiling {
|
||||
char signature[1024];
|
||||
uint64_t ticks;
|
||||
|
||||
public:
|
||||
FunctionProfiling(const char *p_function, const int p_line) {
|
||||
snprintf(signature, 1024, "::%d::%s", p_line, p_function);
|
||||
ticks = OS::get_singleton()->get_ticks_usec();
|
||||
}
|
||||
~FunctionProfiling() {
|
||||
uint64_t t = OS::get_singleton()->get_ticks_usec() - ticks;
|
||||
if (t > 0) {
|
||||
Godot::gdnative_profiling_add_data(signature, t);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
#define GODOT_PROFILING_FUNCTION FunctionProfiling __function_profiling(__FUNCTION__, __LINE__);
|
||||
#else
|
||||
#define GODOT_PROFILING_FUNCTION
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,272 +0,0 @@
|
||||
#ifndef GODOT_MATH_H
|
||||
#define GODOT_MATH_H
|
||||
|
||||
#include "Defs.hpp"
|
||||
#include <cmath>
|
||||
|
||||
namespace godot {
|
||||
namespace Math {
|
||||
|
||||
// Functions reproduced as in Godot's source code `math_funcs.h`.
|
||||
// Some are overloads to automatically support changing real_t into either double or float in the way Godot does.
|
||||
|
||||
inline double fmod(double p_x, double p_y) {
|
||||
return ::fmod(p_x, p_y);
|
||||
}
|
||||
inline float fmod(float p_x, float p_y) {
|
||||
return ::fmodf(p_x, p_y);
|
||||
}
|
||||
|
||||
inline double floor(double p_x) {
|
||||
return ::floor(p_x);
|
||||
}
|
||||
inline float floor(float p_x) {
|
||||
return ::floorf(p_x);
|
||||
}
|
||||
|
||||
inline double exp(double p_x) {
|
||||
return ::exp(p_x);
|
||||
}
|
||||
inline float exp(float p_x) {
|
||||
return ::expf(p_x);
|
||||
}
|
||||
|
||||
inline double sin(double p_x) {
|
||||
return ::sin(p_x);
|
||||
}
|
||||
inline float sin(float p_x) {
|
||||
return ::sinf(p_x);
|
||||
}
|
||||
|
||||
inline double cos(double p_x) {
|
||||
return ::cos(p_x);
|
||||
}
|
||||
inline float cos(float p_x) {
|
||||
return ::cosf(p_x);
|
||||
}
|
||||
|
||||
inline double tan(double p_x) {
|
||||
return ::tan(p_x);
|
||||
}
|
||||
inline float tan(float p_x) {
|
||||
return ::tanf(p_x);
|
||||
}
|
||||
|
||||
inline double asin(double p_x) {
|
||||
return ::asin(p_x);
|
||||
}
|
||||
inline float asin(float p_x) {
|
||||
return ::asinf(p_x);
|
||||
}
|
||||
|
||||
inline double acos(double p_x) {
|
||||
return ::acos(p_x);
|
||||
}
|
||||
inline float acos(float p_x) {
|
||||
return ::acosf(p_x);
|
||||
}
|
||||
|
||||
inline double atan(double p_x) {
|
||||
return ::atan(p_x);
|
||||
}
|
||||
inline float atan(float p_x) {
|
||||
return ::atanf(p_x);
|
||||
}
|
||||
|
||||
inline double atan2(double p_y, double p_x) {
|
||||
return ::atan2(p_y, p_x);
|
||||
}
|
||||
inline float atan2(float p_y, float p_x) {
|
||||
return ::atan2f(p_y, p_x);
|
||||
}
|
||||
|
||||
inline double sqrt(double p_x) {
|
||||
return ::sqrt(p_x);
|
||||
}
|
||||
inline float sqrt(float p_x) {
|
||||
return ::sqrtf(p_x);
|
||||
}
|
||||
|
||||
inline float lerp(float minv, float maxv, float t) {
|
||||
return minv + t * (maxv - minv);
|
||||
}
|
||||
inline double lerp(double minv, double maxv, double t) {
|
||||
return minv + t * (maxv - minv);
|
||||
}
|
||||
|
||||
inline double lerp_angle(double p_from, double p_to, double p_weight) {
|
||||
double difference = fmod(p_to - p_from, Math_TAU);
|
||||
double distance = fmod(2.0 * difference, Math_TAU) - difference;
|
||||
return p_from + distance * p_weight;
|
||||
}
|
||||
inline float lerp_angle(float p_from, float p_to, float p_weight) {
|
||||
float difference = fmod(p_to - p_from, (float)Math_TAU);
|
||||
float distance = fmod(2.0f * difference, (float)Math_TAU) - difference;
|
||||
return p_from + distance * p_weight;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T clamp(T x, T minv, T maxv) {
|
||||
if (x < minv) {
|
||||
return minv;
|
||||
}
|
||||
if (x > maxv) {
|
||||
return maxv;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T min(T a, T b) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T max(T a, T b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T sign(T x) {
|
||||
return static_cast<T>(x < 0 ? -1 : 1);
|
||||
}
|
||||
|
||||
inline double deg2rad(double p_y) {
|
||||
return p_y * Math_PI / 180.0;
|
||||
}
|
||||
inline float deg2rad(float p_y) {
|
||||
return p_y * static_cast<float>(Math_PI) / 180.f;
|
||||
}
|
||||
|
||||
inline double rad2deg(double p_y) {
|
||||
return p_y * 180.0 / Math_PI;
|
||||
}
|
||||
inline float rad2deg(float p_y) {
|
||||
return p_y * 180.f / static_cast<float>(Math_PI);
|
||||
}
|
||||
|
||||
inline double inverse_lerp(double p_from, double p_to, double p_value) {
|
||||
return (p_value - p_from) / (p_to - p_from);
|
||||
}
|
||||
inline float inverse_lerp(float p_from, float p_to, float p_value) {
|
||||
return (p_value - p_from) / (p_to - p_from);
|
||||
}
|
||||
|
||||
inline double range_lerp(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) {
|
||||
return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value));
|
||||
}
|
||||
inline float range_lerp(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) {
|
||||
return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value));
|
||||
}
|
||||
|
||||
inline bool is_equal_approx(real_t a, real_t b) {
|
||||
// Check for exact equality first, required to handle "infinity" values.
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
// Then check for approximate equality.
|
||||
real_t tolerance = CMP_EPSILON * std::abs(a);
|
||||
if (tolerance < CMP_EPSILON) {
|
||||
tolerance = CMP_EPSILON;
|
||||
}
|
||||
return std::abs(a - b) < tolerance;
|
||||
}
|
||||
|
||||
inline bool is_equal_approx(real_t a, real_t b, real_t tolerance) {
|
||||
// Check for exact equality first, required to handle "infinity" values.
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
// Then check for approximate equality.
|
||||
return std::abs(a - b) < tolerance;
|
||||
}
|
||||
|
||||
inline bool is_zero_approx(real_t s) {
|
||||
return std::abs(s) < CMP_EPSILON;
|
||||
}
|
||||
|
||||
inline double smoothstep(double p_from, double p_to, double p_weight) {
|
||||
if (is_equal_approx(static_cast<real_t>(p_from), static_cast<real_t>(p_to))) {
|
||||
return p_from;
|
||||
}
|
||||
double x = clamp((p_weight - p_from) / (p_to - p_from), 0.0, 1.0);
|
||||
return x * x * (3.0 - 2.0 * x);
|
||||
}
|
||||
inline float smoothstep(float p_from, float p_to, float p_weight) {
|
||||
if (is_equal_approx(p_from, p_to)) {
|
||||
return p_from;
|
||||
}
|
||||
float x = clamp((p_weight - p_from) / (p_to - p_from), 0.0f, 1.0f);
|
||||
return x * x * (3.0f - 2.0f * x);
|
||||
}
|
||||
|
||||
inline double move_toward(double p_from, double p_to, double p_delta) {
|
||||
return std::abs(p_to - p_from) <= p_delta ? p_to : p_from + sign(p_to - p_from) * p_delta;
|
||||
}
|
||||
|
||||
inline float move_toward(float p_from, float p_to, float p_delta) {
|
||||
return std::abs(p_to - p_from) <= p_delta ? p_to : p_from + sign(p_to - p_from) * p_delta;
|
||||
}
|
||||
|
||||
inline double linear2db(double p_linear) {
|
||||
return log(p_linear) * 8.6858896380650365530225783783321;
|
||||
}
|
||||
inline float linear2db(float p_linear) {
|
||||
return log(p_linear) * 8.6858896380650365530225783783321f;
|
||||
}
|
||||
|
||||
inline double db2linear(double p_db) {
|
||||
return exp(p_db * 0.11512925464970228420089957273422);
|
||||
}
|
||||
inline float db2linear(float p_db) {
|
||||
return exp(p_db * 0.11512925464970228420089957273422f);
|
||||
}
|
||||
|
||||
inline double round(double p_val) {
|
||||
return (p_val >= 0) ? floor(p_val + 0.5) : -floor(-p_val + 0.5);
|
||||
}
|
||||
inline float round(float p_val) {
|
||||
return (p_val >= 0) ? floor(p_val + 0.5f) : -floor(-p_val + 0.5f);
|
||||
}
|
||||
|
||||
inline int64_t wrapi(int64_t value, int64_t min, int64_t max) {
|
||||
int64_t range = max - min;
|
||||
return range == 0 ? min : min + ((((value - min) % range) + range) % range);
|
||||
}
|
||||
|
||||
inline float wrapf(real_t value, real_t min, real_t max) {
|
||||
const real_t range = max - min;
|
||||
return is_zero_approx(range) ? min : value - (range * floor((value - min) / range));
|
||||
}
|
||||
|
||||
inline float stepify(float p_value, float p_step) {
|
||||
if (p_step != 0) {
|
||||
p_value = floor(p_value / p_step + 0.5f) * p_step;
|
||||
}
|
||||
return p_value;
|
||||
}
|
||||
inline double stepify(double p_value, double p_step) {
|
||||
if (p_step != 0) {
|
||||
p_value = floor(p_value / p_step + 0.5) * p_step;
|
||||
}
|
||||
return p_value;
|
||||
}
|
||||
|
||||
inline unsigned int next_power_of_2(unsigned int x) {
|
||||
if (x == 0)
|
||||
return 0;
|
||||
|
||||
--x;
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
x |= x >> 8;
|
||||
x |= x >> 16;
|
||||
|
||||
return ++x;
|
||||
}
|
||||
|
||||
} // namespace Math
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_MATH_H
|
||||
@@ -1,54 +0,0 @@
|
||||
#ifndef NODEPATH_H
|
||||
#define NODEPATH_H
|
||||
|
||||
#include "String.hpp"
|
||||
|
||||
#include <gdnative/node_path.h>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class NodePath {
|
||||
godot_node_path _node_path;
|
||||
|
||||
friend class Variant;
|
||||
inline explicit NodePath(godot_node_path node_path) {
|
||||
_node_path = node_path;
|
||||
}
|
||||
|
||||
public:
|
||||
NodePath();
|
||||
|
||||
NodePath(const NodePath &other);
|
||||
|
||||
NodePath(const String &from);
|
||||
|
||||
NodePath(const char *contents);
|
||||
|
||||
String get_name(const int idx) const;
|
||||
|
||||
int get_name_count() const;
|
||||
|
||||
String get_subname(const int idx) const;
|
||||
|
||||
int get_subname_count() const;
|
||||
|
||||
bool is_absolute() const;
|
||||
|
||||
bool is_empty() const;
|
||||
|
||||
NodePath get_as_property_path() const;
|
||||
|
||||
String get_concatenated_subnames() const;
|
||||
|
||||
operator String() const;
|
||||
|
||||
void operator=(const NodePath &other);
|
||||
|
||||
bool operator==(const NodePath &other);
|
||||
|
||||
~NodePath();
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // NODEPATH_H
|
||||
@@ -1,68 +0,0 @@
|
||||
#ifndef PLANE_H
|
||||
#define PLANE_H
|
||||
|
||||
#include "Vector3.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace godot {
|
||||
|
||||
enum ClockDirection {
|
||||
|
||||
CLOCKWISE,
|
||||
COUNTERCLOCKWISE
|
||||
};
|
||||
|
||||
class Plane {
|
||||
public:
|
||||
Vector3 normal;
|
||||
real_t d;
|
||||
|
||||
void set_normal(const Vector3 &p_normal);
|
||||
|
||||
inline Vector3 get_normal() const { return normal; } ///Point is coplanar, CMP_EPSILON for precision
|
||||
|
||||
void normalize();
|
||||
|
||||
Plane normalized() const;
|
||||
|
||||
/* Plane-Point operations */
|
||||
|
||||
inline Vector3 center() const { return normal * d; }
|
||||
Vector3 get_any_point() const;
|
||||
Vector3 get_any_perpendicular_normal() const;
|
||||
|
||||
bool is_point_over(const Vector3 &p_point) const; ///< Point is over plane
|
||||
real_t distance_to(const Vector3 &p_point) const;
|
||||
bool has_point(const Vector3 &p_point, real_t _epsilon = CMP_EPSILON) const;
|
||||
|
||||
/* intersections */
|
||||
|
||||
bool intersect_3(const Plane &p_plane1, const Plane &p_plane2, Vector3 *r_result = 0) const;
|
||||
bool intersects_ray(Vector3 p_from, Vector3 p_dir, Vector3 *p_intersection) const;
|
||||
bool intersects_segment(Vector3 p_begin, Vector3 p_end, Vector3 *p_intersection) const;
|
||||
|
||||
Vector3 project(const Vector3 &p_point) const;
|
||||
|
||||
/* misc */
|
||||
|
||||
inline Plane operator-() const { return Plane(-normal, -d); }
|
||||
bool is_almost_like(const Plane &p_plane) const;
|
||||
|
||||
bool operator==(const Plane &p_plane) const;
|
||||
bool operator!=(const Plane &p_plane) const;
|
||||
operator String() const;
|
||||
|
||||
inline Plane() { d = 0; }
|
||||
inline Plane(real_t p_a, real_t p_b, real_t p_c, real_t p_d) :
|
||||
normal(p_a, p_b, p_c),
|
||||
d(p_d) {}
|
||||
|
||||
Plane(const Vector3 &p_normal, real_t p_d);
|
||||
Plane(const Vector3 &p_point, const Vector3 &p_normal);
|
||||
Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_point3, ClockDirection p_dir = CLOCKWISE);
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // PLANE_H
|
||||
@@ -1,736 +0,0 @@
|
||||
#ifndef POOLARRAYS_H
|
||||
#define POOLARRAYS_H
|
||||
|
||||
#include "Defs.hpp"
|
||||
|
||||
#include "Color.hpp"
|
||||
#include "GodotGlobal.hpp"
|
||||
#include "String.hpp"
|
||||
#include "Vector2.hpp"
|
||||
#include "Vector3.hpp"
|
||||
|
||||
#include <gdnative/pool_arrays.h>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class Array;
|
||||
|
||||
class PoolByteArray {
|
||||
godot_pool_byte_array _godot_array;
|
||||
|
||||
friend class String;
|
||||
friend class Variant;
|
||||
inline explicit PoolByteArray(godot_pool_byte_array a) {
|
||||
_godot_array = a;
|
||||
}
|
||||
|
||||
public:
|
||||
class Read {
|
||||
friend class PoolByteArray;
|
||||
godot_pool_byte_array_read_access *_read_access;
|
||||
|
||||
public:
|
||||
inline Read() {
|
||||
_read_access = nullptr;
|
||||
}
|
||||
|
||||
inline Read(const Read &p_other) {
|
||||
_read_access = godot::api->godot_pool_byte_array_read_access_copy(p_other._read_access);
|
||||
}
|
||||
|
||||
inline ~Read() {
|
||||
godot::api->godot_pool_byte_array_read_access_destroy(_read_access);
|
||||
}
|
||||
|
||||
inline const uint8_t *ptr() const {
|
||||
return godot::api->godot_pool_byte_array_read_access_ptr(_read_access);
|
||||
}
|
||||
|
||||
inline const uint8_t &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Read &p_other) {
|
||||
godot::api->godot_pool_byte_array_read_access_operator_assign(_read_access, p_other._read_access);
|
||||
}
|
||||
};
|
||||
|
||||
class Write {
|
||||
friend class PoolByteArray;
|
||||
godot_pool_byte_array_write_access *_write_access;
|
||||
|
||||
public:
|
||||
inline Write() {
|
||||
_write_access = nullptr;
|
||||
}
|
||||
|
||||
inline Write(const Write &p_other) {
|
||||
_write_access = godot::api->godot_pool_byte_array_write_access_copy(p_other._write_access);
|
||||
}
|
||||
|
||||
inline ~Write() {
|
||||
godot::api->godot_pool_byte_array_write_access_destroy(_write_access);
|
||||
}
|
||||
|
||||
inline uint8_t *ptr() const {
|
||||
return godot::api->godot_pool_byte_array_write_access_ptr(_write_access);
|
||||
}
|
||||
|
||||
inline uint8_t &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Write &p_other) {
|
||||
godot::api->godot_pool_byte_array_write_access_operator_assign(_write_access, p_other._write_access);
|
||||
}
|
||||
};
|
||||
|
||||
PoolByteArray();
|
||||
PoolByteArray(const PoolByteArray &p_other);
|
||||
PoolByteArray &operator=(const PoolByteArray &p_other);
|
||||
|
||||
PoolByteArray(const Array &array);
|
||||
|
||||
Read read() const;
|
||||
|
||||
Write write();
|
||||
|
||||
void append(const uint8_t data);
|
||||
|
||||
void append_array(const PoolByteArray &array);
|
||||
|
||||
int insert(const int idx, const uint8_t data);
|
||||
|
||||
void invert();
|
||||
|
||||
void push_back(const uint8_t data);
|
||||
|
||||
void remove(const int idx);
|
||||
|
||||
void resize(const int size);
|
||||
|
||||
void set(const int idx, const uint8_t data);
|
||||
|
||||
uint8_t operator[](const int idx);
|
||||
|
||||
int size() const;
|
||||
|
||||
~PoolByteArray();
|
||||
};
|
||||
|
||||
class PoolIntArray {
|
||||
godot_pool_int_array _godot_array;
|
||||
|
||||
friend class Variant;
|
||||
explicit inline PoolIntArray(godot_pool_int_array a) {
|
||||
_godot_array = a;
|
||||
}
|
||||
|
||||
public:
|
||||
class Read {
|
||||
friend class PoolIntArray;
|
||||
godot_pool_int_array_read_access *_read_access;
|
||||
|
||||
public:
|
||||
inline Read() {
|
||||
_read_access = nullptr;
|
||||
}
|
||||
|
||||
inline Read(const Read &p_other) {
|
||||
_read_access = godot::api->godot_pool_int_array_read_access_copy(p_other._read_access);
|
||||
}
|
||||
|
||||
inline ~Read() {
|
||||
godot::api->godot_pool_int_array_read_access_destroy(_read_access);
|
||||
}
|
||||
|
||||
inline const int *ptr() const {
|
||||
return godot::api->godot_pool_int_array_read_access_ptr(_read_access);
|
||||
}
|
||||
|
||||
inline const int &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Read &p_other) {
|
||||
godot::api->godot_pool_int_array_read_access_operator_assign(_read_access, p_other._read_access);
|
||||
}
|
||||
};
|
||||
|
||||
class Write {
|
||||
friend class PoolIntArray;
|
||||
godot_pool_int_array_write_access *_write_access;
|
||||
|
||||
public:
|
||||
inline Write() {
|
||||
_write_access = nullptr;
|
||||
}
|
||||
|
||||
inline Write(const Write &p_other) {
|
||||
_write_access = godot::api->godot_pool_int_array_write_access_copy(p_other._write_access);
|
||||
}
|
||||
|
||||
inline ~Write() {
|
||||
godot::api->godot_pool_int_array_write_access_destroy(_write_access);
|
||||
}
|
||||
|
||||
inline int *ptr() const {
|
||||
return godot::api->godot_pool_int_array_write_access_ptr(_write_access);
|
||||
}
|
||||
|
||||
inline int &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Write &p_other) {
|
||||
godot::api->godot_pool_int_array_write_access_operator_assign(_write_access, p_other._write_access);
|
||||
}
|
||||
};
|
||||
|
||||
PoolIntArray();
|
||||
PoolIntArray(const PoolIntArray &p_other);
|
||||
PoolIntArray &operator=(const PoolIntArray &p_other);
|
||||
|
||||
PoolIntArray(const Array &array);
|
||||
|
||||
Read read() const;
|
||||
|
||||
Write write();
|
||||
|
||||
void append(const int data);
|
||||
|
||||
void append_array(const PoolIntArray &array);
|
||||
|
||||
int insert(const int idx, const int data);
|
||||
|
||||
void invert();
|
||||
|
||||
void push_back(const int data);
|
||||
|
||||
void remove(const int idx);
|
||||
|
||||
void resize(const int size);
|
||||
|
||||
void set(const int idx, const int data);
|
||||
|
||||
int operator[](const int idx);
|
||||
|
||||
int size() const;
|
||||
|
||||
~PoolIntArray();
|
||||
};
|
||||
|
||||
class PoolRealArray {
|
||||
godot_pool_real_array _godot_array;
|
||||
|
||||
friend class Variant;
|
||||
explicit inline PoolRealArray(godot_pool_real_array a) {
|
||||
_godot_array = a;
|
||||
}
|
||||
|
||||
public:
|
||||
class Read {
|
||||
friend class PoolRealArray;
|
||||
godot_pool_real_array_read_access *_read_access;
|
||||
|
||||
public:
|
||||
inline Read() {
|
||||
_read_access = nullptr;
|
||||
}
|
||||
|
||||
inline Read(const Read &p_other) {
|
||||
_read_access = godot::api->godot_pool_real_array_read_access_copy(p_other._read_access);
|
||||
}
|
||||
|
||||
inline ~Read() {
|
||||
godot::api->godot_pool_real_array_read_access_destroy(_read_access);
|
||||
}
|
||||
|
||||
inline const real_t *ptr() const {
|
||||
return godot::api->godot_pool_real_array_read_access_ptr(_read_access);
|
||||
}
|
||||
|
||||
inline const real_t &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Read &p_other) {
|
||||
godot::api->godot_pool_real_array_read_access_operator_assign(_read_access, p_other._read_access);
|
||||
}
|
||||
};
|
||||
|
||||
class Write {
|
||||
friend class PoolRealArray;
|
||||
godot_pool_real_array_write_access *_write_access;
|
||||
|
||||
public:
|
||||
inline Write() {
|
||||
_write_access = nullptr;
|
||||
}
|
||||
|
||||
inline Write(const Write &p_other) {
|
||||
_write_access = godot::api->godot_pool_real_array_write_access_copy(p_other._write_access);
|
||||
}
|
||||
|
||||
inline ~Write() {
|
||||
godot::api->godot_pool_real_array_write_access_destroy(_write_access);
|
||||
}
|
||||
|
||||
inline real_t *ptr() const {
|
||||
return godot::api->godot_pool_real_array_write_access_ptr(_write_access);
|
||||
}
|
||||
|
||||
inline real_t &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Write &p_other) {
|
||||
godot::api->godot_pool_real_array_write_access_operator_assign(_write_access, p_other._write_access);
|
||||
}
|
||||
};
|
||||
|
||||
PoolRealArray();
|
||||
PoolRealArray(const PoolRealArray &p_other);
|
||||
PoolRealArray &operator=(const PoolRealArray &p_other);
|
||||
|
||||
PoolRealArray(const Array &array);
|
||||
|
||||
Read read() const;
|
||||
|
||||
Write write();
|
||||
|
||||
void append(const real_t data);
|
||||
|
||||
void append_array(const PoolRealArray &array);
|
||||
|
||||
int insert(const int idx, const real_t data);
|
||||
|
||||
void invert();
|
||||
|
||||
void push_back(const real_t data);
|
||||
|
||||
void remove(const int idx);
|
||||
|
||||
void resize(const int size);
|
||||
|
||||
void set(const int idx, const real_t data);
|
||||
|
||||
real_t operator[](const int idx);
|
||||
|
||||
int size() const;
|
||||
|
||||
~PoolRealArray();
|
||||
};
|
||||
|
||||
class PoolStringArray {
|
||||
godot_pool_string_array _godot_array;
|
||||
|
||||
friend class String;
|
||||
friend class Variant;
|
||||
explicit inline PoolStringArray(godot_pool_string_array a) {
|
||||
_godot_array = a;
|
||||
}
|
||||
|
||||
public:
|
||||
class Read {
|
||||
friend class PoolStringArray;
|
||||
godot_pool_string_array_read_access *_read_access;
|
||||
|
||||
public:
|
||||
inline Read() {
|
||||
_read_access = nullptr;
|
||||
}
|
||||
|
||||
inline Read(const Read &p_other) {
|
||||
_read_access = godot::api->godot_pool_string_array_read_access_copy(p_other._read_access);
|
||||
}
|
||||
|
||||
inline ~Read() {
|
||||
godot::api->godot_pool_string_array_read_access_destroy(_read_access);
|
||||
}
|
||||
|
||||
inline const String *ptr() const {
|
||||
return (const String *)godot::api->godot_pool_string_array_read_access_ptr(_read_access);
|
||||
}
|
||||
|
||||
inline const String &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Read &p_other) {
|
||||
godot::api->godot_pool_string_array_read_access_operator_assign(_read_access, p_other._read_access);
|
||||
}
|
||||
};
|
||||
|
||||
class Write {
|
||||
friend class PoolStringArray;
|
||||
godot_pool_string_array_write_access *_write_access;
|
||||
|
||||
public:
|
||||
inline Write() {
|
||||
_write_access = nullptr;
|
||||
}
|
||||
|
||||
inline Write(const Write &p_other) {
|
||||
_write_access = godot::api->godot_pool_string_array_write_access_copy(p_other._write_access);
|
||||
}
|
||||
|
||||
inline ~Write() {
|
||||
godot::api->godot_pool_string_array_write_access_destroy(_write_access);
|
||||
}
|
||||
|
||||
inline String *ptr() const {
|
||||
return (String *)godot::api->godot_pool_string_array_write_access_ptr(_write_access);
|
||||
}
|
||||
|
||||
inline String &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Write &p_other) {
|
||||
godot::api->godot_pool_string_array_write_access_operator_assign(_write_access, p_other._write_access);
|
||||
}
|
||||
};
|
||||
|
||||
PoolStringArray();
|
||||
PoolStringArray(const PoolStringArray &p_other);
|
||||
PoolStringArray &operator=(const PoolStringArray &p_other);
|
||||
|
||||
PoolStringArray(const Array &array);
|
||||
|
||||
Read read() const;
|
||||
|
||||
Write write();
|
||||
|
||||
void append(const String &data);
|
||||
|
||||
void append_array(const PoolStringArray &array);
|
||||
|
||||
int insert(const int idx, const String &data);
|
||||
|
||||
void invert();
|
||||
|
||||
void push_back(const String &data);
|
||||
|
||||
void remove(const int idx);
|
||||
|
||||
void resize(const int size);
|
||||
|
||||
void set(const int idx, const String &data);
|
||||
|
||||
const String operator[](const int idx);
|
||||
|
||||
int size() const;
|
||||
|
||||
~PoolStringArray();
|
||||
};
|
||||
|
||||
class PoolVector2Array {
|
||||
godot_pool_vector2_array _godot_array;
|
||||
|
||||
friend class Variant;
|
||||
explicit inline PoolVector2Array(godot_pool_vector2_array a) {
|
||||
_godot_array = a;
|
||||
}
|
||||
|
||||
public:
|
||||
class Read {
|
||||
friend class PoolVector2Array;
|
||||
godot_pool_vector2_array_read_access *_read_access;
|
||||
|
||||
public:
|
||||
inline Read() {
|
||||
_read_access = nullptr;
|
||||
}
|
||||
|
||||
inline Read(const Read &p_other) {
|
||||
_read_access = godot::api->godot_pool_vector2_array_read_access_copy(p_other._read_access);
|
||||
}
|
||||
|
||||
inline ~Read() {
|
||||
godot::api->godot_pool_vector2_array_read_access_destroy(_read_access);
|
||||
}
|
||||
|
||||
inline const Vector2 *ptr() const {
|
||||
return (const Vector2 *)godot::api->godot_pool_vector2_array_read_access_ptr(_read_access);
|
||||
}
|
||||
|
||||
inline const Vector2 &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Read &p_other) {
|
||||
godot::api->godot_pool_vector2_array_read_access_operator_assign(_read_access, p_other._read_access);
|
||||
}
|
||||
};
|
||||
|
||||
class Write {
|
||||
friend class PoolVector2Array;
|
||||
godot_pool_vector2_array_write_access *_write_access;
|
||||
|
||||
public:
|
||||
inline Write() {
|
||||
_write_access = nullptr;
|
||||
}
|
||||
|
||||
inline Write(const Write &p_other) {
|
||||
_write_access = godot::api->godot_pool_vector2_array_write_access_copy(p_other._write_access);
|
||||
}
|
||||
|
||||
inline ~Write() {
|
||||
godot::api->godot_pool_vector2_array_write_access_destroy(_write_access);
|
||||
}
|
||||
|
||||
inline Vector2 *ptr() const {
|
||||
return (Vector2 *)godot::api->godot_pool_vector2_array_write_access_ptr(_write_access);
|
||||
}
|
||||
|
||||
inline Vector2 &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Write &p_other) {
|
||||
godot::api->godot_pool_vector2_array_write_access_operator_assign(_write_access, p_other._write_access);
|
||||
}
|
||||
};
|
||||
|
||||
PoolVector2Array();
|
||||
PoolVector2Array(const PoolVector2Array &p_other);
|
||||
PoolVector2Array &operator=(const PoolVector2Array &p_other);
|
||||
|
||||
PoolVector2Array(const Array &array);
|
||||
|
||||
Read read() const;
|
||||
|
||||
Write write();
|
||||
|
||||
void append(const Vector2 &data);
|
||||
|
||||
void append_array(const PoolVector2Array &array);
|
||||
|
||||
int insert(const int idx, const Vector2 &data);
|
||||
|
||||
void invert();
|
||||
|
||||
void push_back(const Vector2 &data);
|
||||
|
||||
void remove(const int idx);
|
||||
|
||||
void resize(const int size);
|
||||
|
||||
void set(const int idx, const Vector2 &data);
|
||||
|
||||
const Vector2 operator[](const int idx);
|
||||
|
||||
int size() const;
|
||||
|
||||
~PoolVector2Array();
|
||||
};
|
||||
|
||||
class PoolVector3Array {
|
||||
godot_pool_vector3_array _godot_array;
|
||||
|
||||
friend class Variant;
|
||||
explicit inline PoolVector3Array(godot_pool_vector3_array a) {
|
||||
_godot_array = a;
|
||||
}
|
||||
|
||||
public:
|
||||
class Read {
|
||||
friend class PoolVector3Array;
|
||||
godot_pool_vector3_array_read_access *_read_access;
|
||||
|
||||
public:
|
||||
inline Read() {
|
||||
_read_access = nullptr;
|
||||
}
|
||||
|
||||
inline Read(const Read &p_other) {
|
||||
_read_access = godot::api->godot_pool_vector3_array_read_access_copy(p_other._read_access);
|
||||
}
|
||||
|
||||
inline ~Read() {
|
||||
godot::api->godot_pool_vector3_array_read_access_destroy(_read_access);
|
||||
}
|
||||
|
||||
inline const Vector3 *ptr() const {
|
||||
return (const Vector3 *)godot::api->godot_pool_vector3_array_read_access_ptr(_read_access);
|
||||
}
|
||||
|
||||
inline const Vector3 &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Read &p_other) {
|
||||
godot::api->godot_pool_vector3_array_read_access_operator_assign(_read_access, p_other._read_access);
|
||||
}
|
||||
};
|
||||
|
||||
class Write {
|
||||
friend class PoolVector3Array;
|
||||
godot_pool_vector3_array_write_access *_write_access;
|
||||
|
||||
public:
|
||||
inline Write() {
|
||||
_write_access = nullptr;
|
||||
}
|
||||
|
||||
inline Write(const Write &p_other) {
|
||||
_write_access = godot::api->godot_pool_vector3_array_write_access_copy(p_other._write_access);
|
||||
}
|
||||
|
||||
inline ~Write() {
|
||||
godot::api->godot_pool_vector3_array_write_access_destroy(_write_access);
|
||||
}
|
||||
|
||||
inline Vector3 *ptr() const {
|
||||
return (Vector3 *)godot::api->godot_pool_vector3_array_write_access_ptr(_write_access);
|
||||
}
|
||||
|
||||
inline Vector3 &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Write &p_other) {
|
||||
godot::api->godot_pool_vector3_array_write_access_operator_assign(_write_access, p_other._write_access);
|
||||
}
|
||||
};
|
||||
|
||||
PoolVector3Array();
|
||||
PoolVector3Array(const PoolVector3Array &p_other);
|
||||
PoolVector3Array &operator=(const PoolVector3Array &p_other);
|
||||
|
||||
PoolVector3Array(const Array &array);
|
||||
|
||||
Read read() const;
|
||||
|
||||
Write write();
|
||||
|
||||
void append(const Vector3 &data);
|
||||
|
||||
void append_array(const PoolVector3Array &array);
|
||||
|
||||
int insert(const int idx, const Vector3 &data);
|
||||
|
||||
void invert();
|
||||
|
||||
void push_back(const Vector3 &data);
|
||||
|
||||
void remove(const int idx);
|
||||
|
||||
void resize(const int size);
|
||||
|
||||
void set(const int idx, const Vector3 &data);
|
||||
|
||||
const Vector3 operator[](const int idx);
|
||||
|
||||
int size() const;
|
||||
|
||||
~PoolVector3Array();
|
||||
};
|
||||
|
||||
class PoolColorArray {
|
||||
godot_pool_color_array _godot_array;
|
||||
|
||||
friend class Variant;
|
||||
explicit inline PoolColorArray(godot_pool_color_array a) {
|
||||
_godot_array = a;
|
||||
}
|
||||
|
||||
public:
|
||||
class Read {
|
||||
friend class PoolColorArray;
|
||||
godot_pool_color_array_read_access *_read_access;
|
||||
|
||||
public:
|
||||
inline Read() {
|
||||
_read_access = nullptr;
|
||||
}
|
||||
|
||||
inline Read(const Read &p_other) {
|
||||
_read_access = godot::api->godot_pool_color_array_read_access_copy(p_other._read_access);
|
||||
}
|
||||
|
||||
inline ~Read() {
|
||||
godot::api->godot_pool_color_array_read_access_destroy(_read_access);
|
||||
}
|
||||
|
||||
inline const Color *ptr() const {
|
||||
return (const Color *)godot::api->godot_pool_color_array_read_access_ptr(_read_access);
|
||||
}
|
||||
|
||||
inline const Color &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Read &p_other) {
|
||||
godot::api->godot_pool_color_array_read_access_operator_assign(_read_access, p_other._read_access);
|
||||
}
|
||||
};
|
||||
|
||||
class Write {
|
||||
friend class PoolColorArray;
|
||||
godot_pool_color_array_write_access *_write_access;
|
||||
|
||||
public:
|
||||
inline Write() {
|
||||
_write_access = nullptr;
|
||||
}
|
||||
|
||||
inline Write(const Write &p_other) {
|
||||
_write_access = godot::api->godot_pool_color_array_write_access_copy(p_other._write_access);
|
||||
}
|
||||
|
||||
inline ~Write() {
|
||||
godot::api->godot_pool_color_array_write_access_destroy(_write_access);
|
||||
}
|
||||
|
||||
inline Color *ptr() const {
|
||||
return (Color *)godot::api->godot_pool_color_array_write_access_ptr(_write_access);
|
||||
}
|
||||
|
||||
inline Color &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Write &p_other) {
|
||||
godot::api->godot_pool_color_array_write_access_operator_assign(_write_access, p_other._write_access);
|
||||
}
|
||||
};
|
||||
|
||||
PoolColorArray();
|
||||
PoolColorArray(const PoolColorArray &p_other);
|
||||
PoolColorArray &operator=(const PoolColorArray &p_other);
|
||||
|
||||
PoolColorArray(const Array &array);
|
||||
|
||||
Read read() const;
|
||||
|
||||
Write write();
|
||||
|
||||
void append(const Color &data);
|
||||
|
||||
void append_array(const PoolColorArray &array);
|
||||
|
||||
int insert(const int idx, const Color &data);
|
||||
|
||||
void invert();
|
||||
|
||||
void push_back(const Color &data);
|
||||
|
||||
void remove(const int idx);
|
||||
|
||||
void resize(const int size);
|
||||
|
||||
void set(const int idx, const Color &data);
|
||||
|
||||
const Color operator[](const int idx);
|
||||
|
||||
int size() const;
|
||||
|
||||
~PoolColorArray();
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // POOLARRAYS_H
|
||||
@@ -1,95 +0,0 @@
|
||||
#ifndef QUAT_H
|
||||
#define QUAT_H
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "Vector3.hpp"
|
||||
|
||||
// #include "Basis.h"
|
||||
|
||||
namespace godot {
|
||||
|
||||
class Quat {
|
||||
public:
|
||||
static const Quat IDENTITY;
|
||||
|
||||
real_t x, y, z, w;
|
||||
|
||||
real_t length_squared() const;
|
||||
real_t length() const;
|
||||
|
||||
void normalize();
|
||||
|
||||
Quat normalized() const;
|
||||
|
||||
bool is_normalized() const;
|
||||
|
||||
Quat inverse() const;
|
||||
|
||||
void set_euler_xyz(const Vector3 &p_euler);
|
||||
Vector3 get_euler_xyz() const;
|
||||
void set_euler_yxz(const Vector3 &p_euler);
|
||||
Vector3 get_euler_yxz() const;
|
||||
|
||||
inline void set_euler(const Vector3 &p_euler) { set_euler_yxz(p_euler); }
|
||||
inline Vector3 get_euler() const { return get_euler_yxz(); }
|
||||
|
||||
real_t dot(const Quat &q) const;
|
||||
|
||||
Quat slerp(const Quat &q, const real_t &t) const;
|
||||
|
||||
Quat slerpni(const Quat &q, const real_t &t) const;
|
||||
|
||||
Quat cubic_slerp(const Quat &q, const Quat &prep, const Quat &postq, const real_t &t) const;
|
||||
|
||||
void get_axis_and_angle(Vector3 &r_axis, real_t &r_angle) const;
|
||||
|
||||
void set_axis_angle(const Vector3 &axis, const float angle);
|
||||
|
||||
void operator*=(const Quat &q);
|
||||
Quat operator*(const Quat &q) const;
|
||||
|
||||
Quat operator*(const Vector3 &v) const;
|
||||
|
||||
Vector3 xform(const Vector3 &v) const;
|
||||
|
||||
void operator+=(const Quat &q);
|
||||
void operator-=(const Quat &q);
|
||||
void operator*=(const real_t &s);
|
||||
void operator/=(const real_t &s);
|
||||
Quat operator+(const Quat &q2) const;
|
||||
Quat operator-(const Quat &q2) const;
|
||||
Quat operator-() const;
|
||||
Quat operator*(const real_t &s) const;
|
||||
Quat operator/(const real_t &s) const;
|
||||
|
||||
bool operator==(const Quat &p_quat) const;
|
||||
bool operator!=(const Quat &p_quat) const;
|
||||
|
||||
operator String() const;
|
||||
|
||||
inline void set(real_t p_x, real_t p_y, real_t p_z, real_t p_w) {
|
||||
x = p_x;
|
||||
y = p_y;
|
||||
z = p_z;
|
||||
w = p_w;
|
||||
}
|
||||
inline Quat(real_t p_x, real_t p_y, real_t p_z, real_t p_w) {
|
||||
x = p_x;
|
||||
y = p_y;
|
||||
z = p_z;
|
||||
w = p_w;
|
||||
}
|
||||
Quat(const Vector3 &axis, const real_t &angle);
|
||||
|
||||
Quat(const Vector3 &v0, const Vector3 &v1);
|
||||
|
||||
inline Quat() {
|
||||
x = y = z = 0;
|
||||
w = 1;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // QUAT_H
|
||||
@@ -1,37 +0,0 @@
|
||||
#ifndef RID_H
|
||||
#define RID_H
|
||||
|
||||
#include <gdnative/rid.h>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class Object;
|
||||
|
||||
class RID {
|
||||
godot_rid _godot_rid;
|
||||
|
||||
public:
|
||||
RID();
|
||||
|
||||
RID(Object *p);
|
||||
|
||||
godot_rid _get_godot_rid() const;
|
||||
|
||||
int32_t get_id() const;
|
||||
|
||||
inline bool is_valid() const {
|
||||
// is_valid() is not available in the C API...
|
||||
return *this != RID();
|
||||
}
|
||||
|
||||
bool operator==(const RID &p_other) const;
|
||||
bool operator!=(const RID &p_other) const;
|
||||
bool operator<(const RID &p_other) const;
|
||||
bool operator>(const RID &p_other) const;
|
||||
bool operator<=(const RID &p_other) const;
|
||||
bool operator>=(const RID &p_other) const;
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // RID_H
|
||||
@@ -1,130 +0,0 @@
|
||||
#ifndef RECT2_H
|
||||
#define RECT2_H
|
||||
|
||||
#include "Vector2.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class String;
|
||||
|
||||
typedef Vector2 Size2;
|
||||
typedef Vector2 Point2;
|
||||
|
||||
struct Transform2D;
|
||||
|
||||
struct Rect2 {
|
||||
Point2 position;
|
||||
Size2 size;
|
||||
|
||||
inline const Vector2 &get_position() const { return position; }
|
||||
inline void set_position(const Vector2 &p_position) { position = p_position; }
|
||||
inline const Vector2 &get_size() const { return size; }
|
||||
inline void set_size(const Vector2 &p_size) { size = p_size; }
|
||||
|
||||
inline real_t get_area() const { return size.width * size.height; }
|
||||
|
||||
inline bool intersects(const Rect2 &p_rect) const {
|
||||
if (position.x >= (p_rect.position.x + p_rect.size.width))
|
||||
return false;
|
||||
if ((position.x + size.width) <= p_rect.position.x)
|
||||
return false;
|
||||
if (position.y >= (p_rect.position.y + p_rect.size.height))
|
||||
return false;
|
||||
if ((position.y + size.height) <= p_rect.position.y)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
real_t distance_to(const Vector2 &p_point) const;
|
||||
|
||||
bool intersects_transformed(const Transform2D &p_xform, const Rect2 &p_rect) const;
|
||||
|
||||
bool intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_position = nullptr, Point2 *r_normal = nullptr) const;
|
||||
|
||||
inline bool encloses(const Rect2 &p_rect) const {
|
||||
return (p_rect.position.x >= position.x) && (p_rect.position.y >= position.y) &&
|
||||
((p_rect.position.x + p_rect.size.x) < (position.x + size.x)) &&
|
||||
((p_rect.position.y + p_rect.size.y) < (position.y + size.y));
|
||||
}
|
||||
|
||||
inline bool has_no_area() const {
|
||||
return (size.x <= 0 || size.y <= 0);
|
||||
}
|
||||
Rect2 clip(const Rect2 &p_rect) const;
|
||||
|
||||
Rect2 merge(const Rect2 &p_rect) const;
|
||||
|
||||
inline bool has_point(const Point2 &p_point) const {
|
||||
if (p_point.x < position.x)
|
||||
return false;
|
||||
if (p_point.y < position.y)
|
||||
return false;
|
||||
|
||||
if (p_point.x >= (position.x + size.x))
|
||||
return false;
|
||||
if (p_point.y >= (position.y + size.y))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool no_area() const { return (size.width <= 0 || size.height <= 0); }
|
||||
|
||||
inline bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; }
|
||||
inline bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; }
|
||||
|
||||
inline Rect2 grow(real_t p_by) const {
|
||||
Rect2 g = *this;
|
||||
g.position.x -= p_by;
|
||||
g.position.y -= p_by;
|
||||
g.size.width += p_by * 2;
|
||||
g.size.height += p_by * 2;
|
||||
return g;
|
||||
}
|
||||
|
||||
inline Rect2 expand(const Vector2 &p_vector) const {
|
||||
Rect2 r = *this;
|
||||
r.expand_to(p_vector);
|
||||
return r;
|
||||
}
|
||||
|
||||
inline void expand_to(const Vector2 &p_vector) { //in place function for speed
|
||||
|
||||
Vector2 begin = position;
|
||||
Vector2 end = position + size;
|
||||
|
||||
if (p_vector.x < begin.x)
|
||||
begin.x = p_vector.x;
|
||||
if (p_vector.y < begin.y)
|
||||
begin.y = p_vector.y;
|
||||
|
||||
if (p_vector.x > end.x)
|
||||
end.x = p_vector.x;
|
||||
if (p_vector.y > end.y)
|
||||
end.y = p_vector.y;
|
||||
|
||||
position = begin;
|
||||
size = end - begin;
|
||||
}
|
||||
|
||||
operator String() const;
|
||||
|
||||
inline Rect2() {}
|
||||
inline Rect2(real_t p_x, real_t p_y, real_t p_width, real_t p_height) {
|
||||
position = Point2(p_x, p_y);
|
||||
size = Size2(p_width, p_height);
|
||||
}
|
||||
inline Rect2(const Point2 &p_position, const Size2 &p_size) {
|
||||
position = p_position;
|
||||
size = p_size;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // RECT2_H
|
||||
@@ -1,186 +0,0 @@
|
||||
#ifndef REF_H
|
||||
#define REF_H
|
||||
|
||||
#include "GodotGlobal.hpp"
|
||||
#include "Reference.hpp"
|
||||
#include "Variant.hpp"
|
||||
|
||||
namespace godot {
|
||||
|
||||
// Replicates Godot's Ref<T> behavior
|
||||
// Rewritten from f5234e70be7dec4930c2d5a0e829ff480d044b1d.
|
||||
template <class T>
|
||||
class Ref {
|
||||
// TODO For this nice check to work, each class must actually #include Reference classes mentionned in its methods,
|
||||
// which might be annoying for coders who prefer to forward-declare to reduce compile times
|
||||
// static_assert(std::is_base_of<Reference, T>::value,
|
||||
// "Ref<T> can only be used with classes deriving from Reference");
|
||||
|
||||
T *reference = nullptr;
|
||||
|
||||
void ref(const Ref &p_from) {
|
||||
if (p_from.reference == reference)
|
||||
return;
|
||||
|
||||
unref();
|
||||
|
||||
reference = p_from.reference;
|
||||
if (reference)
|
||||
reference->reference();
|
||||
}
|
||||
|
||||
void ref_pointer(T *p_ref) {
|
||||
ERR_FAIL_COND(p_ref == nullptr);
|
||||
|
||||
if (p_ref->init_ref())
|
||||
reference = p_ref;
|
||||
}
|
||||
|
||||
public:
|
||||
inline bool operator<(const Ref<T> &p_r) const {
|
||||
return reference < p_r.reference;
|
||||
}
|
||||
inline bool operator==(const Ref<T> &p_r) const {
|
||||
return reference == p_r.reference;
|
||||
}
|
||||
inline bool operator!=(const Ref<T> &p_r) const {
|
||||
return reference != p_r.reference;
|
||||
}
|
||||
|
||||
inline T *operator->() {
|
||||
return reference;
|
||||
}
|
||||
|
||||
inline T *operator*() {
|
||||
return reference;
|
||||
}
|
||||
|
||||
inline const T *operator->() const {
|
||||
return reference;
|
||||
}
|
||||
|
||||
inline const T *ptr() const {
|
||||
return reference;
|
||||
}
|
||||
inline T *ptr() {
|
||||
return reference;
|
||||
}
|
||||
|
||||
inline const T *operator*() const {
|
||||
return reference;
|
||||
}
|
||||
|
||||
operator Variant() const {
|
||||
// Note: the C API handles the cases where the object is a Reference,
|
||||
// so the Variant will be correctly constructed with a RefPtr engine-side
|
||||
return Variant((Object *)reference);
|
||||
}
|
||||
|
||||
void operator=(const Ref &p_from) {
|
||||
ref(p_from);
|
||||
}
|
||||
|
||||
template <class T_Other>
|
||||
void operator=(const Ref<T_Other> &p_from) {
|
||||
Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr()));
|
||||
if (refb == nullptr) {
|
||||
unref();
|
||||
return;
|
||||
}
|
||||
Ref r;
|
||||
r.reference = Object::cast_to<T>(refb);
|
||||
ref(r);
|
||||
r.reference = nullptr;
|
||||
}
|
||||
|
||||
void operator=(const Variant &p_variant) {
|
||||
Object *refb = T::___get_from_variant(p_variant);
|
||||
if (refb == nullptr) {
|
||||
unref();
|
||||
return;
|
||||
}
|
||||
Ref r;
|
||||
r.reference = Object::cast_to<T>(refb);
|
||||
ref(r);
|
||||
r.reference = nullptr;
|
||||
}
|
||||
|
||||
Ref(const Ref &p_from) {
|
||||
reference = nullptr;
|
||||
ref(p_from);
|
||||
}
|
||||
|
||||
template <class T_Other>
|
||||
Ref(const Ref<T_Other> &p_from) {
|
||||
reference = nullptr;
|
||||
Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr()));
|
||||
if (refb == nullptr) {
|
||||
unref();
|
||||
return;
|
||||
}
|
||||
Ref r;
|
||||
r.reference = Object::cast_to<T>(refb);
|
||||
ref(r);
|
||||
r.reference = nullptr;
|
||||
}
|
||||
|
||||
Ref(T *p_reference) {
|
||||
if (p_reference)
|
||||
ref_pointer(p_reference);
|
||||
else
|
||||
reference = nullptr;
|
||||
}
|
||||
|
||||
Ref(const Variant &p_variant) {
|
||||
reference = nullptr;
|
||||
Object *refb = T::___get_from_variant(p_variant);
|
||||
if (refb == nullptr) {
|
||||
unref();
|
||||
return;
|
||||
}
|
||||
Ref r;
|
||||
r.reference = Object::cast_to<T>(refb);
|
||||
ref(r);
|
||||
r.reference = nullptr;
|
||||
}
|
||||
|
||||
inline bool is_valid() const { return reference != nullptr; }
|
||||
inline bool is_null() const { return reference == nullptr; }
|
||||
|
||||
void unref() {
|
||||
//TODO this should be moved to mutexes, since this engine does not really
|
||||
// do a lot of referencing on references and stuff
|
||||
// mutexes will avoid more crashes?
|
||||
|
||||
if (reference && reference->unreference()) {
|
||||
//memdelete(reference);
|
||||
reference->free();
|
||||
}
|
||||
reference = nullptr;
|
||||
}
|
||||
|
||||
void instance() {
|
||||
//ref(memnew(T));
|
||||
ref(T::_new());
|
||||
}
|
||||
|
||||
Ref() {
|
||||
reference = nullptr;
|
||||
}
|
||||
|
||||
~Ref() {
|
||||
unref();
|
||||
}
|
||||
|
||||
// Used exclusively in the bindings to recreate the Ref Godot encapsulates in return values,
|
||||
// without adding to the refcount.
|
||||
inline static Ref<T> __internal_constructor(Object *obj) {
|
||||
Ref<T> r;
|
||||
r.reference = (T *)obj;
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif
|
||||
@@ -1,154 +0,0 @@
|
||||
#ifndef STRING_H
|
||||
#define STRING_H
|
||||
|
||||
#include <gdnative/string.h>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class NodePath;
|
||||
class Variant;
|
||||
class PoolByteArray;
|
||||
class PoolIntArray;
|
||||
class PoolRealArray;
|
||||
class PoolStringArray;
|
||||
class String;
|
||||
|
||||
class CharString {
|
||||
friend class String;
|
||||
|
||||
godot_char_string _char_string;
|
||||
|
||||
public:
|
||||
~CharString();
|
||||
|
||||
int length() const;
|
||||
const char *get_data() const;
|
||||
};
|
||||
|
||||
class String {
|
||||
godot_string _godot_string;
|
||||
|
||||
friend class Dictionary;
|
||||
friend class NodePath;
|
||||
friend class Variant;
|
||||
explicit inline String(godot_string contents) :
|
||||
_godot_string(contents) {}
|
||||
|
||||
public:
|
||||
String();
|
||||
String(const char *contents);
|
||||
String(const wchar_t *contents);
|
||||
String(const wchar_t c);
|
||||
String(const String &other);
|
||||
String(String &&other);
|
||||
|
||||
~String();
|
||||
|
||||
static String num(double p_num, int p_decimals = -1);
|
||||
static String num_scientific(double p_num);
|
||||
static String num_real(double p_num);
|
||||
static String num_int64(int64_t p_num, int base = 10, bool capitalize_hex = false);
|
||||
static String chr(godot_char_type p_char);
|
||||
static String md5(const uint8_t *p_md5);
|
||||
static String hex_encode_buffer(const uint8_t *p_buffer, int p_len);
|
||||
|
||||
wchar_t &operator[](const int idx);
|
||||
wchar_t operator[](const int idx) const;
|
||||
|
||||
void operator=(const String &s);
|
||||
void operator=(String &&s);
|
||||
bool operator==(const String &s) const;
|
||||
bool operator!=(const String &s) const;
|
||||
String operator+(const String &s) const;
|
||||
void operator+=(const String &s);
|
||||
void operator+=(const wchar_t c);
|
||||
bool operator<(const String &s) const;
|
||||
bool operator<=(const String &s) const;
|
||||
bool operator>(const String &s) const;
|
||||
bool operator>=(const String &s) const;
|
||||
|
||||
operator NodePath() const;
|
||||
|
||||
int length() const;
|
||||
const wchar_t *unicode_str() const;
|
||||
char *alloc_c_string() const;
|
||||
CharString utf8() const;
|
||||
CharString ascii(bool p_extended = false) const;
|
||||
|
||||
bool begins_with(String &s) const;
|
||||
bool begins_with_char_array(const char *p_char_array) const;
|
||||
PoolStringArray bigrams() const;
|
||||
String c_escape() const;
|
||||
String c_unescape() const;
|
||||
String capitalize() const;
|
||||
bool empty() const;
|
||||
bool ends_with(String &text) const;
|
||||
void erase(int position, int chars);
|
||||
int find(String what, int from = 0) const;
|
||||
int find_last(String what) const;
|
||||
int findn(String what, int from = 0) const;
|
||||
String format(Variant values) const;
|
||||
String format(Variant values, String placeholder) const;
|
||||
String get_base_dir() const;
|
||||
String get_basename() const;
|
||||
String get_extension() const;
|
||||
String get_file() const;
|
||||
int hash() const;
|
||||
int hex_to_int() const;
|
||||
String insert(int position, String what) const;
|
||||
bool is_abs_path() const;
|
||||
bool is_rel_path() const;
|
||||
bool is_subsequence_of(String text) const;
|
||||
bool is_subsequence_ofi(String text) const;
|
||||
bool is_valid_float() const;
|
||||
bool is_valid_html_color() const;
|
||||
bool is_valid_identifier() const;
|
||||
bool is_valid_integer() const;
|
||||
bool is_valid_ip_address() const;
|
||||
String json_escape() const;
|
||||
String left(int position) const;
|
||||
bool match(String expr) const;
|
||||
bool matchn(String expr) const;
|
||||
PoolByteArray md5_buffer() const;
|
||||
String md5_text() const;
|
||||
int ord_at(int at) const;
|
||||
String pad_decimals(int digits) const;
|
||||
String pad_zeros(int digits) const;
|
||||
String percent_decode() const;
|
||||
String percent_encode() const;
|
||||
String plus_file(String file) const;
|
||||
String replace(String what, String forwhat) const;
|
||||
String replacen(String what, String forwhat) const;
|
||||
int rfind(String what, int from = -1) const;
|
||||
int rfindn(String what, int from = -1) const;
|
||||
String right(int position) const;
|
||||
PoolByteArray sha256_buffer() const;
|
||||
String sha256_text() const;
|
||||
float similarity(String text) const;
|
||||
PoolStringArray split(String divisor, bool allow_empty = true) const;
|
||||
PoolIntArray split_ints(String divisor, bool allow_empty = true) const;
|
||||
PoolRealArray split_floats(String divisor, bool allow_empty = true) const;
|
||||
String strip_edges(bool left = true, bool right = true) const;
|
||||
String substr(int from, int len) const;
|
||||
float to_float() const;
|
||||
int64_t to_int() const;
|
||||
String to_lower() const;
|
||||
String to_upper() const;
|
||||
String xml_escape() const;
|
||||
String xml_unescape() const;
|
||||
signed char casecmp_to(String p_str) const;
|
||||
signed char nocasecmp_to(String p_str) const;
|
||||
signed char naturalnocasecmp_to(String p_str) const;
|
||||
String dedent() const;
|
||||
PoolStringArray rsplit(const String &divisor, const bool allow_empty = true, const int maxsplit = 0) const;
|
||||
String rstrip(const String &chars) const;
|
||||
String trim_prefix(const String &prefix) const;
|
||||
String trim_suffix(const String &suffix) const;
|
||||
};
|
||||
|
||||
String operator+(const char *a, const String &b);
|
||||
String operator+(const wchar_t *a, const String &b);
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // STRING_H
|
||||
@@ -1,19 +0,0 @@
|
||||
#ifndef TAGDB_HPP
|
||||
#define TAGDB_HPP
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace godot {
|
||||
|
||||
namespace _TagDB {
|
||||
|
||||
void register_type(size_t type_tag, size_t base_type_tag);
|
||||
bool is_type_known(size_t type_tag);
|
||||
void register_global_type(const char *name, size_t type_tag, size_t base_type_tag);
|
||||
bool is_type_compatible(size_t type_tag, size_t base_type_tag);
|
||||
|
||||
} // namespace _TagDB
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // TAGDB_HPP
|
||||
@@ -1,91 +0,0 @@
|
||||
#ifndef TRANSFORM_H
|
||||
#define TRANSFORM_H
|
||||
|
||||
#include "Basis.hpp"
|
||||
|
||||
#include "AABB.hpp"
|
||||
#include "Plane.hpp"
|
||||
|
||||
namespace godot {
|
||||
|
||||
class Transform {
|
||||
public:
|
||||
static const Transform IDENTITY;
|
||||
static const Transform FLIP_X;
|
||||
static const Transform FLIP_Y;
|
||||
static const Transform FLIP_Z;
|
||||
|
||||
Basis basis;
|
||||
Vector3 origin;
|
||||
|
||||
void invert();
|
||||
Transform inverse() const;
|
||||
|
||||
void affine_invert();
|
||||
Transform affine_inverse() const;
|
||||
|
||||
Transform rotated(const Vector3 &p_axis, real_t p_phi) const;
|
||||
|
||||
void rotate(const Vector3 &p_axis, real_t p_phi);
|
||||
void rotate_basis(const Vector3 &p_axis, real_t p_phi);
|
||||
|
||||
void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up);
|
||||
Transform looking_at(const Vector3 &p_target, const Vector3 &p_up) const;
|
||||
|
||||
void scale(const Vector3 &p_scale);
|
||||
Transform scaled(const Vector3 &p_scale) const;
|
||||
void scale_basis(const Vector3 &p_scale);
|
||||
void translate(real_t p_tx, real_t p_ty, real_t p_tz);
|
||||
void translate(const Vector3 &p_translation);
|
||||
Transform translated(const Vector3 &p_translation) const;
|
||||
|
||||
inline const Basis &get_basis() const { return basis; }
|
||||
inline void set_basis(const Basis &p_basis) { basis = p_basis; }
|
||||
|
||||
inline const Vector3 &get_origin() const { return origin; }
|
||||
inline void set_origin(const Vector3 &p_origin) { origin = p_origin; }
|
||||
|
||||
void orthonormalize();
|
||||
Transform orthonormalized() const;
|
||||
|
||||
bool operator==(const Transform &p_transform) const;
|
||||
bool operator!=(const Transform &p_transform) const;
|
||||
|
||||
Vector3 xform(const Vector3 &p_vector) const;
|
||||
Vector3 xform_inv(const Vector3 &p_vector) const;
|
||||
|
||||
Plane xform(const Plane &p_plane) const;
|
||||
Plane xform_inv(const Plane &p_plane) const;
|
||||
|
||||
AABB xform(const AABB &p_aabb) const;
|
||||
AABB xform_inv(const AABB &p_aabb) const;
|
||||
|
||||
void operator*=(const Transform &p_transform);
|
||||
Transform operator*(const Transform &p_transform) const;
|
||||
|
||||
inline Vector3 operator*(const Vector3 &p_vector) const {
|
||||
return Vector3(
|
||||
basis.elements[0].dot(p_vector) + origin.x,
|
||||
basis.elements[1].dot(p_vector) + origin.y,
|
||||
basis.elements[2].dot(p_vector) + origin.z);
|
||||
}
|
||||
|
||||
Transform interpolate_with(const Transform &p_transform, real_t p_c) const;
|
||||
|
||||
Transform inverse_xform(const Transform &t) const;
|
||||
|
||||
void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t tx, real_t ty, real_t tz);
|
||||
|
||||
operator String() const;
|
||||
|
||||
inline Transform(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t tx, real_t ty, real_t tz) {
|
||||
set(xx, xy, xz, yx, yy, yz, zx, zy, zz, tx, ty, tz);
|
||||
}
|
||||
|
||||
Transform(const Basis &p_basis, const Vector3 &p_origin = Vector3());
|
||||
inline Transform() {}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // TRANSFORM_H
|
||||
@@ -1,106 +0,0 @@
|
||||
#ifndef TRANSFORM2D_H
|
||||
#define TRANSFORM2D_H
|
||||
|
||||
#include "Vector2.hpp"
|
||||
|
||||
namespace godot {
|
||||
|
||||
typedef Vector2 Size2;
|
||||
|
||||
struct Rect2;
|
||||
|
||||
struct Transform2D {
|
||||
static const Transform2D IDENTITY;
|
||||
static const Transform2D FLIP_X;
|
||||
static const Transform2D FLIP_Y;
|
||||
|
||||
// Warning #1: basis of Transform2D is stored differently from Basis. In terms of elements array, the basis matrix looks like "on paper":
|
||||
// M = (elements[0][0] elements[1][0])
|
||||
// (elements[0][1] elements[1][1])
|
||||
// This is such that the columns, which can be interpreted as basis vectors of the coordinate system "painted" on the object, can be accessed as elements[i].
|
||||
// Note that this is the opposite of the indices in mathematical texts, meaning: $M_{12}$ in a math book corresponds to elements[1][0] here.
|
||||
// This requires additional care when working with explicit indices.
|
||||
// See https://en.wikipedia.org/wiki/Row-_and_column-major_order for further reading.
|
||||
|
||||
// Warning #2: 2D be aware that unlike 3D code, 2D code uses a left-handed coordinate system: Y-axis points down,
|
||||
// and angle is measure from +X to +Y in a clockwise-fashion.
|
||||
|
||||
Vector2 elements[3];
|
||||
|
||||
inline real_t tdotx(const Vector2 &v) const { return elements[0][0] * v.x + elements[1][0] * v.y; }
|
||||
inline real_t tdoty(const Vector2 &v) const { return elements[0][1] * v.x + elements[1][1] * v.y; }
|
||||
|
||||
inline const Vector2 &operator[](int p_idx) const { return elements[p_idx]; }
|
||||
inline Vector2 &operator[](int p_idx) { return elements[p_idx]; }
|
||||
|
||||
inline Vector2 get_axis(int p_axis) const {
|
||||
ERR_FAIL_INDEX_V(p_axis, 3, Vector2());
|
||||
return elements[p_axis];
|
||||
}
|
||||
inline void set_axis(int p_axis, const Vector2 &p_vec) {
|
||||
ERR_FAIL_INDEX(p_axis, 3);
|
||||
elements[p_axis] = p_vec;
|
||||
}
|
||||
|
||||
void invert();
|
||||
Transform2D inverse() const;
|
||||
|
||||
void affine_invert();
|
||||
Transform2D affine_inverse() const;
|
||||
|
||||
void set_rotation(real_t p_phi);
|
||||
real_t get_rotation() const;
|
||||
void set_rotation_and_scale(real_t p_phi, const Size2 &p_scale);
|
||||
void rotate(real_t p_phi);
|
||||
|
||||
void scale(const Size2 &p_scale);
|
||||
void scale_basis(const Size2 &p_scale);
|
||||
void translate(real_t p_tx, real_t p_ty);
|
||||
void translate(const Vector2 &p_translation);
|
||||
|
||||
real_t basis_determinant() const;
|
||||
|
||||
Size2 get_scale() const;
|
||||
|
||||
inline const Vector2 &get_origin() const { return elements[2]; }
|
||||
inline void set_origin(const Vector2 &p_origin) { elements[2] = p_origin; }
|
||||
|
||||
Transform2D scaled(const Size2 &p_scale) const;
|
||||
Transform2D basis_scaled(const Size2 &p_scale) const;
|
||||
Transform2D translated(const Vector2 &p_offset) const;
|
||||
Transform2D rotated(real_t p_phi) const;
|
||||
|
||||
Transform2D untranslated() const;
|
||||
|
||||
void orthonormalize();
|
||||
Transform2D orthonormalized() const;
|
||||
|
||||
bool operator==(const Transform2D &p_transform) const;
|
||||
bool operator!=(const Transform2D &p_transform) const;
|
||||
|
||||
void operator*=(const Transform2D &p_transform);
|
||||
Transform2D operator*(const Transform2D &p_transform) const;
|
||||
|
||||
Transform2D interpolate_with(const Transform2D &p_transform, real_t p_c) const;
|
||||
|
||||
Vector2 basis_xform(const Vector2 &p_vec) const;
|
||||
Vector2 basis_xform_inv(const Vector2 &p_vec) const;
|
||||
Vector2 xform(const Vector2 &p_vec) const;
|
||||
Vector2 xform_inv(const Vector2 &p_vec) const;
|
||||
Rect2 xform(const Rect2 &p_vec) const;
|
||||
Rect2 xform_inv(const Rect2 &p_vec) const;
|
||||
|
||||
operator String() const;
|
||||
|
||||
Transform2D(real_t xx, real_t xy, real_t yx, real_t yy, real_t ox, real_t oy);
|
||||
|
||||
Transform2D(real_t p_rot, const Vector2 &p_pos);
|
||||
inline Transform2D() {
|
||||
elements[0][0] = 1.0;
|
||||
elements[1][1] = 1.0;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // TRANSFORM2D_H
|
||||
@@ -1,276 +0,0 @@
|
||||
#ifndef VARIANT_H
|
||||
#define VARIANT_H
|
||||
|
||||
#include <gdnative/variant.h>
|
||||
|
||||
#include "Defs.hpp"
|
||||
|
||||
#include "AABB.hpp"
|
||||
#include "Basis.hpp"
|
||||
#include "Color.hpp"
|
||||
#include "NodePath.hpp"
|
||||
#include "Plane.hpp"
|
||||
#include "PoolArrays.hpp"
|
||||
#include "Quat.hpp"
|
||||
#include "RID.hpp"
|
||||
#include "Rect2.hpp"
|
||||
#include "String.hpp"
|
||||
#include "Transform.hpp"
|
||||
#include "Transform2D.hpp"
|
||||
#include "Vector2.hpp"
|
||||
#include "Vector3.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class Dictionary;
|
||||
|
||||
class Array;
|
||||
|
||||
class Variant {
|
||||
godot_variant _godot_variant;
|
||||
|
||||
friend class Array;
|
||||
inline explicit Variant(godot_variant v) {
|
||||
_godot_variant = v;
|
||||
}
|
||||
|
||||
public:
|
||||
enum Type {
|
||||
|
||||
NIL,
|
||||
|
||||
// atomic types
|
||||
BOOL,
|
||||
INT,
|
||||
REAL,
|
||||
STRING,
|
||||
|
||||
// math types
|
||||
|
||||
VECTOR2, // 5
|
||||
RECT2,
|
||||
VECTOR3,
|
||||
TRANSFORM2D,
|
||||
PLANE,
|
||||
QUAT, // 10
|
||||
RECT3, //sorry naming convention fail :( not like it's used often
|
||||
BASIS,
|
||||
TRANSFORM,
|
||||
|
||||
// misc types
|
||||
COLOR,
|
||||
NODE_PATH, // 15
|
||||
_RID,
|
||||
OBJECT,
|
||||
DICTIONARY,
|
||||
ARRAY,
|
||||
|
||||
// arrays
|
||||
POOL_BYTE_ARRAY, // 20
|
||||
POOL_INT_ARRAY,
|
||||
POOL_REAL_ARRAY,
|
||||
POOL_STRING_ARRAY,
|
||||
POOL_VECTOR2_ARRAY,
|
||||
POOL_VECTOR3_ARRAY, // 25
|
||||
POOL_COLOR_ARRAY,
|
||||
|
||||
VARIANT_MAX
|
||||
|
||||
};
|
||||
|
||||
enum Operator {
|
||||
|
||||
//comparation
|
||||
OP_EQUAL,
|
||||
OP_NOT_EQUAL,
|
||||
OP_LESS,
|
||||
OP_LESS_EQUAL,
|
||||
OP_GREATER,
|
||||
OP_GREATER_EQUAL,
|
||||
|
||||
//mathematic
|
||||
OP_ADD,
|
||||
OP_SUBSTRACT,
|
||||
OP_MULTIPLY,
|
||||
OP_DIVIDE,
|
||||
OP_NEGATE,
|
||||
OP_POSITIVE,
|
||||
OP_MODULE,
|
||||
OP_STRING_CONCAT,
|
||||
|
||||
//bitwise
|
||||
OP_SHIFT_LEFT,
|
||||
OP_SHIFT_RIGHT,
|
||||
OP_BIT_AND,
|
||||
OP_BIT_OR,
|
||||
OP_BIT_XOR,
|
||||
OP_BIT_NEGATE,
|
||||
|
||||
//logic
|
||||
OP_AND,
|
||||
OP_OR,
|
||||
OP_XOR,
|
||||
OP_NOT,
|
||||
|
||||
//containment
|
||||
OP_IN,
|
||||
OP_MAX
|
||||
|
||||
};
|
||||
|
||||
Variant();
|
||||
|
||||
Variant(const Variant &v);
|
||||
|
||||
Variant(bool p_bool);
|
||||
|
||||
Variant(signed int p_int);
|
||||
|
||||
Variant(unsigned int p_int);
|
||||
|
||||
Variant(signed short p_short);
|
||||
|
||||
inline Variant(unsigned short p_short) :
|
||||
Variant((unsigned int)p_short) {}
|
||||
|
||||
inline Variant(signed char p_char) :
|
||||
Variant((signed int)p_char) {}
|
||||
|
||||
inline Variant(unsigned char p_char) :
|
||||
Variant((unsigned int)p_char) {}
|
||||
Variant(int64_t p_char);
|
||||
|
||||
Variant(uint64_t p_char);
|
||||
|
||||
Variant(float p_float);
|
||||
|
||||
Variant(double p_double);
|
||||
|
||||
Variant(const String &p_string);
|
||||
|
||||
Variant(const char *const p_cstring);
|
||||
|
||||
Variant(const wchar_t *p_wstring);
|
||||
|
||||
Variant(const Vector2 &p_vector2);
|
||||
|
||||
Variant(const Rect2 &p_rect2);
|
||||
|
||||
Variant(const Vector3 &p_vector3);
|
||||
|
||||
Variant(const Plane &p_plane);
|
||||
|
||||
Variant(const AABB &p_aabb);
|
||||
|
||||
Variant(const Quat &p_quat);
|
||||
|
||||
Variant(const Basis &p_transform);
|
||||
|
||||
Variant(const Transform2D &p_transform);
|
||||
|
||||
Variant(const Transform &p_transform);
|
||||
|
||||
Variant(const Color &p_color);
|
||||
|
||||
Variant(const NodePath &p_path);
|
||||
|
||||
Variant(const RID &p_rid);
|
||||
|
||||
Variant(const Object *p_object);
|
||||
|
||||
Variant(const Dictionary &p_dictionary);
|
||||
|
||||
Variant(const Array &p_array);
|
||||
|
||||
Variant(const PoolByteArray &p_raw_array);
|
||||
|
||||
Variant(const PoolIntArray &p_int_array);
|
||||
|
||||
Variant(const PoolRealArray &p_real_array);
|
||||
|
||||
Variant(const PoolStringArray &p_string_array);
|
||||
|
||||
Variant(const PoolVector2Array &p_vector2_array);
|
||||
|
||||
Variant(const PoolVector3Array &p_vector3_array);
|
||||
|
||||
Variant(const PoolColorArray &p_color_array);
|
||||
|
||||
Variant &operator=(const Variant &v);
|
||||
|
||||
operator bool() const;
|
||||
operator signed int() const;
|
||||
operator unsigned int() const;
|
||||
operator signed short() const;
|
||||
operator unsigned short() const;
|
||||
operator signed char() const;
|
||||
operator unsigned char() const;
|
||||
operator int64_t() const;
|
||||
operator uint64_t() const;
|
||||
|
||||
operator wchar_t() const;
|
||||
|
||||
operator float() const;
|
||||
|
||||
operator double() const;
|
||||
operator String() const;
|
||||
operator Vector2() const;
|
||||
operator Rect2() const;
|
||||
operator Vector3() const;
|
||||
operator Plane() const;
|
||||
operator AABB() const;
|
||||
operator Quat() const;
|
||||
operator Basis() const;
|
||||
operator Transform() const;
|
||||
operator Transform2D() const;
|
||||
|
||||
operator Color() const;
|
||||
|
||||
operator NodePath() const;
|
||||
operator RID() const;
|
||||
operator godot_object *() const;
|
||||
|
||||
template <typename T>
|
||||
operator T *() const { return static_cast<T *>(T::___get_from_variant(*this)); }
|
||||
|
||||
operator Dictionary() const;
|
||||
operator Array() const;
|
||||
|
||||
operator PoolByteArray() const;
|
||||
operator PoolIntArray() const;
|
||||
operator PoolRealArray() const;
|
||||
operator PoolStringArray() const;
|
||||
operator PoolVector2Array() const;
|
||||
operator PoolVector3Array() const;
|
||||
operator PoolColorArray() const;
|
||||
|
||||
Type get_type() const;
|
||||
|
||||
Variant call(const String &method, const Variant **args, const int arg_count);
|
||||
|
||||
bool has_method(const String &method);
|
||||
|
||||
bool operator==(const Variant &b) const;
|
||||
|
||||
bool operator!=(const Variant &b) const;
|
||||
|
||||
bool operator<(const Variant &b) const;
|
||||
|
||||
bool operator<=(const Variant &b) const;
|
||||
|
||||
bool operator>(const Variant &b) const;
|
||||
|
||||
bool operator>=(const Variant &b) const;
|
||||
|
||||
bool hash_compare(const Variant &b) const;
|
||||
|
||||
bool booleanize() const;
|
||||
|
||||
~Variant();
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // VARIANT_H
|
||||
@@ -1,276 +0,0 @@
|
||||
#ifndef VECTOR2_H
|
||||
#define VECTOR2_H
|
||||
|
||||
#include <gdnative/vector2.h>
|
||||
|
||||
#include "Defs.hpp"
|
||||
|
||||
#include <Math.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class String;
|
||||
|
||||
struct Vector2 {
|
||||
enum Axis {
|
||||
AXIS_X = 0,
|
||||
AXIS_Y,
|
||||
AXIS_COUNT
|
||||
};
|
||||
|
||||
static const Vector2 ZERO;
|
||||
static const Vector2 ONE;
|
||||
static const Vector2 INF;
|
||||
|
||||
// Coordinate system of the 2D engine
|
||||
static const Vector2 LEFT;
|
||||
static const Vector2 RIGHT;
|
||||
static const Vector2 UP;
|
||||
static const Vector2 DOWN;
|
||||
|
||||
union {
|
||||
real_t x;
|
||||
real_t width;
|
||||
};
|
||||
union {
|
||||
real_t y;
|
||||
real_t height;
|
||||
};
|
||||
|
||||
inline Vector2(real_t p_x, real_t p_y) {
|
||||
x = p_x;
|
||||
y = p_y;
|
||||
}
|
||||
|
||||
inline Vector2() {
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
inline real_t &operator[](int p_idx) {
|
||||
return p_idx ? y : x;
|
||||
}
|
||||
|
||||
inline const real_t &operator[](int p_idx) const {
|
||||
return p_idx ? y : x;
|
||||
}
|
||||
|
||||
inline Vector2 operator+(const Vector2 &p_v) const {
|
||||
return Vector2(x + p_v.x, y + p_v.y);
|
||||
}
|
||||
|
||||
inline void operator+=(const Vector2 &p_v) {
|
||||
x += p_v.x;
|
||||
y += p_v.y;
|
||||
}
|
||||
|
||||
inline Vector2 operator-(const Vector2 &p_v) const {
|
||||
return Vector2(x - p_v.x, y - p_v.y);
|
||||
}
|
||||
|
||||
inline void operator-=(const Vector2 &p_v) {
|
||||
x -= p_v.x;
|
||||
y -= p_v.y;
|
||||
}
|
||||
|
||||
inline Vector2 operator*(const Vector2 &p_v1) const {
|
||||
return Vector2(x * p_v1.x, y * p_v1.y);
|
||||
}
|
||||
|
||||
inline Vector2 operator*(const real_t &rvalue) const {
|
||||
return Vector2(x * rvalue, y * rvalue);
|
||||
}
|
||||
|
||||
inline void operator*=(const real_t &rvalue) {
|
||||
x *= rvalue;
|
||||
y *= rvalue;
|
||||
}
|
||||
|
||||
inline void operator*=(const Vector2 &rvalue) {
|
||||
*this = *this * rvalue;
|
||||
}
|
||||
|
||||
inline Vector2 operator/(const Vector2 &p_v1) const {
|
||||
return Vector2(x / p_v1.x, y / p_v1.y);
|
||||
}
|
||||
|
||||
inline Vector2 operator/(const real_t &rvalue) const {
|
||||
return Vector2(x / rvalue, y / rvalue);
|
||||
}
|
||||
|
||||
inline void operator/=(const real_t &rvalue) {
|
||||
x /= rvalue;
|
||||
y /= rvalue;
|
||||
}
|
||||
|
||||
inline Vector2 operator-() const {
|
||||
return Vector2(-x, -y);
|
||||
}
|
||||
|
||||
bool operator==(const Vector2 &p_vec2) const;
|
||||
|
||||
bool operator!=(const Vector2 &p_vec2) const;
|
||||
|
||||
inline bool operator<(const Vector2 &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); }
|
||||
inline bool operator<=(const Vector2 &p_vec2) const { return (x == p_vec2.x) ? (y <= p_vec2.y) : (x <= p_vec2.x); }
|
||||
|
||||
inline void normalize() {
|
||||
real_t l = x * x + y * y;
|
||||
if (l != 0) {
|
||||
l = sqrt(l);
|
||||
x /= l;
|
||||
y /= l;
|
||||
}
|
||||
}
|
||||
|
||||
inline Vector2 normalized() const {
|
||||
Vector2 v = *this;
|
||||
v.normalize();
|
||||
return v;
|
||||
}
|
||||
|
||||
inline real_t length() const {
|
||||
return sqrt(x * x + y * y);
|
||||
}
|
||||
|
||||
inline real_t length_squared() const {
|
||||
return x * x + y * y;
|
||||
}
|
||||
|
||||
inline real_t distance_to(const Vector2 &p_vector2) const {
|
||||
return sqrt((x - p_vector2.x) * (x - p_vector2.x) + (y - p_vector2.y) * (y - p_vector2.y));
|
||||
}
|
||||
|
||||
inline real_t distance_squared_to(const Vector2 &p_vector2) const {
|
||||
return (x - p_vector2.x) * (x - p_vector2.x) + (y - p_vector2.y) * (y - p_vector2.y);
|
||||
}
|
||||
|
||||
inline real_t angle_to(const Vector2 &p_vector2) const {
|
||||
return atan2(cross(p_vector2), dot(p_vector2));
|
||||
}
|
||||
|
||||
inline real_t angle_to_point(const Vector2 &p_vector2) const {
|
||||
return atan2(y - p_vector2.y, x - p_vector2.x);
|
||||
}
|
||||
|
||||
inline Vector2 direction_to(const Vector2 &p_b) const {
|
||||
Vector2 ret(p_b.x - x, p_b.y - y);
|
||||
ret.normalize();
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline real_t dot(const Vector2 &p_other) const {
|
||||
return x * p_other.x + y * p_other.y;
|
||||
}
|
||||
|
||||
inline real_t cross(const Vector2 &p_other) const {
|
||||
return x * p_other.y - y * p_other.x;
|
||||
}
|
||||
|
||||
inline Vector2 cross(real_t p_other) const {
|
||||
return Vector2(p_other * y, -p_other * x);
|
||||
}
|
||||
|
||||
Vector2 project(const Vector2 &p_vec) const;
|
||||
|
||||
Vector2 plane_project(real_t p_d, const Vector2 &p_vec) const;
|
||||
|
||||
Vector2 clamped(real_t p_len) const;
|
||||
|
||||
static inline Vector2 linear_interpolate(const Vector2 &p_a, const Vector2 &p_b, real_t p_t) {
|
||||
Vector2 res = p_a;
|
||||
res.x += (p_t * (p_b.x - p_a.x));
|
||||
res.y += (p_t * (p_b.y - p_a.y));
|
||||
return res;
|
||||
}
|
||||
|
||||
inline Vector2 linear_interpolate(const Vector2 &p_b, real_t p_t) const {
|
||||
Vector2 res = *this;
|
||||
res.x += (p_t * (p_b.x - x));
|
||||
res.y += (p_t * (p_b.y - y));
|
||||
return res;
|
||||
}
|
||||
|
||||
Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_t) const;
|
||||
|
||||
Vector2 move_toward(const Vector2 &p_to, const real_t p_delta) const {
|
||||
Vector2 v = *this;
|
||||
Vector2 vd = p_to - v;
|
||||
real_t len = vd.length();
|
||||
return len <= p_delta || len < CMP_EPSILON ? p_to : v + vd / len * p_delta;
|
||||
}
|
||||
|
||||
inline Vector2 slide(const Vector2 &p_vec) const {
|
||||
return p_vec - *this * this->dot(p_vec);
|
||||
}
|
||||
|
||||
inline Vector2 bounce(const Vector2 &p_normal) const {
|
||||
return -reflect(p_normal);
|
||||
}
|
||||
|
||||
inline Vector2 reflect(const Vector2 &p_normal) const {
|
||||
return -(*this - p_normal * this->dot(p_normal) * 2.0);
|
||||
}
|
||||
|
||||
inline real_t angle() const {
|
||||
return atan2(y, x);
|
||||
}
|
||||
|
||||
inline void set_rotation(real_t p_radians) {
|
||||
x = cosf(p_radians);
|
||||
y = sinf(p_radians);
|
||||
}
|
||||
|
||||
inline Vector2 abs() const {
|
||||
return Vector2(fabs(x), fabs(y));
|
||||
}
|
||||
|
||||
inline Vector2 rotated(real_t p_by) const {
|
||||
Vector2 v;
|
||||
v.set_rotation(angle() + p_by);
|
||||
v *= length();
|
||||
return v;
|
||||
}
|
||||
|
||||
inline Vector2 tangent() const {
|
||||
return Vector2(y, -x);
|
||||
}
|
||||
|
||||
inline Vector2 floor() const {
|
||||
return Vector2(Math::floor(x), Math::floor(y));
|
||||
}
|
||||
|
||||
inline Vector2 snapped(const Vector2 &p_by) const {
|
||||
return Vector2(
|
||||
Math::stepify(x, p_by.x),
|
||||
Math::stepify(y, p_by.y));
|
||||
}
|
||||
|
||||
inline real_t aspect() const { return width / height; }
|
||||
|
||||
operator String() const;
|
||||
};
|
||||
|
||||
inline Vector2 operator*(real_t p_scalar, const Vector2 &p_vec) {
|
||||
return p_vec * p_scalar;
|
||||
}
|
||||
|
||||
namespace Math {
|
||||
|
||||
// Convenience, since they exist in GDScript
|
||||
|
||||
inline Vector2 cartesian2polar(Vector2 v) {
|
||||
return Vector2(Math::sqrt(v.x * v.x + v.y * v.y), Math::atan2(v.y, v.x));
|
||||
}
|
||||
|
||||
inline Vector2 polar2cartesian(Vector2 v) {
|
||||
// x == radius
|
||||
// y == angle
|
||||
return Vector2(v.x * Math::cos(v.y), v.x * Math::sin(v.y));
|
||||
}
|
||||
|
||||
} // namespace Math
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // VECTOR2_H
|
||||
@@ -1,312 +0,0 @@
|
||||
#ifndef VECTOR3_H
|
||||
#define VECTOR3_H
|
||||
|
||||
#include <gdnative/vector3.h>
|
||||
|
||||
#include "Defs.hpp"
|
||||
|
||||
#include "String.hpp"
|
||||
|
||||
#include <Math.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class Basis;
|
||||
|
||||
struct Vector3 {
|
||||
enum Axis {
|
||||
AXIS_X,
|
||||
AXIS_Y,
|
||||
AXIS_Z,
|
||||
AXIS_COUNT
|
||||
};
|
||||
|
||||
static const Vector3 ZERO;
|
||||
static const Vector3 ONE;
|
||||
static const Vector3 INF;
|
||||
|
||||
// Coordinate system of the 3D engine
|
||||
static const Vector3 LEFT;
|
||||
static const Vector3 RIGHT;
|
||||
static const Vector3 UP;
|
||||
static const Vector3 DOWN;
|
||||
static const Vector3 FORWARD;
|
||||
static const Vector3 BACK;
|
||||
|
||||
union {
|
||||
struct {
|
||||
real_t x;
|
||||
real_t y;
|
||||
real_t z;
|
||||
};
|
||||
|
||||
real_t coord[3]; // Not for direct access, use [] operator instead
|
||||
};
|
||||
|
||||
inline Vector3(real_t x, real_t y, real_t z) {
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
this->z = z;
|
||||
}
|
||||
|
||||
inline Vector3() {
|
||||
this->x = 0;
|
||||
this->y = 0;
|
||||
this->z = 0;
|
||||
}
|
||||
|
||||
inline const real_t &operator[](int p_axis) const {
|
||||
return coord[p_axis];
|
||||
}
|
||||
|
||||
inline real_t &operator[](int p_axis) {
|
||||
return coord[p_axis];
|
||||
}
|
||||
|
||||
inline Vector3 &operator+=(const Vector3 &p_v) {
|
||||
x += p_v.x;
|
||||
y += p_v.y;
|
||||
z += p_v.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vector3 operator+(const Vector3 &p_v) const {
|
||||
Vector3 v = *this;
|
||||
v += p_v;
|
||||
return v;
|
||||
}
|
||||
|
||||
inline Vector3 &operator-=(const Vector3 &p_v) {
|
||||
x -= p_v.x;
|
||||
y -= p_v.y;
|
||||
z -= p_v.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vector3 operator-(const Vector3 &p_v) const {
|
||||
Vector3 v = *this;
|
||||
v -= p_v;
|
||||
return v;
|
||||
}
|
||||
|
||||
inline Vector3 &operator*=(const Vector3 &p_v) {
|
||||
x *= p_v.x;
|
||||
y *= p_v.y;
|
||||
z *= p_v.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vector3 operator*(const Vector3 &p_v) const {
|
||||
Vector3 v = *this;
|
||||
v *= p_v;
|
||||
return v;
|
||||
}
|
||||
|
||||
inline Vector3 &operator/=(const Vector3 &p_v) {
|
||||
x /= p_v.x;
|
||||
y /= p_v.y;
|
||||
z /= p_v.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vector3 operator/(const Vector3 &p_v) const {
|
||||
Vector3 v = *this;
|
||||
v /= p_v;
|
||||
return v;
|
||||
}
|
||||
|
||||
inline Vector3 &operator*=(real_t p_scalar) {
|
||||
*this *= Vector3(p_scalar, p_scalar, p_scalar);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vector3 operator*(real_t p_scalar) const {
|
||||
Vector3 v = *this;
|
||||
v *= p_scalar;
|
||||
return v;
|
||||
}
|
||||
|
||||
inline Vector3 &operator/=(real_t p_scalar) {
|
||||
*this /= Vector3(p_scalar, p_scalar, p_scalar);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vector3 operator/(real_t p_scalar) const {
|
||||
Vector3 v = *this;
|
||||
v /= p_scalar;
|
||||
return v;
|
||||
}
|
||||
|
||||
inline Vector3 operator-() const {
|
||||
return Vector3(-x, -y, -z);
|
||||
}
|
||||
|
||||
inline bool operator==(const Vector3 &p_v) const {
|
||||
return (x == p_v.x && y == p_v.y && z == p_v.z);
|
||||
}
|
||||
|
||||
inline bool operator!=(const Vector3 &p_v) const {
|
||||
return (x != p_v.x || y != p_v.y || z != p_v.z);
|
||||
}
|
||||
|
||||
bool operator<(const Vector3 &p_v) const;
|
||||
|
||||
bool operator<=(const Vector3 &p_v) const;
|
||||
|
||||
inline Vector3 abs() const {
|
||||
return Vector3(::fabs(x), ::fabs(y), ::fabs(z));
|
||||
}
|
||||
|
||||
inline Vector3 ceil() const {
|
||||
return Vector3(::ceil(x), ::ceil(y), ::ceil(z));
|
||||
}
|
||||
|
||||
inline Vector3 cross(const Vector3 &b) const {
|
||||
Vector3 ret(
|
||||
(y * b.z) - (z * b.y),
|
||||
(z * b.x) - (x * b.z),
|
||||
(x * b.y) - (y * b.x));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline Vector3 linear_interpolate(const Vector3 &p_b, real_t p_t) const {
|
||||
return Vector3(
|
||||
x + (p_t * (p_b.x - x)),
|
||||
y + (p_t * (p_b.y - y)),
|
||||
z + (p_t * (p_b.z - z)));
|
||||
}
|
||||
|
||||
inline Vector3 slerp(const Vector3 &p_b, real_t p_t) const {
|
||||
real_t theta = angle_to(p_b);
|
||||
return rotated(cross(p_b).normalized(), theta * p_t);
|
||||
}
|
||||
|
||||
Vector3 cubic_interpolate(const Vector3 &b, const Vector3 &pre_a, const Vector3 &post_b, const real_t t) const;
|
||||
|
||||
Vector3 move_toward(const Vector3 &p_to, const real_t p_delta) const {
|
||||
Vector3 v = *this;
|
||||
Vector3 vd = p_to - v;
|
||||
real_t len = vd.length();
|
||||
return len <= p_delta || len < CMP_EPSILON ? p_to : v + vd / len * p_delta;
|
||||
}
|
||||
|
||||
Vector3 bounce(const Vector3 &p_normal) const {
|
||||
return -reflect(p_normal);
|
||||
}
|
||||
|
||||
inline real_t length() const {
|
||||
real_t x2 = x * x;
|
||||
real_t y2 = y * y;
|
||||
real_t z2 = z * z;
|
||||
|
||||
return ::sqrt(x2 + y2 + z2);
|
||||
}
|
||||
|
||||
inline real_t length_squared() const {
|
||||
real_t x2 = x * x;
|
||||
real_t y2 = y * y;
|
||||
real_t z2 = z * z;
|
||||
|
||||
return x2 + y2 + z2;
|
||||
}
|
||||
|
||||
inline real_t distance_squared_to(const Vector3 &b) const {
|
||||
return (b - *this).length_squared();
|
||||
}
|
||||
|
||||
inline real_t distance_to(const Vector3 &b) const {
|
||||
return (b - *this).length();
|
||||
}
|
||||
|
||||
inline real_t dot(const Vector3 &b) const {
|
||||
return x * b.x + y * b.y + z * b.z;
|
||||
}
|
||||
|
||||
inline Vector3 project(const Vector3 &p_b) const {
|
||||
return p_b * (dot(p_b) / p_b.length_squared());
|
||||
}
|
||||
|
||||
inline real_t angle_to(const Vector3 &b) const {
|
||||
return std::atan2(cross(b).length(), dot(b));
|
||||
}
|
||||
|
||||
inline Vector3 direction_to(const Vector3 &p_b) const {
|
||||
Vector3 ret(p_b.x - x, p_b.y - y, p_b.z - z);
|
||||
ret.normalize();
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline Vector3 floor() const {
|
||||
return Vector3(::floor(x), ::floor(y), ::floor(z));
|
||||
}
|
||||
|
||||
inline Vector3 inverse() const {
|
||||
return Vector3(1.f / x, 1.f / y, 1.f / z);
|
||||
}
|
||||
|
||||
inline bool is_normalized() const {
|
||||
return std::abs(length_squared() - 1.f) < 0.00001f;
|
||||
}
|
||||
|
||||
Basis outer(const Vector3 &b) const;
|
||||
|
||||
int max_axis() const;
|
||||
|
||||
int min_axis() const;
|
||||
|
||||
inline void normalize() {
|
||||
real_t l = length();
|
||||
if (l == 0) {
|
||||
x = y = z = 0;
|
||||
} else {
|
||||
x /= l;
|
||||
y /= l;
|
||||
z /= l;
|
||||
}
|
||||
}
|
||||
|
||||
inline Vector3 normalized() const {
|
||||
Vector3 v = *this;
|
||||
v.normalize();
|
||||
return v;
|
||||
}
|
||||
|
||||
inline Vector3 reflect(const Vector3 &p_normal) const {
|
||||
return -(*this - p_normal * this->dot(p_normal) * 2.0);
|
||||
}
|
||||
|
||||
inline Vector3 rotated(const Vector3 &axis, const real_t phi) const {
|
||||
Vector3 v = *this;
|
||||
v.rotate(axis, phi);
|
||||
return v;
|
||||
}
|
||||
|
||||
void rotate(const Vector3 &p_axis, real_t p_phi);
|
||||
|
||||
inline Vector3 slide(const Vector3 &by) const {
|
||||
return *this - by * this->dot(by);
|
||||
}
|
||||
|
||||
void snap(real_t p_val);
|
||||
|
||||
inline Vector3 snapped(const float by) {
|
||||
Vector3 v = *this;
|
||||
v.snap(by);
|
||||
return v;
|
||||
}
|
||||
|
||||
operator String() const;
|
||||
};
|
||||
|
||||
inline Vector3 operator*(real_t p_scalar, const Vector3 &p_vec) {
|
||||
return p_vec * p_scalar;
|
||||
}
|
||||
|
||||
inline Vector3 vec3_cross(const Vector3 &p_a, const Vector3 &p_b) {
|
||||
return p_a.cross(p_b);
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // VECTOR3_H
|
||||
@@ -1,17 +0,0 @@
|
||||
#ifndef WRAPPED_HPP
|
||||
#define WRAPPED_HPP
|
||||
|
||||
#include <gdnative/gdnative.h>
|
||||
|
||||
namespace godot {
|
||||
|
||||
// This is an internal base class used by the bindings. You should not need to access its members.
|
||||
class _Wrapped {
|
||||
public:
|
||||
godot_object *_owner;
|
||||
size_t _type_tag;
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // WRAPPED_HPP
|
||||
2
include/gen/.gitignore
vendored
2
include/gen/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
*
|
||||
!.gitignore
|
||||
62
include/godot_cpp/classes/editor_plugin_registration.hpp
Normal file
62
include/godot_cpp/classes/editor_plugin_registration.hpp
Normal 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
|
||||
288
include/godot_cpp/classes/ref.hpp
Normal file
288
include/godot_cpp/classes/ref.hpp
Normal file
@@ -0,0 +1,288 @@
|
||||
/**************************************************************************/
|
||||
/* ref.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_REF_HPP
|
||||
#define GODOT_REF_HPP
|
||||
|
||||
#include <godot_cpp/core/defs.hpp>
|
||||
|
||||
#include <godot_cpp/classes/object.hpp>
|
||||
#include <godot_cpp/classes/ref_counted.hpp>
|
||||
#include <godot_cpp/core/binder_common.hpp>
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
#include <godot_cpp/variant/variant.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
// Helper class for RefCounted objects, same as Godot one.
|
||||
|
||||
class RefCounted;
|
||||
|
||||
template <typename T>
|
||||
class Ref {
|
||||
T *reference = nullptr;
|
||||
|
||||
void ref(const Ref &p_from) {
|
||||
if (p_from.reference == reference) {
|
||||
return;
|
||||
}
|
||||
|
||||
unref();
|
||||
|
||||
reference = p_from.reference;
|
||||
if (reference) {
|
||||
reference->reference();
|
||||
}
|
||||
}
|
||||
|
||||
void ref_pointer(T *p_ref) {
|
||||
ERR_FAIL_NULL(p_ref);
|
||||
|
||||
if (p_ref->init_ref()) {
|
||||
reference = p_ref;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ bool operator==(const T *p_ptr) const {
|
||||
return reference == p_ptr;
|
||||
}
|
||||
_FORCE_INLINE_ bool operator!=(const T *p_ptr) const {
|
||||
return reference != p_ptr;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator<(const Ref<T> &p_r) const {
|
||||
return reference < p_r.reference;
|
||||
}
|
||||
_FORCE_INLINE_ bool operator==(const Ref<T> &p_r) const {
|
||||
return reference == p_r.reference;
|
||||
}
|
||||
_FORCE_INLINE_ bool operator!=(const Ref<T> &p_r) const {
|
||||
return reference != p_r.reference;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ T *operator*() const {
|
||||
return reference;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ T *operator->() const {
|
||||
return reference;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ T *ptr() const {
|
||||
return reference;
|
||||
}
|
||||
|
||||
operator Variant() const {
|
||||
return Variant(reference);
|
||||
}
|
||||
|
||||
void operator=(const Ref &p_from) {
|
||||
ref(p_from);
|
||||
}
|
||||
|
||||
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) {
|
||||
unref();
|
||||
return;
|
||||
}
|
||||
|
||||
Ref r;
|
||||
r.reference = Object::cast_to<T>(refb);
|
||||
ref(r);
|
||||
r.reference = nullptr;
|
||||
}
|
||||
|
||||
void operator=(const Variant &p_variant) {
|
||||
// Needs testing, Variant has a cast to Object * here.
|
||||
|
||||
// Object *object = p_variant.get_validated_object();
|
||||
Object *object = p_variant;
|
||||
|
||||
if (object == reference) {
|
||||
return;
|
||||
}
|
||||
|
||||
unref();
|
||||
|
||||
if (!object) {
|
||||
return;
|
||||
}
|
||||
|
||||
T *r = Object::cast_to<T>(object);
|
||||
if (r && r->reference()) {
|
||||
reference = r;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T_Other>
|
||||
void reference_ptr(T_Other *p_ptr) {
|
||||
if (reference == p_ptr) {
|
||||
return;
|
||||
}
|
||||
unref();
|
||||
|
||||
T *r = Object::cast_to<T>(p_ptr);
|
||||
if (r) {
|
||||
ref_pointer(r);
|
||||
}
|
||||
}
|
||||
|
||||
Ref(const Ref &p_from) {
|
||||
ref(p_from);
|
||||
}
|
||||
|
||||
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) {
|
||||
unref();
|
||||
return;
|
||||
}
|
||||
|
||||
Ref r;
|
||||
r.reference = Object::cast_to<T>(refb);
|
||||
ref(r);
|
||||
r.reference = nullptr;
|
||||
}
|
||||
|
||||
Ref(T *p_reference) {
|
||||
if (p_reference) {
|
||||
ref_pointer(p_reference);
|
||||
}
|
||||
}
|
||||
|
||||
Ref(const Variant &p_variant) {
|
||||
// Needs testing, Variant has a cast to Object * here.
|
||||
|
||||
// Object *object = p_variant.get_validated_object();
|
||||
Object *object = p_variant;
|
||||
|
||||
if (!object) {
|
||||
return;
|
||||
}
|
||||
|
||||
T *r = Object::cast_to<T>(object);
|
||||
if (r && r->reference()) {
|
||||
reference = r;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool is_valid() const { return reference != nullptr; }
|
||||
inline bool is_null() const { return reference == nullptr; }
|
||||
|
||||
void unref() {
|
||||
if (reference && reference->unreference()) {
|
||||
memdelete(reference);
|
||||
}
|
||||
reference = nullptr;
|
||||
}
|
||||
|
||||
void instantiate() {
|
||||
ref(memnew(T()));
|
||||
}
|
||||
|
||||
Ref() {}
|
||||
|
||||
~Ref() {
|
||||
unref();
|
||||
}
|
||||
|
||||
// Used exclusively in the bindings to recreate the Ref Godot encapsulates in return values,
|
||||
// without adding to the refcount.
|
||||
inline static Ref<T> _gde_internal_constructor(Object *obj) {
|
||||
Ref<T> r;
|
||||
r.reference = (T *)obj;
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PtrToArg<Ref<T>> {
|
||||
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
|
||||
GDExtensionRefPtr ref = (GDExtensionRefPtr)p_ptr;
|
||||
if (unlikely(!p_ptr)) {
|
||||
return Ref<T>();
|
||||
}
|
||||
return Ref<T>(reinterpret_cast<T *>(godot::internal::get_object_instance_binding(godot::internal::gdextension_interface_ref_get_object(ref))));
|
||||
}
|
||||
|
||||
typedef Ref<T> EncodeT;
|
||||
|
||||
_FORCE_INLINE_ static void encode(Ref<T> p_val, void *p_ptr) {
|
||||
GDExtensionRefPtr ref = (GDExtensionRefPtr)p_ptr;
|
||||
ERR_FAIL_NULL(ref);
|
||||
|
||||
// This code assumes that p_ptr points to an unset Ref<T> variable on the Godot side
|
||||
// so we only set it if we have an object to set.
|
||||
if (p_val.is_valid()) {
|
||||
godot::internal::gdextension_interface_ref_set_object(ref, p_val->_owner);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PtrToArg<const Ref<T> &> {
|
||||
typedef Ref<T> EncodeT;
|
||||
|
||||
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
|
||||
GDExtensionRefPtr ref = const_cast<GDExtensionRefPtr>(p_ptr);
|
||||
if (unlikely(!p_ptr)) {
|
||||
return Ref<T>();
|
||||
}
|
||||
return Ref<T>(reinterpret_cast<T *>(godot::internal::get_object_instance_binding(godot::internal::gdextension_interface_ref_get_object(ref))));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct GetTypeInfo<Ref<T>, typename EnableIf<TypeInherits<RefCounted, T>::value>::type> {
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct GetTypeInfo<const Ref<T> &, typename EnableIf<TypeInherits<RefCounted, T>::value>::type> {
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_REF_HPP
|
||||
520
include/godot_cpp/classes/wrapped.hpp
Normal file
520
include/godot_cpp/classes/wrapped.hpp
Normal file
@@ -0,0 +1,520 @@
|
||||
/**************************************************************************/
|
||||
/* wrapped.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_WRAPPED_HPP
|
||||
#define GODOT_WRAPPED_HPP
|
||||
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
|
||||
#include <godot_cpp/core/property_info.hpp>
|
||||
|
||||
#include <godot_cpp/templates/list.hpp>
|
||||
#include <godot_cpp/templates/vector.hpp>
|
||||
|
||||
#include <godot_cpp/godot.hpp>
|
||||
|
||||
#if defined(MACOS_ENABLED) && defined(HOT_RELOAD_ENABLED)
|
||||
#include <mutex>
|
||||
#define _GODOT_CPP_AVOID_THREAD_LOCAL
|
||||
#define _GODOT_CPP_THREAD_LOCAL
|
||||
#else
|
||||
#define _GODOT_CPP_THREAD_LOCAL thread_local
|
||||
#endif
|
||||
|
||||
namespace godot {
|
||||
|
||||
class ClassDB;
|
||||
|
||||
typedef void GodotObject;
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool> = true>
|
||||
_ALWAYS_INLINE_ void _pre_initialize();
|
||||
|
||||
// Base for all engine classes, to contain the pointer to the engine instance.
|
||||
class Wrapped {
|
||||
friend class GDExtensionBinding;
|
||||
friend class ClassDB;
|
||||
friend void postinitialize_handler(Wrapped *);
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool>>
|
||||
friend _ALWAYS_INLINE_ void _pre_initialize();
|
||||
|
||||
#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
|
||||
static std::recursive_mutex _constructing_mutex;
|
||||
#endif
|
||||
|
||||
_GODOT_CPP_THREAD_LOCAL static const StringName *_constructing_extension_class_name;
|
||||
_GODOT_CPP_THREAD_LOCAL static const GDExtensionInstanceBindingCallbacks *_constructing_class_binding_callbacks;
|
||||
|
||||
#ifdef HOT_RELOAD_ENABLED
|
||||
_GODOT_CPP_THREAD_LOCAL static GDExtensionObjectPtr _constructing_recreate_owner;
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
_ALWAYS_INLINE_ static void _set_construct_info() {
|
||||
_constructing_extension_class_name = T::_get_extension_class_name();
|
||||
_constructing_class_binding_callbacks = &T::_gde_binding_callbacks;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool _is_extension_class() const { return false; }
|
||||
static const StringName *_get_extension_class_name(); // This is needed to retrieve the class name before the godot object has its _extension and _extension_instance members assigned.
|
||||
|
||||
void _notification(int p_what) {}
|
||||
bool _set(const StringName &p_name, const Variant &p_property) { return false; }
|
||||
bool _get(const StringName &p_name, Variant &r_property) const { return false; }
|
||||
void _get_property_list(List<PropertyInfo> *p_list) const {}
|
||||
bool _property_can_revert(const StringName &p_name) const { return false; }
|
||||
bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return false; }
|
||||
void _validate_property(PropertyInfo &p_property) const {}
|
||||
String _to_string() const { return "<Wrapped#0>"; }
|
||||
|
||||
static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what, GDExtensionBool p_reversed) {}
|
||||
static GDExtensionBool set_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionConstVariantPtr p_value) { return false; }
|
||||
static GDExtensionBool get_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { return false; }
|
||||
static const GDExtensionPropertyInfo *get_property_list_bind(GDExtensionClassInstancePtr p_instance, uint32_t *r_count) { return nullptr; }
|
||||
static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list, uint32_t p_count) {}
|
||||
static GDExtensionBool property_can_revert_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name) { return false; }
|
||||
static GDExtensionBool property_get_revert_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { return false; }
|
||||
static GDExtensionBool validate_property_bind(GDExtensionClassInstancePtr p_instance, GDExtensionPropertyInfo *p_property) { return false; }
|
||||
static void to_string_bind(GDExtensionClassInstancePtr p_instance, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out) {}
|
||||
|
||||
// The only reason this has to be held here, is when we return results of `_get_property_list` to Godot, we pass
|
||||
// pointers to strings in this list. They have to remain valid to pass the bridge, until the list is freed by Godot...
|
||||
::godot::List<::godot::PropertyInfo> plist_owned;
|
||||
|
||||
void _postinitialize();
|
||||
virtual void _notificationv(int32_t p_what, bool p_reversed = false) {}
|
||||
|
||||
Wrapped(const StringName p_godot_class);
|
||||
Wrapped(GodotObject *p_godot_object);
|
||||
virtual ~Wrapped() {}
|
||||
|
||||
public:
|
||||
static const StringName &get_class_static() {
|
||||
static const StringName string_name = StringName("Wrapped");
|
||||
return string_name;
|
||||
}
|
||||
|
||||
// Must be public but you should not touch this.
|
||||
GodotObject *_owner = nullptr;
|
||||
};
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool>>
|
||||
_ALWAYS_INLINE_ void _pre_initialize() {
|
||||
#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
|
||||
Wrapped::_constructing_mutex.lock();
|
||||
#endif
|
||||
Wrapped::_set_construct_info<T>();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void snarray_add_str(Vector<StringName> &arr) {
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void snarray_add_str(Vector<StringName> &arr, const StringName &p_str) {
|
||||
arr.push_back(p_str);
|
||||
}
|
||||
|
||||
template <typename... P>
|
||||
_FORCE_INLINE_ void snarray_add_str(Vector<StringName> &arr, const StringName &p_str, P... p_args) {
|
||||
arr.push_back(p_str);
|
||||
snarray_add_str(arr, p_args...);
|
||||
}
|
||||
|
||||
template <typename... P>
|
||||
_FORCE_INLINE_ Vector<StringName> snarray(P... p_args) {
|
||||
Vector<StringName> arr;
|
||||
snarray_add_str(arr, p_args...);
|
||||
return arr;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
GDExtensionPropertyInfo *create_c_property_list(const ::godot::List<::godot::PropertyInfo> &plist_cpp, uint32_t *r_size);
|
||||
void free_c_property_list(GDExtensionPropertyInfo *plist);
|
||||
|
||||
typedef void (*EngineClassRegistrationCallback)();
|
||||
void add_engine_class_registration_callback(EngineClassRegistrationCallback p_callback);
|
||||
void register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks);
|
||||
void register_engine_classes();
|
||||
|
||||
template <typename T>
|
||||
struct EngineClassRegistration {
|
||||
EngineClassRegistration() {
|
||||
add_engine_class_registration_callback(&EngineClassRegistration<T>::callback);
|
||||
}
|
||||
|
||||
static void callback() {
|
||||
register_engine_class(T::get_class_static(), &T::_gde_binding_callbacks);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace godot
|
||||
|
||||
// Use this on top of your own classes.
|
||||
// Note: the trail of `***` is to keep sane diffs in PRs, because clang-format otherwise moves every `\` which makes
|
||||
// every line of the macro different
|
||||
#define GDCLASS(m_class, m_inherits) /***********************************************************************************************************************************************/ \
|
||||
private: \
|
||||
void operator=(const m_class & /*p_rval*/) {} \
|
||||
friend class ::godot::ClassDB; \
|
||||
friend class ::godot::Wrapped; \
|
||||
\
|
||||
protected: \
|
||||
virtual bool _is_extension_class() const override { return true; } \
|
||||
\
|
||||
static const ::godot::StringName *_get_extension_class_name() { \
|
||||
const ::godot::StringName &string_name = get_class_static(); \
|
||||
return &string_name; \
|
||||
} \
|
||||
\
|
||||
static void (*_get_bind_methods())() { \
|
||||
return &m_class::_bind_methods; \
|
||||
} \
|
||||
\
|
||||
static void (::godot::Wrapped::*_get_notification())(int) { \
|
||||
return (void(::godot::Wrapped::*)(int)) & m_class::_notification; \
|
||||
} \
|
||||
\
|
||||
static bool (::godot::Wrapped::*_get_set())(const ::godot::StringName &p_name, const ::godot::Variant &p_property) { \
|
||||
return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name, const ::godot::Variant &p_property)) & m_class::_set; \
|
||||
} \
|
||||
\
|
||||
static bool (::godot::Wrapped::*_get_get())(const ::godot::StringName &p_name, ::godot::Variant &r_ret) const { \
|
||||
return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name, ::godot::Variant &r_ret) const) & m_class::_get; \
|
||||
} \
|
||||
\
|
||||
static void (::godot::Wrapped::*_get_get_property_list())(::godot::List<::godot::PropertyInfo> * p_list) const { \
|
||||
return (void(::godot::Wrapped::*)(::godot::List<::godot::PropertyInfo> * p_list) const) & m_class::_get_property_list; \
|
||||
} \
|
||||
\
|
||||
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 &) const { \
|
||||
return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name, ::godot::Variant &) const) & m_class::_property_get_revert; \
|
||||
} \
|
||||
\
|
||||
static void (::godot::Wrapped::*_get_validate_property())(::godot::PropertyInfo & p_property) const { \
|
||||
return (void(::godot::Wrapped::*)(::godot::PropertyInfo & p_property) const) & m_class::_validate_property; \
|
||||
} \
|
||||
\
|
||||
static ::godot::String (::godot::Wrapped::*_get_to_string())() const { \
|
||||
return (::godot::String(::godot::Wrapped::*)() const) & m_class::_to_string; \
|
||||
} \
|
||||
\
|
||||
template <typename T, typename B> \
|
||||
static void register_virtuals() { \
|
||||
m_inherits::register_virtuals<T, B>(); \
|
||||
} \
|
||||
\
|
||||
public: \
|
||||
typedef m_class self_type; \
|
||||
typedef m_inherits parent_type; \
|
||||
\
|
||||
static void initialize_class() { \
|
||||
static bool initialized = false; \
|
||||
if (initialized) { \
|
||||
return; \
|
||||
} \
|
||||
m_inherits::initialize_class(); \
|
||||
if (m_class::_get_bind_methods() != m_inherits::_get_bind_methods()) { \
|
||||
_bind_methods(); \
|
||||
m_inherits::register_virtuals<m_class, m_inherits>(); \
|
||||
} \
|
||||
initialized = true; \
|
||||
} \
|
||||
\
|
||||
static const ::godot::StringName &get_class_static() { \
|
||||
static const ::godot::StringName string_name = ::godot::StringName(#m_class); \
|
||||
return string_name; \
|
||||
} \
|
||||
\
|
||||
static const ::godot::StringName &get_parent_class_static() { \
|
||||
return m_inherits::get_class_static(); \
|
||||
} \
|
||||
\
|
||||
static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what, GDExtensionBool p_reversed) { \
|
||||
if (p_instance && m_class::_get_notification()) { \
|
||||
if (!p_reversed) { \
|
||||
m_inherits::notification_bind(p_instance, p_what, p_reversed); \
|
||||
} \
|
||||
if (m_class::_get_notification() != m_inherits::_get_notification()) { \
|
||||
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
|
||||
cls->_notification(p_what); \
|
||||
} \
|
||||
if (p_reversed) { \
|
||||
m_inherits::notification_bind(p_instance, p_what, p_reversed); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static GDExtensionBool set_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionConstVariantPtr p_value) { \
|
||||
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 false; \
|
||||
} \
|
||||
\
|
||||
static GDExtensionBool get_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { \
|
||||
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 false; \
|
||||
} \
|
||||
\
|
||||
static inline bool has_get_property_list() { \
|
||||
return m_class::_get_get_property_list() && m_class::_get_get_property_list() != m_inherits::_get_get_property_list(); \
|
||||
} \
|
||||
\
|
||||
static const GDExtensionPropertyInfo *get_property_list_bind(GDExtensionClassInstancePtr p_instance, uint32_t *r_count) { \
|
||||
if (!p_instance) { \
|
||||
if (r_count) \
|
||||
*r_count = 0; \
|
||||
return nullptr; \
|
||||
} \
|
||||
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
|
||||
::godot::List<::godot::PropertyInfo> &plist_cpp = cls->plist_owned; \
|
||||
ERR_FAIL_COND_V_MSG(!plist_cpp.is_empty(), nullptr, "Internal error, property list was not freed by engine!"); \
|
||||
cls->_get_property_list(&plist_cpp); \
|
||||
return ::godot::internal::create_c_property_list(plist_cpp, r_count); \
|
||||
} \
|
||||
\
|
||||
static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list, uint32_t /*p_count*/) { \
|
||||
if (p_instance) { \
|
||||
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
|
||||
cls->plist_owned.clear(); \
|
||||
::godot::internal::free_c_property_list(const_cast<GDExtensionPropertyInfo *>(p_list)); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static GDExtensionBool property_can_revert_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name) { \
|
||||
if (p_instance && m_class::_get_property_can_revert()) { \
|
||||
if (m_class::_get_property_can_revert() != m_inherits::_get_property_can_revert()) { \
|
||||
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
|
||||
return cls->_property_can_revert(*reinterpret_cast<const ::godot::StringName *>(p_name)); \
|
||||
} \
|
||||
return m_inherits::property_can_revert_bind(p_instance, p_name); \
|
||||
} \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
static GDExtensionBool property_get_revert_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { \
|
||||
if (p_instance && m_class::_get_property_get_revert()) { \
|
||||
if (m_class::_get_property_get_revert() != m_inherits::_get_property_get_revert()) { \
|
||||
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
|
||||
return cls->_property_get_revert(*reinterpret_cast<const ::godot::StringName *>(p_name), *reinterpret_cast<::godot::Variant *>(r_ret)); \
|
||||
} \
|
||||
return m_inherits::property_get_revert_bind(p_instance, p_name, r_ret); \
|
||||
} \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
static GDExtensionBool validate_property_bind(GDExtensionClassInstancePtr p_instance, GDExtensionPropertyInfo *p_property) { \
|
||||
bool ret = false; \
|
||||
if (p_instance && m_class::_get_validate_property()) { \
|
||||
ret = m_inherits::validate_property_bind(p_instance, p_property); \
|
||||
if (m_class::_get_validate_property() != m_inherits::_get_validate_property()) { \
|
||||
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
|
||||
::godot::PropertyInfo info(p_property); \
|
||||
cls->_validate_property(info); \
|
||||
info._update(p_property); \
|
||||
return true; \
|
||||
} \
|
||||
} \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
static void to_string_bind(GDExtensionClassInstancePtr p_instance, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out) { \
|
||||
if (p_instance && m_class::_get_to_string()) { \
|
||||
if (m_class::_get_to_string() != m_inherits::_get_to_string()) { \
|
||||
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
|
||||
*reinterpret_cast<::godot::String *>(r_out) = cls->_to_string(); \
|
||||
*r_is_valid = true; \
|
||||
return; \
|
||||
} \
|
||||
m_inherits::to_string_bind(p_instance, r_is_valid, r_out); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static void free(void * /*data*/, GDExtensionClassInstancePtr ptr) { \
|
||||
if (ptr) { \
|
||||
m_class *cls = reinterpret_cast<m_class *>(ptr); \
|
||||
cls->~m_class(); \
|
||||
::godot::Memory::free_static(cls); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
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 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, \
|
||||
}; \
|
||||
\
|
||||
protected: \
|
||||
virtual void _notificationv(int32_t p_what, bool p_reversed = false) override { \
|
||||
m_class::notification_bind(this, p_what, p_reversed); \
|
||||
} \
|
||||
\
|
||||
private:
|
||||
|
||||
// Don't use this for your classes, use GDCLASS() instead.
|
||||
#define GDEXTENSION_CLASS_ALIAS(m_class, m_alias_for, m_inherits) /******************************************************************************************************************/ \
|
||||
private: \
|
||||
inline static ::godot::internal::EngineClassRegistration<m_class> _gde_engine_class_registration_helper; \
|
||||
void operator=(const m_class &p_rval) {} \
|
||||
friend class ::godot::ClassDB; \
|
||||
friend class ::godot::Wrapped; \
|
||||
\
|
||||
protected: \
|
||||
m_class(const char *p_godot_class) : m_inherits(p_godot_class) {} \
|
||||
m_class(GodotObject *p_godot_object) : m_inherits(p_godot_object) {} \
|
||||
\
|
||||
static void _bind_methods() {} \
|
||||
\
|
||||
static void (*_get_bind_methods())() { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
static void (Wrapped::*_get_notification())(int) { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
static bool (Wrapped::*_get_set())(const ::godot::StringName &p_name, const Variant &p_property) { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
static bool (Wrapped::*_get_get())(const ::godot::StringName &p_name, Variant &r_ret) const { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
static inline bool has_get_property_list() { \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
static void (Wrapped::*_get_get_property_list())(List<PropertyInfo> * p_list) const { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
static bool (Wrapped::*_get_property_can_revert())(const ::godot::StringName &p_name) const { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
static bool (Wrapped::*_get_property_get_revert())(const ::godot::StringName &p_name, Variant &) const { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
static void (Wrapped::*_get_validate_property())(::godot::PropertyInfo & p_property) const { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
static String (Wrapped::*_get_to_string())() const { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
public: \
|
||||
typedef m_class self_type; \
|
||||
typedef m_inherits parent_type; \
|
||||
\
|
||||
static void initialize_class() {} \
|
||||
\
|
||||
static const ::godot::StringName &get_class_static() { \
|
||||
static const ::godot::StringName string_name = ::godot::StringName(#m_alias_for); \
|
||||
return string_name; \
|
||||
} \
|
||||
\
|
||||
static const ::godot::StringName &get_parent_class_static() { \
|
||||
return m_inherits::get_class_static(); \
|
||||
} \
|
||||
\
|
||||
static void free(void *data, GDExtensionClassInstancePtr ptr) { \
|
||||
} \
|
||||
\
|
||||
static void *_gde_binding_create_callback(void *p_token, void *p_instance) { \
|
||||
/* Do not call memnew here, we don't want the post-initializer to be called */ \
|
||||
return new ("", "") m_class((GodotObject *)p_instance); \
|
||||
} \
|
||||
static void _gde_binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \
|
||||
/* Explicitly call the deconstructor to ensure proper lifecycle for non-trivial members */ \
|
||||
reinterpret_cast<m_class *>(p_binding)->~m_class(); \
|
||||
Memory::free_static(reinterpret_cast<m_class *>(p_binding)); \
|
||||
} \
|
||||
static GDExtensionBool _gde_binding_reference_callback(void *p_token, void *p_instance, GDExtensionBool p_reference) { \
|
||||
return true; \
|
||||
} \
|
||||
static constexpr GDExtensionInstanceBindingCallbacks _gde_binding_callbacks = { \
|
||||
_gde_binding_create_callback, \
|
||||
_gde_binding_free_callback, \
|
||||
_gde_binding_reference_callback, \
|
||||
}; \
|
||||
m_class() : m_class(#m_alias_for) {} \
|
||||
\
|
||||
private:
|
||||
|
||||
// Don't use this for your classes, use GDCLASS() instead.
|
||||
#define GDEXTENSION_CLASS(m_class, m_inherits) GDEXTENSION_CLASS_ALIAS(m_class, m_class, m_inherits)
|
||||
|
||||
#define GDVIRTUAL_CALL(m_name, ...) _gdvirtual_##m_name##_call<false>(__VA_ARGS__)
|
||||
#define GDVIRTUAL_CALL_PTR(m_obj, m_name, ...) m_obj->_gdvirtual_##m_name##_call<false>(__VA_ARGS__)
|
||||
|
||||
#define GDVIRTUAL_REQUIRED_CALL(m_name, ...) _gdvirtual_##m_name##_call<true>(__VA_ARGS__)
|
||||
#define GDVIRTUAL_REQUIRED_CALL_PTR(m_obj, m_name, ...) m_obj->_gdvirtual_##m_name##_call<true>(__VA_ARGS__)
|
||||
|
||||
#define GDVIRTUAL_BIND(m_name, ...) ::godot::ClassDB::add_virtual_method(get_class_static(), _gdvirtual_##m_name##_get_method_info(), ::godot::snarray(__VA_ARGS__));
|
||||
#define GDVIRTUAL_IS_OVERRIDDEN(m_name) _gdvirtual_##m_name##_overridden()
|
||||
#define GDVIRTUAL_IS_OVERRIDDEN_PTR(m_obj, m_name) m_obj->_gdvirtual_##m_name##_overridden()
|
||||
|
||||
#endif // GODOT_WRAPPED_HPP
|
||||
696
include/godot_cpp/core/binder_common.hpp
Normal file
696
include/godot_cpp/core/binder_common.hpp
Normal file
@@ -0,0 +1,696 @@
|
||||
/**************************************************************************/
|
||||
/* binder_common.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_BINDER_COMMON_HPP
|
||||
#define GODOT_BINDER_COMMON_HPP
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
|
||||
#include <godot_cpp/core/method_ptrcall.hpp>
|
||||
#include <godot_cpp/core/type_info.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
namespace godot {
|
||||
|
||||
#define VARIANT_ENUM_CAST(m_enum) \
|
||||
namespace godot { \
|
||||
MAKE_ENUM_TYPE_INFO(m_enum) \
|
||||
template <> \
|
||||
struct VariantCaster<m_enum> { \
|
||||
static _FORCE_INLINE_ m_enum cast(const Variant &p_variant) { \
|
||||
return (m_enum)p_variant.operator int64_t(); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct PtrToArg<m_enum> { \
|
||||
_FORCE_INLINE_ static m_enum convert(const void *p_ptr) { \
|
||||
return m_enum(*reinterpret_cast<const int64_t *>(p_ptr)); \
|
||||
} \
|
||||
typedef int64_t EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(m_enum p_val, void *p_ptr) { \
|
||||
*reinterpret_cast<int64_t *>(p_ptr) = p_val; \
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
|
||||
#define VARIANT_BITFIELD_CAST(m_enum) \
|
||||
namespace godot { \
|
||||
MAKE_BITFIELD_TYPE_INFO(m_enum) \
|
||||
template <> \
|
||||
struct VariantCaster<BitField<m_enum>> { \
|
||||
static _FORCE_INLINE_ BitField<m_enum> cast(const Variant &p_variant) { \
|
||||
return BitField<m_enum>(p_variant.operator int64_t()); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct PtrToArg<BitField<m_enum>> { \
|
||||
_FORCE_INLINE_ static BitField<m_enum> convert(const void *p_ptr) { \
|
||||
return BitField<m_enum>(*reinterpret_cast<const int64_t *>(p_ptr)); \
|
||||
} \
|
||||
typedef int64_t EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(BitField<m_enum> p_val, void *p_ptr) { \
|
||||
*reinterpret_cast<int64_t *>(p_ptr) = p_val; \
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct VariantCaster {
|
||||
static _FORCE_INLINE_ T cast(const Variant &p_variant) {
|
||||
using TStripped = std::remove_pointer_t<T>;
|
||||
if constexpr (std::is_base_of<Object, TStripped>::value) {
|
||||
return Object::cast_to<TStripped>(p_variant);
|
||||
} else {
|
||||
return p_variant;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct VariantCaster<T &> {
|
||||
static _FORCE_INLINE_ T cast(const Variant &p_variant) {
|
||||
using TStripped = std::remove_pointer_t<T>;
|
||||
if constexpr (std::is_base_of<Object, TStripped>::value) {
|
||||
return Object::cast_to<TStripped>(p_variant);
|
||||
} else {
|
||||
return p_variant;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct VariantCaster<const T &> {
|
||||
static _FORCE_INLINE_ T cast(const Variant &p_variant) {
|
||||
using TStripped = std::remove_pointer_t<T>;
|
||||
if constexpr (std::is_base_of<Object, TStripped>::value) {
|
||||
return Object::cast_to<TStripped>(p_variant);
|
||||
} else {
|
||||
return p_variant;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct VariantObjectClassChecker {
|
||||
static _FORCE_INLINE_ bool check(const Variant &p_variant) {
|
||||
using TStripped = std::remove_pointer_t<T>;
|
||||
if constexpr (std::is_base_of<Object, TStripped>::value) {
|
||||
Object *obj = p_variant;
|
||||
return Object::cast_to<TStripped>(p_variant) || !obj;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Ref;
|
||||
|
||||
template <typename T>
|
||||
struct VariantObjectClassChecker<const Ref<T> &> {
|
||||
static _FORCE_INLINE_ bool check(const Variant &p_variant) {
|
||||
Object *obj = p_variant;
|
||||
const Ref<T> node = p_variant;
|
||||
return node.ptr() || !obj;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct VariantCasterAndValidate {
|
||||
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) {
|
||||
GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE);
|
||||
if (!internal::gdextension_interface_variant_can_convert_strict(static_cast<GDExtensionVariantType>(p_args[p_arg_idx]->get_type()), argtype) ||
|
||||
!VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = p_arg_idx;
|
||||
r_error.expected = argtype;
|
||||
}
|
||||
|
||||
return VariantCaster<T>::cast(*p_args[p_arg_idx]);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct VariantCasterAndValidate<T &> {
|
||||
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) {
|
||||
GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE);
|
||||
if (!internal::gdextension_interface_variant_can_convert_strict(static_cast<GDExtensionVariantType>(p_args[p_arg_idx]->get_type()), argtype) ||
|
||||
!VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = p_arg_idx;
|
||||
r_error.expected = argtype;
|
||||
}
|
||||
|
||||
return VariantCaster<T>::cast(*p_args[p_arg_idx]);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct VariantCasterAndValidate<const T &> {
|
||||
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) {
|
||||
GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE);
|
||||
if (!internal::gdextension_interface_variant_can_convert_strict(static_cast<GDExtensionVariantType>(p_args[p_arg_idx]->get_type()), argtype) ||
|
||||
!VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = p_arg_idx;
|
||||
r_error.expected = argtype;
|
||||
}
|
||||
|
||||
return VariantCaster<T>::cast(*p_args[p_arg_idx]);
|
||||
}
|
||||
};
|
||||
|
||||
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 <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 <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 <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 <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 <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 <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 <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 <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;
|
||||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
(p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
|
||||
#else
|
||||
(p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
|
||||
#endif
|
||||
(void)(p_args); // Avoid warning.
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
(p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
|
||||
#else
|
||||
(p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
|
||||
#endif
|
||||
(void)(p_args); // Avoid warning.
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
r_ret = (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
|
||||
#else
|
||||
r_ret = (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
|
||||
#endif
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
r_ret = (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
|
||||
#else
|
||||
r_ret = (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
|
||||
#endif
|
||||
(void)p_args;
|
||||
}
|
||||
|
||||
template <typename T, typename... P>
|
||||
void call_with_variant_args(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, int p_argcount, GDExtensionCallError &r_error) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((size_t)p_argcount < sizeof...(P)) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
call_with_variant_args_helper<T, P...>(p_instance, p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P>
|
||||
void call_with_variant_args_ret(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((size_t)p_argcount < sizeof...(P)) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
call_with_variant_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P>
|
||||
void call_with_variant_args_retc(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((size_t)p_argcount < sizeof...(P)) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
call_with_variant_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename... P>
|
||||
void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
|
||||
|
||||
int32_t dvs = (int32_t)default_values.size();
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (missing > dvs) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Variant args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; // Avoid zero sized array.
|
||||
std::array<const Variant *, sizeof...(P)> argsp;
|
||||
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
|
||||
if (i < p_argcount) {
|
||||
args[i] = Variant(p_args[i]);
|
||||
} else {
|
||||
args[i] = default_values[i - p_argcount + (dvs - missing)];
|
||||
}
|
||||
argsp[i] = &args[i];
|
||||
}
|
||||
|
||||
call_with_variant_args_helper(p_instance, p_method, argsp.data(), r_error, BuildIndexSequence<sizeof...(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)) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
|
||||
|
||||
int32_t dvs = (int32_t)default_values.size();
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (missing > dvs) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Variant args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; // Avoid zero sized array.
|
||||
std::array<const Variant *, sizeof...(P)> argsp;
|
||||
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
|
||||
if (i < p_argcount) {
|
||||
args[i] = Variant(p_args[i]);
|
||||
} else {
|
||||
args[i] = default_values[i - p_argcount + (dvs - missing)];
|
||||
}
|
||||
argsp[i] = &args[i];
|
||||
}
|
||||
|
||||
call_with_variant_argsc_helper(p_instance, p_method, argsp.data(), r_error, BuildIndexSequence<sizeof...(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)) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
|
||||
|
||||
int32_t dvs = (int32_t)default_values.size();
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (missing > dvs) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Variant args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; // Avoid zero sized array.
|
||||
std::array<const Variant *, sizeof...(P)> argsp;
|
||||
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
|
||||
if (i < p_argcount) {
|
||||
args[i] = Variant(p_args[i]);
|
||||
} else {
|
||||
args[i] = default_values[i - p_argcount + (dvs - missing)];
|
||||
}
|
||||
argsp[i] = &args[i];
|
||||
}
|
||||
|
||||
call_with_variant_args_ret_helper(p_instance, p_method, argsp.data(), r_ret, r_error, BuildIndexSequence<sizeof...(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)) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
|
||||
|
||||
int32_t dvs = (int32_t)default_values.size();
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (missing > dvs) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Variant args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; // Avoid zero sized array.
|
||||
std::array<const Variant *, sizeof...(P)> argsp;
|
||||
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
|
||||
if (i < p_argcount) {
|
||||
args[i] = Variant(p_args[i]);
|
||||
} else {
|
||||
args[i] = default_values[i - p_argcount + (dvs - missing)];
|
||||
}
|
||||
argsp[i] = &args[i];
|
||||
}
|
||||
|
||||
call_with_variant_args_retc_helper(p_instance, p_method, argsp.data(), r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
// GCC raises "parameter 'p_args' set but not used" when P = {},
|
||||
// it's not clever enough to treat other P values as making this branch valid.
|
||||
#if defined(DEBUG_METHODS_ENABLED) && defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
|
||||
#endif
|
||||
|
||||
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);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
template <typename... P>
|
||||
GDExtensionVariantType call_get_argument_type(int p_arg) {
|
||||
GDExtensionVariantType type = GDEXTENSION_VARIANT_TYPE_NIL;
|
||||
int index = 0;
|
||||
// I think rocket science is simpler than modern C++.
|
||||
using expand_type = int[];
|
||||
expand_type a{ 0, (call_get_argument_type_helper<P>(p_arg, index, type), 0)... };
|
||||
(void)a; // Suppress (valid, but unavoidable) -Wunused-variable warning.
|
||||
(void)index; // Suppress GCC warning.
|
||||
return type;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
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++.
|
||||
using expand_type = int[];
|
||||
expand_type a{ 0, (call_get_argument_type_info_helper<P>(p_arg, index, info), 0)... };
|
||||
(void)a; // Suppress (valid, but unavoidable) -Wunused-variable warning.
|
||||
(void)index; // Suppress GCC warning.
|
||||
}
|
||||
|
||||
template <typename Q>
|
||||
void call_get_argument_metadata_helper(int p_arg, int &index, GDExtensionClassMethodArgumentMetadata &md) {
|
||||
if (p_arg == index) {
|
||||
md = GetTypeInfo<Q>::METADATA;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
template <typename... P>
|
||||
GDExtensionClassMethodArgumentMetadata call_get_argument_metadata(int p_arg) {
|
||||
GDExtensionClassMethodArgumentMetadata md = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
|
||||
int index = 0;
|
||||
// I think rocket science is simpler than modern C++.
|
||||
using expand_type = int[];
|
||||
expand_type a{ 0, (call_get_argument_metadata_helper<P>(p_arg, index, md), 0)... };
|
||||
(void)a; // Suppress (valid, but unavoidable) -Wunused-variable warning.
|
||||
(void)index;
|
||||
return md;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
(p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
|
||||
#else
|
||||
(p_method)(VariantCaster<P>::cast(*p_args[Is])...);
|
||||
#endif
|
||||
}
|
||||
|
||||
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)) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
|
||||
|
||||
int32_t dvs = default_values.size();
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (missing > dvs) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Variant args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; // Avoid zero sized array.
|
||||
std::array<const Variant *, sizeof...(P)> argsp;
|
||||
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
|
||||
if (i < p_argcount) {
|
||||
args[i] = Variant(p_args[i]);
|
||||
} else {
|
||||
args[i] = default_values[i - p_argcount + (dvs - missing)];
|
||||
}
|
||||
argsp[i] = &args[i];
|
||||
}
|
||||
|
||||
call_with_variant_args_static(p_method, argsp.data(), r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
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 <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 <typename R, typename... P>
|
||||
void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((size_t)p_argcount < sizeof...(P)) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
call_with_variant_args_static_ret<R, P...>(p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename... P>
|
||||
void call_with_variant_args_static_ret(void (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((size_t)p_argcount < sizeof...(P)) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
call_with_variant_args_static<P...>(p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename R, typename... P, size_t... Is>
|
||||
void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) {
|
||||
r_error.error = GDEXTENSION_CALL_OK;
|
||||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
r_ret = (p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
|
||||
#else
|
||||
r_ret = (p_method)(VariantCaster<P>::cast(*p_args[Is])...);
|
||||
#endif
|
||||
}
|
||||
|
||||
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)) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
|
||||
|
||||
int32_t dvs = default_values.size();
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (missing > dvs) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Variant args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; // Avoid zero sized array.
|
||||
std::array<const Variant *, sizeof...(P)> argsp;
|
||||
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
|
||||
if (i < p_argcount) {
|
||||
args[i] = Variant(p_args[i]);
|
||||
} else {
|
||||
args[i] = default_values[i - p_argcount + (dvs - missing)];
|
||||
}
|
||||
argsp[i] = &args[i];
|
||||
}
|
||||
|
||||
call_with_variant_args_static_ret(p_method, argsp.data(), r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
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 <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)>{});
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#include <godot_cpp/classes/global_constants_binds.hpp>
|
||||
#include <godot_cpp/variant/builtin_binds.hpp>
|
||||
|
||||
#endif // GODOT_BINDER_COMMON_HPP
|
||||
92
include/godot_cpp/core/builtin_ptrcall.hpp
Normal file
92
include/godot_cpp/core/builtin_ptrcall.hpp
Normal file
@@ -0,0 +1,92 @@
|
||||
/**************************************************************************/
|
||||
/* builtin_ptrcall.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_BUILTIN_PTRCALL_HPP
|
||||
#define GODOT_BUILTIN_PTRCALL_HPP
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
#include <godot_cpp/core/object.hpp>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace godot {
|
||||
|
||||
namespace internal {
|
||||
|
||||
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 <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... } };
|
||||
method(base, call_args.data(), &ret, sizeof...(Args));
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 <typename T>
|
||||
T _call_builtin_operator_ptr(const GDExtensionPtrOperatorEvaluator op, GDExtensionConstTypePtr left, GDExtensionConstTypePtr right) {
|
||||
T ret;
|
||||
op(left, right, &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T _call_builtin_ptr_getter(const GDExtensionPtrGetter getter, GDExtensionConstTypePtr base) {
|
||||
T ret;
|
||||
getter(base, &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_BUILTIN_PTRCALL_HPP
|
||||
365
include/godot_cpp/core/class_db.hpp
Normal file
365
include/godot_cpp/core/class_db.hpp
Normal file
@@ -0,0 +1,365 @@
|
||||
/**************************************************************************/
|
||||
/* class_db.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_CLASS_DB_HPP
|
||||
#define GODOT_CLASS_DB_HPP
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
|
||||
#include <godot_cpp/core/defs.hpp>
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
#include <godot_cpp/core/method_bind.hpp>
|
||||
#include <godot_cpp/core/object.hpp>
|
||||
#include <godot_cpp/core/print_string.hpp>
|
||||
|
||||
#include <godot_cpp/classes/class_db_singleton.hpp>
|
||||
|
||||
// Makes callable_mp readily available in all classes connecting signals.
|
||||
// Needs to come after method_bind and object have been included.
|
||||
#include <godot_cpp/variant/callable_method_pointer.hpp>
|
||||
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
// Needed to use StringName as key in `std::unordered_map`
|
||||
template <>
|
||||
struct std::hash<godot::StringName> {
|
||||
std::size_t operator()(godot::StringName const &s) const noexcept {
|
||||
return s.hash();
|
||||
}
|
||||
};
|
||||
|
||||
namespace godot {
|
||||
|
||||
#define DEFVAL(m_defval) (m_defval)
|
||||
|
||||
struct MethodDefinition {
|
||||
StringName name;
|
||||
std::list<StringName> args;
|
||||
MethodDefinition() {}
|
||||
MethodDefinition(StringName p_name) :
|
||||
name(p_name) {}
|
||||
};
|
||||
|
||||
MethodDefinition D_METHOD(StringName p_name);
|
||||
MethodDefinition D_METHOD(StringName p_name, StringName p_arg1);
|
||||
template <typename... Args>
|
||||
MethodDefinition D_METHOD(StringName p_name, StringName p_arg1, Args... args) {
|
||||
MethodDefinition md = D_METHOD(p_name, args...);
|
||||
md.args.push_front(p_arg1);
|
||||
return md;
|
||||
}
|
||||
|
||||
class ClassDB {
|
||||
static GDExtensionInitializationLevel current_level;
|
||||
|
||||
friend class godot::GDExtensionBinding;
|
||||
|
||||
public:
|
||||
struct ClassInfo {
|
||||
StringName name;
|
||||
StringName parent_name;
|
||||
GDExtensionInitializationLevel level = GDEXTENSION_INITIALIZATION_SCENE;
|
||||
std::unordered_map<StringName, MethodBind *> method_map;
|
||||
std::set<StringName> signal_names;
|
||||
std::unordered_map<StringName, GDExtensionClassCallVirtual> virtual_methods;
|
||||
std::set<StringName> property_names;
|
||||
std::set<StringName> constant_names;
|
||||
// Pointer to the parent custom class, if any. Will be null if the parent class is a Godot class.
|
||||
ClassInfo *parent_ptr = nullptr;
|
||||
};
|
||||
|
||||
private:
|
||||
// This may only contain custom classes, not Godot classes
|
||||
static std::unordered_map<StringName, ClassInfo> classes;
|
||||
static std::unordered_map<StringName, const GDExtensionInstanceBindingCallbacks *> instance_binding_callbacks;
|
||||
// Used to remember the custom class registration order.
|
||||
static std::vector<StringName> class_register_order;
|
||||
static std::unordered_map<StringName, Object *> engine_singletons;
|
||||
static std::mutex engine_singletons_mutex;
|
||||
|
||||
static MethodBind *bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const void **p_defs, int p_defcount);
|
||||
static void initialize_class(const ClassInfo &cl);
|
||||
static void bind_method_godot(const StringName &p_class_name, MethodBind *p_method);
|
||||
|
||||
template <typename T, bool is_abstract>
|
||||
static void _register_class(bool p_virtual = false, bool p_exposed = true, bool p_runtime = false);
|
||||
|
||||
template <typename T>
|
||||
static GDExtensionObjectPtr _create_instance_func(void *data) {
|
||||
if constexpr (!std::is_abstract_v<T>) {
|
||||
T *new_object = memnew(T);
|
||||
return new_object->_owner;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static GDExtensionClassInstancePtr _recreate_instance_func(void *data, GDExtensionObjectPtr obj) {
|
||||
if constexpr (!std::is_abstract_v<T>) {
|
||||
#ifdef HOT_RELOAD_ENABLED
|
||||
#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
|
||||
std::lock_guard<std::recursive_mutex> lk(Wrapped::_constructing_mutex);
|
||||
#endif
|
||||
Wrapped::_constructing_recreate_owner = obj;
|
||||
T *new_instance = (T *)memalloc(sizeof(T));
|
||||
memnew_placement(new_instance, T);
|
||||
return new_instance;
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename T>
|
||||
static void register_class(bool p_virtual = false);
|
||||
template <typename T>
|
||||
static void register_abstract_class();
|
||||
template <typename T>
|
||||
static void register_internal_class();
|
||||
template <typename T>
|
||||
static void register_runtime_class();
|
||||
|
||||
_FORCE_INLINE_ static void _register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
|
||||
instance_binding_callbacks[p_name] = p_callbacks;
|
||||
}
|
||||
|
||||
static void _register_engine_singleton(const StringName &p_class_name, Object *p_singleton) {
|
||||
std::lock_guard<std::mutex> lock(engine_singletons_mutex);
|
||||
std::unordered_map<StringName, Object *>::const_iterator i = engine_singletons.find(p_class_name);
|
||||
if (i != engine_singletons.end()) {
|
||||
ERR_FAIL_COND((*i).second != p_singleton);
|
||||
return;
|
||||
}
|
||||
engine_singletons[p_class_name] = p_singleton;
|
||||
}
|
||||
|
||||
static void _unregister_engine_singleton(const StringName &p_class_name) {
|
||||
std::lock_guard<std::mutex> lock(engine_singletons_mutex);
|
||||
engine_singletons.erase(p_class_name);
|
||||
}
|
||||
|
||||
template <typename N, typename M, typename... VarArgs>
|
||||
static MethodBind *bind_method(N p_method_name, M p_method, VarArgs... p_args);
|
||||
|
||||
template <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 <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);
|
||||
static void add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix);
|
||||
static void add_property(const StringName &p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index = -1);
|
||||
static void add_signal(const StringName &p_class, const MethodInfo &p_signal);
|
||||
static void bind_integer_constant(const StringName &p_class_name, const StringName &p_enum_name, const StringName &p_constant_name, GDExtensionInt p_constant_value, bool p_is_bitfield = false);
|
||||
// Binds an implementation of a virtual method defined in Godot.
|
||||
static void bind_virtual_method(const StringName &p_class, const StringName &p_method, GDExtensionClassCallVirtual p_call);
|
||||
// Add a new virtual method that can be implemented by scripts.
|
||||
static void add_virtual_method(const StringName &p_class, const MethodInfo &p_method, const Vector<StringName> &p_arg_names = Vector<StringName>());
|
||||
|
||||
static MethodBind *get_method(const StringName &p_class, const StringName &p_method);
|
||||
|
||||
static GDExtensionClassCallVirtual get_virtual_func(void *p_userdata, GDExtensionConstStringNamePtr p_name);
|
||||
static const GDExtensionInstanceBindingCallbacks *get_instance_binding_callbacks(const StringName &p_class);
|
||||
|
||||
static void initialize(GDExtensionInitializationLevel p_level);
|
||||
static void deinitialize(GDExtensionInitializationLevel p_level);
|
||||
|
||||
CLASSDB_SINGLETON_FORWARD_METHODS;
|
||||
};
|
||||
|
||||
#define BIND_CONSTANT(m_constant) \
|
||||
::godot::ClassDB::bind_integer_constant(get_class_static(), "", #m_constant, m_constant);
|
||||
|
||||
#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);
|
||||
|
||||
#define BIND_BITFIELD_FLAG(m_constant) \
|
||||
::godot::ClassDB::bind_integer_constant(get_class_static(), ::godot::_gde_constant_get_bitfield_name(m_constant, #m_constant), #m_constant, m_constant, true);
|
||||
|
||||
#define BIND_VIRTUAL_METHOD(m_class, m_method) \
|
||||
{ \
|
||||
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); \
|
||||
}
|
||||
|
||||
template <typename T, bool is_abstract>
|
||||
void ClassDB::_register_class(bool p_virtual, bool p_exposed, bool p_runtime) {
|
||||
static_assert(TypesAreSame<typename T::self_type, T>::value, "Class not declared properly, please use GDCLASS.");
|
||||
static_assert(!FunctionsAreSame<T::self_type::_bind_methods, T::parent_type::_bind_methods>::value, "Class must declare 'static void _bind_methods'.");
|
||||
static_assert(!std::is_abstract_v<T> || is_abstract, "Class is abstract, please use GDREGISTER_ABSTRACT_CLASS.");
|
||||
instance_binding_callbacks[T::get_class_static()] = &T::_gde_binding_callbacks;
|
||||
|
||||
// Register this class within our plugin
|
||||
ClassInfo cl;
|
||||
cl.name = T::get_class_static();
|
||||
cl.parent_name = T::get_parent_class_static();
|
||||
cl.level = current_level;
|
||||
std::unordered_map<StringName, ClassInfo>::iterator parent_it = classes.find(cl.parent_name);
|
||||
if (parent_it != classes.end()) {
|
||||
// Assign parent if it is also a custom class
|
||||
cl.parent_ptr = &parent_it->second;
|
||||
}
|
||||
classes[cl.name] = cl;
|
||||
class_register_order.push_back(cl.name);
|
||||
|
||||
// Register this class with Godot
|
||||
GDExtensionClassCreationInfo3 class_info = {
|
||||
p_virtual, // GDExtensionBool is_virtual;
|
||||
is_abstract, // GDExtensionBool is_abstract;
|
||||
p_exposed, // GDExtensionBool is_exposed;
|
||||
p_runtime, // GDExtensionBool is_runtime;
|
||||
T::set_bind, // GDExtensionClassSet set_func;
|
||||
T::get_bind, // GDExtensionClassGet get_func;
|
||||
T::has_get_property_list() ? T::get_property_list_bind : nullptr, // GDExtensionClassGetPropertyList get_property_list_func;
|
||||
T::free_property_list_bind, // GDExtensionClassFreePropertyList2 free_property_list_func;
|
||||
T::property_can_revert_bind, // GDExtensionClassPropertyCanRevert property_can_revert_func;
|
||||
T::property_get_revert_bind, // GDExtensionClassPropertyGetRevert property_get_revert_func;
|
||||
T::validate_property_bind, // GDExtensionClassValidateProperty validate_property_func;
|
||||
T::notification_bind, // GDExtensionClassNotification2 notification_func;
|
||||
T::to_string_bind, // GDExtensionClassToString to_string_func;
|
||||
nullptr, // GDExtensionClassReference reference_func;
|
||||
nullptr, // GDExtensionClassUnreference unreference_func;
|
||||
&_create_instance_func<T>, // GDExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
|
||||
T::free, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
|
||||
&_recreate_instance_func<T>, // GDExtensionClassRecreateInstance recreate_instance_func;
|
||||
&ClassDB::get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
|
||||
nullptr, // GDExtensionClassCallVirtualWithData call_virtual_func;
|
||||
nullptr, // GDExtensionClassGetRID get_rid;
|
||||
(void *)&T::get_class_static(), // void *class_userdata;
|
||||
};
|
||||
|
||||
internal::gdextension_interface_classdb_register_extension_class3(internal::library, cl.name._native_ptr(), cl.parent_name._native_ptr(), &class_info);
|
||||
|
||||
// call bind_methods etc. to register all members of the class
|
||||
T::initialize_class();
|
||||
|
||||
// now register our class within ClassDB within Godot
|
||||
initialize_class(classes[cl.name]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ClassDB::register_class(bool p_virtual) {
|
||||
ClassDB::_register_class<T, false>(p_virtual);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ClassDB::register_abstract_class() {
|
||||
ClassDB::_register_class<T, true>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ClassDB::register_internal_class() {
|
||||
ClassDB::_register_class<T, false>(false, false);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ClassDB::register_runtime_class() {
|
||||
ClassDB::_register_class<T, false>(false, true, true);
|
||||
}
|
||||
|
||||
template <typename N, typename M, typename... VarArgs>
|
||||
MethodBind *ClassDB::bind_method(N p_method_name, M p_method, VarArgs... p_args) {
|
||||
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
|
||||
const Variant *argptrs[sizeof...(p_args) + 1];
|
||||
for (uint32_t i = 0; i < sizeof...(p_args); i++) {
|
||||
argptrs[i] = &args[i];
|
||||
}
|
||||
MethodBind *bind = create_method_bind(p_method);
|
||||
return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const void **)argptrs, sizeof...(p_args));
|
||||
}
|
||||
|
||||
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];
|
||||
for (uint32_t i = 0; i < sizeof...(p_args); i++) {
|
||||
argptrs[i] = &args[i];
|
||||
}
|
||||
MethodBind *bind = create_static_method_bind(p_method);
|
||||
bind->set_instance_class(p_class);
|
||||
return bind_methodfi(0, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const void **)argptrs, sizeof...(p_args));
|
||||
}
|
||||
|
||||
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_NULL_V(bind, nullptr);
|
||||
|
||||
bind->set_name(p_name);
|
||||
bind->set_default_arguments(p_default_args);
|
||||
|
||||
StringName instance_type = bind->get_instance_class();
|
||||
|
||||
std::unordered_map<StringName, ClassInfo>::iterator type_it = classes.find(instance_type);
|
||||
if (type_it == classes.end()) {
|
||||
memdelete(bind);
|
||||
ERR_FAIL_V_MSG(nullptr, String("Class '{0}' doesn't exist.").format(Array::make(instance_type)));
|
||||
}
|
||||
|
||||
ClassInfo &type = type_it->second;
|
||||
|
||||
if (type.method_map.find(p_name) != type.method_map.end()) {
|
||||
memdelete(bind);
|
||||
ERR_FAIL_V_MSG(nullptr, String("Binding duplicate method: {0}::{1}.").format(Array::make(instance_type, p_method)));
|
||||
}
|
||||
|
||||
// register our method bind within our plugin
|
||||
type.method_map[p_name] = bind;
|
||||
|
||||
// and register with godot
|
||||
bind_method_godot(type.name, bind);
|
||||
|
||||
return bind;
|
||||
}
|
||||
|
||||
#define GDREGISTER_CLASS(m_class) ::godot::ClassDB::register_class<m_class>();
|
||||
#define GDREGISTER_VIRTUAL_CLASS(m_class) ::godot::ClassDB::register_class<m_class>(true);
|
||||
#define GDREGISTER_ABSTRACT_CLASS(m_class) ::godot::ClassDB::register_abstract_class<m_class>();
|
||||
#define GDREGISTER_INTERNAL_CLASS(m_class) ::godot::ClassDB::register_internal_class<m_class>();
|
||||
#define GDREGISTER_RUNTIME_CLASS(m_class) ::godot::ClassDB::register_runtime_class<m_class>();
|
||||
|
||||
} // namespace godot
|
||||
|
||||
CLASSDB_SINGLETON_VARIANT_CAST;
|
||||
|
||||
#endif // GODOT_CLASS_DB_HPP
|
||||
134
include/godot_cpp/core/defs.hpp
Normal file
134
include/godot_cpp/core/defs.hpp
Normal file
@@ -0,0 +1,134 @@
|
||||
/**************************************************************************/
|
||||
/* defs.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_DEFS_HPP
|
||||
#define GODOT_DEFS_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
namespace godot {
|
||||
|
||||
#if !defined(GDE_EXPORT)
|
||||
#if defined(_WIN32)
|
||||
#define GDE_EXPORT __declspec(dllexport)
|
||||
#elif defined(__GNUC__)
|
||||
#define GDE_EXPORT __attribute__((visibility("default")))
|
||||
#else
|
||||
#define GDE_EXPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Turn argument to string constant:
|
||||
// https://gcc.gnu.org/onlinedocs/cpp/Stringizing.html#Stringizing
|
||||
#ifndef _STR
|
||||
#define _STR(m_x) #m_x
|
||||
#define _MKSTR(m_x) _STR(m_x)
|
||||
#endif
|
||||
|
||||
// Should always inline no matter what.
|
||||
#ifndef _ALWAYS_INLINE_
|
||||
#if defined(__GNUC__)
|
||||
#define _ALWAYS_INLINE_ __attribute__((always_inline)) inline
|
||||
#elif defined(_MSC_VER)
|
||||
#define _ALWAYS_INLINE_ __forceinline
|
||||
#else
|
||||
#define _ALWAYS_INLINE_ inline
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Should always inline, except in debug builds because it makes debugging harder.
|
||||
#ifndef _FORCE_INLINE_
|
||||
#ifdef DISABLE_FORCED_INLINE
|
||||
#define _FORCE_INLINE_ inline
|
||||
#else
|
||||
#define _FORCE_INLINE_ _ALWAYS_INLINE_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Windows badly defines a lot of stuff we'll never use. Undefine it.
|
||||
#ifdef _WIN32
|
||||
#undef min // override standard definition
|
||||
#undef max // override standard definition
|
||||
#undef ERROR // override (really stupid) wingdi.h standard definition
|
||||
#undef DELETE // override (another really stupid) winnt.h standard definition
|
||||
#undef MessageBox // override winuser.h standard definition
|
||||
#undef MIN // override standard definition
|
||||
#undef MAX // override standard definition
|
||||
#undef CLAMP // override standard definition
|
||||
#undef Error
|
||||
#undef OK
|
||||
#undef CONNECT_DEFERRED // override from Windows SDK, clashes with Object enum
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define likely(x) x
|
||||
#define unlikely(x) x
|
||||
#endif
|
||||
|
||||
#ifdef REAL_T_IS_DOUBLE
|
||||
typedef double real_t;
|
||||
#else
|
||||
typedef float real_t;
|
||||
#endif
|
||||
|
||||
// Generic swap template.
|
||||
#ifndef SWAP
|
||||
#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y))
|
||||
template <typename T>
|
||||
inline void __swap_tmpl(T &x, T &y) {
|
||||
T aux = x;
|
||||
x = y;
|
||||
y = aux;
|
||||
}
|
||||
#endif // SWAP
|
||||
|
||||
// Home-made index sequence trick, so it can be used everywhere without the costly include of std::tuple.
|
||||
// https://stackoverflow.com/questions/15014096/c-index-of-type-during-variadic-template-expansion
|
||||
template <size_t... Is>
|
||||
struct IndexSequence {};
|
||||
|
||||
template <size_t N, size_t... Is>
|
||||
struct BuildIndexSequence : BuildIndexSequence<N - 1, N - 1, Is...> {};
|
||||
|
||||
template <size_t... Is>
|
||||
struct BuildIndexSequence<0, Is...> : IndexSequence<Is...> {};
|
||||
|
||||
} //namespace godot
|
||||
|
||||
// To maintain compatibility an alias is defined outside the namespace.
|
||||
// Consider it deprecated.
|
||||
using real_t = godot::real_t;
|
||||
|
||||
#endif // GODOT_DEFS_HPP
|
||||
97
include/godot_cpp/core/engine_ptrcall.hpp
Normal file
97
include/godot_cpp/core/engine_ptrcall.hpp
Normal file
@@ -0,0 +1,97 @@
|
||||
/**************************************************************************/
|
||||
/* engine_ptrcall.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_ENGINE_PTRCALL_HPP
|
||||
#define GODOT_ENGINE_PTRCALL_HPP
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
|
||||
#include <godot_cpp/core/binder_common.hpp>
|
||||
#include <godot_cpp/core/object.hpp>
|
||||
#include <godot_cpp/godot.hpp>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace godot {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename O, typename... Args>
|
||||
O *_call_native_mb_ret_obj(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) {
|
||||
GodotObject *ret = nullptr;
|
||||
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
|
||||
internal::gdextension_interface_object_method_bind_ptrcall(mb, instance, mb_args.data(), &ret);
|
||||
if (ret == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<O *>(internal::get_object_instance_binding(ret));
|
||||
}
|
||||
|
||||
template <typename R, typename... Args>
|
||||
R _call_native_mb_ret(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) {
|
||||
typename PtrToArg<R>::EncodeT ret;
|
||||
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
|
||||
internal::gdextension_interface_object_method_bind_ptrcall(mb, instance, mb_args.data(), &ret);
|
||||
return static_cast<R>(ret);
|
||||
}
|
||||
|
||||
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 <typename R, typename... Args>
|
||||
R _call_utility_ret(GDExtensionPtrUtilityFunction func, const Args &...args) {
|
||||
typename PtrToArg<R>::EncodeT ret;
|
||||
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
|
||||
func(&ret, mb_args.data(), mb_args.size());
|
||||
return static_cast<R>(ret);
|
||||
}
|
||||
|
||||
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 <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());
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_ENGINE_PTRCALL_HPP
|
||||
806
include/godot_cpp/core/error_macros.hpp
Normal file
806
include/godot_cpp/core/error_macros.hpp
Normal file
@@ -0,0 +1,806 @@
|
||||
/**************************************************************************/
|
||||
/* error_macros.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_ERROR_MACROS_HPP
|
||||
#define GODOT_ERROR_MACROS_HPP
|
||||
|
||||
#include <godot_cpp/core/defs.hpp>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class String;
|
||||
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, bool p_editor_notify = false, bool p_is_warning = false);
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, bool p_editor_notify = false, bool p_is_warning = false);
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, bool p_editor_notify = false, bool p_is_warning = false);
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, bool p_editor_notify = false, bool p_is_warning = false);
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const String &p_message, bool p_editor_notify = false, bool p_is_warning = false);
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, bool p_editor_notify = false, bool p_is_warning = false);
|
||||
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message = "", bool p_editor_notify = false, bool p_fatal = false);
|
||||
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool p_editor_notify = false, bool p_fatal = false);
|
||||
void _err_flush_stdout();
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define FUNCTION_STR __FUNCTION__
|
||||
#else
|
||||
#define FUNCTION_STR __FUNCTION__
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/**
|
||||
* Don't use GENERATE_TRAP() directly, should only be used be the macros below.
|
||||
*/
|
||||
#define GENERATE_TRAP() __debugbreak()
|
||||
#else
|
||||
/**
|
||||
* Don't use GENERATE_TRAP() directly, should only be used be the macros below.
|
||||
*/
|
||||
#define GENERATE_TRAP() __builtin_trap()
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Error macros.
|
||||
* WARNING: These macros work in the opposite way to assert().
|
||||
*
|
||||
* Unlike exceptions and asserts, these macros try to maintain consistency and stability.
|
||||
* In most cases, bugs and/or invalid data are not fatal. They should never allow a perfectly
|
||||
* running application to fail or crash.
|
||||
* Always try to return processable data, so the engine can keep running well.
|
||||
* Use the _MSG versions to print a meaningful message to help with debugging.
|
||||
*
|
||||
* The `((void)0)` no-op statement is used as a trick to force us to put a semicolon after
|
||||
* those macros, making them look like proper statements.
|
||||
* The if wrappers are used to ensure that the macro replacement does not trigger unexpected
|
||||
* issues when expanded e.g. after an `if (cond) ERR_FAIL();` without braces.
|
||||
*/
|
||||
|
||||
// Index out of bounds error macros.
|
||||
// These macros should be used instead of `ERR_FAIL_COND` for bounds checking.
|
||||
|
||||
// Integer index out of bounds error macros.
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_INDEX_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
|
||||
* If not, the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_INDEX(m_index, m_size) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
|
||||
* If not, prints `m_msg` and the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_INDEX_MSG(m_index, m_size, m_msg) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_INDEX_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_INDEX_EDMSG(m_index, m_size, m_msg) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_INDEX_V_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
|
||||
* If not, the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_INDEX_V(m_index, m_size, m_retval) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
|
||||
* If not, prints `m_msg` and the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_INDEX_V_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_INDEX_MSG` or `ERR_FAIL_INDEX_V_MSG`.
|
||||
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and
|
||||
* there is no sensible error message.
|
||||
*
|
||||
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
|
||||
* If not, the application crashes.
|
||||
*/
|
||||
#define CRASH_BAD_INDEX(m_index, m_size) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", false, true); \
|
||||
::godot::_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_INDEX_MSG` or `ERR_FAIL_INDEX_V_MSG`.
|
||||
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable.
|
||||
*
|
||||
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
|
||||
* If not, prints `m_msg` and the application crashes.
|
||||
*/
|
||||
#define CRASH_BAD_INDEX_MSG(m_index, m_size, m_msg) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, false, true); \
|
||||
::godot::_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
// Unsigned integer index out of bounds error macros.
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_UNSIGNED_INDEX_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures an unsigned integer index `m_index` is less than `m_size`.
|
||||
* If not, the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_UNSIGNED_INDEX(m_index, m_size) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures an unsigned integer index `m_index` is less than `m_size`.
|
||||
* If not, prints `m_msg` and the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_UNSIGNED_INDEX_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_UNSIGNED_INDEX_EDMSG(m_index, m_size, m_msg) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_UNSIGNED_INDEX_V_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures an unsigned integer index `m_index` is less than `m_size`.
|
||||
* If not, the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_UNSIGNED_INDEX_V(m_index, m_size, m_retval) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures an unsigned integer index `m_index` is less than `m_size`.
|
||||
* If not, prints `m_msg` and the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_UNSIGNED_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_UNSIGNED_INDEX_V_EDMSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_UNSIGNED_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_UNSIGNED_INDEX_MSG` or `ERR_FAIL_UNSIGNED_INDEX_V_MSG`.
|
||||
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and
|
||||
* there is no sensible error message.
|
||||
*
|
||||
* Ensures an unsigned integer index `m_index` is less than `m_size`.
|
||||
* If not, the application crashes.
|
||||
*/
|
||||
#define CRASH_BAD_UNSIGNED_INDEX(m_index, m_size) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", false, true); \
|
||||
::godot::_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_UNSIGNED_INDEX_MSG` or `ERR_FAIL_UNSIGNED_INDEX_V_MSG`.
|
||||
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable.
|
||||
*
|
||||
* Ensures an unsigned integer index `m_index` is less than `m_size`.
|
||||
* If not, prints `m_msg` and the application crashes.
|
||||
*/
|
||||
#define CRASH_BAD_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, false, true); \
|
||||
::godot::_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
// Null reference error macros.
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_NULL_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures a pointer `m_param` is not null.
|
||||
* If it is null, the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_NULL(m_param) \
|
||||
if (unlikely(m_param == nullptr)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null."); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures a pointer `m_param` is not null.
|
||||
* If it is null, prints `m_msg` and the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_NULL_MSG(m_param, m_msg) \
|
||||
if (unlikely(m_param == nullptr)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_NULL_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_NULL_EDMSG(m_param, m_msg) \
|
||||
if (unlikely(m_param == nullptr)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg, true); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_NULL_V_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures a pointer `m_param` is not null.
|
||||
* If it is null, the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_NULL_V(m_param, m_retval) \
|
||||
if (unlikely(m_param == nullptr)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null."); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures a pointer `m_param` is not null.
|
||||
* If it is null, prints `m_msg` and the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_NULL_V_MSG(m_param, m_retval, m_msg) \
|
||||
if (unlikely(m_param == nullptr)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_NULL_V_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_NULL_V_EDMSG(m_param, m_retval, m_msg) \
|
||||
if (unlikely(m_param == nullptr)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg, true); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
* If checking for null use ERR_FAIL_NULL_MSG instead.
|
||||
* If checking index bounds use ERR_FAIL_INDEX_MSG instead.
|
||||
*
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_COND(m_cond) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true."); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, prints `m_msg` and the current function returns.
|
||||
*
|
||||
* If checking for null use ERR_FAIL_NULL_MSG instead.
|
||||
* If checking index bounds use ERR_FAIL_INDEX_MSG instead.
|
||||
*/
|
||||
#define ERR_FAIL_COND_MSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true.", m_msg); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_COND_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_COND_EDMSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true.", m_msg, true); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_V_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
* If checking for null use ERR_FAIL_NULL_V_MSG instead.
|
||||
* If checking index bounds use ERR_FAIL_INDEX_V_MSG instead.
|
||||
*
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_COND_V(m_cond, m_retval) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval)); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, prints `m_msg` and the current function returns `m_retval`.
|
||||
*
|
||||
* If checking for null use ERR_FAIL_NULL_V_MSG instead.
|
||||
* If checking index bounds use ERR_FAIL_INDEX_V_MSG instead.
|
||||
*/
|
||||
#define ERR_FAIL_COND_V_MSG(m_cond, m_retval, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval), m_msg); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_COND_V_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_COND_V_EDMSG(m_cond, m_retval, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval), m_msg, true); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_CONTINUE_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, the current loop continues.
|
||||
*/
|
||||
#define ERR_CONTINUE(m_cond) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing."); \
|
||||
continue; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, prints `m_msg` and the current loop continues.
|
||||
*/
|
||||
#define ERR_CONTINUE_MSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing.", m_msg); \
|
||||
continue; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_CONTINUE_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_CONTINUE_EDMSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing.", m_msg, true); \
|
||||
continue; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_BREAK_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, the current loop breaks.
|
||||
*/
|
||||
#define ERR_BREAK(m_cond) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking."); \
|
||||
break; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, prints `m_msg` and the current loop breaks.
|
||||
*/
|
||||
#define ERR_BREAK_MSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking.", m_msg); \
|
||||
break; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_BREAK_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_BREAK_EDMSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking.", m_msg, true); \
|
||||
break; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_COND_V_MSG`.
|
||||
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and
|
||||
* there is no sensible error message.
|
||||
*
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, the application crashes.
|
||||
*/
|
||||
#define CRASH_COND(m_cond) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true."); \
|
||||
::godot::_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_COND_V_MSG`.
|
||||
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable.
|
||||
*
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, prints `m_msg` and the application crashes.
|
||||
*/
|
||||
#define CRASH_COND_MSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true.", m_msg); \
|
||||
::godot::_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
// Generic error macros.
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_MSG`.
|
||||
* Only use this macro if more complex error detection or recovery is required, and
|
||||
* there is no sensible error message.
|
||||
*
|
||||
* The current function returns.
|
||||
*/
|
||||
#define ERR_FAIL() \
|
||||
if (true) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed."); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_MSG`.
|
||||
* Only use this macro if more complex error detection or recovery is required.
|
||||
*
|
||||
* Prints `m_msg`, and the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_MSG(m_msg) \
|
||||
if (true) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed.", m_msg); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_EDMSG(m_msg) \
|
||||
if (true) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed.", m_msg, true); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_V_MSG` or `ERR_FAIL_V_MSG`.
|
||||
* Only use this macro if more complex error detection or recovery is required, and
|
||||
* there is no sensible error message.
|
||||
*
|
||||
* The current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_V(m_retval) \
|
||||
if (true) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval)); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_V_MSG`.
|
||||
* Only use this macro if more complex error detection or recovery is required.
|
||||
*
|
||||
* Prints `m_msg`, and the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_V_MSG(m_retval, m_msg) \
|
||||
if (true) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval), m_msg); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_V_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_V_EDMSG(m_retval, m_msg) \
|
||||
if (true) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval), m_msg, true); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_MSG`, `ERR_FAIL_COND_V_MSG`, `ERR_CONTINUE_MSG` or `ERR_BREAK_MSG`.
|
||||
* Only use this macro at the start of a function that has not been implemented yet, or
|
||||
* if more complex error detection or recovery is required.
|
||||
*
|
||||
* Prints `m_msg`.
|
||||
*/
|
||||
#define ERR_PRINT(m_msg) \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg)
|
||||
|
||||
/**
|
||||
* Same as `ERR_PRINT` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_PRINT_ED(m_msg) \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true)
|
||||
|
||||
/**
|
||||
* Prints `m_msg` once during the application lifetime.
|
||||
*/
|
||||
#define ERR_PRINT_ONCE(m_msg) \
|
||||
if (true) { \
|
||||
static bool first_print = true; \
|
||||
if (first_print) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg); \
|
||||
first_print = false; \
|
||||
} \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_PRINT_ONCE` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_PRINT_ONCE_ED(m_msg) \
|
||||
if (true) { \
|
||||
static bool first_print = true; \
|
||||
if (first_print) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true); \
|
||||
first_print = false; \
|
||||
} \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
// Print warning message macros.
|
||||
|
||||
/**
|
||||
* Prints `m_msg`.
|
||||
*
|
||||
* If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
|
||||
*/
|
||||
#define WARN_PRINT(m_msg) \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, false, true)
|
||||
|
||||
/**
|
||||
* Same as `WARN_PRINT` but also notifies the editor.
|
||||
*/
|
||||
#define WARN_PRINT_ED(m_msg) \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true, true)
|
||||
|
||||
/**
|
||||
* Prints `m_msg` once during the application lifetime.
|
||||
*
|
||||
* If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
|
||||
*/
|
||||
#define WARN_PRINT_ONCE(m_msg) \
|
||||
if (true) { \
|
||||
static bool first_print = true; \
|
||||
if (first_print) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, false, true); \
|
||||
first_print = false; \
|
||||
} \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `WARN_PRINT_ONCE` but also notifies the editor.
|
||||
*/
|
||||
#define WARN_PRINT_ONCE_ED(m_msg) \
|
||||
if (true) { \
|
||||
static bool first_print = true; \
|
||||
if (first_print) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true, true); \
|
||||
first_print = false; \
|
||||
} \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
// Print deprecated warning message macros.
|
||||
|
||||
/**
|
||||
* Warns that the current function is deprecated.
|
||||
*/
|
||||
#define WARN_DEPRECATED \
|
||||
if (true) { \
|
||||
static std::atomic<bool> warning_shown; \
|
||||
if (!warning_shown.load()) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", false, true); \
|
||||
warning_shown.store(true); \
|
||||
} \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Warns that the current function is deprecated and prints `m_msg`.
|
||||
*/
|
||||
#define WARN_DEPRECATED_MSG(m_msg) \
|
||||
if (true) { \
|
||||
static std::atomic<bool> warning_shown; \
|
||||
if (!warning_shown.load()) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", m_msg, false, true); \
|
||||
warning_shown.store(true); \
|
||||
} \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Do not use.
|
||||
* If the application should never reach this point use CRASH_NOW_MSG(m_msg) to explain why.
|
||||
*
|
||||
* The application crashes.
|
||||
*/
|
||||
#define CRASH_NOW() \
|
||||
if (true) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed."); \
|
||||
::godot::_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Only use if the application should never reach this point.
|
||||
*
|
||||
* Prints `m_msg`, and then the application crashes.
|
||||
*/
|
||||
#define CRASH_NOW_MSG(m_msg) \
|
||||
if (true) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed.", m_msg); \
|
||||
::godot::_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* This should be a 'free' assert for program flow and should not be needed in any releases,
|
||||
* only used in dev builds.
|
||||
*/
|
||||
#ifdef DEBUG_ENABLED
|
||||
#define DEV_ASSERT(m_cond) \
|
||||
if (unlikely(!(m_cond))) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: DEV_ASSERT failed \"" _STR(m_cond) "\" is false."); \
|
||||
::godot::_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
#else
|
||||
#define DEV_ASSERT(m_cond)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Gives an error message when a method bind is invalid (likely the hash changed).
|
||||
* Avoids crashing the application in this case. It's not free, so it's debug only.
|
||||
*/
|
||||
#ifdef DEBUG_ENABLED
|
||||
#define CHECK_METHOD_BIND_RET(m_mb, m_ret) \
|
||||
if (unlikely(!m_mb)) { \
|
||||
ERR_PRINT_ONCE("Method bind was not found. Likely the engine method changed to an incompatible version."); \
|
||||
return m_ret; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
#define CHECK_METHOD_BIND(m_mb) \
|
||||
if (unlikely(!m_mb)) { \
|
||||
ERR_PRINT_ONCE("Method bind was not found. Likely the engine method changed to an incompatible version."); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
#else
|
||||
#define CHECK_METHOD_BIND_RET(m_mb, m_ret)
|
||||
#define CHECK_METHOD_BIND(m_mb)
|
||||
#endif
|
||||
|
||||
#endif // GODOT_ERROR_MACROS_HPP
|
||||
819
include/godot_cpp/core/math.hpp
Normal file
819
include/godot_cpp/core/math.hpp
Normal file
@@ -0,0 +1,819 @@
|
||||
/**************************************************************************/
|
||||
/* math.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_MATH_HPP
|
||||
#define GODOT_MATH_HPP
|
||||
|
||||
#include <godot_cpp/core/defs.hpp>
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace godot {
|
||||
|
||||
#define Math_SQRT12 0.7071067811865475244008443621048490
|
||||
#define Math_SQRT2 1.4142135623730950488016887242
|
||||
#define Math_LN2 0.6931471805599453094172321215
|
||||
#define Math_PI 3.1415926535897932384626433833
|
||||
#define Math_TAU 6.2831853071795864769252867666
|
||||
#define Math_E 2.7182818284590452353602874714
|
||||
#define Math_INF INFINITY
|
||||
#define Math_NAN NAN
|
||||
|
||||
// Make room for our constexpr's below by overriding potential system-specific macros.
|
||||
#undef ABS
|
||||
#undef SIGN
|
||||
#undef MIN
|
||||
#undef MAX
|
||||
#undef CLAMP
|
||||
|
||||
// Generic ABS function, for math uses please use Math::abs.
|
||||
template <typename T>
|
||||
constexpr T ABS(T m_v) {
|
||||
return m_v < 0 ? -m_v : m_v;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr const T SIGN(const T m_v) {
|
||||
return m_v == 0 ? 0.0f : (m_v < 0 ? -1.0f : +1.0f);
|
||||
}
|
||||
|
||||
template <typename T, typename T2>
|
||||
constexpr auto MIN(const T m_a, const T2 m_b) {
|
||||
return m_a < m_b ? m_a : m_b;
|
||||
}
|
||||
|
||||
template <typename T, typename T2>
|
||||
constexpr auto MAX(const T m_a, const T2 m_b) {
|
||||
return m_a > m_b ? m_a : m_b;
|
||||
}
|
||||
|
||||
template <typename T, typename T2, typename T3>
|
||||
constexpr auto CLAMP(const T m_a, const T2 m_min, const T3 m_max) {
|
||||
return m_a < m_min ? m_min : (m_a > m_max ? m_max : m_a);
|
||||
}
|
||||
|
||||
// Generic swap template.
|
||||
#ifndef SWAP
|
||||
#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y))
|
||||
template <typename T>
|
||||
inline void __swap_tmpl(T &x, T &y) {
|
||||
T aux = x;
|
||||
x = y;
|
||||
y = aux;
|
||||
}
|
||||
#endif // SWAP
|
||||
|
||||
/* Functions to handle powers of 2 and shifting. */
|
||||
|
||||
// Function to find the next power of 2 to an integer.
|
||||
static _FORCE_INLINE_ unsigned int next_power_of_2(unsigned int x) {
|
||||
if (x == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
--x;
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
x |= x >> 8;
|
||||
x |= x >> 16;
|
||||
|
||||
return ++x;
|
||||
}
|
||||
|
||||
// Function to find the previous power of 2 to an integer.
|
||||
static _FORCE_INLINE_ unsigned int previous_power_of_2(unsigned int x) {
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
x |= x >> 8;
|
||||
x |= x >> 16;
|
||||
return x - (x >> 1);
|
||||
}
|
||||
|
||||
// Function to find the closest power of 2 to an integer.
|
||||
static _FORCE_INLINE_ unsigned int closest_power_of_2(unsigned int x) {
|
||||
unsigned int nx = next_power_of_2(x);
|
||||
unsigned int px = previous_power_of_2(x);
|
||||
return (nx - x) > (x - px) ? px : nx;
|
||||
}
|
||||
|
||||
// Get a shift value from a power of 2.
|
||||
static inline int get_shift_from_power_of_2(unsigned int p_bits) {
|
||||
for (unsigned int i = 0; i < 32; i++) {
|
||||
if (p_bits == (unsigned int)(1 << i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static _FORCE_INLINE_ T nearest_power_of_2_templated(T x) {
|
||||
--x;
|
||||
|
||||
// The number of operations on x is the base two logarithm
|
||||
// of the number of bits in the type. Add three to account
|
||||
// for sizeof(T) being in bytes.
|
||||
size_t num = get_shift_from_power_of_2(sizeof(T)) + 3;
|
||||
|
||||
// If the compiler is smart, it unrolls this loop.
|
||||
// If it's dumb, this is a bit slow.
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
x |= x >> (1 << i);
|
||||
}
|
||||
|
||||
return ++x;
|
||||
}
|
||||
|
||||
// Function to find the nearest (bigger) power of 2 to an integer.
|
||||
static inline unsigned int nearest_shift(unsigned int p_number) {
|
||||
for (int i = 30; i >= 0; i--) {
|
||||
if (p_number & (1 << i)) {
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// constexpr function to find the floored log2 of a number
|
||||
template <typename T>
|
||||
constexpr T floor_log2(T x) {
|
||||
return x < 2 ? x : 1 + floor_log2(x >> 1);
|
||||
}
|
||||
|
||||
// Get the number of bits needed to represent the number.
|
||||
// IE, if you pass in 8, you will get 4.
|
||||
// If you want to know how many bits are needed to store 8 values however, pass in (8 - 1).
|
||||
template <typename T>
|
||||
constexpr T get_num_bits(T x) {
|
||||
return floor_log2(x);
|
||||
}
|
||||
|
||||
// Swap 16, 32 and 64 bits value for endianness.
|
||||
#if defined(__GNUC__)
|
||||
#define BSWAP16(x) __builtin_bswap16(x)
|
||||
#define BSWAP32(x) __builtin_bswap32(x)
|
||||
#define BSWAP64(x) __builtin_bswap64(x)
|
||||
#else
|
||||
static inline uint16_t BSWAP16(uint16_t x) {
|
||||
return (x >> 8) | (x << 8);
|
||||
}
|
||||
|
||||
static inline uint32_t BSWAP32(uint32_t x) {
|
||||
return ((x << 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x >> 24));
|
||||
}
|
||||
|
||||
static inline uint64_t BSWAP64(uint64_t x) {
|
||||
x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32;
|
||||
x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
|
||||
x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8;
|
||||
return x;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace Math {
|
||||
|
||||
// This epsilon should match the one used by Godot for consistency.
|
||||
// Using `f` when `real_t` is float.
|
||||
#define CMP_EPSILON 0.00001f
|
||||
#define CMP_EPSILON2 (CMP_EPSILON * CMP_EPSILON)
|
||||
|
||||
// This epsilon is for values related to a unit size (scalar or vector len).
|
||||
#ifdef PRECISE_MATH_CHECKS
|
||||
#define UNIT_EPSILON 0.00001
|
||||
#else
|
||||
// Tolerate some more floating point error normally.
|
||||
#define UNIT_EPSILON 0.001
|
||||
#endif
|
||||
|
||||
// Functions reproduced as in Godot's source code `math_funcs.h`.
|
||||
// Some are overloads to automatically support changing real_t into either double or float in the way Godot does.
|
||||
|
||||
inline double fmod(double p_x, double p_y) {
|
||||
return ::fmod(p_x, p_y);
|
||||
}
|
||||
inline float fmod(float p_x, float p_y) {
|
||||
return ::fmodf(p_x, p_y);
|
||||
}
|
||||
|
||||
inline double fposmod(double p_x, double p_y) {
|
||||
double value = Math::fmod(p_x, p_y);
|
||||
if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
|
||||
value += p_y;
|
||||
}
|
||||
value += 0.0;
|
||||
return value;
|
||||
}
|
||||
inline float fposmod(float p_x, float p_y) {
|
||||
float value = Math::fmod(p_x, p_y);
|
||||
if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
|
||||
value += p_y;
|
||||
}
|
||||
value += 0.0f;
|
||||
return value;
|
||||
}
|
||||
|
||||
inline float fposmodp(float p_x, float p_y) {
|
||||
float value = Math::fmod(p_x, p_y);
|
||||
if (value < 0) {
|
||||
value += p_y;
|
||||
}
|
||||
value += 0.0f;
|
||||
return value;
|
||||
}
|
||||
inline double fposmodp(double p_x, double p_y) {
|
||||
double value = Math::fmod(p_x, p_y);
|
||||
if (value < 0) {
|
||||
value += p_y;
|
||||
}
|
||||
value += 0.0;
|
||||
return value;
|
||||
}
|
||||
|
||||
inline int64_t posmod(int64_t p_x, int64_t p_y) {
|
||||
int64_t value = p_x % p_y;
|
||||
if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
|
||||
value += p_y;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
inline double floor(double p_x) {
|
||||
return ::floor(p_x);
|
||||
}
|
||||
inline float floor(float p_x) {
|
||||
return ::floorf(p_x);
|
||||
}
|
||||
|
||||
inline double ceil(double p_x) {
|
||||
return ::ceil(p_x);
|
||||
}
|
||||
inline float ceil(float p_x) {
|
||||
return ::ceilf(p_x);
|
||||
}
|
||||
|
||||
inline double exp(double p_x) {
|
||||
return ::exp(p_x);
|
||||
}
|
||||
inline float exp(float p_x) {
|
||||
return ::expf(p_x);
|
||||
}
|
||||
|
||||
inline double sin(double p_x) {
|
||||
return ::sin(p_x);
|
||||
}
|
||||
inline float sin(float p_x) {
|
||||
return ::sinf(p_x);
|
||||
}
|
||||
|
||||
inline double cos(double p_x) {
|
||||
return ::cos(p_x);
|
||||
}
|
||||
inline float cos(float p_x) {
|
||||
return ::cosf(p_x);
|
||||
}
|
||||
|
||||
inline double tan(double p_x) {
|
||||
return ::tan(p_x);
|
||||
}
|
||||
inline float tan(float p_x) {
|
||||
return ::tanf(p_x);
|
||||
}
|
||||
|
||||
inline double sinh(double p_x) {
|
||||
return ::sinh(p_x);
|
||||
}
|
||||
inline float sinh(float p_x) {
|
||||
return ::sinhf(p_x);
|
||||
}
|
||||
|
||||
inline float sinc(float p_x) {
|
||||
return p_x == 0 ? 1 : ::sin(p_x) / p_x;
|
||||
}
|
||||
inline double sinc(double p_x) {
|
||||
return p_x == 0 ? 1 : ::sin(p_x) / p_x;
|
||||
}
|
||||
|
||||
inline float sincn(float p_x) {
|
||||
return (float)sinc(Math_PI * p_x);
|
||||
}
|
||||
inline double sincn(double p_x) {
|
||||
return sinc(Math_PI * p_x);
|
||||
}
|
||||
|
||||
inline double cosh(double p_x) {
|
||||
return ::cosh(p_x);
|
||||
}
|
||||
inline float cosh(float p_x) {
|
||||
return ::coshf(p_x);
|
||||
}
|
||||
|
||||
inline double tanh(double p_x) {
|
||||
return ::tanh(p_x);
|
||||
}
|
||||
inline float tanh(float p_x) {
|
||||
return ::tanhf(p_x);
|
||||
}
|
||||
|
||||
inline double asin(double p_x) {
|
||||
return ::asin(p_x);
|
||||
}
|
||||
inline float asin(float p_x) {
|
||||
return ::asinf(p_x);
|
||||
}
|
||||
|
||||
inline double acos(double p_x) {
|
||||
return ::acos(p_x);
|
||||
}
|
||||
inline float acos(float p_x) {
|
||||
return ::acosf(p_x);
|
||||
}
|
||||
|
||||
inline double atan(double p_x) {
|
||||
return ::atan(p_x);
|
||||
}
|
||||
inline float atan(float p_x) {
|
||||
return ::atanf(p_x);
|
||||
}
|
||||
|
||||
inline double atan2(double p_y, double p_x) {
|
||||
return ::atan2(p_y, p_x);
|
||||
}
|
||||
inline float atan2(float p_y, float p_x) {
|
||||
return ::atan2f(p_y, p_x);
|
||||
}
|
||||
|
||||
inline double sqrt(double p_x) {
|
||||
return ::sqrt(p_x);
|
||||
}
|
||||
inline float sqrt(float p_x) {
|
||||
return ::sqrtf(p_x);
|
||||
}
|
||||
|
||||
inline double pow(double p_x, double p_y) {
|
||||
return ::pow(p_x, p_y);
|
||||
}
|
||||
inline float pow(float p_x, float p_y) {
|
||||
return ::powf(p_x, p_y);
|
||||
}
|
||||
|
||||
inline double log(double p_x) {
|
||||
return ::log(p_x);
|
||||
}
|
||||
inline float log(float p_x) {
|
||||
return ::logf(p_x);
|
||||
}
|
||||
|
||||
inline float lerp(float minv, float maxv, float t) {
|
||||
return minv + t * (maxv - minv);
|
||||
}
|
||||
inline double lerp(double minv, double maxv, double t) {
|
||||
return minv + t * (maxv - minv);
|
||||
}
|
||||
|
||||
inline double lerp_angle(double p_from, double p_to, double p_weight) {
|
||||
double difference = fmod(p_to - p_from, Math_TAU);
|
||||
double distance = fmod(2.0 * difference, Math_TAU) - difference;
|
||||
return p_from + distance * p_weight;
|
||||
}
|
||||
inline float lerp_angle(float p_from, float p_to, float p_weight) {
|
||||
float difference = fmod(p_to - p_from, (float)Math_TAU);
|
||||
float distance = fmod(2.0f * difference, (float)Math_TAU) - difference;
|
||||
return p_from + distance * p_weight;
|
||||
}
|
||||
|
||||
inline double cubic_interpolate(double p_from, double p_to, double p_pre, double p_post, double p_weight) {
|
||||
return 0.5 *
|
||||
((p_from * 2.0) +
|
||||
(-p_pre + p_to) * p_weight +
|
||||
(2.0 * p_pre - 5.0 * p_from + 4.0 * p_to - p_post) * (p_weight * p_weight) +
|
||||
(-p_pre + 3.0 * p_from - 3.0 * p_to + p_post) * (p_weight * p_weight * p_weight));
|
||||
}
|
||||
|
||||
inline float cubic_interpolate(float p_from, float p_to, float p_pre, float p_post, float p_weight) {
|
||||
return 0.5f *
|
||||
((p_from * 2.0f) +
|
||||
(-p_pre + p_to) * p_weight +
|
||||
(2.0f * p_pre - 5.0f * p_from + 4.0f * p_to - p_post) * (p_weight * p_weight) +
|
||||
(-p_pre + 3.0f * p_from - 3.0f * p_to + p_post) * (p_weight * p_weight * p_weight));
|
||||
}
|
||||
|
||||
inline double cubic_interpolate_angle(double p_from, double p_to, double p_pre, double p_post, double p_weight) {
|
||||
double from_rot = fmod(p_from, Math_TAU);
|
||||
|
||||
double pre_diff = fmod(p_pre - from_rot, Math_TAU);
|
||||
double pre_rot = from_rot + fmod(2.0 * pre_diff, Math_TAU) - pre_diff;
|
||||
|
||||
double to_diff = fmod(p_to - from_rot, Math_TAU);
|
||||
double to_rot = from_rot + fmod(2.0 * to_diff, Math_TAU) - to_diff;
|
||||
|
||||
double post_diff = fmod(p_post - to_rot, Math_TAU);
|
||||
double post_rot = to_rot + fmod(2.0 * post_diff, Math_TAU) - post_diff;
|
||||
|
||||
return cubic_interpolate(from_rot, to_rot, pre_rot, post_rot, p_weight);
|
||||
}
|
||||
|
||||
inline float cubic_interpolate_angle(float p_from, float p_to, float p_pre, float p_post, float p_weight) {
|
||||
float from_rot = fmod(p_from, (float)Math_TAU);
|
||||
|
||||
float pre_diff = fmod(p_pre - from_rot, (float)Math_TAU);
|
||||
float pre_rot = from_rot + fmod(2.0f * pre_diff, (float)Math_TAU) - pre_diff;
|
||||
|
||||
float to_diff = fmod(p_to - from_rot, (float)Math_TAU);
|
||||
float to_rot = from_rot + fmod(2.0f * to_diff, (float)Math_TAU) - to_diff;
|
||||
|
||||
float post_diff = fmod(p_post - to_rot, (float)Math_TAU);
|
||||
float post_rot = to_rot + fmod(2.0f * post_diff, (float)Math_TAU) - post_diff;
|
||||
|
||||
return cubic_interpolate(from_rot, to_rot, pre_rot, post_rot, p_weight);
|
||||
}
|
||||
|
||||
inline double cubic_interpolate_in_time(double p_from, double p_to, double p_pre, double p_post, double p_weight,
|
||||
double p_to_t, double p_pre_t, double p_post_t) {
|
||||
/* Barry-Goldman method */
|
||||
double t = Math::lerp(0.0, p_to_t, p_weight);
|
||||
double a1 = Math::lerp(p_pre, p_from, p_pre_t == 0 ? 0.0 : (t - p_pre_t) / -p_pre_t);
|
||||
double a2 = Math::lerp(p_from, p_to, p_to_t == 0 ? 0.5 : t / p_to_t);
|
||||
double a3 = Math::lerp(p_to, p_post, p_post_t - p_to_t == 0 ? 1.0 : (t - p_to_t) / (p_post_t - p_to_t));
|
||||
double b1 = Math::lerp(a1, a2, p_to_t - p_pre_t == 0 ? 0.0 : (t - p_pre_t) / (p_to_t - p_pre_t));
|
||||
double b2 = Math::lerp(a2, a3, p_post_t == 0 ? 1.0 : t / p_post_t);
|
||||
return Math::lerp(b1, b2, p_to_t == 0 ? 0.5 : t / p_to_t);
|
||||
}
|
||||
|
||||
inline float cubic_interpolate_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight,
|
||||
float p_to_t, float p_pre_t, float p_post_t) {
|
||||
/* Barry-Goldman method */
|
||||
float t = Math::lerp(0.0f, p_to_t, p_weight);
|
||||
float a1 = Math::lerp(p_pre, p_from, p_pre_t == 0 ? 0.0f : (t - p_pre_t) / -p_pre_t);
|
||||
float a2 = Math::lerp(p_from, p_to, p_to_t == 0 ? 0.5f : t / p_to_t);
|
||||
float a3 = Math::lerp(p_to, p_post, p_post_t - p_to_t == 0 ? 1.0f : (t - p_to_t) / (p_post_t - p_to_t));
|
||||
float b1 = Math::lerp(a1, a2, p_to_t - p_pre_t == 0 ? 0.0f : (t - p_pre_t) / (p_to_t - p_pre_t));
|
||||
float b2 = Math::lerp(a2, a3, p_post_t == 0 ? 1.0f : t / p_post_t);
|
||||
return Math::lerp(b1, b2, p_to_t == 0 ? 0.5f : t / p_to_t);
|
||||
}
|
||||
|
||||
inline double cubic_interpolate_angle_in_time(double p_from, double p_to, double p_pre, double p_post, double p_weight,
|
||||
double p_to_t, double p_pre_t, double p_post_t) {
|
||||
double from_rot = fmod(p_from, Math_TAU);
|
||||
|
||||
double pre_diff = fmod(p_pre - from_rot, Math_TAU);
|
||||
double pre_rot = from_rot + fmod(2.0 * pre_diff, Math_TAU) - pre_diff;
|
||||
|
||||
double to_diff = fmod(p_to - from_rot, Math_TAU);
|
||||
double to_rot = from_rot + fmod(2.0 * to_diff, Math_TAU) - to_diff;
|
||||
|
||||
double post_diff = fmod(p_post - to_rot, Math_TAU);
|
||||
double post_rot = to_rot + fmod(2.0 * post_diff, Math_TAU) - post_diff;
|
||||
|
||||
return cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t);
|
||||
}
|
||||
|
||||
inline float cubic_interpolate_angle_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight,
|
||||
float p_to_t, float p_pre_t, float p_post_t) {
|
||||
float from_rot = fmod(p_from, (float)Math_TAU);
|
||||
|
||||
float pre_diff = fmod(p_pre - from_rot, (float)Math_TAU);
|
||||
float pre_rot = from_rot + fmod(2.0f * pre_diff, (float)Math_TAU) - pre_diff;
|
||||
|
||||
float to_diff = fmod(p_to - from_rot, (float)Math_TAU);
|
||||
float to_rot = from_rot + fmod(2.0f * to_diff, (float)Math_TAU) - to_diff;
|
||||
|
||||
float post_diff = fmod(p_post - to_rot, (float)Math_TAU);
|
||||
float post_rot = to_rot + fmod(2.0f * post_diff, (float)Math_TAU) - post_diff;
|
||||
|
||||
return cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t);
|
||||
}
|
||||
|
||||
inline double bezier_interpolate(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) {
|
||||
/* Formula from Wikipedia article on Bezier curves. */
|
||||
double omt = (1.0 - p_t);
|
||||
double omt2 = omt * omt;
|
||||
double omt3 = omt2 * omt;
|
||||
double t2 = p_t * p_t;
|
||||
double t3 = t2 * p_t;
|
||||
|
||||
return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3;
|
||||
}
|
||||
|
||||
inline float bezier_interpolate(float p_start, float p_control_1, float p_control_2, float p_end, float p_t) {
|
||||
/* Formula from Wikipedia article on Bezier curves. */
|
||||
float omt = (1.0f - p_t);
|
||||
float omt2 = omt * omt;
|
||||
float omt3 = omt2 * omt;
|
||||
float t2 = p_t * p_t;
|
||||
float t3 = t2 * p_t;
|
||||
|
||||
return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0f + p_control_2 * omt * t2 * 3.0f + p_end * t3;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T clamp(T x, T minv, T maxv) {
|
||||
if (x < minv) {
|
||||
return minv;
|
||||
}
|
||||
if (x > maxv) {
|
||||
return maxv;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T min(T a, T b) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T max(T a, T b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T sign(T x) {
|
||||
return static_cast<T>(SIGN(x));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T abs(T x) {
|
||||
return std::abs(x);
|
||||
}
|
||||
|
||||
inline double deg_to_rad(double p_y) {
|
||||
return p_y * Math_PI / 180.0;
|
||||
}
|
||||
inline float deg_to_rad(float p_y) {
|
||||
return p_y * static_cast<float>(Math_PI) / 180.f;
|
||||
}
|
||||
|
||||
inline double rad_to_deg(double p_y) {
|
||||
return p_y * 180.0 / Math_PI;
|
||||
}
|
||||
inline float rad_to_deg(float p_y) {
|
||||
return p_y * 180.f / static_cast<float>(Math_PI);
|
||||
}
|
||||
|
||||
inline double inverse_lerp(double p_from, double p_to, double p_value) {
|
||||
return (p_value - p_from) / (p_to - p_from);
|
||||
}
|
||||
inline float inverse_lerp(float p_from, float p_to, float p_value) {
|
||||
return (p_value - p_from) / (p_to - p_from);
|
||||
}
|
||||
|
||||
inline double remap(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) {
|
||||
return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value));
|
||||
}
|
||||
inline float remap(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) {
|
||||
return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value));
|
||||
}
|
||||
|
||||
inline bool is_nan(float p_val) {
|
||||
return std::isnan(p_val);
|
||||
}
|
||||
|
||||
inline bool is_nan(double p_val) {
|
||||
return std::isnan(p_val);
|
||||
}
|
||||
|
||||
inline bool is_inf(float p_val) {
|
||||
return std::isinf(p_val);
|
||||
}
|
||||
|
||||
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) {
|
||||
return true;
|
||||
}
|
||||
// Then check for approximate equality.
|
||||
float tolerance = (float)CMP_EPSILON * abs(a);
|
||||
if (tolerance < (float)CMP_EPSILON) {
|
||||
tolerance = (float)CMP_EPSILON;
|
||||
}
|
||||
return abs(a - b) < tolerance;
|
||||
}
|
||||
|
||||
inline bool is_equal_approx(float a, float b, float tolerance) {
|
||||
// Check for exact equality first, required to handle "infinity" values.
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
// Then check for approximate equality.
|
||||
return abs(a - b) < tolerance;
|
||||
}
|
||||
|
||||
inline bool is_zero_approx(float s) {
|
||||
return abs(s) < (float)CMP_EPSILON;
|
||||
}
|
||||
|
||||
inline bool is_equal_approx(double a, double b) {
|
||||
// Check for exact equality first, required to handle "infinity" values.
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
// Then check for approximate equality.
|
||||
double tolerance = CMP_EPSILON * abs(a);
|
||||
if (tolerance < CMP_EPSILON) {
|
||||
tolerance = CMP_EPSILON;
|
||||
}
|
||||
return abs(a - b) < tolerance;
|
||||
}
|
||||
|
||||
inline bool is_equal_approx(double a, double b, double tolerance) {
|
||||
// Check for exact equality first, required to handle "infinity" values.
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
// Then check for approximate equality.
|
||||
return abs(a - b) < tolerance;
|
||||
}
|
||||
|
||||
inline bool is_zero_approx(double s) {
|
||||
return abs(s) < CMP_EPSILON;
|
||||
}
|
||||
|
||||
inline float absf(float g) {
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
|
||||
u.f = g;
|
||||
u.i &= 2147483647u;
|
||||
return u.f;
|
||||
}
|
||||
|
||||
inline double absd(double g) {
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
u.d = g;
|
||||
u.i &= (uint64_t)9223372036854775807ull;
|
||||
return u.d;
|
||||
}
|
||||
|
||||
inline double smoothstep(double p_from, double p_to, double p_weight) {
|
||||
if (is_equal_approx(static_cast<real_t>(p_from), static_cast<real_t>(p_to))) {
|
||||
return p_from;
|
||||
}
|
||||
double x = clamp((p_weight - p_from) / (p_to - p_from), 0.0, 1.0);
|
||||
return x * x * (3.0 - 2.0 * x);
|
||||
}
|
||||
inline float smoothstep(float p_from, float p_to, float p_weight) {
|
||||
if (is_equal_approx(p_from, p_to)) {
|
||||
return p_from;
|
||||
}
|
||||
float x = clamp((p_weight - p_from) / (p_to - p_from), 0.0f, 1.0f);
|
||||
return x * x * (3.0f - 2.0f * x);
|
||||
}
|
||||
|
||||
inline double move_toward(double p_from, double p_to, double p_delta) {
|
||||
return std::abs(p_to - p_from) <= p_delta ? p_to : p_from + sign(p_to - p_from) * p_delta;
|
||||
}
|
||||
|
||||
inline float move_toward(float p_from, float p_to, float p_delta) {
|
||||
return std::abs(p_to - p_from) <= p_delta ? p_to : p_from + sign(p_to - p_from) * p_delta;
|
||||
}
|
||||
|
||||
inline double linear2db(double p_linear) {
|
||||
return log(p_linear) * 8.6858896380650365530225783783321;
|
||||
}
|
||||
inline float linear2db(float p_linear) {
|
||||
return log(p_linear) * 8.6858896380650365530225783783321f;
|
||||
}
|
||||
|
||||
inline double db2linear(double p_db) {
|
||||
return exp(p_db * 0.11512925464970228420089957273422);
|
||||
}
|
||||
inline float db2linear(float p_db) {
|
||||
return exp(p_db * 0.11512925464970228420089957273422f);
|
||||
}
|
||||
|
||||
inline double round(double p_val) {
|
||||
return (p_val >= 0) ? floor(p_val + 0.5) : -floor(-p_val + 0.5);
|
||||
}
|
||||
inline float round(float p_val) {
|
||||
return (p_val >= 0) ? floor(p_val + 0.5f) : -floor(-p_val + 0.5f);
|
||||
}
|
||||
|
||||
inline int64_t wrapi(int64_t value, int64_t min, int64_t max) {
|
||||
int64_t range = max - min;
|
||||
return range == 0 ? min : min + ((((value - min) % range) + range) % range);
|
||||
}
|
||||
|
||||
inline float wrapf(real_t value, real_t min, real_t max) {
|
||||
const real_t range = max - min;
|
||||
return is_zero_approx(range) ? min : value - (range * floor((value - min) / range));
|
||||
}
|
||||
|
||||
inline float fract(float value) {
|
||||
return value - floor(value);
|
||||
}
|
||||
|
||||
inline double fract(double value) {
|
||||
return value - floor(value);
|
||||
}
|
||||
|
||||
inline float pingpong(float value, float length) {
|
||||
return (length != 0.0f) ? abs(fract((value - length) / (length * 2.0f)) * length * 2.0f - length) : 0.0f;
|
||||
}
|
||||
|
||||
inline double pingpong(double value, double length) {
|
||||
return (length != 0.0) ? abs(fract((value - length) / (length * 2.0)) * length * 2.0 - length) : 0.0;
|
||||
}
|
||||
|
||||
// This function should be as fast as possible and rounding mode should not matter.
|
||||
inline int fast_ftoi(float a) {
|
||||
static int b;
|
||||
|
||||
#if (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0603) || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP // windows 8 phone?
|
||||
b = (int)((a > 0.0) ? (a + 0.5) : (a - 0.5));
|
||||
|
||||
#elif defined(_MSC_VER) && _MSC_VER < 1800
|
||||
__asm fld a __asm fistp b
|
||||
/*#elif defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) )
|
||||
// use AT&T inline assembly style, document that
|
||||
// we use memory as output (=m) and input (m)
|
||||
__asm__ __volatile__ (
|
||||
"flds %1 \n\t"
|
||||
"fistpl %0 \n\t"
|
||||
: "=m" (b)
|
||||
: "m" (a));*/
|
||||
|
||||
#else
|
||||
b = lrintf(a); // assuming everything but msvc 2012 or earlier has lrint
|
||||
#endif
|
||||
return b;
|
||||
}
|
||||
|
||||
inline double snapped(double p_value, double p_step) {
|
||||
if (p_step != 0) {
|
||||
p_value = Math::floor(p_value / p_step + 0.5) * p_step;
|
||||
}
|
||||
return p_value;
|
||||
}
|
||||
|
||||
inline float snap_scalar(float p_offset, float p_step, float p_target) {
|
||||
return p_step != 0 ? Math::snapped(p_target - p_offset, p_step) + p_offset : p_target;
|
||||
}
|
||||
|
||||
inline float snap_scalar_separation(float p_offset, float p_step, float p_target, float p_separation) {
|
||||
if (p_step != 0) {
|
||||
float a = Math::snapped(p_target - p_offset, p_step + p_separation) + p_offset;
|
||||
float b = a;
|
||||
if (p_target >= 0) {
|
||||
b -= p_separation;
|
||||
} else {
|
||||
b += p_step;
|
||||
}
|
||||
return (Math::abs(p_target - a) < Math::abs(p_target - b)) ? a : b;
|
||||
}
|
||||
return p_target;
|
||||
}
|
||||
|
||||
} // namespace Math
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_MATH_HPP
|
||||
220
include/godot_cpp/core/memory.hpp
Normal file
220
include/godot_cpp/core/memory.hpp
Normal file
@@ -0,0 +1,220 @@
|
||||
/**************************************************************************/
|
||||
/* memory.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_MEMORY_HPP
|
||||
#define GODOT_MEMORY_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <godot_cpp/core/defs.hpp>
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
#include <godot_cpp/godot.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
// p_dummy argument is added to avoid conflicts with the engine functions when both engine and GDExtension are built as a static library on iOS.
|
||||
void *operator new(size_t p_size, const char *p_dummy, const char *p_description); ///< operator new that takes a description and uses MemoryStaticPool
|
||||
void *operator new(size_t p_size, const char *p_dummy, void *(*p_allocfunc)(size_t p_size)); ///< operator new that takes a description and uses MemoryStaticPool
|
||||
void *operator new(size_t p_size, const char *p_dummy, void *p_pointer, size_t check, const char *p_description); ///< operator new that takes a description and uses a pointer to the preallocated memory
|
||||
|
||||
_ALWAYS_INLINE_ void *operator new(size_t p_size, const char *p_dummy, void *p_pointer, size_t check, const char *p_description) {
|
||||
return p_pointer;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// When compiling with VC++ 2017, the above declarations of placement new generate many irrelevant warnings (C4291).
|
||||
// The purpose of the following definitions is to muffle these warnings, not to provide a usable implementation of placement delete.
|
||||
void operator delete(void *p_mem, const char *p_dummy, const char *p_description);
|
||||
void operator delete(void *p_mem, const char *p_dummy, void *(*p_allocfunc)(size_t p_size));
|
||||
void operator delete(void *p_mem, const char *p_dummy, void *p_pointer, size_t check, const char *p_description);
|
||||
#endif
|
||||
|
||||
namespace godot {
|
||||
|
||||
class Wrapped;
|
||||
|
||||
class Memory {
|
||||
Memory();
|
||||
|
||||
public:
|
||||
// Alignment: ↓ max_align_t ↓ uint64_t ↓ max_align_t
|
||||
// ┌─────────────────┬──┬────────────────┬──┬───────────...
|
||||
// │ uint64_t │░░│ uint64_t │░░│ T[]
|
||||
// │ alloc size │░░│ element count │░░│ data
|
||||
// └─────────────────┴──┴────────────────┴──┴───────────...
|
||||
// Offset: ↑ SIZE_OFFSET ↑ ELEMENT_OFFSET ↑ DATA_OFFSET
|
||||
// Note: "alloc size" is used and set by the engine and is never accessed or changed for the extension.
|
||||
|
||||
static constexpr size_t SIZE_OFFSET = 0;
|
||||
static constexpr size_t ELEMENT_OFFSET = ((SIZE_OFFSET + sizeof(uint64_t)) % alignof(uint64_t) == 0) ? (SIZE_OFFSET + sizeof(uint64_t)) : ((SIZE_OFFSET + sizeof(uint64_t)) + alignof(uint64_t) - ((SIZE_OFFSET + sizeof(uint64_t)) % alignof(uint64_t)));
|
||||
static constexpr size_t DATA_OFFSET = ((ELEMENT_OFFSET + sizeof(uint64_t)) % alignof(max_align_t) == 0) ? (ELEMENT_OFFSET + sizeof(uint64_t)) : ((ELEMENT_OFFSET + sizeof(uint64_t)) + alignof(max_align_t) - ((ELEMENT_OFFSET + sizeof(uint64_t)) % alignof(max_align_t)));
|
||||
|
||||
static void *alloc_static(size_t p_bytes, bool p_pad_align = false);
|
||||
static void *realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align = false);
|
||||
static void free_static(void *p_ptr, bool p_pad_align = false);
|
||||
};
|
||||
|
||||
template <typename T, std::enable_if_t<!std::is_base_of<::godot::Wrapped, T>::value, bool> = true>
|
||||
_ALWAYS_INLINE_ void _pre_initialize() {}
|
||||
|
||||
_ALWAYS_INLINE_ void postinitialize_handler(void *) {}
|
||||
|
||||
template <typename T>
|
||||
_ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
|
||||
postinitialize_handler(p_obj);
|
||||
return p_obj;
|
||||
}
|
||||
|
||||
#define memalloc(m_size) ::godot::Memory::alloc_static(m_size)
|
||||
#define memrealloc(m_mem, m_size) ::godot::Memory::realloc_static(m_mem, m_size)
|
||||
#define memfree(m_mem) ::godot::Memory::free_static(m_mem)
|
||||
|
||||
#define memnew(m_class) (::godot::_pre_initialize<std::remove_pointer_t<decltype(new ("", "") m_class)>>(), ::godot::_post_initialize(new ("", "") m_class))
|
||||
|
||||
#define memnew_allocator(m_class, m_allocator) (::godot::_pre_initialize<std::remove_pointer_t<decltype(new ("", "") m_class)>>(), ::godot::_post_initialize(new ("", m_allocator::alloc) m_class))
|
||||
#define memnew_placement(m_placement, m_class) (::godot::_pre_initialize<std::remove_pointer_t<decltype(new ("", "") m_class)>>(), ::godot::_post_initialize(new ("", m_placement, sizeof(m_class), "") m_class))
|
||||
|
||||
// Generic comparator used in Map, List, etc.
|
||||
template <typename T>
|
||||
struct Comparator {
|
||||
_ALWAYS_INLINE_ bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void memdelete(T *p_class, typename std::enable_if<!std::is_base_of_v<godot::Wrapped, T>>::type * = nullptr) {
|
||||
if constexpr (!std::is_trivially_destructible_v<T>) {
|
||||
p_class->~T();
|
||||
}
|
||||
|
||||
Memory::free_static(p_class);
|
||||
}
|
||||
|
||||
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 <typename T, typename A>
|
||||
void memdelete_allocator(T *p_class) {
|
||||
if constexpr (!std::is_trivially_destructible_v<T>) {
|
||||
p_class->~T();
|
||||
}
|
||||
|
||||
A::free(p_class);
|
||||
}
|
||||
|
||||
class DefaultAllocator {
|
||||
public:
|
||||
_ALWAYS_INLINE_ static void *alloc(size_t p_memory) { return Memory::alloc_static(p_memory); }
|
||||
_ALWAYS_INLINE_ static void free(void *p_ptr) { Memory::free_static(p_ptr); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class DefaultTypedAllocator {
|
||||
public:
|
||||
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) {
|
||||
return nullptr;
|
||||
}
|
||||
/** overloading operator new[] cannot be done , because it may not return the real allocated address (it may pad the 'element count' before the actual array). Because of that, it must be done by hand. This is the
|
||||
same strategy used by std::vector, and the Vector class, so it should be safe.*/
|
||||
|
||||
size_t len = sizeof(T) * p_elements;
|
||||
uint8_t *mem = (uint8_t *)Memory::alloc_static(len, true);
|
||||
T *failptr = nullptr; // Get rid of a warning.
|
||||
ERR_FAIL_NULL_V(mem, failptr);
|
||||
|
||||
uint64_t *_elem_count_ptr = _get_element_count_ptr(mem);
|
||||
*(_elem_count_ptr) = p_elements;
|
||||
|
||||
if constexpr (!std::is_trivially_destructible_v<T>) {
|
||||
T *elems = (T *)mem;
|
||||
|
||||
/* call operator new */
|
||||
for (size_t i = 0; i < p_elements; i++) {
|
||||
new ("", &elems[i], sizeof(T), p_descr) T;
|
||||
}
|
||||
}
|
||||
|
||||
return (T *)mem;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
Memory::free_static(ptr, true);
|
||||
}
|
||||
|
||||
struct _GlobalNil {
|
||||
int color = 1;
|
||||
_GlobalNil *right;
|
||||
_GlobalNil *left;
|
||||
_GlobalNil *parent;
|
||||
|
||||
_GlobalNil();
|
||||
};
|
||||
|
||||
struct _GlobalNilClass {
|
||||
static _GlobalNil _nil;
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_MEMORY_HPP
|
||||
743
include/godot_cpp/core/method_bind.hpp
Normal file
743
include/godot_cpp/core/method_bind.hpp
Normal file
@@ -0,0 +1,743 @@
|
||||
/**************************************************************************/
|
||||
/* method_bind.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_METHOD_BIND_HPP
|
||||
#define GODOT_METHOD_BIND_HPP
|
||||
|
||||
#include <godot_cpp/core/binder_common.hpp>
|
||||
#include <godot_cpp/core/type_info.hpp>
|
||||
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
|
||||
#include <godot_cpp/classes/global_constants.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class MethodBind {
|
||||
uint32_t hint_flags = METHOD_FLAGS_DEFAULT;
|
||||
StringName name;
|
||||
StringName instance_class;
|
||||
int argument_count = 0;
|
||||
|
||||
bool _static = false;
|
||||
bool _const = false;
|
||||
bool _returns = false;
|
||||
bool _vararg = false;
|
||||
|
||||
std::vector<StringName> argument_names;
|
||||
GDExtensionVariantType *argument_types = nullptr;
|
||||
std::vector<Variant> default_arguments;
|
||||
|
||||
protected:
|
||||
void _set_const(bool p_const);
|
||||
void _set_static(bool p_static);
|
||||
void _set_returns(bool p_returns);
|
||||
void _set_vararg(bool p_vararg);
|
||||
virtual GDExtensionVariantType gen_argument_type(int p_arg) const = 0;
|
||||
virtual PropertyInfo gen_argument_type_info(int p_arg) const = 0;
|
||||
void _generate_argument_types(int p_count);
|
||||
|
||||
void set_argument_count(int p_count) { argument_count = p_count; }
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ const std::vector<Variant> &get_default_arguments() const { return default_arguments; }
|
||||
_FORCE_INLINE_ int get_default_argument_count() const { return (int)default_arguments.size(); }
|
||||
|
||||
_FORCE_INLINE_ Variant has_default_argument(int p_arg) const {
|
||||
const int num_default_args = (int)(default_arguments.size());
|
||||
const int idx = p_arg - (argument_count - num_default_args);
|
||||
|
||||
if (idx < 0 || idx >= num_default_args) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_FORCE_INLINE_ Variant get_default_argument(int p_arg) const {
|
||||
const int num_default_args = (int)(default_arguments.size());
|
||||
const int idx = p_arg - (argument_count - num_default_args);
|
||||
|
||||
if (idx < 0 || idx >= num_default_args) {
|
||||
return Variant();
|
||||
} else {
|
||||
return default_arguments[idx];
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ GDExtensionVariantType get_argument_type(int p_argument) const {
|
||||
ERR_FAIL_COND_V(p_argument < -1 || p_argument > argument_count, GDEXTENSION_VARIANT_TYPE_NIL);
|
||||
return argument_types[p_argument + 1];
|
||||
}
|
||||
|
||||
PropertyInfo get_argument_info(int p_argument) const;
|
||||
|
||||
std::vector<PropertyInfo> get_arguments_info_list() const {
|
||||
std::vector<PropertyInfo> vec;
|
||||
// First element is return value
|
||||
vec.reserve(argument_count + 1);
|
||||
for (int i = 0; i < argument_count + 1; i++) {
|
||||
vec.push_back(get_argument_info(i - 1));
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
void set_argument_names(const std::vector<StringName> &p_names);
|
||||
std::vector<StringName> get_argument_names() const;
|
||||
|
||||
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_argument) const = 0;
|
||||
|
||||
_FORCE_INLINE_ void set_hint_flags(uint32_t p_hint_flags) { hint_flags = p_hint_flags; }
|
||||
_FORCE_INLINE_ uint32_t get_hint_flags() const { return hint_flags | (is_const() ? GDEXTENSION_METHOD_FLAG_CONST : 0) | (is_vararg() ? GDEXTENSION_METHOD_FLAG_VARARG : 0) | (is_static() ? GDEXTENSION_METHOD_FLAG_STATIC : 0); }
|
||||
_FORCE_INLINE_ StringName get_instance_class() const { return instance_class; }
|
||||
_FORCE_INLINE_ void set_instance_class(StringName p_class) { instance_class = p_class; }
|
||||
|
||||
_FORCE_INLINE_ int get_argument_count() const { return argument_count; }
|
||||
|
||||
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const = 0;
|
||||
virtual void ptrcall(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return) const = 0;
|
||||
|
||||
StringName get_name() const;
|
||||
void set_name(const StringName &p_name);
|
||||
_FORCE_INLINE_ bool is_const() const { return _const; }
|
||||
_FORCE_INLINE_ bool is_static() const { return _static; }
|
||||
_FORCE_INLINE_ bool is_vararg() const { return _vararg; }
|
||||
_FORCE_INLINE_ bool has_return() const { return _returns; }
|
||||
|
||||
void set_default_arguments(const std::vector<Variant> &p_default_arguments) { default_arguments = p_default_arguments; }
|
||||
|
||||
std::vector<GDExtensionClassMethodArgumentMetadata> get_arguments_metadata_list() const {
|
||||
std::vector<GDExtensionClassMethodArgumentMetadata> vec;
|
||||
// First element is return value
|
||||
vec.reserve(argument_count + 1);
|
||||
for (int i = 0; i < argument_count + 1; i++) {
|
||||
vec.push_back(get_argument_metadata(i - 1));
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
static void bind_call(void *p_method_userdata, GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error);
|
||||
static void bind_ptrcall(void *p_method_userdata, GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return);
|
||||
|
||||
virtual ~MethodBind();
|
||||
};
|
||||
|
||||
template <typename Derived, typename T, typename R, bool should_returns>
|
||||
class MethodBindVarArgBase : public MethodBind {
|
||||
protected:
|
||||
R(T::*method)
|
||||
(const Variant **, GDExtensionInt, GDExtensionCallError &);
|
||||
std::vector<PropertyInfo> arguments;
|
||||
|
||||
public:
|
||||
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
|
||||
if (p_arg < 0) {
|
||||
return _gen_return_type_info();
|
||||
} else if ((size_t)(p_arg) < arguments.size()) {
|
||||
return arguments[p_arg];
|
||||
} else {
|
||||
return make_property_info(Variant::Type::NIL, "vararg", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
|
||||
}
|
||||
}
|
||||
|
||||
virtual GDExtensionVariantType gen_argument_type(int p_arg) const {
|
||||
return static_cast<GDExtensionVariantType>(gen_argument_type_info(p_arg).type);
|
||||
}
|
||||
|
||||
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int) const {
|
||||
return GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
}
|
||||
|
||||
virtual void ptrcall(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return) const {
|
||||
ERR_FAIL(); // Can't call.
|
||||
}
|
||||
|
||||
MethodBindVarArgBase(
|
||||
R (T::*p_method)(const Variant **, GDExtensionInt, GDExtensionCallError &),
|
||||
const MethodInfo &p_method_info,
|
||||
bool p_return_nil_is_variant) :
|
||||
method(p_method) {
|
||||
_set_vararg(true);
|
||||
_set_const(true);
|
||||
set_argument_count(p_method_info.arguments.size());
|
||||
if (p_method_info.arguments.size()) {
|
||||
arguments = p_method_info.arguments;
|
||||
|
||||
std::vector<StringName> names;
|
||||
names.reserve(p_method_info.arguments.size());
|
||||
for (size_t i = 0; i < p_method_info.arguments.size(); i++) {
|
||||
names.push_back(p_method_info.arguments[i].name);
|
||||
}
|
||||
set_argument_names(names);
|
||||
}
|
||||
|
||||
_generate_argument_types((int)p_method_info.arguments.size());
|
||||
_set_returns(should_returns);
|
||||
}
|
||||
|
||||
~MethodBindVarArgBase() {}
|
||||
|
||||
private:
|
||||
PropertyInfo _gen_return_type_info() const {
|
||||
return reinterpret_cast<const Derived *>(this)->_gen_return_type_info_impl();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class MethodBindVarArgT : public MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false> {
|
||||
friend class MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>;
|
||||
|
||||
public:
|
||||
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const {
|
||||
(static_cast<T *>(p_instance)->*MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>::method)((const Variant **)p_args, p_argument_count, r_error);
|
||||
return {};
|
||||
}
|
||||
|
||||
MethodBindVarArgT(
|
||||
void (T::*p_method)(const Variant **, GDExtensionInt, GDExtensionCallError &),
|
||||
const MethodInfo &p_method_info,
|
||||
bool p_return_nil_is_variant) :
|
||||
MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>(p_method, p_method_info, p_return_nil_is_variant) {
|
||||
}
|
||||
|
||||
private:
|
||||
PropertyInfo _gen_return_type_info_impl() const {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
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 <typename T, typename R>
|
||||
class MethodBindVarArgTR : public MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true> {
|
||||
friend class MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>;
|
||||
|
||||
public:
|
||||
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const {
|
||||
return (static_cast<T *>(p_instance)->*MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>::method)((const Variant **)p_args, p_argument_count, r_error);
|
||||
}
|
||||
|
||||
MethodBindVarArgTR(
|
||||
R (T::*p_method)(const Variant **, GDExtensionInt, GDExtensionCallError &),
|
||||
const MethodInfo &p_info,
|
||||
bool p_return_nil_is_variant) :
|
||||
MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>(p_method, p_info, p_return_nil_is_variant) {
|
||||
}
|
||||
|
||||
private:
|
||||
PropertyInfo _gen_return_type_info_impl() const {
|
||||
return GetTypeInfo<R>::get_class_info();
|
||||
}
|
||||
};
|
||||
|
||||
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());
|
||||
return a;
|
||||
}
|
||||
|
||||
#ifndef TYPED_METHOD_BIND
|
||||
class _gde_UnexistingClass;
|
||||
#define MB_T _gde_UnexistingClass
|
||||
#else
|
||||
#define MB_T T
|
||||
#endif
|
||||
|
||||
// No return, not const.
|
||||
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
template <typename T, typename... P>
|
||||
#else
|
||||
template <typename... P>
|
||||
#endif // TYPED_METHOD_BIND
|
||||
class MethodBindT : public MethodBind {
|
||||
void (MB_T::*method)(P...);
|
||||
|
||||
protected:
|
||||
// GCC raises warnings in the case P = {} as the comparison is always false...
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wlogical-op"
|
||||
#endif
|
||||
virtual GDExtensionVariantType gen_argument_type(int p_arg) const {
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
return call_get_argument_type<P...>(p_arg);
|
||||
} else {
|
||||
return GDEXTENSION_VARIANT_TYPE_NIL;
|
||||
}
|
||||
}
|
||||
|
||||
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
|
||||
PropertyInfo pi;
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
call_get_argument_type_info<P...>(p_arg, pi);
|
||||
} else {
|
||||
pi = PropertyInfo();
|
||||
}
|
||||
return pi;
|
||||
}
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_argument) const {
|
||||
return call_get_argument_metadata<P...>(p_argument);
|
||||
}
|
||||
|
||||
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const {
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
call_with_variant_args_dv(static_cast<T *>(p_instance), method, p_args, (int)p_argument_count, r_error, get_default_arguments());
|
||||
#else
|
||||
call_with_variant_args_dv(reinterpret_cast<MB_T *>(p_instance), method, p_args, p_argument_count, r_error, get_default_arguments());
|
||||
#endif
|
||||
return Variant();
|
||||
}
|
||||
virtual void ptrcall(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret) const {
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
call_with_ptr_args<T, P...>(static_cast<T *>(p_instance), method, p_args, nullptr);
|
||||
#else
|
||||
call_with_ptr_args<MB_T, P...>(reinterpret_cast<MB_T *>(p_instance), method, p_args, nullptr);
|
||||
#endif // TYPED_METHOD_BIND
|
||||
}
|
||||
|
||||
MethodBindT(void (MB_T::*p_method)(P...)) {
|
||||
method = p_method;
|
||||
_generate_argument_types(sizeof...(P));
|
||||
set_argument_count(sizeof...(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));
|
||||
#else
|
||||
MethodBind *a = memnew((MethodBindT<P...>)(reinterpret_cast<void (MB_T::*)(P...)>(p_method)));
|
||||
#endif // TYPED_METHOD_BIND
|
||||
a->set_instance_class(T::get_class_static());
|
||||
return a;
|
||||
}
|
||||
|
||||
// No return, const.
|
||||
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
template <typename T, typename... P>
|
||||
#else
|
||||
template <typename... P>
|
||||
#endif // TYPED_METHOD_BIND
|
||||
class MethodBindTC : public MethodBind {
|
||||
void (MB_T::*method)(P...) const;
|
||||
|
||||
protected:
|
||||
// GCC raises warnings in the case P = {} as the comparison is always false...
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wlogical-op"
|
||||
#endif
|
||||
virtual GDExtensionVariantType gen_argument_type(int p_arg) const {
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
return call_get_argument_type<P...>(p_arg);
|
||||
} else {
|
||||
return GDEXTENSION_VARIANT_TYPE_NIL;
|
||||
}
|
||||
}
|
||||
|
||||
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
|
||||
PropertyInfo pi;
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
call_get_argument_type_info<P...>(p_arg, pi);
|
||||
} else {
|
||||
pi = PropertyInfo();
|
||||
}
|
||||
return pi;
|
||||
}
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_argument) const {
|
||||
return call_get_argument_metadata<P...>(p_argument);
|
||||
}
|
||||
|
||||
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const {
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
call_with_variant_argsc_dv(static_cast<T *>(p_instance), method, p_args, (int)p_argument_count, r_error, get_default_arguments());
|
||||
#else
|
||||
call_with_variant_argsc_dv(reinterpret_cast<MB_T *>(p_instance), method, p_args, p_argument_count, r_error, get_default_arguments());
|
||||
#endif
|
||||
return Variant();
|
||||
}
|
||||
virtual void ptrcall(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret) const {
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
call_with_ptr_args<T, P...>(static_cast<T *>(p_instance), method, p_args, nullptr);
|
||||
#else
|
||||
call_with_ptr_args<MB_T, P...>(reinterpret_cast<MB_T *>(p_instance), method, p_args, nullptr);
|
||||
#endif // TYPED_METHOD_BIND
|
||||
}
|
||||
|
||||
MethodBindTC(void (MB_T::*p_method)(P...) const) {
|
||||
method = p_method;
|
||||
_generate_argument_types(sizeof...(P));
|
||||
set_argument_count(sizeof...(P));
|
||||
_set_const(true);
|
||||
}
|
||||
};
|
||||
|
||||
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));
|
||||
#else
|
||||
MethodBind *a = memnew((MethodBindTC<P...>)(reinterpret_cast<void (MB_T::*)(P...) const>(p_method)));
|
||||
#endif // TYPED_METHOD_BIND
|
||||
a->set_instance_class(T::get_class_static());
|
||||
return a;
|
||||
}
|
||||
|
||||
// Return, not const.
|
||||
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
template <typename T, typename R, typename... P>
|
||||
#else
|
||||
template <typename R, typename... P>
|
||||
#endif // TYPED_METHOD_BIND
|
||||
class MethodBindTR : public MethodBind {
|
||||
R(MB_T::*method)
|
||||
(P...);
|
||||
|
||||
protected:
|
||||
// GCC raises warnings in the case P = {} as the comparison is always false...
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wlogical-op"
|
||||
#endif
|
||||
virtual GDExtensionVariantType gen_argument_type(int p_arg) const {
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
return call_get_argument_type<P...>(p_arg);
|
||||
} else {
|
||||
return GDExtensionVariantType(GetTypeInfo<R>::VARIANT_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
PropertyInfo pi;
|
||||
call_get_argument_type_info<P...>(p_arg, pi);
|
||||
return pi;
|
||||
} else {
|
||||
return GetTypeInfo<R>::get_class_info();
|
||||
}
|
||||
}
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_argument) const {
|
||||
if (p_argument >= 0) {
|
||||
return call_get_argument_metadata<P...>(p_argument);
|
||||
} else {
|
||||
return GetTypeInfo<R>::METADATA;
|
||||
}
|
||||
}
|
||||
|
||||
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const {
|
||||
Variant ret;
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
call_with_variant_args_ret_dv(static_cast<T *>(p_instance), method, p_args, (int)p_argument_count, ret, r_error, get_default_arguments());
|
||||
#else
|
||||
call_with_variant_args_ret_dv((MB_T *)p_instance, method, p_args, p_argument_count, ret, r_error, get_default_arguments());
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
virtual void ptrcall(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret) const {
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
call_with_ptr_args<T, R, P...>(static_cast<T *>(p_instance), method, p_args, r_ret);
|
||||
#else
|
||||
call_with_ptr_args<MB_T, R, P...>(reinterpret_cast<MB_T *>(p_instance), method, p_args, r_ret);
|
||||
#endif // TYPED_METHOD_BIND
|
||||
}
|
||||
|
||||
MethodBindTR(R (MB_T::*p_method)(P...)) {
|
||||
method = p_method;
|
||||
_generate_argument_types(sizeof...(P));
|
||||
set_argument_count(sizeof...(P));
|
||||
_set_returns(true);
|
||||
}
|
||||
};
|
||||
|
||||
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));
|
||||
#else
|
||||
MethodBind *a = memnew((MethodBindTR<R, P...>)(reinterpret_cast<R (MB_T::*)(P...)>(p_method)));
|
||||
#endif // TYPED_METHOD_BIND
|
||||
a->set_instance_class(T::get_class_static());
|
||||
return a;
|
||||
}
|
||||
|
||||
// Return, const.
|
||||
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
template <typename T, typename R, typename... P>
|
||||
#else
|
||||
template <typename R, typename... P>
|
||||
#endif // TYPED_METHOD_BIND
|
||||
class MethodBindTRC : public MethodBind {
|
||||
R(MB_T::*method)
|
||||
(P...) const;
|
||||
|
||||
protected:
|
||||
// GCC raises warnings in the case P = {} as the comparison is always false...
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wlogical-op"
|
||||
#endif
|
||||
virtual GDExtensionVariantType gen_argument_type(int p_arg) const {
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
return call_get_argument_type<P...>(p_arg);
|
||||
} else {
|
||||
return GDExtensionVariantType(GetTypeInfo<R>::VARIANT_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
PropertyInfo pi;
|
||||
call_get_argument_type_info<P...>(p_arg, pi);
|
||||
return pi;
|
||||
} else {
|
||||
return GetTypeInfo<R>::get_class_info();
|
||||
}
|
||||
}
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_argument) const {
|
||||
if (p_argument >= 0) {
|
||||
return call_get_argument_metadata<P...>(p_argument);
|
||||
} else {
|
||||
return GetTypeInfo<R>::METADATA;
|
||||
}
|
||||
}
|
||||
|
||||
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const {
|
||||
Variant ret;
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
call_with_variant_args_retc_dv(static_cast<T *>(p_instance), method, p_args, (int)p_argument_count, ret, r_error, get_default_arguments());
|
||||
#else
|
||||
call_with_variant_args_retc_dv((MB_T *)p_instance, method, p_args, p_argument_count, ret, r_error, get_default_arguments());
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
virtual void ptrcall(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret) const {
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
call_with_ptr_args<T, R, P...>(static_cast<T *>(p_instance), method, p_args, r_ret);
|
||||
#else
|
||||
call_with_ptr_args<MB_T, R, P...>(reinterpret_cast<MB_T *>(p_instance), method, p_args, r_ret);
|
||||
#endif // TYPED_METHOD_BIND
|
||||
}
|
||||
|
||||
MethodBindTRC(R (MB_T::*p_method)(P...) const) {
|
||||
method = p_method;
|
||||
_generate_argument_types(sizeof...(P));
|
||||
set_argument_count(sizeof...(P));
|
||||
_set_returns(true);
|
||||
_set_const(true);
|
||||
}
|
||||
};
|
||||
|
||||
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));
|
||||
#else
|
||||
MethodBind *a = memnew((MethodBindTRC<R, P...>)(reinterpret_cast<R (MB_T::*)(P...) const>(p_method)));
|
||||
#endif // TYPED_METHOD_BIND
|
||||
a->set_instance_class(T::get_class_static());
|
||||
return a;
|
||||
}
|
||||
|
||||
// STATIC BINDS
|
||||
|
||||
// no return
|
||||
|
||||
template <typename... P>
|
||||
class MethodBindTS : public MethodBind {
|
||||
void (*function)(P...);
|
||||
|
||||
protected:
|
||||
// GCC raises warnings in the case P = {} as the comparison is always false...
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wlogical-op"
|
||||
#endif
|
||||
virtual GDExtensionVariantType gen_argument_type(int p_arg) const {
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
return call_get_argument_type<P...>(p_arg);
|
||||
} else {
|
||||
return GDEXTENSION_VARIANT_TYPE_NIL;
|
||||
}
|
||||
}
|
||||
|
||||
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
|
||||
PropertyInfo pi;
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
call_get_argument_type_info<P...>(p_arg, pi);
|
||||
} else {
|
||||
pi = PropertyInfo();
|
||||
}
|
||||
return pi;
|
||||
}
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_arg) const {
|
||||
return call_get_argument_metadata<P...>(p_arg);
|
||||
}
|
||||
|
||||
virtual Variant call(GDExtensionClassInstancePtr p_object, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_arg_count, GDExtensionCallError &r_error) const {
|
||||
(void)p_object; // unused
|
||||
call_with_variant_args_static_dv(function, p_args, p_arg_count, r_error, get_default_arguments());
|
||||
return Variant();
|
||||
}
|
||||
|
||||
virtual void ptrcall(GDExtensionClassInstancePtr p_object, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret) const {
|
||||
(void)p_object;
|
||||
(void)r_ret;
|
||||
call_with_ptr_args_static_method(function, p_args);
|
||||
}
|
||||
|
||||
MethodBindTS(void (*p_function)(P...)) {
|
||||
function = p_function;
|
||||
_generate_argument_types(sizeof...(P));
|
||||
set_argument_count(sizeof...(P));
|
||||
_set_static(true);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... P>
|
||||
MethodBind *create_static_method_bind(void (*p_method)(P...)) {
|
||||
MethodBind *a = memnew((MethodBindTS<P...>)(p_method));
|
||||
return a;
|
||||
}
|
||||
|
||||
// return
|
||||
|
||||
template <typename R, typename... P>
|
||||
class MethodBindTRS : public MethodBind {
|
||||
R(*function)
|
||||
(P...);
|
||||
|
||||
protected:
|
||||
// GCC raises warnings in the case P = {} as the comparison is always false...
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wlogical-op"
|
||||
#endif
|
||||
virtual GDExtensionVariantType gen_argument_type(int p_arg) const {
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
return call_get_argument_type<P...>(p_arg);
|
||||
} else {
|
||||
return GDExtensionVariantType(GetTypeInfo<R>::VARIANT_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
PropertyInfo pi;
|
||||
call_get_argument_type_info<P...>(p_arg, pi);
|
||||
return pi;
|
||||
} else {
|
||||
return GetTypeInfo<R>::get_class_info();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_arg) const {
|
||||
if (p_arg >= 0) {
|
||||
return call_get_argument_metadata<P...>(p_arg);
|
||||
} else {
|
||||
return GetTypeInfo<R>::METADATA;
|
||||
}
|
||||
}
|
||||
|
||||
virtual Variant call(GDExtensionClassInstancePtr p_object, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_arg_count, GDExtensionCallError &r_error) const {
|
||||
Variant ret;
|
||||
call_with_variant_args_static_ret_dv(function, p_args, p_arg_count, ret, r_error, get_default_arguments());
|
||||
return ret;
|
||||
}
|
||||
|
||||
virtual void ptrcall(GDExtensionClassInstancePtr p_object, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret) const {
|
||||
(void)p_object;
|
||||
call_with_ptr_args_static_method_ret(function, p_args, r_ret);
|
||||
}
|
||||
|
||||
MethodBindTRS(R (*p_function)(P...)) {
|
||||
function = p_function;
|
||||
_generate_argument_types(sizeof...(P));
|
||||
set_argument_count(sizeof...(P));
|
||||
_set_static(true);
|
||||
_set_returns(true);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename R, typename... P>
|
||||
MethodBind *create_static_method_bind(R (*p_method)(P...)) {
|
||||
MethodBind *a = memnew((MethodBindTRS<R, P...>)(p_method));
|
||||
return a;
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_METHOD_BIND_HPP
|
||||
241
include/godot_cpp/core/method_ptrcall.hpp
Normal file
241
include/godot_cpp/core/method_ptrcall.hpp
Normal file
@@ -0,0 +1,241 @@
|
||||
/**************************************************************************/
|
||||
/* method_ptrcall.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_METHOD_PTRCALL_HPP
|
||||
#define GODOT_METHOD_PTRCALL_HPP
|
||||
|
||||
#include <godot_cpp/core/defs.hpp>
|
||||
|
||||
#include <godot_cpp/core/object.hpp>
|
||||
#include <godot_cpp/godot.hpp>
|
||||
#include <godot_cpp/variant/variant.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <typename T>
|
||||
struct PtrToArg {};
|
||||
|
||||
#define MAKE_PTRARG(m_type) \
|
||||
template <> \
|
||||
struct PtrToArg<m_type> { \
|
||||
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
|
||||
return *reinterpret_cast<const m_type *>(p_ptr); \
|
||||
} \
|
||||
typedef m_type EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
|
||||
*reinterpret_cast<m_type *>(p_ptr) = p_val; \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct PtrToArg<const m_type &> { \
|
||||
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
|
||||
return *reinterpret_cast<const m_type *>(p_ptr); \
|
||||
} \
|
||||
typedef m_type EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
|
||||
*reinterpret_cast<m_type *>(p_ptr) = p_val; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define MAKE_PTRARGCONV(m_type, m_conv) \
|
||||
template <> \
|
||||
struct PtrToArg<m_type> { \
|
||||
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
|
||||
return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \
|
||||
} \
|
||||
typedef m_conv EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
|
||||
*reinterpret_cast<m_conv *>(p_ptr) = static_cast<m_conv>(p_val); \
|
||||
} \
|
||||
_FORCE_INLINE_ static m_conv encode_arg(m_type p_val) { \
|
||||
return static_cast<m_conv>(p_val); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct PtrToArg<const m_type &> { \
|
||||
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
|
||||
return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \
|
||||
} \
|
||||
typedef m_conv EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
|
||||
*reinterpret_cast<m_conv *>(p_ptr) = static_cast<m_conv>(p_val); \
|
||||
} \
|
||||
_FORCE_INLINE_ static m_conv encode_arg(m_type p_val) { \
|
||||
return static_cast<m_conv>(p_val); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define MAKE_PTRARG_BY_REFERENCE(m_type) \
|
||||
template <> \
|
||||
struct PtrToArg<m_type> { \
|
||||
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
|
||||
return *reinterpret_cast<const m_type *>(p_ptr); \
|
||||
} \
|
||||
typedef m_type EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(const m_type &p_val, void *p_ptr) { \
|
||||
*reinterpret_cast<m_type *>(p_ptr) = p_val; \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct PtrToArg<const m_type &> { \
|
||||
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
|
||||
return *reinterpret_cast<const m_type *>(p_ptr); \
|
||||
} \
|
||||
typedef m_type EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(const m_type &p_val, void *p_ptr) { \
|
||||
*reinterpret_cast<m_type *>(p_ptr) = p_val; \
|
||||
} \
|
||||
}
|
||||
|
||||
MAKE_PTRARGCONV(bool, uint8_t);
|
||||
// Integer types.
|
||||
MAKE_PTRARGCONV(uint8_t, int64_t);
|
||||
MAKE_PTRARGCONV(int8_t, int64_t);
|
||||
MAKE_PTRARGCONV(uint16_t, int64_t);
|
||||
MAKE_PTRARGCONV(int16_t, int64_t);
|
||||
MAKE_PTRARGCONV(uint32_t, int64_t);
|
||||
MAKE_PTRARGCONV(int32_t, int64_t);
|
||||
MAKE_PTRARGCONV(char16_t, int64_t);
|
||||
MAKE_PTRARGCONV(char32_t, int64_t);
|
||||
MAKE_PTRARGCONV(wchar_t, int64_t);
|
||||
MAKE_PTRARG(int64_t);
|
||||
MAKE_PTRARG(uint64_t);
|
||||
// Float types
|
||||
MAKE_PTRARGCONV(float, double);
|
||||
MAKE_PTRARG(double);
|
||||
|
||||
MAKE_PTRARG(String);
|
||||
MAKE_PTRARG(Vector2);
|
||||
MAKE_PTRARG(Vector2i);
|
||||
MAKE_PTRARG(Rect2);
|
||||
MAKE_PTRARG(Rect2i);
|
||||
MAKE_PTRARG_BY_REFERENCE(Vector3);
|
||||
MAKE_PTRARG_BY_REFERENCE(Vector3i);
|
||||
MAKE_PTRARG(Transform2D);
|
||||
MAKE_PTRARG_BY_REFERENCE(Vector4);
|
||||
MAKE_PTRARG_BY_REFERENCE(Vector4i);
|
||||
MAKE_PTRARG_BY_REFERENCE(Plane);
|
||||
MAKE_PTRARG(Quaternion);
|
||||
MAKE_PTRARG_BY_REFERENCE(AABB);
|
||||
MAKE_PTRARG_BY_REFERENCE(Basis);
|
||||
MAKE_PTRARG_BY_REFERENCE(Transform3D);
|
||||
MAKE_PTRARG_BY_REFERENCE(Projection);
|
||||
MAKE_PTRARG_BY_REFERENCE(Color);
|
||||
MAKE_PTRARG(StringName);
|
||||
MAKE_PTRARG(NodePath);
|
||||
MAKE_PTRARG(RID);
|
||||
// Object doesn't need this.
|
||||
MAKE_PTRARG(Callable);
|
||||
MAKE_PTRARG(Signal);
|
||||
MAKE_PTRARG(Dictionary);
|
||||
MAKE_PTRARG(Array);
|
||||
MAKE_PTRARG(PackedByteArray);
|
||||
MAKE_PTRARG(PackedInt32Array);
|
||||
MAKE_PTRARG(PackedInt64Array);
|
||||
MAKE_PTRARG(PackedFloat32Array);
|
||||
MAKE_PTRARG(PackedFloat64Array);
|
||||
MAKE_PTRARG(PackedStringArray);
|
||||
MAKE_PTRARG(PackedVector2Array);
|
||||
MAKE_PTRARG(PackedVector3Array);
|
||||
MAKE_PTRARG(PackedVector4Array);
|
||||
MAKE_PTRARG(PackedColorArray);
|
||||
MAKE_PTRARG_BY_REFERENCE(Variant);
|
||||
|
||||
// This is for Object.
|
||||
|
||||
template <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 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) = likely(p_var) ? p_var->_owner : nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
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 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) = likely(p_var) ? p_var->_owner : nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
// Pointers.
|
||||
#define GDVIRTUAL_NATIVE_PTR(m_type) \
|
||||
template <> \
|
||||
struct PtrToArg<m_type *> { \
|
||||
_FORCE_INLINE_ static m_type *convert(const void *p_ptr) { \
|
||||
return (m_type *)(*(void **)p_ptr); \
|
||||
} \
|
||||
typedef m_type *EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(m_type *p_var, void *p_ptr) { \
|
||||
*reinterpret_cast<m_type **>(p_ptr) = p_var; \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
template <> \
|
||||
struct PtrToArg<const m_type *> { \
|
||||
_FORCE_INLINE_ static const m_type *convert(const void *p_ptr) { \
|
||||
return (const m_type *)(*(const void **)p_ptr); \
|
||||
} \
|
||||
typedef const m_type *EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(const m_type *p_var, void *p_ptr) { \
|
||||
*reinterpret_cast<const m_type **>(p_ptr) = p_var; \
|
||||
} \
|
||||
}
|
||||
|
||||
GDVIRTUAL_NATIVE_PTR(void);
|
||||
GDVIRTUAL_NATIVE_PTR(bool);
|
||||
GDVIRTUAL_NATIVE_PTR(char);
|
||||
GDVIRTUAL_NATIVE_PTR(char16_t);
|
||||
GDVIRTUAL_NATIVE_PTR(char32_t);
|
||||
GDVIRTUAL_NATIVE_PTR(wchar_t);
|
||||
GDVIRTUAL_NATIVE_PTR(uint8_t);
|
||||
GDVIRTUAL_NATIVE_PTR(uint8_t *);
|
||||
GDVIRTUAL_NATIVE_PTR(int8_t);
|
||||
GDVIRTUAL_NATIVE_PTR(uint16_t);
|
||||
GDVIRTUAL_NATIVE_PTR(int16_t);
|
||||
GDVIRTUAL_NATIVE_PTR(uint32_t);
|
||||
GDVIRTUAL_NATIVE_PTR(int32_t);
|
||||
GDVIRTUAL_NATIVE_PTR(int64_t);
|
||||
GDVIRTUAL_NATIVE_PTR(uint64_t);
|
||||
GDVIRTUAL_NATIVE_PTR(float);
|
||||
GDVIRTUAL_NATIVE_PTR(double);
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_METHOD_PTRCALL_HPP
|
||||
59
include/godot_cpp/core/mutex_lock.hpp
Normal file
59
include/godot_cpp/core/mutex_lock.hpp
Normal file
@@ -0,0 +1,59 @@
|
||||
/**************************************************************************/
|
||||
/* mutex_lock.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_MUTEX_LOCK_HPP
|
||||
#define GODOT_MUTEX_LOCK_HPP
|
||||
|
||||
#include <godot_cpp/classes/mutex.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class MutexLock {
|
||||
const Mutex &mutex;
|
||||
|
||||
public:
|
||||
_ALWAYS_INLINE_ explicit MutexLock(const Mutex &p_mutex) :
|
||||
mutex(p_mutex) {
|
||||
const_cast<Mutex *>(&mutex)->lock();
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ ~MutexLock() {
|
||||
const_cast<Mutex *>(&mutex)->unlock();
|
||||
}
|
||||
};
|
||||
|
||||
#define _THREAD_SAFE_CLASS_ mutable Mutex _thread_safe_;
|
||||
#define _THREAD_SAFE_METHOD_ MutexLock _thread_safe_method_(_thread_safe_);
|
||||
#define _THREAD_SAFE_LOCK_ _thread_safe_.lock();
|
||||
#define _THREAD_SAFE_UNLOCK_ _thread_safe_.unlock();
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_MUTEX_LOCK_HPP
|
||||
152
include/godot_cpp/core/object.hpp
Normal file
152
include/godot_cpp/core/object.hpp
Normal file
@@ -0,0 +1,152 @@
|
||||
/**************************************************************************/
|
||||
/* object.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_OBJECT_HPP
|
||||
#define GODOT_OBJECT_HPP
|
||||
|
||||
#include <godot_cpp/core/defs.hpp>
|
||||
|
||||
#include <godot_cpp/core/object_id.hpp>
|
||||
|
||||
#include <godot_cpp/core/property_info.hpp>
|
||||
|
||||
#include <godot_cpp/variant/variant.hpp>
|
||||
|
||||
#include <godot_cpp/classes/object.hpp>
|
||||
|
||||
#include <godot_cpp/godot.hpp>
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#define ADD_SIGNAL(m_signal) ::godot::ClassDB::add_signal(get_class_static(), m_signal)
|
||||
#define ADD_GROUP(m_name, m_prefix) ::godot::ClassDB::add_property_group(get_class_static(), m_name, m_prefix)
|
||||
#define ADD_SUBGROUP(m_name, m_prefix) ::godot::ClassDB::add_property_subgroup(get_class_static(), m_name, m_prefix)
|
||||
#define ADD_PROPERTY(m_property, m_setter, m_getter) ::godot::ClassDB::add_property(get_class_static(), m_property, m_setter, m_getter)
|
||||
#define ADD_PROPERTYI(m_property, m_setter, m_getter, m_index) ::godot::ClassDB::add_property(get_class_static(), m_property, m_setter, m_getter, m_index)
|
||||
|
||||
namespace godot {
|
||||
|
||||
namespace internal {
|
||||
|
||||
Object *get_object_instance_binding(GodotObject *);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
struct MethodInfo {
|
||||
StringName name;
|
||||
PropertyInfo return_val;
|
||||
uint32_t flags;
|
||||
int id = 0;
|
||||
std::vector<PropertyInfo> arguments;
|
||||
std::vector<Variant> default_arguments;
|
||||
GDExtensionClassMethodArgumentMetadata return_val_metadata;
|
||||
std::vector<GDExtensionClassMethodArgumentMetadata> arguments_metadata;
|
||||
|
||||
inline bool operator==(const MethodInfo &p_method) const { return id == p_method.id; }
|
||||
inline bool operator<(const MethodInfo &p_method) const { return id == p_method.id ? (name < p_method.name) : (id < p_method.id); }
|
||||
|
||||
operator Dictionary() const;
|
||||
|
||||
static MethodInfo from_dict(const Dictionary &p_dict);
|
||||
|
||||
MethodInfo();
|
||||
MethodInfo(StringName p_name);
|
||||
template <typename... Args>
|
||||
MethodInfo(StringName p_name, const Args &...args);
|
||||
MethodInfo(Variant::Type ret);
|
||||
MethodInfo(Variant::Type ret, StringName p_name);
|
||||
template <typename... Args>
|
||||
MethodInfo(Variant::Type ret, StringName p_name, const Args &...args);
|
||||
MethodInfo(const PropertyInfo &p_ret, StringName p_name);
|
||||
template <typename... Args>
|
||||
MethodInfo(const PropertyInfo &p_ret, StringName p_name, const Args &...);
|
||||
};
|
||||
|
||||
template <typename... Args>
|
||||
MethodInfo::MethodInfo(StringName p_name, const Args &...args) :
|
||||
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
|
||||
arguments = { 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 <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... };
|
||||
}
|
||||
|
||||
class ObjectDB {
|
||||
public:
|
||||
static Object *get_instance(uint64_t p_object_id) {
|
||||
GDExtensionObjectPtr obj = internal::gdextension_interface_object_get_instance_from_id(p_object_id);
|
||||
if (obj == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return internal::get_object_instance_binding(obj);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
T *Object::cast_to(Object *p_object) {
|
||||
if (p_object == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
StringName class_name = T::get_class_static();
|
||||
GDExtensionObjectPtr casted = internal::gdextension_interface_object_cast_to(p_object->_owner, internal::gdextension_interface_classdb_get_class_tag(class_name._native_ptr()));
|
||||
if (casted == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return dynamic_cast<T *>(internal::get_object_instance_binding(casted));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T *Object::cast_to(const Object *p_object) {
|
||||
if (p_object == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
StringName class_name = T::get_class_static();
|
||||
GDExtensionObjectPtr casted = internal::gdextension_interface_object_cast_to(p_object->_owner, internal::gdextension_interface_classdb_get_class_tag(class_name._native_ptr()));
|
||||
if (casted == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return dynamic_cast<const T *>(internal::get_object_instance_binding(casted));
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_OBJECT_HPP
|
||||
62
include/godot_cpp/core/object_id.hpp
Normal file
62
include/godot_cpp/core/object_id.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/**************************************************************************/
|
||||
/* object_id.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_OBJECT_ID_HPP
|
||||
#define GODOT_OBJECT_ID_HPP
|
||||
|
||||
#include <godot_cpp/core/defs.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class ObjectID {
|
||||
uint64_t id = 0;
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ bool is_ref_counted() const { return (id & (uint64_t(1) << 63)) != 0; }
|
||||
_FORCE_INLINE_ bool is_valid() const { return id != 0; }
|
||||
_FORCE_INLINE_ bool is_null() const { return id == 0; }
|
||||
_FORCE_INLINE_ operator uint64_t() const { return id; }
|
||||
_FORCE_INLINE_ operator int64_t() const { return id; }
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const ObjectID &p_id) const { return id == p_id.id; }
|
||||
_FORCE_INLINE_ bool operator!=(const ObjectID &p_id) const { return id != p_id.id; }
|
||||
_FORCE_INLINE_ bool operator<(const ObjectID &p_id) const { return id < p_id.id; }
|
||||
|
||||
_FORCE_INLINE_ void operator=(int64_t p_int64) { id = p_int64; }
|
||||
_FORCE_INLINE_ void operator=(uint64_t p_uint64) { id = p_uint64; }
|
||||
|
||||
_FORCE_INLINE_ ObjectID() {}
|
||||
_FORCE_INLINE_ explicit ObjectID(const uint64_t p_id) { id = p_id; }
|
||||
_FORCE_INLINE_ explicit ObjectID(const int64_t p_id) { id = p_id; }
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_OBJECT_ID_HPP
|
||||
73
include/godot_cpp/core/print_string.hpp
Normal file
73
include/godot_cpp/core/print_string.hpp
Normal file
@@ -0,0 +1,73 @@
|
||||
/**************************************************************************/
|
||||
/* print_string.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_PRINT_STRING_HPP
|
||||
#define GODOT_PRINT_STRING_HPP
|
||||
|
||||
#include <godot_cpp/variant/utility_functions.hpp>
|
||||
|
||||
namespace godot {
|
||||
inline void print_error(const Variant &p_variant) {
|
||||
UtilityFunctions::printerr(p_variant);
|
||||
}
|
||||
|
||||
inline void print_line(const Variant &p_variant) {
|
||||
UtilityFunctions::print(p_variant);
|
||||
}
|
||||
|
||||
inline void print_line_rich(const Variant &p_variant) {
|
||||
UtilityFunctions::print_rich(p_variant);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void print_error(const Variant &p_variant, Args... p_args) {
|
||||
UtilityFunctions::printerr(p_variant, p_args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void print_line(const Variant &p_variant, Args... p_args) {
|
||||
UtilityFunctions::print(p_variant, p_args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void print_line_rich(const Variant &p_variant, Args... p_args) {
|
||||
UtilityFunctions::print_rich(p_variant, p_args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void print_verbose(const Variant &p_variant, Args... p_args) {
|
||||
UtilityFunctions::print_verbose(p_variant, p_args...);
|
||||
}
|
||||
|
||||
bool is_print_verbose_enabled();
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_PRINT_STRING_HPP
|
||||
132
include/godot_cpp/core/property_info.hpp
Normal file
132
include/godot_cpp/core/property_info.hpp
Normal file
@@ -0,0 +1,132 @@
|
||||
/**************************************************************************/
|
||||
/* property_info.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_PROPERTY_INFO_HPP
|
||||
#define GODOT_PROPERTY_INFO_HPP
|
||||
|
||||
#include <godot_cpp/core/defs.hpp>
|
||||
|
||||
#include <godot_cpp/classes/global_constants.hpp>
|
||||
|
||||
#include <godot_cpp/variant/variant.hpp>
|
||||
|
||||
#include <godot_cpp/godot.hpp>
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
|
||||
namespace godot {
|
||||
|
||||
struct PropertyInfo {
|
||||
Variant::Type type = Variant::NIL;
|
||||
StringName name;
|
||||
StringName class_name;
|
||||
uint32_t hint = PROPERTY_HINT_NONE;
|
||||
String hint_string;
|
||||
uint32_t usage = PROPERTY_USAGE_DEFAULT;
|
||||
|
||||
PropertyInfo() = default;
|
||||
|
||||
PropertyInfo(Variant::Type 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 = "") :
|
||||
type(p_type),
|
||||
name(p_name),
|
||||
hint(p_hint),
|
||||
hint_string(p_hint_string),
|
||||
usage(p_usage) {
|
||||
if (hint == PROPERTY_HINT_RESOURCE_TYPE) {
|
||||
class_name = hint_string;
|
||||
} else {
|
||||
class_name = p_class_name;
|
||||
}
|
||||
}
|
||||
|
||||
PropertyInfo(GDExtensionVariantType p_type, const StringName &p_name, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "", uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const StringName &p_class_name = "") :
|
||||
PropertyInfo((Variant::Type)p_type, p_name, p_hint, p_hint_string, p_usage, p_class_name) {}
|
||||
|
||||
PropertyInfo(const GDExtensionPropertyInfo *p_info) :
|
||||
PropertyInfo(p_info->type, *reinterpret_cast<StringName *>(p_info->name), (PropertyHint)p_info->hint, *reinterpret_cast<String *>(p_info->hint_string), p_info->usage, *reinterpret_cast<StringName *>(p_info->class_name)) {}
|
||||
|
||||
operator Dictionary() const {
|
||||
Dictionary dict;
|
||||
dict["name"] = name;
|
||||
dict["class_name"] = class_name;
|
||||
dict["type"] = type;
|
||||
dict["hint"] = hint;
|
||||
dict["hint_string"] = hint_string;
|
||||
dict["usage"] = usage;
|
||||
return dict;
|
||||
}
|
||||
|
||||
static PropertyInfo from_dict(const Dictionary &p_dict) {
|
||||
PropertyInfo pi;
|
||||
if (p_dict.has("type")) {
|
||||
pi.type = Variant::Type(int(p_dict["type"]));
|
||||
}
|
||||
if (p_dict.has("name")) {
|
||||
pi.name = p_dict["name"];
|
||||
}
|
||||
if (p_dict.has("class_name")) {
|
||||
pi.class_name = p_dict["class_name"];
|
||||
}
|
||||
if (p_dict.has("hint")) {
|
||||
pi.hint = PropertyHint(int(p_dict["hint"]));
|
||||
}
|
||||
if (p_dict.has("hint_string")) {
|
||||
pi.hint_string = p_dict["hint_string"];
|
||||
}
|
||||
if (p_dict.has("usage")) {
|
||||
pi.usage = p_dict["usage"];
|
||||
}
|
||||
return pi;
|
||||
}
|
||||
|
||||
void _update(GDExtensionPropertyInfo *p_info) {
|
||||
p_info->type = (GDExtensionVariantType)type;
|
||||
*(reinterpret_cast<StringName *>(p_info->name)) = name;
|
||||
p_info->hint = hint;
|
||||
*(reinterpret_cast<String *>(p_info->hint_string)) = hint_string;
|
||||
p_info->usage = usage;
|
||||
*(reinterpret_cast<StringName *>(p_info->class_name)) = class_name;
|
||||
}
|
||||
|
||||
GDExtensionPropertyInfo _to_gdextension() const {
|
||||
return {
|
||||
(GDExtensionVariantType)type,
|
||||
name._native_ptr(),
|
||||
class_name._native_ptr(),
|
||||
hint,
|
||||
hint_string._native_ptr(),
|
||||
usage,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_PROPERTY_INFO_HPP
|
||||
420
include/godot_cpp/core/type_info.hpp
Normal file
420
include/godot_cpp/core/type_info.hpp
Normal file
@@ -0,0 +1,420 @@
|
||||
/**************************************************************************/
|
||||
/* type_info.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_TYPE_INFO_HPP
|
||||
#define GODOT_TYPE_INFO_HPP
|
||||
|
||||
#include <godot_cpp/core/object.hpp>
|
||||
#include <godot_cpp/variant/typed_array.hpp>
|
||||
#include <godot_cpp/variant/variant.hpp>
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <bool C, typename T = void>
|
||||
struct EnableIf {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct EnableIf<false, T> {
|
||||
};
|
||||
|
||||
template <typename, typename>
|
||||
struct TypesAreSame {
|
||||
static bool const value = false;
|
||||
};
|
||||
|
||||
template <typename A>
|
||||
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();
|
||||
|
||||
static char (&test(B *))[1];
|
||||
static char (&test(...))[2];
|
||||
|
||||
static bool const value = sizeof(test(get_d())) == sizeof(char) &&
|
||||
!TypesAreSame<B volatile const, void volatile const>::value;
|
||||
};
|
||||
|
||||
static PropertyInfo make_property_info(Variant::Type p_type, const StringName &p_name, uint32_t p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "", uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const StringName &p_class_name = "") {
|
||||
PropertyInfo info;
|
||||
info.type = p_type;
|
||||
info.name = p_name;
|
||||
info.hint = p_hint;
|
||||
info.hint_string = p_hint_string;
|
||||
info.usage = p_usage;
|
||||
if (p_hint == PROPERTY_HINT_RESOURCE_TYPE) {
|
||||
info.class_name = p_hint_string;
|
||||
} else {
|
||||
info.class_name = p_class_name;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
// If the compiler fails because it's trying to instantiate the primary 'GetTypeInfo' template
|
||||
// instead of one of the specializations, it's most likely because the type 'T' is not supported.
|
||||
// If 'T' is a class that inherits 'Object', make sure it can see the actual class declaration
|
||||
// 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 <typename T, typename = void>
|
||||
struct GetTypeInfo;
|
||||
|
||||
#define MAKE_TYPE_INFO(m_type, m_var_type) \
|
||||
template <> \
|
||||
struct GetTypeInfo<m_type> { \
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = m_var_type; \
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return make_property_info((Variant::Type)VARIANT_TYPE, ""); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct GetTypeInfo<const m_type &> { \
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = m_var_type; \
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return make_property_info((Variant::Type)VARIANT_TYPE, ""); \
|
||||
} \
|
||||
};
|
||||
|
||||
#define MAKE_TYPE_INFO_WITH_META(m_type, m_var_type, m_metadata) \
|
||||
template <> \
|
||||
struct GetTypeInfo<m_type> { \
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = m_var_type; \
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = m_metadata; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return make_property_info((Variant::Type)VARIANT_TYPE, ""); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct GetTypeInfo<const m_type &> { \
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = m_var_type; \
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = m_metadata; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return make_property_info((Variant::Type)VARIANT_TYPE, ""); \
|
||||
} \
|
||||
};
|
||||
|
||||
MAKE_TYPE_INFO(bool, GDEXTENSION_VARIANT_TYPE_BOOL)
|
||||
MAKE_TYPE_INFO_WITH_META(uint8_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT8)
|
||||
MAKE_TYPE_INFO_WITH_META(int8_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT8)
|
||||
MAKE_TYPE_INFO_WITH_META(uint16_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT16)
|
||||
MAKE_TYPE_INFO_WITH_META(int16_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT16)
|
||||
MAKE_TYPE_INFO_WITH_META(uint32_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT32)
|
||||
MAKE_TYPE_INFO_WITH_META(int32_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT32)
|
||||
MAKE_TYPE_INFO_WITH_META(uint64_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT64)
|
||||
MAKE_TYPE_INFO_WITH_META(int64_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT64)
|
||||
MAKE_TYPE_INFO(char16_t, GDEXTENSION_VARIANT_TYPE_INT)
|
||||
MAKE_TYPE_INFO(char32_t, GDEXTENSION_VARIANT_TYPE_INT)
|
||||
MAKE_TYPE_INFO_WITH_META(float, GDEXTENSION_VARIANT_TYPE_FLOAT, GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_FLOAT)
|
||||
MAKE_TYPE_INFO_WITH_META(double, GDEXTENSION_VARIANT_TYPE_FLOAT, GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_DOUBLE)
|
||||
|
||||
MAKE_TYPE_INFO(String, GDEXTENSION_VARIANT_TYPE_STRING)
|
||||
MAKE_TYPE_INFO(Vector2, GDEXTENSION_VARIANT_TYPE_VECTOR2)
|
||||
MAKE_TYPE_INFO(Vector2i, GDEXTENSION_VARIANT_TYPE_VECTOR2I)
|
||||
MAKE_TYPE_INFO(Rect2, GDEXTENSION_VARIANT_TYPE_RECT2)
|
||||
MAKE_TYPE_INFO(Rect2i, GDEXTENSION_VARIANT_TYPE_RECT2I)
|
||||
MAKE_TYPE_INFO(Vector3, GDEXTENSION_VARIANT_TYPE_VECTOR3)
|
||||
MAKE_TYPE_INFO(Vector3i, GDEXTENSION_VARIANT_TYPE_VECTOR3I)
|
||||
MAKE_TYPE_INFO(Transform2D, GDEXTENSION_VARIANT_TYPE_TRANSFORM2D)
|
||||
MAKE_TYPE_INFO(Vector4, GDEXTENSION_VARIANT_TYPE_VECTOR4)
|
||||
MAKE_TYPE_INFO(Vector4i, GDEXTENSION_VARIANT_TYPE_VECTOR4I)
|
||||
MAKE_TYPE_INFO(Plane, GDEXTENSION_VARIANT_TYPE_PLANE)
|
||||
MAKE_TYPE_INFO(Quaternion, GDEXTENSION_VARIANT_TYPE_QUATERNION)
|
||||
MAKE_TYPE_INFO(AABB, GDEXTENSION_VARIANT_TYPE_AABB)
|
||||
MAKE_TYPE_INFO(Basis, GDEXTENSION_VARIANT_TYPE_BASIS)
|
||||
MAKE_TYPE_INFO(Transform3D, GDEXTENSION_VARIANT_TYPE_TRANSFORM3D)
|
||||
MAKE_TYPE_INFO(Projection, GDEXTENSION_VARIANT_TYPE_PROJECTION)
|
||||
MAKE_TYPE_INFO(Color, GDEXTENSION_VARIANT_TYPE_COLOR)
|
||||
MAKE_TYPE_INFO(StringName, GDEXTENSION_VARIANT_TYPE_STRING_NAME)
|
||||
MAKE_TYPE_INFO(NodePath, GDEXTENSION_VARIANT_TYPE_NODE_PATH)
|
||||
MAKE_TYPE_INFO(RID, GDEXTENSION_VARIANT_TYPE_RID)
|
||||
MAKE_TYPE_INFO(Callable, GDEXTENSION_VARIANT_TYPE_CALLABLE)
|
||||
MAKE_TYPE_INFO(Signal, GDEXTENSION_VARIANT_TYPE_SIGNAL)
|
||||
MAKE_TYPE_INFO(Dictionary, GDEXTENSION_VARIANT_TYPE_DICTIONARY)
|
||||
MAKE_TYPE_INFO(Array, GDEXTENSION_VARIANT_TYPE_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedByteArray, GDEXTENSION_VARIANT_TYPE_PACKED_BYTE_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedInt32Array, GDEXTENSION_VARIANT_TYPE_PACKED_INT32_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedInt64Array, GDEXTENSION_VARIANT_TYPE_PACKED_INT64_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedFloat32Array, GDEXTENSION_VARIANT_TYPE_PACKED_FLOAT32_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedFloat64Array, GDEXTENSION_VARIANT_TYPE_PACKED_FLOAT64_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedStringArray, GDEXTENSION_VARIANT_TYPE_PACKED_STRING_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedVector2Array, GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR2_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedVector3Array, GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR3_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedVector4Array, GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR4_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedColorArray, GDEXTENSION_VARIANT_TYPE_PACKED_COLOR_ARRAY)
|
||||
|
||||
// For variant.
|
||||
template <>
|
||||
struct GetTypeInfo<Variant> {
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_NIL;
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return make_property_info(Variant::Type::NIL, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct GetTypeInfo<const Variant &> {
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_NIL;
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return make_property_info(Variant::Type::NIL, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct GetTypeInfo<const T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
|
||||
}
|
||||
};
|
||||
|
||||
inline String enum_qualified_name_to_class_info_name(const String &p_qualified_name) {
|
||||
PackedStringArray parts = p_qualified_name.split("::", false);
|
||||
if (parts.size() <= 2) {
|
||||
return String(".").join(parts);
|
||||
}
|
||||
// Contains namespace. We only want the class and enum names.
|
||||
return parts[parts.size() - 2] + "." + parts[parts.size() - 1];
|
||||
}
|
||||
|
||||
#define TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_impl) \
|
||||
template <> \
|
||||
struct GetTypeInfo<m_impl> { \
|
||||
static constexpr Variant::Type VARIANT_TYPE = Variant::INT; \
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return make_property_info(Variant::Type::INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_ENUM, \
|
||||
enum_qualified_name_to_class_info_name(#m_enum)); \
|
||||
} \
|
||||
};
|
||||
|
||||
#define MAKE_ENUM_TYPE_INFO(m_enum) \
|
||||
TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum) \
|
||||
TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum const) \
|
||||
TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum &) \
|
||||
TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, const m_enum &)
|
||||
|
||||
template <typename T>
|
||||
inline StringName _gde_constant_get_enum_name(T param, StringName p_constant) {
|
||||
if (GetTypeInfo<T>::VARIANT_TYPE == Variant::NIL) {
|
||||
ERR_PRINT(("Missing VARIANT_ENUM_CAST for constant's enum: " + String(p_constant)).utf8().get_data());
|
||||
}
|
||||
return GetTypeInfo<T>::get_class_info().class_name;
|
||||
}
|
||||
|
||||
template <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) { 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; }
|
||||
};
|
||||
|
||||
#define TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_impl) \
|
||||
template <> \
|
||||
struct GetTypeInfo<m_impl> { \
|
||||
static constexpr Variant::Type VARIANT_TYPE = Variant::INT; \
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return make_property_info(Variant::Type::INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \
|
||||
enum_qualified_name_to_class_info_name(#m_enum)); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct GetTypeInfo<BitField<m_impl>> { \
|
||||
static constexpr Variant::Type VARIANT_TYPE = Variant::INT; \
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return make_property_info(Variant::Type::INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \
|
||||
enum_qualified_name_to_class_info_name(#m_enum)); \
|
||||
} \
|
||||
};
|
||||
|
||||
#define MAKE_BITFIELD_TYPE_INFO(m_enum) \
|
||||
TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum) \
|
||||
TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum const) \
|
||||
TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum &) \
|
||||
TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, const m_enum &)
|
||||
|
||||
template <typename T>
|
||||
inline StringName _gde_constant_get_bitfield_name(T param, StringName p_constant) {
|
||||
if (GetTypeInfo<T>::VARIANT_TYPE == Variant::NIL) {
|
||||
ERR_PRINT(("Missing VARIANT_ENUM_CAST for constant's bitfield: " + String(p_constant)).utf8().get_data());
|
||||
}
|
||||
return GetTypeInfo<BitField<T>>::get_class_info().class_name;
|
||||
}
|
||||
|
||||
template <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));
|
||||
}
|
||||
typedef Array EncodeT;
|
||||
_FORCE_INLINE_ static void encode(TypedArray<T> p_val, void *p_ptr) {
|
||||
*reinterpret_cast<Array *>(p_ptr) = p_val;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PtrToArg<const TypedArray<T> &> {
|
||||
typedef Array EncodeT;
|
||||
_FORCE_INLINE_ static TypedArray<T>
|
||||
convert(const void *p_ptr) {
|
||||
return TypedArray<T>(*reinterpret_cast<const Array *>(p_ptr));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct GetTypeInfo<TypedArray<T>> {
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_ARRAY;
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return make_property_info(Variant::Type::ARRAY, "", PROPERTY_HINT_ARRAY_TYPE, T::get_class_static());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct GetTypeInfo<const TypedArray<T> &> {
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_ARRAY;
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return make_property_info(Variant::Type::ARRAY, "", PROPERTY_HINT_ARRAY_TYPE, T::get_class_static());
|
||||
}
|
||||
};
|
||||
|
||||
#define MAKE_TYPED_ARRAY_INFO(m_type, m_variant_type) \
|
||||
template <> \
|
||||
struct GetTypeInfo<TypedArray<m_type>> { \
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_ARRAY; \
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return make_property_info(Variant::Type::ARRAY, "", PROPERTY_HINT_ARRAY_TYPE, Variant::get_type_name(m_variant_type).utf8().get_data()); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct GetTypeInfo<const TypedArray<m_type> &> { \
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_ARRAY; \
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return make_property_info(Variant::Type::ARRAY, "", PROPERTY_HINT_ARRAY_TYPE, Variant::get_type_name(m_variant_type).utf8().get_data()); \
|
||||
} \
|
||||
};
|
||||
|
||||
MAKE_TYPED_ARRAY_INFO(bool, Variant::BOOL)
|
||||
MAKE_TYPED_ARRAY_INFO(uint8_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(int8_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(uint16_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(int16_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(uint32_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(int32_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(uint64_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(int64_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(float, Variant::FLOAT)
|
||||
MAKE_TYPED_ARRAY_INFO(double, Variant::FLOAT)
|
||||
MAKE_TYPED_ARRAY_INFO(String, Variant::STRING)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector2, Variant::VECTOR2)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector2i, Variant::VECTOR2I)
|
||||
MAKE_TYPED_ARRAY_INFO(Rect2, Variant::RECT2)
|
||||
MAKE_TYPED_ARRAY_INFO(Rect2i, Variant::RECT2I)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector3, Variant::VECTOR3)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector3i, Variant::VECTOR3I)
|
||||
MAKE_TYPED_ARRAY_INFO(Transform2D, Variant::TRANSFORM2D)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector4, Variant::VECTOR4)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector4i, Variant::VECTOR4I)
|
||||
MAKE_TYPED_ARRAY_INFO(Plane, Variant::PLANE)
|
||||
MAKE_TYPED_ARRAY_INFO(Quaternion, Variant::QUATERNION)
|
||||
MAKE_TYPED_ARRAY_INFO(AABB, Variant::AABB)
|
||||
MAKE_TYPED_ARRAY_INFO(Basis, Variant::BASIS)
|
||||
MAKE_TYPED_ARRAY_INFO(Transform3D, Variant::TRANSFORM3D)
|
||||
MAKE_TYPED_ARRAY_INFO(Projection, Variant::PROJECTION)
|
||||
MAKE_TYPED_ARRAY_INFO(Color, Variant::COLOR)
|
||||
MAKE_TYPED_ARRAY_INFO(StringName, Variant::STRING_NAME)
|
||||
MAKE_TYPED_ARRAY_INFO(NodePath, Variant::NODE_PATH)
|
||||
MAKE_TYPED_ARRAY_INFO(RID, Variant::RID)
|
||||
MAKE_TYPED_ARRAY_INFO(Callable, Variant::CALLABLE)
|
||||
MAKE_TYPED_ARRAY_INFO(Signal, Variant::SIGNAL)
|
||||
MAKE_TYPED_ARRAY_INFO(Dictionary, Variant::DICTIONARY)
|
||||
MAKE_TYPED_ARRAY_INFO(Array, Variant::ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedByteArray, Variant::PACKED_BYTE_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedInt32Array, Variant::PACKED_INT32_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedInt64Array, Variant::PACKED_INT64_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedStringArray, Variant::PACKED_STRING_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
|
||||
/*
|
||||
MAKE_TYPED_ARRAY_INFO(IPAddress, Variant::STRING)
|
||||
*/
|
||||
|
||||
#undef MAKE_TYPED_ARRAY_INFO
|
||||
|
||||
#define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info())
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_TYPE_INFO_HPP
|
||||
266
include/godot_cpp/godot.hpp
Normal file
266
include/godot_cpp/godot.hpp
Normal file
@@ -0,0 +1,266 @@
|
||||
/**************************************************************************/
|
||||
/* godot.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_GODOT_HPP
|
||||
#define GODOT_GODOT_HPP
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
|
||||
namespace godot {
|
||||
|
||||
namespace internal {
|
||||
|
||||
extern "C" GDExtensionInterfaceGetProcAddress gdextension_interface_get_proc_address;
|
||||
extern "C" GDExtensionClassLibraryPtr library;
|
||||
extern "C" void *token;
|
||||
|
||||
extern "C" GDExtensionGodotVersion godot_version;
|
||||
|
||||
// All of the GDExtension interface functions.
|
||||
extern "C" GDExtensionInterfaceGetGodotVersion gdextension_interface_get_godot_version;
|
||||
extern "C" GDExtensionInterfaceMemAlloc gdextension_interface_mem_alloc;
|
||||
extern "C" GDExtensionInterfaceMemRealloc gdextension_interface_mem_realloc;
|
||||
extern "C" GDExtensionInterfaceMemFree gdextension_interface_mem_free;
|
||||
extern "C" GDExtensionInterfacePrintError gdextension_interface_print_error;
|
||||
extern "C" GDExtensionInterfacePrintErrorWithMessage gdextension_interface_print_error_with_message;
|
||||
extern "C" GDExtensionInterfacePrintWarning gdextension_interface_print_warning;
|
||||
extern "C" GDExtensionInterfacePrintWarningWithMessage gdextension_interface_print_warning_with_message;
|
||||
extern "C" GDExtensionInterfacePrintScriptError gdextension_interface_print_script_error;
|
||||
extern "C" GDExtensionInterfacePrintScriptErrorWithMessage gdextension_interface_print_script_error_with_message;
|
||||
extern "C" GDExtensionInterfaceGetNativeStructSize gdextension_interface_get_native_struct_size;
|
||||
extern "C" GDExtensionInterfaceVariantNewCopy gdextension_interface_variant_new_copy;
|
||||
extern "C" GDExtensionInterfaceVariantNewNil gdextension_interface_variant_new_nil;
|
||||
extern "C" GDExtensionInterfaceVariantDestroy gdextension_interface_variant_destroy;
|
||||
extern "C" GDExtensionInterfaceVariantCall gdextension_interface_variant_call;
|
||||
extern "C" GDExtensionInterfaceVariantCallStatic gdextension_interface_variant_call_static;
|
||||
extern "C" GDExtensionInterfaceVariantEvaluate gdextension_interface_variant_evaluate;
|
||||
extern "C" GDExtensionInterfaceVariantSet gdextension_interface_variant_set;
|
||||
extern "C" GDExtensionInterfaceVariantSetNamed gdextension_interface_variant_set_named;
|
||||
extern "C" GDExtensionInterfaceVariantSetKeyed gdextension_interface_variant_set_keyed;
|
||||
extern "C" GDExtensionInterfaceVariantSetIndexed gdextension_interface_variant_set_indexed;
|
||||
extern "C" GDExtensionInterfaceVariantGet gdextension_interface_variant_get;
|
||||
extern "C" GDExtensionInterfaceVariantGetNamed gdextension_interface_variant_get_named;
|
||||
extern "C" GDExtensionInterfaceVariantGetKeyed gdextension_interface_variant_get_keyed;
|
||||
extern "C" GDExtensionInterfaceVariantGetIndexed gdextension_interface_variant_get_indexed;
|
||||
extern "C" GDExtensionInterfaceVariantIterInit gdextension_interface_variant_iter_init;
|
||||
extern "C" GDExtensionInterfaceVariantIterNext gdextension_interface_variant_iter_next;
|
||||
extern "C" GDExtensionInterfaceVariantIterGet gdextension_interface_variant_iter_get;
|
||||
extern "C" GDExtensionInterfaceVariantHash gdextension_interface_variant_hash;
|
||||
extern "C" GDExtensionInterfaceVariantRecursiveHash gdextension_interface_variant_recursive_hash;
|
||||
extern "C" GDExtensionInterfaceVariantHashCompare gdextension_interface_variant_hash_compare;
|
||||
extern "C" GDExtensionInterfaceVariantBooleanize gdextension_interface_variant_booleanize;
|
||||
extern "C" GDExtensionInterfaceVariantDuplicate gdextension_interface_variant_duplicate;
|
||||
extern "C" GDExtensionInterfaceVariantStringify gdextension_interface_variant_stringify;
|
||||
extern "C" GDExtensionInterfaceVariantGetType gdextension_interface_variant_get_type;
|
||||
extern "C" GDExtensionInterfaceVariantHasMethod gdextension_interface_variant_has_method;
|
||||
extern "C" GDExtensionInterfaceVariantHasMember gdextension_interface_variant_has_member;
|
||||
extern "C" GDExtensionInterfaceVariantHasKey gdextension_interface_variant_has_key;
|
||||
extern "C" GDExtensionInterfaceVariantGetTypeName gdextension_interface_variant_get_type_name;
|
||||
extern "C" GDExtensionInterfaceVariantCanConvert gdextension_interface_variant_can_convert;
|
||||
extern "C" GDExtensionInterfaceVariantCanConvertStrict gdextension_interface_variant_can_convert_strict;
|
||||
extern "C" GDExtensionInterfaceGetVariantFromTypeConstructor gdextension_interface_get_variant_from_type_constructor;
|
||||
extern "C" GDExtensionInterfaceGetVariantToTypeConstructor gdextension_interface_get_variant_to_type_constructor;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrOperatorEvaluator gdextension_interface_variant_get_ptr_operator_evaluator;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrBuiltinMethod gdextension_interface_variant_get_ptr_builtin_method;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrConstructor gdextension_interface_variant_get_ptr_constructor;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrDestructor gdextension_interface_variant_get_ptr_destructor;
|
||||
extern "C" GDExtensionInterfaceVariantConstruct gdextension_interface_variant_construct;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrSetter gdextension_interface_variant_get_ptr_setter;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrGetter gdextension_interface_variant_get_ptr_getter;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrIndexedSetter gdextension_interface_variant_get_ptr_indexed_setter;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrIndexedGetter gdextension_interface_variant_get_ptr_indexed_getter;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrKeyedSetter gdextension_interface_variant_get_ptr_keyed_setter;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrKeyedGetter gdextension_interface_variant_get_ptr_keyed_getter;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrKeyedChecker gdextension_interface_variant_get_ptr_keyed_checker;
|
||||
extern "C" GDExtensionInterfaceVariantGetConstantValue gdextension_interface_variant_get_constant_value;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrUtilityFunction gdextension_interface_variant_get_ptr_utility_function;
|
||||
extern "C" GDExtensionInterfaceStringNewWithLatin1Chars gdextension_interface_string_new_with_latin1_chars;
|
||||
extern "C" GDExtensionInterfaceStringNewWithUtf8Chars gdextension_interface_string_new_with_utf8_chars;
|
||||
extern "C" GDExtensionInterfaceStringNewWithUtf16Chars gdextension_interface_string_new_with_utf16_chars;
|
||||
extern "C" GDExtensionInterfaceStringNewWithUtf32Chars gdextension_interface_string_new_with_utf32_chars;
|
||||
extern "C" GDExtensionInterfaceStringNewWithWideChars gdextension_interface_string_new_with_wide_chars;
|
||||
extern "C" GDExtensionInterfaceStringNewWithLatin1CharsAndLen gdextension_interface_string_new_with_latin1_chars_and_len;
|
||||
extern "C" GDExtensionInterfaceStringNewWithUtf8CharsAndLen gdextension_interface_string_new_with_utf8_chars_and_len;
|
||||
extern "C" GDExtensionInterfaceStringNewWithUtf8CharsAndLen2 gdextension_interface_string_new_with_utf8_chars_and_len2;
|
||||
extern "C" GDExtensionInterfaceStringNewWithUtf16CharsAndLen gdextension_interface_string_new_with_utf16_chars_and_len;
|
||||
extern "C" GDExtensionInterfaceStringNewWithUtf16CharsAndLen2 gdextension_interface_string_new_with_utf16_chars_and_len2;
|
||||
extern "C" GDExtensionInterfaceStringNewWithUtf32CharsAndLen gdextension_interface_string_new_with_utf32_chars_and_len;
|
||||
extern "C" GDExtensionInterfaceStringNewWithWideCharsAndLen gdextension_interface_string_new_with_wide_chars_and_len;
|
||||
extern "C" GDExtensionInterfaceStringToLatin1Chars gdextension_interface_string_to_latin1_chars;
|
||||
extern "C" GDExtensionInterfaceStringToUtf8Chars gdextension_interface_string_to_utf8_chars;
|
||||
extern "C" GDExtensionInterfaceStringToUtf16Chars gdextension_interface_string_to_utf16_chars;
|
||||
extern "C" GDExtensionInterfaceStringToUtf32Chars gdextension_interface_string_to_utf32_chars;
|
||||
extern "C" GDExtensionInterfaceStringToWideChars gdextension_interface_string_to_wide_chars;
|
||||
extern "C" GDExtensionInterfaceStringOperatorIndex gdextension_interface_string_operator_index;
|
||||
extern "C" GDExtensionInterfaceStringOperatorIndexConst gdextension_interface_string_operator_index_const;
|
||||
extern "C" GDExtensionInterfaceStringOperatorPlusEqString gdextension_interface_string_operator_plus_eq_string;
|
||||
extern "C" GDExtensionInterfaceStringOperatorPlusEqChar gdextension_interface_string_operator_plus_eq_char;
|
||||
extern "C" GDExtensionInterfaceStringOperatorPlusEqCstr gdextension_interface_string_operator_plus_eq_cstr;
|
||||
extern "C" GDExtensionInterfaceStringOperatorPlusEqWcstr gdextension_interface_string_operator_plus_eq_wcstr;
|
||||
extern "C" GDExtensionInterfaceStringOperatorPlusEqC32str gdextension_interface_string_operator_plus_eq_c32str;
|
||||
extern "C" GDExtensionInterfaceStringResize gdextension_interface_string_resize;
|
||||
extern "C" GDExtensionInterfaceStringNameNewWithLatin1Chars gdextension_interface_string_name_new_with_latin1_chars;
|
||||
extern "C" GDExtensionInterfaceXmlParserOpenBuffer gdextension_interface_xml_parser_open_buffer;
|
||||
extern "C" GDExtensionInterfaceFileAccessStoreBuffer gdextension_interface_file_access_store_buffer;
|
||||
extern "C" GDExtensionInterfaceFileAccessGetBuffer gdextension_interface_file_access_get_buffer;
|
||||
extern "C" GDExtensionInterfaceWorkerThreadPoolAddNativeGroupTask gdextension_interface_worker_thread_pool_add_native_group_task;
|
||||
extern "C" GDExtensionInterfaceWorkerThreadPoolAddNativeTask gdextension_interface_worker_thread_pool_add_native_task;
|
||||
extern "C" GDExtensionInterfacePackedByteArrayOperatorIndex gdextension_interface_packed_byte_array_operator_index;
|
||||
extern "C" GDExtensionInterfacePackedByteArrayOperatorIndexConst gdextension_interface_packed_byte_array_operator_index_const;
|
||||
extern "C" GDExtensionInterfacePackedColorArrayOperatorIndex gdextension_interface_packed_color_array_operator_index;
|
||||
extern "C" GDExtensionInterfacePackedColorArrayOperatorIndexConst gdextension_interface_packed_color_array_operator_index_const;
|
||||
extern "C" GDExtensionInterfacePackedFloat32ArrayOperatorIndex gdextension_interface_packed_float32_array_operator_index;
|
||||
extern "C" GDExtensionInterfacePackedFloat32ArrayOperatorIndexConst gdextension_interface_packed_float32_array_operator_index_const;
|
||||
extern "C" GDExtensionInterfacePackedFloat64ArrayOperatorIndex gdextension_interface_packed_float64_array_operator_index;
|
||||
extern "C" GDExtensionInterfacePackedFloat64ArrayOperatorIndexConst gdextension_interface_packed_float64_array_operator_index_const;
|
||||
extern "C" GDExtensionInterfacePackedInt32ArrayOperatorIndex gdextension_interface_packed_int32_array_operator_index;
|
||||
extern "C" GDExtensionInterfacePackedInt32ArrayOperatorIndexConst gdextension_interface_packed_int32_array_operator_index_const;
|
||||
extern "C" GDExtensionInterfacePackedInt64ArrayOperatorIndex gdextension_interface_packed_int64_array_operator_index;
|
||||
extern "C" GDExtensionInterfacePackedInt64ArrayOperatorIndexConst gdextension_interface_packed_int64_array_operator_index_const;
|
||||
extern "C" GDExtensionInterfacePackedStringArrayOperatorIndex gdextension_interface_packed_string_array_operator_index;
|
||||
extern "C" GDExtensionInterfacePackedStringArrayOperatorIndexConst gdextension_interface_packed_string_array_operator_index_const;
|
||||
extern "C" GDExtensionInterfacePackedVector2ArrayOperatorIndex gdextension_interface_packed_vector2_array_operator_index;
|
||||
extern "C" GDExtensionInterfacePackedVector2ArrayOperatorIndexConst gdextension_interface_packed_vector2_array_operator_index_const;
|
||||
extern "C" GDExtensionInterfacePackedVector3ArrayOperatorIndex gdextension_interface_packed_vector3_array_operator_index;
|
||||
extern "C" GDExtensionInterfacePackedVector3ArrayOperatorIndexConst gdextension_interface_packed_vector3_array_operator_index_const;
|
||||
extern "C" GDExtensionInterfacePackedVector4ArrayOperatorIndex gdextension_interface_packed_vector4_array_operator_index;
|
||||
extern "C" GDExtensionInterfacePackedVector4ArrayOperatorIndexConst gdextension_interface_packed_vector4_array_operator_index_const;
|
||||
extern "C" GDExtensionInterfaceArrayOperatorIndex gdextension_interface_array_operator_index;
|
||||
extern "C" GDExtensionInterfaceArrayOperatorIndexConst gdextension_interface_array_operator_index_const;
|
||||
extern "C" GDExtensionInterfaceArrayRef gdextension_interface_array_ref;
|
||||
extern "C" GDExtensionInterfaceArraySetTyped gdextension_interface_array_set_typed;
|
||||
extern "C" GDExtensionInterfaceDictionaryOperatorIndex gdextension_interface_dictionary_operator_index;
|
||||
extern "C" GDExtensionInterfaceDictionaryOperatorIndexConst gdextension_interface_dictionary_operator_index_const;
|
||||
extern "C" GDExtensionInterfaceObjectMethodBindCall gdextension_interface_object_method_bind_call;
|
||||
extern "C" GDExtensionInterfaceObjectMethodBindPtrcall gdextension_interface_object_method_bind_ptrcall;
|
||||
extern "C" GDExtensionInterfaceObjectDestroy gdextension_interface_object_destroy;
|
||||
extern "C" GDExtensionInterfaceGlobalGetSingleton gdextension_interface_global_get_singleton;
|
||||
extern "C" GDExtensionInterfaceObjectGetInstanceBinding gdextension_interface_object_get_instance_binding;
|
||||
extern "C" GDExtensionInterfaceObjectSetInstanceBinding gdextension_interface_object_set_instance_binding;
|
||||
extern "C" GDExtensionInterfaceObjectFreeInstanceBinding gdextension_interface_object_free_instance_binding;
|
||||
extern "C" GDExtensionInterfaceObjectSetInstance gdextension_interface_object_set_instance;
|
||||
extern "C" GDExtensionInterfaceObjectGetClassName gdextension_interface_object_get_class_name;
|
||||
extern "C" GDExtensionInterfaceObjectCastTo gdextension_interface_object_cast_to;
|
||||
extern "C" GDExtensionInterfaceObjectGetInstanceFromId gdextension_interface_object_get_instance_from_id;
|
||||
extern "C" GDExtensionInterfaceObjectGetInstanceId gdextension_interface_object_get_instance_id;
|
||||
extern "C" GDExtensionInterfaceObjectHasScriptMethod gdextension_interface_object_has_script_method;
|
||||
extern "C" GDExtensionInterfaceObjectCallScriptMethod gdextension_interface_object_call_script_method;
|
||||
extern "C" GDExtensionInterfaceCallableCustomCreate2 gdextension_interface_callable_custom_create2;
|
||||
extern "C" GDExtensionInterfaceCallableCustomGetUserData gdextension_interface_callable_custom_get_userdata;
|
||||
extern "C" GDExtensionInterfaceRefGetObject gdextension_interface_ref_get_object;
|
||||
extern "C" GDExtensionInterfaceRefSetObject gdextension_interface_ref_set_object;
|
||||
extern "C" GDExtensionInterfaceScriptInstanceCreate3 gdextension_interface_script_instance_create3;
|
||||
extern "C" GDExtensionInterfacePlaceHolderScriptInstanceCreate gdextension_interface_placeholder_script_instance_create;
|
||||
extern "C" GDExtensionInterfacePlaceHolderScriptInstanceUpdate gdextension_interface_placeholder_script_instance_update;
|
||||
extern "C" GDExtensionInterfaceClassdbConstructObject gdextension_interface_classdb_construct_object;
|
||||
extern "C" GDExtensionInterfaceClassdbGetMethodBind gdextension_interface_classdb_get_method_bind;
|
||||
extern "C" GDExtensionInterfaceClassdbGetClassTag gdextension_interface_classdb_get_class_tag;
|
||||
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClass3 gdextension_interface_classdb_register_extension_class3;
|
||||
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassMethod gdextension_interface_classdb_register_extension_class_method;
|
||||
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassVirtualMethod gdextension_interface_classdb_register_extension_class_virtual_method;
|
||||
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant gdextension_interface_classdb_register_extension_class_integer_constant;
|
||||
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassProperty gdextension_interface_classdb_register_extension_class_property;
|
||||
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassPropertyIndexed gdextension_interface_classdb_register_extension_class_property_indexed;
|
||||
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassPropertyGroup gdextension_interface_classdb_register_extension_class_property_group;
|
||||
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassPropertySubgroup gdextension_interface_classdb_register_extension_class_property_subgroup;
|
||||
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassSignal gdextension_interface_classdb_register_extension_class_signal;
|
||||
extern "C" GDExtensionInterfaceClassdbUnregisterExtensionClass gdextension_interface_classdb_unregister_extension_class;
|
||||
extern "C" GDExtensionInterfaceGetLibraryPath gdextension_interface_get_library_path;
|
||||
extern "C" GDExtensionInterfaceEditorAddPlugin gdextension_interface_editor_add_plugin;
|
||||
extern "C" GDExtensionInterfaceEditorRemovePlugin gdextension_interface_editor_remove_plugin;
|
||||
extern "C" GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars gdextension_interface_editor_help_load_xml_from_utf8_chars;
|
||||
extern "C" GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen gdextension_interface_editor_help_load_xml_from_utf8_chars_and_len;
|
||||
extern "C" GDExtensionInterfaceImagePtrw gdextension_interface_image_ptrw;
|
||||
extern "C" GDExtensionInterfaceImagePtr gdextension_interface_image_ptr;
|
||||
|
||||
class DocDataRegistration {
|
||||
public:
|
||||
DocDataRegistration(const char *p_hash, int p_uncompressed_size, int p_compressed_size, const unsigned char *p_data);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
enum ModuleInitializationLevel {
|
||||
MODULE_INITIALIZATION_LEVEL_CORE = GDEXTENSION_INITIALIZATION_CORE,
|
||||
MODULE_INITIALIZATION_LEVEL_SERVERS = GDEXTENSION_INITIALIZATION_SERVERS,
|
||||
MODULE_INITIALIZATION_LEVEL_SCENE = GDEXTENSION_INITIALIZATION_SCENE,
|
||||
MODULE_INITIALIZATION_LEVEL_EDITOR = GDEXTENSION_INITIALIZATION_EDITOR,
|
||||
MODULE_INITIALIZATION_LEVEL_MAX
|
||||
};
|
||||
|
||||
class GDExtensionBinding {
|
||||
public:
|
||||
using Callback = void (*)(ModuleInitializationLevel p_level);
|
||||
|
||||
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 *p_userdata, GDExtensionInitializationLevel p_level);
|
||||
static void deinitialize_level(void *p_userdata, GDExtensionInitializationLevel p_level);
|
||||
|
||||
class InitObject {
|
||||
GDExtensionInterfaceGetProcAddress get_proc_address;
|
||||
GDExtensionClassLibraryPtr library;
|
||||
GDExtensionInitialization *initialization;
|
||||
mutable InitData *init_data = nullptr;
|
||||
|
||||
public:
|
||||
InitObject(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);
|
||||
|
||||
void register_initializer(Callback p_init) const;
|
||||
void register_terminator(Callback p_init) const;
|
||||
void set_minimum_library_initialization_level(ModuleInitializationLevel p_level) const;
|
||||
|
||||
GDExtensionBool init() const;
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_GODOT_HPP
|
||||
492
include/godot_cpp/templates/cowdata.hpp
Normal file
492
include/godot_cpp/templates/cowdata.hpp
Normal file
@@ -0,0 +1,492 @@
|
||||
/**************************************************************************/
|
||||
/* cowdata.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_COWDATA_HPP
|
||||
#define GODOT_COWDATA_HPP
|
||||
|
||||
#include <godot_cpp/classes/global_constants.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 <typename T>
|
||||
class Vector;
|
||||
|
||||
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 <typename T>
|
||||
class CowData {
|
||||
template <typename TV>
|
||||
friend class Vector;
|
||||
|
||||
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
|
||||
|
||||
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 (SafeNumeric<USize> *)((uint8_t *)_ptr - DATA_OFFSET + REF_COUNT_OFFSET);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ USize *_get_size() const {
|
||||
if (!_ptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return (USize *)((uint8_t *)_ptr - DATA_OFFSET + SIZE_OFFSET);
|
||||
}
|
||||
|
||||
_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;
|
||||
}
|
||||
#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_po2(o);
|
||||
if (__builtin_add_overflow(o, static_cast<USize>(32), &p)) {
|
||||
return false; // No longer allocated here.
|
||||
}
|
||||
#else
|
||||
// Speed is more important than correctness here, do the operations unchecked
|
||||
// and hope for the best.
|
||||
*out = _get_alloc_size(p_elements);
|
||||
#endif
|
||||
return *out;
|
||||
}
|
||||
|
||||
void _unref(void *p_data);
|
||||
void _ref(const CowData *p_from);
|
||||
void _ref(const CowData &p_from);
|
||||
USize _copy_on_write();
|
||||
|
||||
public:
|
||||
void operator=(const CowData<T> &p_from) { _ref(p_from); }
|
||||
|
||||
_FORCE_INLINE_ T *ptrw() {
|
||||
_copy_on_write();
|
||||
return _ptr;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ const T *ptr() const {
|
||||
return _ptr;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Size size() const {
|
||||
USize *size = (USize *)_get_size();
|
||||
if (size) {
|
||||
return *size;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void clear() { resize(0); }
|
||||
_FORCE_INLINE_ bool is_empty() const { return _ptr == nullptr; }
|
||||
|
||||
_FORCE_INLINE_ void set(Size p_index, const T &p_elem) {
|
||||
ERR_FAIL_INDEX(p_index, size());
|
||||
_copy_on_write();
|
||||
_ptr[p_index] = p_elem;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ T &get_m(Size p_index) {
|
||||
CRASH_BAD_INDEX(p_index, size());
|
||||
_copy_on_write();
|
||||
return _ptr[p_index];
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ const T &get(Size p_index) const {
|
||||
CRASH_BAD_INDEX(p_index, size());
|
||||
|
||||
return _ptr[p_index];
|
||||
}
|
||||
|
||||
template <bool p_ensure_zero = false>
|
||||
Error resize(Size p_size);
|
||||
|
||||
_FORCE_INLINE_ void remove_at(Size p_index) {
|
||||
ERR_FAIL_INDEX(p_index, size());
|
||||
T *p = ptrw();
|
||||
Size len = size();
|
||||
for (Size i = p_index; i < len - 1; i++) {
|
||||
p[i] = p[i + 1];
|
||||
}
|
||||
|
||||
resize(len - 1);
|
||||
}
|
||||
|
||||
Error insert(Size p_pos, const T &p_val) {
|
||||
ERR_FAIL_INDEX_V(p_pos, size() + 1, ERR_INVALID_PARAMETER);
|
||||
resize(size() + 1);
|
||||
for (Size i = (size() - 1); i > p_pos; i--) {
|
||||
set(i, get(i - 1));
|
||||
}
|
||||
set(p_pos, p_val);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
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); };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void CowData<T>::_unref(void *p_data) {
|
||||
if (!p_data) {
|
||||
return;
|
||||
}
|
||||
|
||||
SafeNumeric<USize> *refc = _get_refcount();
|
||||
|
||||
if (refc->decrement() > 0) {
|
||||
return; // still in use
|
||||
}
|
||||
// clean up
|
||||
|
||||
if constexpr (!std::is_trivially_destructible_v<T>) {
|
||||
USize *count = _get_size();
|
||||
T *data = (T *)(count + 1);
|
||||
|
||||
for (USize i = 0; i < *count; ++i) {
|
||||
// call destructors
|
||||
data[i].~T();
|
||||
}
|
||||
}
|
||||
|
||||
// free mem
|
||||
Memory::free_static(((uint8_t *)p_data) - DATA_OFFSET, false);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename CowData<T>::USize CowData<T>::_copy_on_write() {
|
||||
if (!_ptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SafeNumeric<USize> *refc = _get_refcount();
|
||||
|
||||
USize rc = refc->get();
|
||||
if (unlikely(rc > 1)) {
|
||||
/* in use by more than me */
|
||||
USize current_size = *_get_size();
|
||||
|
||||
uint8_t *mem_new = (uint8_t *)Memory::alloc_static(_get_alloc_size(current_size) + DATA_OFFSET, false);
|
||||
ERR_FAIL_NULL_V(mem_new, 0);
|
||||
|
||||
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) = current_size; //size
|
||||
|
||||
// initialize new elements
|
||||
if constexpr (std::is_trivially_copyable_v<T>) {
|
||||
memcpy((uint8_t *)_data_ptr, _ptr, current_size * sizeof(T));
|
||||
} else {
|
||||
for (USize i = 0; i < current_size; i++) {
|
||||
memnew_placement(&_data_ptr[i], T(_ptr[i]));
|
||||
}
|
||||
}
|
||||
|
||||
_unref(_ptr);
|
||||
_ptr = _data_ptr;
|
||||
|
||||
rc = 1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
Size current_size = size();
|
||||
|
||||
if (p_size == current_size) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
if (p_size == 0) {
|
||||
// wants to clean up
|
||||
_unref(_ptr);
|
||||
_ptr = nullptr;
|
||||
return OK;
|
||||
}
|
||||
|
||||
// possibly changing size, copy on write
|
||||
USize rc = _copy_on_write();
|
||||
|
||||
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
|
||||
uint8_t *mem_new = (uint8_t *)Memory::alloc_static(alloc_size + DATA_OFFSET, false);
|
||||
ERR_FAIL_NULL_V(mem_new, ERR_OUT_OF_MEMORY);
|
||||
|
||||
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 {
|
||||
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);
|
||||
|
||||
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 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 constexpr (!std::is_trivially_destructible_v<T>) {
|
||||
// deinitialize no longer needed elements
|
||||
for (USize i = p_size; i < *_get_size(); i++) {
|
||||
T *t = &_ptr[i];
|
||||
t->~T();
|
||||
}
|
||||
}
|
||||
|
||||
if (alloc_size != current_alloc_size) {
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename CowData<T>::Size CowData<T>::find(const T &p_val, Size p_from) const {
|
||||
Size ret = -1;
|
||||
|
||||
if (p_from < 0 || size() == 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (Size i = p_from; i < size(); i++) {
|
||||
if (get(i) == p_val) {
|
||||
ret = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 <typename T>
|
||||
void CowData<T>::_ref(const CowData &p_from) {
|
||||
if (_ptr == p_from._ptr) {
|
||||
return; // self assign, do nothing.
|
||||
}
|
||||
|
||||
_unref(_ptr);
|
||||
_ptr = nullptr;
|
||||
|
||||
if (!p_from._ptr) {
|
||||
return; // nothing to do
|
||||
}
|
||||
|
||||
if (p_from._get_refcount()->conditional_increment() > 0) { // could reference
|
||||
_ptr = p_from._ptr;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
CowData<T>::~CowData() {
|
||||
_unref(_ptr);
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_COWDATA_HPP
|
||||
591
include/godot_cpp/templates/hash_map.hpp
Normal file
591
include/godot_cpp/templates/hash_map.hpp
Normal file
@@ -0,0 +1,591 @@
|
||||
/**************************************************************************/
|
||||
/* hash_map.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_HASH_MAP_HPP
|
||||
#define GODOT_HASH_MAP_HPP
|
||||
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
#include <godot_cpp/templates/hashfuncs.hpp>
|
||||
#include <godot_cpp/templates/pair.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
/**
|
||||
* A HashMap implementation that uses open addressing with Robin Hood hashing.
|
||||
* Robin Hood hashing swaps out entries that have a smaller probing distance
|
||||
* than the to-be-inserted entry, that evens out the average probing distance
|
||||
* and enables faster lookups. Backward shift deletion is employed to further
|
||||
* improve the performance and to avoid infinite loops in rare cases.
|
||||
*
|
||||
* Keys and values are stored in a double linked list by insertion order. This
|
||||
* has a slight performance overhead on lookup, which can be mostly compensated
|
||||
* using a paged allocator if required.
|
||||
*
|
||||
* The assignment operator copy the pairs from one map to the other.
|
||||
*/
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
struct HashMapElement {
|
||||
HashMapElement *next = nullptr;
|
||||
HashMapElement *prev = nullptr;
|
||||
KeyValue<TKey, TValue> data;
|
||||
HashMapElement() {}
|
||||
HashMapElement(const TKey &p_key, const TValue &p_value) :
|
||||
data(p_key, p_value) {}
|
||||
};
|
||||
|
||||
template <typename TKey, typename TValue,
|
||||
typename Hasher = HashMapHasherDefault,
|
||||
typename Comparator = HashMapComparatorDefault<TKey>,
|
||||
typename Allocator = DefaultTypedAllocator<HashMapElement<TKey, TValue>>>
|
||||
class HashMap {
|
||||
public:
|
||||
const uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime.
|
||||
const float MAX_OCCUPANCY = 0.75;
|
||||
const uint32_t EMPTY_HASH = 0;
|
||||
|
||||
private:
|
||||
Allocator element_alloc;
|
||||
HashMapElement<TKey, TValue> **elements = nullptr;
|
||||
uint32_t *hashes = nullptr;
|
||||
HashMapElement<TKey, TValue> *head_element = nullptr;
|
||||
HashMapElement<TKey, TValue> *tail_element = nullptr;
|
||||
|
||||
uint32_t capacity_index = 0;
|
||||
uint32_t num_elements = 0;
|
||||
|
||||
_FORCE_INLINE_ uint32_t _hash(const TKey &p_key) const {
|
||||
uint32_t hash = Hasher::hash(p_key);
|
||||
|
||||
if (unlikely(hash == EMPTY_HASH)) {
|
||||
hash = EMPTY_HASH + 1;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash, uint32_t p_capacity) const {
|
||||
uint32_t original_pos = p_hash % p_capacity;
|
||||
return (p_pos - original_pos + p_capacity) % p_capacity;
|
||||
}
|
||||
|
||||
bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const {
|
||||
if (elements == nullptr) {
|
||||
return false; // Failed lookups, no elements
|
||||
}
|
||||
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
uint32_t hash = _hash(p_key);
|
||||
uint32_t pos = hash % capacity;
|
||||
uint32_t distance = 0;
|
||||
|
||||
while (true) {
|
||||
if (hashes[pos] == EMPTY_HASH) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (distance > _get_probe_length(pos, hashes[pos], capacity)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hashes[pos] == hash && Comparator::compare(elements[pos]->data.key, p_key)) {
|
||||
r_pos = pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
pos = (pos + 1) % capacity;
|
||||
distance++;
|
||||
}
|
||||
}
|
||||
|
||||
void _insert_with_hash(uint32_t p_hash, HashMapElement<TKey, TValue> *p_value) {
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
uint32_t hash = p_hash;
|
||||
HashMapElement<TKey, TValue> *value = p_value;
|
||||
uint32_t distance = 0;
|
||||
uint32_t pos = hash % capacity;
|
||||
|
||||
while (true) {
|
||||
if (hashes[pos] == EMPTY_HASH) {
|
||||
elements[pos] = value;
|
||||
hashes[pos] = hash;
|
||||
|
||||
num_elements++;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Not an empty slot, let's check the probing length of the existing one.
|
||||
uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity);
|
||||
if (existing_probe_len < distance) {
|
||||
SWAP(hash, hashes[pos]);
|
||||
SWAP(value, elements[pos]);
|
||||
distance = existing_probe_len;
|
||||
}
|
||||
|
||||
pos = (pos + 1) % capacity;
|
||||
distance++;
|
||||
}
|
||||
}
|
||||
|
||||
void _resize_and_rehash(uint32_t p_new_capacity_index) {
|
||||
uint32_t old_capacity = hash_table_size_primes[capacity_index];
|
||||
|
||||
// Capacity can't be 0.
|
||||
capacity_index = MAX((uint32_t)MIN_CAPACITY_INDEX, p_new_capacity_index);
|
||||
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
|
||||
HashMapElement<TKey, TValue> **old_elements = elements;
|
||||
uint32_t *old_hashes = hashes;
|
||||
|
||||
num_elements = 0;
|
||||
hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||
elements = reinterpret_cast<HashMapElement<TKey, TValue> **>(Memory::alloc_static(sizeof(HashMapElement<TKey, TValue> *) * capacity));
|
||||
|
||||
for (uint32_t i = 0; i < capacity; i++) {
|
||||
hashes[i] = 0;
|
||||
elements[i] = nullptr;
|
||||
}
|
||||
|
||||
if (old_capacity == 0) {
|
||||
// Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < old_capacity; i++) {
|
||||
if (old_hashes[i] == EMPTY_HASH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
_insert_with_hash(old_hashes[i], old_elements[i]);
|
||||
}
|
||||
|
||||
Memory::free_static(old_elements);
|
||||
Memory::free_static(old_hashes);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ HashMapElement<TKey, TValue> *_insert(const TKey &p_key, const TValue &p_value, bool p_front_insert = false) {
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
if (unlikely(elements == nullptr)) {
|
||||
// Allocate on demand to save memory.
|
||||
|
||||
hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||
elements = reinterpret_cast<HashMapElement<TKey, TValue> **>(Memory::alloc_static(sizeof(HashMapElement<TKey, TValue> *) * capacity));
|
||||
|
||||
for (uint32_t i = 0; i < capacity; i++) {
|
||||
hashes[i] = EMPTY_HASH;
|
||||
elements[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
|
||||
if (exists) {
|
||||
elements[pos]->data.value = p_value;
|
||||
return elements[pos];
|
||||
} else {
|
||||
if (num_elements + 1 > MAX_OCCUPANCY * capacity) {
|
||||
ERR_FAIL_COND_V_MSG(capacity_index + 1 == HASH_TABLE_SIZE_MAX, nullptr, "Hash table maximum capacity reached, aborting insertion.");
|
||||
_resize_and_rehash(capacity_index + 1);
|
||||
}
|
||||
|
||||
HashMapElement<TKey, TValue> *elem = element_alloc.new_allocation(HashMapElement<TKey, TValue>(p_key, p_value));
|
||||
|
||||
if (tail_element == nullptr) {
|
||||
head_element = elem;
|
||||
tail_element = elem;
|
||||
} else if (p_front_insert) {
|
||||
head_element->prev = elem;
|
||||
elem->next = head_element;
|
||||
head_element = elem;
|
||||
} else {
|
||||
tail_element->next = elem;
|
||||
elem->prev = tail_element;
|
||||
tail_element = elem;
|
||||
}
|
||||
|
||||
uint32_t hash = _hash(p_key);
|
||||
_insert_with_hash(hash, elem);
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ uint32_t get_capacity() const { return hash_table_size_primes[capacity_index]; }
|
||||
_FORCE_INLINE_ uint32_t size() const { return num_elements; }
|
||||
|
||||
/* Standard Godot Container API */
|
||||
|
||||
bool is_empty() const {
|
||||
return num_elements == 0;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
if (elements == nullptr) {
|
||||
return;
|
||||
}
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
for (uint32_t i = 0; i < capacity; i++) {
|
||||
if (hashes[i] == EMPTY_HASH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
hashes[i] = EMPTY_HASH;
|
||||
element_alloc.delete_allocation(elements[i]);
|
||||
elements[i] = nullptr;
|
||||
}
|
||||
|
||||
tail_element = nullptr;
|
||||
head_element = nullptr;
|
||||
num_elements = 0;
|
||||
}
|
||||
|
||||
TValue &get(const TKey &p_key) {
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
CRASH_COND_MSG(!exists, "HashMap key not found.");
|
||||
return elements[pos]->data.value;
|
||||
}
|
||||
|
||||
const TValue &get(const TKey &p_key) const {
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
CRASH_COND_MSG(!exists, "HashMap key not found.");
|
||||
return elements[pos]->data.value;
|
||||
}
|
||||
|
||||
const TValue *getptr(const TKey &p_key) const {
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
|
||||
if (exists) {
|
||||
return &elements[pos]->data.value;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TValue *getptr(const TKey &p_key) {
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
|
||||
if (exists) {
|
||||
return &elements[pos]->data.value;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool has(const TKey &p_key) const {
|
||||
uint32_t _pos = 0;
|
||||
return _lookup_pos(p_key, _pos);
|
||||
}
|
||||
|
||||
bool erase(const TKey &p_key) {
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
|
||||
if (!exists) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
uint32_t next_pos = (pos + 1) % capacity;
|
||||
while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity) != 0) {
|
||||
SWAP(hashes[next_pos], hashes[pos]);
|
||||
SWAP(elements[next_pos], elements[pos]);
|
||||
pos = next_pos;
|
||||
next_pos = (pos + 1) % capacity;
|
||||
}
|
||||
|
||||
hashes[pos] = EMPTY_HASH;
|
||||
|
||||
if (head_element == elements[pos]) {
|
||||
head_element = elements[pos]->next;
|
||||
}
|
||||
|
||||
if (tail_element == elements[pos]) {
|
||||
tail_element = elements[pos]->prev;
|
||||
}
|
||||
|
||||
if (elements[pos]->prev) {
|
||||
elements[pos]->prev->next = elements[pos]->next;
|
||||
}
|
||||
|
||||
if (elements[pos]->next) {
|
||||
elements[pos]->next->prev = elements[pos]->prev;
|
||||
}
|
||||
|
||||
element_alloc.delete_allocation(elements[pos]);
|
||||
elements[pos] = nullptr;
|
||||
|
||||
num_elements--;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reserves space for a number of elements, useful to avoid many resizes and rehashes.
|
||||
// If adding a known (possibly large) number of elements at once, must be larger than old capacity.
|
||||
void reserve(uint32_t p_new_capacity) {
|
||||
uint32_t new_index = capacity_index;
|
||||
|
||||
while (hash_table_size_primes[new_index] < p_new_capacity) {
|
||||
ERR_FAIL_COND_MSG(new_index + 1 == (uint32_t)HASH_TABLE_SIZE_MAX, nullptr);
|
||||
new_index++;
|
||||
}
|
||||
|
||||
if (new_index == capacity_index) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (elements == nullptr) {
|
||||
capacity_index = new_index;
|
||||
return; // Unallocated yet.
|
||||
}
|
||||
_resize_and_rehash(new_index);
|
||||
}
|
||||
|
||||
/** Iterator API **/
|
||||
|
||||
struct ConstIterator {
|
||||
_FORCE_INLINE_ const KeyValue<TKey, TValue> &operator*() const {
|
||||
return E->data;
|
||||
}
|
||||
_FORCE_INLINE_ const KeyValue<TKey, TValue> *operator->() const { return &E->data; }
|
||||
_FORCE_INLINE_ ConstIterator &operator++() {
|
||||
if (E) {
|
||||
E = E->next;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator &operator--() {
|
||||
if (E) {
|
||||
E = E->prev;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; }
|
||||
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; }
|
||||
|
||||
_FORCE_INLINE_ explicit operator bool() const {
|
||||
return E != nullptr;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ ConstIterator(const HashMapElement<TKey, TValue> *p_E) { E = p_E; }
|
||||
_FORCE_INLINE_ ConstIterator() {}
|
||||
_FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
|
||||
_FORCE_INLINE_ void operator=(const ConstIterator &p_it) {
|
||||
E = p_it.E;
|
||||
}
|
||||
|
||||
private:
|
||||
const HashMapElement<TKey, TValue> *E = nullptr;
|
||||
};
|
||||
|
||||
struct Iterator {
|
||||
_FORCE_INLINE_ KeyValue<TKey, TValue> &operator*() const {
|
||||
return E->data;
|
||||
}
|
||||
_FORCE_INLINE_ KeyValue<TKey, TValue> *operator->() const { return &E->data; }
|
||||
_FORCE_INLINE_ Iterator &operator++() {
|
||||
if (E) {
|
||||
E = E->next;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ Iterator &operator--() {
|
||||
if (E) {
|
||||
E = E->prev;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
|
||||
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
|
||||
|
||||
_FORCE_INLINE_ explicit operator bool() const {
|
||||
return E != nullptr;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Iterator(HashMapElement<TKey, TValue> *p_E) { E = p_E; }
|
||||
_FORCE_INLINE_ Iterator() {}
|
||||
_FORCE_INLINE_ Iterator(const Iterator &p_it) { E = p_it.E; }
|
||||
_FORCE_INLINE_ void operator=(const Iterator &p_it) {
|
||||
E = p_it.E;
|
||||
}
|
||||
|
||||
operator ConstIterator() const {
|
||||
return ConstIterator(E);
|
||||
}
|
||||
|
||||
private:
|
||||
HashMapElement<TKey, TValue> *E = nullptr;
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ Iterator begin() {
|
||||
return Iterator(head_element);
|
||||
}
|
||||
_FORCE_INLINE_ Iterator end() {
|
||||
return Iterator(nullptr);
|
||||
}
|
||||
_FORCE_INLINE_ Iterator last() {
|
||||
return Iterator(tail_element);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Iterator find(const TKey &p_key) {
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
if (!exists) {
|
||||
return end();
|
||||
}
|
||||
return Iterator(elements[pos]);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void remove(const Iterator &p_iter) {
|
||||
if (p_iter) {
|
||||
erase(p_iter->key);
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ ConstIterator begin() const {
|
||||
return ConstIterator(head_element);
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator end() const {
|
||||
return ConstIterator(nullptr);
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator last() const {
|
||||
return ConstIterator(tail_element);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ ConstIterator find(const TKey &p_key) const {
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
if (!exists) {
|
||||
return end();
|
||||
}
|
||||
return ConstIterator(elements[pos]);
|
||||
}
|
||||
|
||||
/* Indexing */
|
||||
|
||||
const TValue &operator[](const TKey &p_key) const {
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
CRASH_COND(!exists);
|
||||
return elements[pos]->data.value;
|
||||
}
|
||||
|
||||
TValue &operator[](const TKey &p_key) {
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
if (!exists) {
|
||||
return _insert(p_key, TValue())->data.value;
|
||||
} else {
|
||||
return elements[pos]->data.value;
|
||||
}
|
||||
}
|
||||
|
||||
/* Insert */
|
||||
|
||||
Iterator insert(const TKey &p_key, const TValue &p_value, bool p_front_insert = false) {
|
||||
return Iterator(_insert(p_key, p_value, p_front_insert));
|
||||
}
|
||||
|
||||
/* Constructors */
|
||||
|
||||
HashMap(const HashMap &p_other) {
|
||||
reserve(hash_table_size_primes[p_other.capacity_index]);
|
||||
|
||||
if (p_other.num_elements == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const KeyValue<TKey, TValue> &E : p_other) {
|
||||
insert(E.key, E.value);
|
||||
}
|
||||
}
|
||||
|
||||
void operator=(const HashMap &p_other) {
|
||||
if (this == &p_other) {
|
||||
return; // Ignore self assignment.
|
||||
}
|
||||
if (num_elements != 0) {
|
||||
clear();
|
||||
}
|
||||
|
||||
reserve(hash_table_size_primes[p_other.capacity_index]);
|
||||
|
||||
if (p_other.elements == nullptr) {
|
||||
return; // Nothing to copy.
|
||||
}
|
||||
|
||||
for (const KeyValue<TKey, TValue> &E : p_other) {
|
||||
insert(E.key, E.value);
|
||||
}
|
||||
}
|
||||
|
||||
HashMap(uint32_t p_initial_capacity) {
|
||||
// Capacity can't be 0.
|
||||
capacity_index = 0;
|
||||
reserve(p_initial_capacity);
|
||||
}
|
||||
HashMap() {
|
||||
capacity_index = MIN_CAPACITY_INDEX;
|
||||
}
|
||||
|
||||
uint32_t debug_get_hash(uint32_t p_index) {
|
||||
if (num_elements == 0) {
|
||||
return 0;
|
||||
}
|
||||
ERR_FAIL_INDEX_V(p_index, get_capacity(), 0);
|
||||
return hashes[p_index];
|
||||
}
|
||||
Iterator debug_get_element(uint32_t p_index) {
|
||||
if (num_elements == 0) {
|
||||
return Iterator();
|
||||
}
|
||||
ERR_FAIL_INDEX_V(p_index, get_capacity(), Iterator());
|
||||
return Iterator(elements[p_index]);
|
||||
}
|
||||
|
||||
~HashMap() {
|
||||
clear();
|
||||
|
||||
if (elements != nullptr) {
|
||||
Memory::free_static(elements);
|
||||
Memory::free_static(hashes);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_HASH_MAP_HPP
|
||||
477
include/godot_cpp/templates/hash_set.hpp
Normal file
477
include/godot_cpp/templates/hash_set.hpp
Normal file
@@ -0,0 +1,477 @@
|
||||
/**************************************************************************/
|
||||
/* hash_set.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_HASH_SET_HPP
|
||||
#define GODOT_HASH_SET_HPP
|
||||
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
#include <godot_cpp/templates/hash_map.hpp>
|
||||
#include <godot_cpp/templates/hashfuncs.hpp>
|
||||
#include <godot_cpp/templates/pair.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
/**
|
||||
* Implementation of Set using a bidi indexed hash map.
|
||||
* Use RBSet instead of this only if the following conditions are met:
|
||||
*
|
||||
* - You need to keep an iterator or const pointer to Key and you intend to add/remove elements in the meantime.
|
||||
* - Iteration order does matter (via operator<)
|
||||
*
|
||||
*/
|
||||
|
||||
template <typename TKey,
|
||||
typename Hasher = HashMapHasherDefault,
|
||||
typename Comparator = HashMapComparatorDefault<TKey>>
|
||||
class HashSet {
|
||||
public:
|
||||
static constexpr uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime.
|
||||
static constexpr float MAX_OCCUPANCY = 0.75;
|
||||
static constexpr uint32_t EMPTY_HASH = 0;
|
||||
|
||||
private:
|
||||
TKey *keys = nullptr;
|
||||
uint32_t *hash_to_key = nullptr;
|
||||
uint32_t *key_to_hash = nullptr;
|
||||
uint32_t *hashes = nullptr;
|
||||
|
||||
uint32_t capacity_index = 0;
|
||||
uint32_t num_elements = 0;
|
||||
|
||||
_FORCE_INLINE_ uint32_t _hash(const TKey &p_key) const {
|
||||
uint32_t hash = Hasher::hash(p_key);
|
||||
|
||||
if (unlikely(hash == EMPTY_HASH)) {
|
||||
hash = EMPTY_HASH + 1;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash, uint32_t p_capacity) const {
|
||||
uint32_t original_pos = p_hash % p_capacity;
|
||||
return (p_pos - original_pos + p_capacity) % p_capacity;
|
||||
}
|
||||
|
||||
bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const {
|
||||
if (keys == nullptr) {
|
||||
return false; // Failed lookups, no elements
|
||||
}
|
||||
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
uint32_t hash = _hash(p_key);
|
||||
uint32_t pos = hash % capacity;
|
||||
uint32_t distance = 0;
|
||||
|
||||
while (true) {
|
||||
if (hashes[pos] == EMPTY_HASH) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (distance > _get_probe_length(pos, hashes[pos], capacity)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hashes[pos] == hash && Comparator::compare(keys[hash_to_key[pos]], p_key)) {
|
||||
r_pos = hash_to_key[pos];
|
||||
return true;
|
||||
}
|
||||
|
||||
pos = (pos + 1) % capacity;
|
||||
distance++;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t _insert_with_hash(uint32_t p_hash, uint32_t p_index) {
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
uint32_t hash = p_hash;
|
||||
uint32_t index = p_index;
|
||||
uint32_t distance = 0;
|
||||
uint32_t pos = hash % capacity;
|
||||
|
||||
while (true) {
|
||||
if (hashes[pos] == EMPTY_HASH) {
|
||||
hashes[pos] = hash;
|
||||
key_to_hash[index] = pos;
|
||||
hash_to_key[pos] = index;
|
||||
return pos;
|
||||
}
|
||||
|
||||
// Not an empty slot, let's check the probing length of the existing one.
|
||||
uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity);
|
||||
if (existing_probe_len < distance) {
|
||||
key_to_hash[index] = pos;
|
||||
SWAP(hash, hashes[pos]);
|
||||
SWAP(index, hash_to_key[pos]);
|
||||
distance = existing_probe_len;
|
||||
}
|
||||
|
||||
pos = (pos + 1) % capacity;
|
||||
distance++;
|
||||
}
|
||||
}
|
||||
|
||||
void _resize_and_rehash(uint32_t p_new_capacity_index) {
|
||||
// Capacity can't be 0.
|
||||
capacity_index = MAX((uint32_t)MIN_CAPACITY_INDEX, p_new_capacity_index);
|
||||
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
|
||||
uint32_t *old_hashes = hashes;
|
||||
uint32_t *old_key_to_hash = key_to_hash;
|
||||
|
||||
hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||
keys = reinterpret_cast<TKey *>(Memory::realloc_static(keys, sizeof(TKey) * capacity));
|
||||
key_to_hash = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||
hash_to_key = reinterpret_cast<uint32_t *>(Memory::realloc_static(hash_to_key, sizeof(uint32_t) * capacity));
|
||||
|
||||
for (uint32_t i = 0; i < capacity; i++) {
|
||||
hashes[i] = EMPTY_HASH;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < num_elements; i++) {
|
||||
uint32_t h = old_hashes[old_key_to_hash[i]];
|
||||
_insert_with_hash(h, i);
|
||||
}
|
||||
|
||||
Memory::free_static(old_hashes);
|
||||
Memory::free_static(old_key_to_hash);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int32_t _insert(const TKey &p_key) {
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
if (unlikely(keys == nullptr)) {
|
||||
// Allocate on demand to save memory.
|
||||
|
||||
hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||
keys = reinterpret_cast<TKey *>(Memory::alloc_static(sizeof(TKey) * capacity));
|
||||
key_to_hash = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||
hash_to_key = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||
|
||||
for (uint32_t i = 0; i < capacity; i++) {
|
||||
hashes[i] = EMPTY_HASH;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
|
||||
if (exists) {
|
||||
return pos;
|
||||
} else {
|
||||
if (num_elements + 1 > MAX_OCCUPANCY * capacity) {
|
||||
ERR_FAIL_COND_V_MSG(capacity_index + 1 == HASH_TABLE_SIZE_MAX, -1, "Hash table maximum capacity reached, aborting insertion.");
|
||||
_resize_and_rehash(capacity_index + 1);
|
||||
}
|
||||
|
||||
uint32_t hash = _hash(p_key);
|
||||
memnew_placement(&keys[num_elements], TKey(p_key));
|
||||
_insert_with_hash(hash, num_elements);
|
||||
num_elements++;
|
||||
return num_elements - 1;
|
||||
}
|
||||
}
|
||||
|
||||
void _init_from(const HashSet &p_other) {
|
||||
capacity_index = p_other.capacity_index;
|
||||
num_elements = p_other.num_elements;
|
||||
|
||||
if (p_other.num_elements == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
|
||||
hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||
keys = reinterpret_cast<TKey *>(Memory::alloc_static(sizeof(TKey) * capacity));
|
||||
key_to_hash = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||
hash_to_key = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||
|
||||
for (uint32_t i = 0; i < num_elements; i++) {
|
||||
memnew_placement(&keys[i], TKey(p_other.keys[i]));
|
||||
key_to_hash[i] = p_other.key_to_hash[i];
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < capacity; i++) {
|
||||
hashes[i] = p_other.hashes[i];
|
||||
hash_to_key[i] = p_other.hash_to_key[i];
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ uint32_t get_capacity() const { return hash_table_size_primes[capacity_index]; }
|
||||
_FORCE_INLINE_ uint32_t size() const { return num_elements; }
|
||||
|
||||
/* Standard Godot Container API */
|
||||
|
||||
bool is_empty() const {
|
||||
return num_elements == 0;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
if (keys == nullptr) {
|
||||
return;
|
||||
}
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
for (uint32_t i = 0; i < capacity; i++) {
|
||||
hashes[i] = EMPTY_HASH;
|
||||
}
|
||||
for (uint32_t i = 0; i < num_elements; i++) {
|
||||
keys[i].~TKey();
|
||||
}
|
||||
|
||||
num_elements = 0;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool has(const TKey &p_key) const {
|
||||
uint32_t _pos = 0;
|
||||
return _lookup_pos(p_key, _pos);
|
||||
}
|
||||
|
||||
bool erase(const TKey &p_key) {
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
|
||||
if (!exists) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t key_pos = pos;
|
||||
pos = key_to_hash[pos]; // make hash pos
|
||||
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
uint32_t next_pos = (pos + 1) % capacity;
|
||||
while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity) != 0) {
|
||||
uint32_t kpos = hash_to_key[pos];
|
||||
uint32_t kpos_next = hash_to_key[next_pos];
|
||||
SWAP(key_to_hash[kpos], key_to_hash[kpos_next]);
|
||||
SWAP(hashes[next_pos], hashes[pos]);
|
||||
SWAP(hash_to_key[next_pos], hash_to_key[pos]);
|
||||
|
||||
pos = next_pos;
|
||||
next_pos = (pos + 1) % capacity;
|
||||
}
|
||||
|
||||
hashes[pos] = EMPTY_HASH;
|
||||
keys[key_pos].~TKey();
|
||||
num_elements--;
|
||||
if (key_pos < num_elements) {
|
||||
// Not the last key, move the last one here to keep keys lineal
|
||||
memnew_placement(&keys[key_pos], TKey(keys[num_elements]));
|
||||
keys[num_elements].~TKey();
|
||||
key_to_hash[key_pos] = key_to_hash[num_elements];
|
||||
hash_to_key[key_to_hash[num_elements]] = key_pos;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reserves space for a number of elements, useful to avoid many resizes and rehashes.
|
||||
// If adding a known (possibly large) number of elements at once, must be larger than old capacity.
|
||||
void reserve(uint32_t p_new_capacity) {
|
||||
uint32_t new_index = capacity_index;
|
||||
|
||||
while (hash_table_size_primes[new_index] < p_new_capacity) {
|
||||
ERR_FAIL_COND_MSG(new_index + 1 == (uint32_t)HASH_TABLE_SIZE_MAX, nullptr);
|
||||
new_index++;
|
||||
}
|
||||
|
||||
if (new_index == capacity_index) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (keys == nullptr) {
|
||||
capacity_index = new_index;
|
||||
return; // Unallocated yet.
|
||||
}
|
||||
_resize_and_rehash(new_index);
|
||||
}
|
||||
|
||||
/** Iterator API **/
|
||||
|
||||
struct Iterator {
|
||||
_FORCE_INLINE_ const TKey &operator*() const {
|
||||
return keys[index];
|
||||
}
|
||||
_FORCE_INLINE_ const TKey *operator->() const {
|
||||
return &keys[index];
|
||||
}
|
||||
_FORCE_INLINE_ Iterator &operator++() {
|
||||
index++;
|
||||
if (index >= (int32_t)num_keys) {
|
||||
index = -1;
|
||||
keys = nullptr;
|
||||
num_keys = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ Iterator &operator--() {
|
||||
index--;
|
||||
if (index < 0) {
|
||||
index = -1;
|
||||
keys = nullptr;
|
||||
num_keys = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return keys == b.keys && index == b.index; }
|
||||
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return keys != b.keys || index != b.index; }
|
||||
|
||||
_FORCE_INLINE_ explicit operator bool() const {
|
||||
return keys != nullptr;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Iterator(const TKey *p_keys, uint32_t p_num_keys, int32_t p_index = -1) {
|
||||
keys = p_keys;
|
||||
num_keys = p_num_keys;
|
||||
index = p_index;
|
||||
}
|
||||
_FORCE_INLINE_ Iterator() {}
|
||||
_FORCE_INLINE_ Iterator(const Iterator &p_it) {
|
||||
keys = p_it.keys;
|
||||
num_keys = p_it.num_keys;
|
||||
index = p_it.index;
|
||||
}
|
||||
_FORCE_INLINE_ void operator=(const Iterator &p_it) {
|
||||
keys = p_it.keys;
|
||||
num_keys = p_it.num_keys;
|
||||
index = p_it.index;
|
||||
}
|
||||
|
||||
private:
|
||||
const TKey *keys = nullptr;
|
||||
uint32_t num_keys = 0;
|
||||
int32_t index = -1;
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ Iterator begin() const {
|
||||
return num_elements ? Iterator(keys, num_elements, 0) : Iterator();
|
||||
}
|
||||
_FORCE_INLINE_ Iterator end() const {
|
||||
return Iterator();
|
||||
}
|
||||
_FORCE_INLINE_ Iterator last() const {
|
||||
if (num_elements == 0) {
|
||||
return Iterator();
|
||||
}
|
||||
return Iterator(keys, num_elements, num_elements - 1);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Iterator find(const TKey &p_key) const {
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
if (!exists) {
|
||||
return end();
|
||||
}
|
||||
return Iterator(keys, num_elements, pos);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void remove(const Iterator &p_iter) {
|
||||
if (p_iter) {
|
||||
erase(*p_iter);
|
||||
}
|
||||
}
|
||||
|
||||
/* Insert */
|
||||
|
||||
Iterator insert(const TKey &p_key) {
|
||||
uint32_t pos = _insert(p_key);
|
||||
return Iterator(keys, num_elements, pos);
|
||||
}
|
||||
|
||||
/* Constructors */
|
||||
|
||||
HashSet(const HashSet &p_other) {
|
||||
_init_from(p_other);
|
||||
}
|
||||
|
||||
void operator=(const HashSet &p_other) {
|
||||
if (this == &p_other) {
|
||||
return; // Ignore self assignment.
|
||||
}
|
||||
|
||||
clear();
|
||||
|
||||
if (keys != nullptr) {
|
||||
Memory::free_static(keys);
|
||||
Memory::free_static(key_to_hash);
|
||||
Memory::free_static(hash_to_key);
|
||||
Memory::free_static(hashes);
|
||||
keys = nullptr;
|
||||
hashes = nullptr;
|
||||
hash_to_key = nullptr;
|
||||
key_to_hash = nullptr;
|
||||
}
|
||||
|
||||
_init_from(p_other);
|
||||
}
|
||||
|
||||
HashSet(uint32_t p_initial_capacity) {
|
||||
// Capacity can't be 0.
|
||||
capacity_index = 0;
|
||||
reserve(p_initial_capacity);
|
||||
}
|
||||
HashSet() {
|
||||
capacity_index = MIN_CAPACITY_INDEX;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
clear();
|
||||
|
||||
if (keys != nullptr) {
|
||||
Memory::free_static(keys);
|
||||
Memory::free_static(key_to_hash);
|
||||
Memory::free_static(hash_to_key);
|
||||
Memory::free_static(hashes);
|
||||
keys = nullptr;
|
||||
hashes = nullptr;
|
||||
hash_to_key = nullptr;
|
||||
key_to_hash = nullptr;
|
||||
}
|
||||
capacity_index = MIN_CAPACITY_INDEX;
|
||||
}
|
||||
|
||||
~HashSet() {
|
||||
clear();
|
||||
|
||||
if (keys != nullptr) {
|
||||
Memory::free_static(keys);
|
||||
Memory::free_static(key_to_hash);
|
||||
Memory::free_static(hash_to_key);
|
||||
Memory::free_static(hashes);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_HASH_SET_HPP
|
||||
526
include/godot_cpp/templates/hashfuncs.hpp
Normal file
526
include/godot_cpp/templates/hashfuncs.hpp
Normal file
@@ -0,0 +1,526 @@
|
||||
/**************************************************************************/
|
||||
/* hashfuncs.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_HASHFUNCS_HPP
|
||||
#define GODOT_HASHFUNCS_HPP
|
||||
|
||||
// Needed for fastmod.
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#include <godot_cpp/core/math.hpp>
|
||||
#include <godot_cpp/core/object.hpp>
|
||||
#include <godot_cpp/variant/aabb.hpp>
|
||||
#include <godot_cpp/variant/node_path.hpp>
|
||||
#include <godot_cpp/variant/rect2.hpp>
|
||||
#include <godot_cpp/variant/rect2i.hpp>
|
||||
#include <godot_cpp/variant/rid.hpp>
|
||||
#include <godot_cpp/variant/string.hpp>
|
||||
#include <godot_cpp/variant/string_name.hpp>
|
||||
#include <godot_cpp/variant/variant.hpp>
|
||||
#include <godot_cpp/variant/vector2.hpp>
|
||||
#include <godot_cpp/variant/vector2i.hpp>
|
||||
#include <godot_cpp/variant/vector3.hpp>
|
||||
#include <godot_cpp/variant/vector3i.hpp>
|
||||
#include <godot_cpp/variant/vector4.hpp>
|
||||
#include <godot_cpp/variant/vector4i.hpp>
|
||||
|
||||
/**
|
||||
* Hashing functions
|
||||
*/
|
||||
|
||||
namespace godot {
|
||||
|
||||
/**
|
||||
* DJB2 Hash function
|
||||
* @param C String
|
||||
* @return 32-bits hashcode
|
||||
*/
|
||||
static _FORCE_INLINE_ uint32_t hash_djb2(const char *p_cstr) {
|
||||
const unsigned char *chr = (const unsigned char *)p_cstr;
|
||||
uint32_t hash = 5381;
|
||||
uint32_t c;
|
||||
|
||||
while ((c = *chr++)) {
|
||||
hash = ((hash << 5) + hash) ^ c; /* hash * 33 ^ c */
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash_djb2_buffer(const uint8_t *p_buff, int p_len, uint32_t p_prev = 5381) {
|
||||
uint32_t hash = p_prev;
|
||||
|
||||
for (int i = 0; i < p_len; i++) {
|
||||
hash = ((hash << 5) + hash) ^ p_buff[i]; /* hash * 33 + c */
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash_djb2_one_32(uint32_t p_in, uint32_t p_prev = 5381) {
|
||||
return ((p_prev << 5) + p_prev) ^ p_in;
|
||||
}
|
||||
|
||||
/**
|
||||
* Thomas Wang's 64-bit to 32-bit Hash function:
|
||||
* https://web.archive.org/web/20071223173210/https:/www.concentric.net/~Ttwang/tech/inthash.htm
|
||||
*
|
||||
* @param p_int - 64-bit unsigned integer key to be hashed
|
||||
* @return unsigned 32-bit value representing hashcode
|
||||
*/
|
||||
static _FORCE_INLINE_ uint32_t hash_one_uint64(const uint64_t p_int) {
|
||||
uint64_t v = p_int;
|
||||
v = (~v) + (v << 18); // v = (v << 18) - v - 1;
|
||||
v = v ^ (v >> 31);
|
||||
v = v * 21; // v = (v + (v << 2)) + (v << 4);
|
||||
v = v ^ (v >> 11);
|
||||
v = v + (v << 6);
|
||||
v = v ^ (v >> 22);
|
||||
return uint32_t(v);
|
||||
}
|
||||
|
||||
#define HASH_MURMUR3_SEED 0x7F07C65
|
||||
// Murmurhash3 32-bit version.
|
||||
// All MurmurHash versions are public domain software, and the author disclaims all copyright to their code.
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash_murmur3_one_32(uint32_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
|
||||
p_in *= 0xcc9e2d51;
|
||||
p_in = (p_in << 15) | (p_in >> 17);
|
||||
p_in *= 0x1b873593;
|
||||
|
||||
p_seed ^= p_in;
|
||||
p_seed = (p_seed << 13) | (p_seed >> 19);
|
||||
p_seed = p_seed * 5 + 0xe6546b64;
|
||||
|
||||
return p_seed;
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash_murmur3_one_float(float p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
|
||||
// Normalize +/- 0.0 and NaN values so they hash the same.
|
||||
if (p_in == 0.0f) {
|
||||
u.f = 0.0;
|
||||
} else if (Math::is_nan(p_in)) {
|
||||
u.f = NAN;
|
||||
} else {
|
||||
u.f = p_in;
|
||||
}
|
||||
|
||||
return hash_murmur3_one_32(u.i, p_seed);
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash_murmur3_one_64(uint64_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
|
||||
p_seed = hash_murmur3_one_32(p_in & 0xFFFFFFFF, p_seed);
|
||||
return hash_murmur3_one_32(p_in >> 32, p_seed);
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash_murmur3_one_double(double p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
|
||||
// Normalize +/- 0.0 and NaN values so they hash the same.
|
||||
if (p_in == 0.0f) {
|
||||
u.d = 0.0;
|
||||
} else if (Math::is_nan(p_in)) {
|
||||
u.d = NAN;
|
||||
} else {
|
||||
u.d = p_in;
|
||||
}
|
||||
|
||||
return hash_murmur3_one_64(u.i, p_seed);
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash_murmur3_one_real(real_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
|
||||
#ifdef REAL_T_IS_DOUBLE
|
||||
return hash_murmur3_one_double(p_in, p_seed);
|
||||
#else
|
||||
return hash_murmur3_one_float(p_in, p_seed);
|
||||
#endif
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash_rotl32(uint32_t x, int8_t r) {
|
||||
return (x << r) | (x >> (32 - r));
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash_fmix32(uint32_t h) {
|
||||
h ^= h >> 16;
|
||||
h *= 0x85ebca6b;
|
||||
h ^= h >> 13;
|
||||
h *= 0xc2b2ae35;
|
||||
h ^= h >> 16;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash_murmur3_buffer(const void *key, int length, const uint32_t seed = HASH_MURMUR3_SEED) {
|
||||
// Although not required, this is a random prime number.
|
||||
const uint8_t *data = (const uint8_t *)key;
|
||||
const int nblocks = length / 4;
|
||||
|
||||
uint32_t h1 = seed;
|
||||
|
||||
const uint32_t c1 = 0xcc9e2d51;
|
||||
const uint32_t c2 = 0x1b873593;
|
||||
|
||||
const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4);
|
||||
|
||||
for (int i = -nblocks; i; i++) {
|
||||
uint32_t k1 = blocks[i];
|
||||
|
||||
k1 *= c1;
|
||||
k1 = hash_rotl32(k1, 15);
|
||||
k1 *= c2;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = hash_rotl32(h1, 13);
|
||||
h1 = h1 * 5 + 0xe6546b64;
|
||||
}
|
||||
|
||||
const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
|
||||
|
||||
uint32_t k1 = 0;
|
||||
|
||||
switch (length & 3) {
|
||||
case 3:
|
||||
k1 ^= tail[2] << 16;
|
||||
[[fallthrough]];
|
||||
case 2:
|
||||
k1 ^= tail[1] << 8;
|
||||
[[fallthrough]];
|
||||
case 1:
|
||||
k1 ^= tail[0];
|
||||
k1 *= c1;
|
||||
k1 = hash_rotl32(k1, 15);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
}
|
||||
|
||||
// Finalize with additional bit mixing.
|
||||
h1 ^= length;
|
||||
return hash_fmix32(h1);
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash_djb2_one_float(double p_in, uint32_t p_prev = 5381) {
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
|
||||
// Normalize +/- 0.0 and NaN values so they hash the same.
|
||||
if (p_in == 0.0f) {
|
||||
u.d = 0.0;
|
||||
} else if (Math::is_nan(p_in)) {
|
||||
u.d = NAN;
|
||||
} else {
|
||||
u.d = p_in;
|
||||
}
|
||||
|
||||
return ((p_prev << 5) + p_prev) + hash_one_uint64(u.i);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static _FORCE_INLINE_ uint32_t hash_make_uint32_t(T p_in) {
|
||||
union {
|
||||
T t;
|
||||
uint32_t _u32;
|
||||
} _u;
|
||||
_u._u32 = 0;
|
||||
_u.t = p_in;
|
||||
return _u._u32;
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint64_t hash_djb2_one_float_64(double p_in, uint64_t p_prev = 5381) {
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
|
||||
// Normalize +/- 0.0 and NaN values so they hash the same.
|
||||
if (p_in == 0.0f) {
|
||||
u.d = 0.0;
|
||||
} else if (Math::is_nan(p_in)) {
|
||||
u.d = NAN;
|
||||
} else {
|
||||
u.d = p_in;
|
||||
}
|
||||
|
||||
return ((p_prev << 5) + p_prev) + u.i;
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint64_t hash_djb2_one_64(uint64_t p_in, uint64_t p_prev = 5381) {
|
||||
return ((p_prev << 5) + p_prev) ^ p_in;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static _FORCE_INLINE_ uint64_t hash_make_uint64_t(T p_in) {
|
||||
union {
|
||||
T t;
|
||||
uint64_t _u64;
|
||||
} _u;
|
||||
_u._u64 = 0; // in case p_in is smaller
|
||||
|
||||
_u.t = p_in;
|
||||
return _u._u64;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class Ref;
|
||||
|
||||
struct HashMapHasherDefault {
|
||||
// Generic hash function for any type.
|
||||
template <typename T>
|
||||
static _FORCE_INLINE_ uint32_t hash(const T *p_pointer) { return hash_one_uint64((uint64_t)p_pointer); }
|
||||
|
||||
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(); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const char *p_cstr) { return hash_djb2(p_cstr); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return hash_fmix32(p_wchar); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return hash_fmix32(p_uchar); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return hash_fmix32(p_uchar); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const RID &p_rid) { return hash_one_uint64(p_rid.get_id()); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const ObjectID &p_id) { return hash_one_uint64(p_id); }
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) { return hash_one_uint64(p_int); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash_one_uint64(p_int); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const float p_float) { return hash_murmur3_one_float(p_float); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const double p_double) { return hash_murmur3_one_double(p_double); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const uint32_t p_int) { return hash_fmix32(p_int); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const int32_t p_int) { return hash_fmix32(p_int); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const uint16_t p_int) { return hash_fmix32(p_int); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const int16_t p_int) { return hash_fmix32(p_int); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return hash_fmix32(p_int); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return hash_fmix32(p_int); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const Vector2i &p_vec) {
|
||||
uint32_t h = hash_murmur3_one_32(p_vec.x);
|
||||
h = hash_murmur3_one_32(p_vec.y, h);
|
||||
return hash_fmix32(h);
|
||||
}
|
||||
static _FORCE_INLINE_ uint32_t hash(const Vector3i &p_vec) {
|
||||
uint32_t h = hash_murmur3_one_32(p_vec.x);
|
||||
h = hash_murmur3_one_32(p_vec.y, h);
|
||||
h = hash_murmur3_one_32(p_vec.z, h);
|
||||
return hash_fmix32(h);
|
||||
}
|
||||
static _FORCE_INLINE_ uint32_t hash(const Vector4i &p_vec) {
|
||||
uint32_t h = hash_murmur3_one_32(p_vec.x);
|
||||
h = hash_murmur3_one_32(p_vec.y, h);
|
||||
h = hash_murmur3_one_32(p_vec.z, h);
|
||||
h = hash_murmur3_one_32(p_vec.w, h);
|
||||
return hash_fmix32(h);
|
||||
}
|
||||
static _FORCE_INLINE_ uint32_t hash(const Vector2 &p_vec) {
|
||||
uint32_t h = hash_murmur3_one_real(p_vec.x);
|
||||
h = hash_murmur3_one_real(p_vec.y, h);
|
||||
return hash_fmix32(h);
|
||||
}
|
||||
static _FORCE_INLINE_ uint32_t hash(const Vector3 &p_vec) {
|
||||
uint32_t h = hash_murmur3_one_real(p_vec.x);
|
||||
h = hash_murmur3_one_real(p_vec.y, h);
|
||||
h = hash_murmur3_one_real(p_vec.z, h);
|
||||
return hash_fmix32(h);
|
||||
}
|
||||
static _FORCE_INLINE_ uint32_t hash(const Vector4 &p_vec) {
|
||||
uint32_t h = hash_murmur3_one_real(p_vec.x);
|
||||
h = hash_murmur3_one_real(p_vec.y, h);
|
||||
h = hash_murmur3_one_real(p_vec.z, h);
|
||||
h = hash_murmur3_one_real(p_vec.w, h);
|
||||
return hash_fmix32(h);
|
||||
}
|
||||
static _FORCE_INLINE_ uint32_t hash(const Rect2i &p_rect) {
|
||||
uint32_t h = hash_murmur3_one_32(p_rect.position.x);
|
||||
h = hash_murmur3_one_32(p_rect.position.y, h);
|
||||
h = hash_murmur3_one_32(p_rect.size.x, h);
|
||||
h = hash_murmur3_one_32(p_rect.size.y, h);
|
||||
return hash_fmix32(h);
|
||||
}
|
||||
static _FORCE_INLINE_ uint32_t hash(const Rect2 &p_rect) {
|
||||
uint32_t h = hash_murmur3_one_real(p_rect.position.x);
|
||||
h = hash_murmur3_one_real(p_rect.position.y, h);
|
||||
h = hash_murmur3_one_real(p_rect.size.x, h);
|
||||
h = hash_murmur3_one_real(p_rect.size.y, h);
|
||||
return hash_fmix32(h);
|
||||
}
|
||||
static _FORCE_INLINE_ uint32_t hash(const AABB &p_aabb) {
|
||||
uint32_t h = hash_murmur3_one_real(p_aabb.position.x);
|
||||
h = hash_murmur3_one_real(p_aabb.position.y, h);
|
||||
h = hash_murmur3_one_real(p_aabb.position.z, h);
|
||||
h = hash_murmur3_one_real(p_aabb.size.x, h);
|
||||
h = hash_murmur3_one_real(p_aabb.size.y, h);
|
||||
h = hash_murmur3_one_real(p_aabb.size.z, h);
|
||||
return hash_fmix32(h);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct HashMapComparatorDefault {
|
||||
static bool compare(const T &p_lhs, const T &p_rhs) {
|
||||
return p_lhs == p_rhs;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct HashMapComparatorDefault<float> {
|
||||
static bool compare(const float &p_lhs, const float &p_rhs) {
|
||||
return (p_lhs == p_rhs) || (Math::is_nan(p_lhs) && Math::is_nan(p_rhs));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct HashMapComparatorDefault<double> {
|
||||
static bool compare(const double &p_lhs, const double &p_rhs) {
|
||||
return (p_lhs == p_rhs) || (Math::is_nan(p_lhs) && Math::is_nan(p_rhs));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct HashMapComparatorDefault<Vector2> {
|
||||
static bool compare(const Vector2 &p_lhs, const Vector2 &p_rhs) {
|
||||
return ((p_lhs.x == p_rhs.x) || (Math::is_nan(p_lhs.x) && Math::is_nan(p_rhs.x))) && ((p_lhs.y == p_rhs.y) || (Math::is_nan(p_lhs.y) && Math::is_nan(p_rhs.y)));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct HashMapComparatorDefault<Vector3> {
|
||||
static bool compare(const Vector3 &p_lhs, const Vector3 &p_rhs) {
|
||||
return ((p_lhs.x == p_rhs.x) || (Math::is_nan(p_lhs.x) && Math::is_nan(p_rhs.x))) && ((p_lhs.y == p_rhs.y) || (Math::is_nan(p_lhs.y) && Math::is_nan(p_rhs.y))) && ((p_lhs.z == p_rhs.z) || (Math::is_nan(p_lhs.z) && Math::is_nan(p_rhs.z)));
|
||||
}
|
||||
};
|
||||
|
||||
constexpr uint32_t HASH_TABLE_SIZE_MAX = 29;
|
||||
|
||||
const uint32_t hash_table_size_primes[HASH_TABLE_SIZE_MAX] = {
|
||||
5,
|
||||
13,
|
||||
23,
|
||||
47,
|
||||
97,
|
||||
193,
|
||||
389,
|
||||
769,
|
||||
1543,
|
||||
3079,
|
||||
6151,
|
||||
12289,
|
||||
24593,
|
||||
49157,
|
||||
98317,
|
||||
196613,
|
||||
393241,
|
||||
786433,
|
||||
1572869,
|
||||
3145739,
|
||||
6291469,
|
||||
12582917,
|
||||
25165843,
|
||||
50331653,
|
||||
100663319,
|
||||
201326611,
|
||||
402653189,
|
||||
805306457,
|
||||
1610612741,
|
||||
};
|
||||
|
||||
// Computed with elem_i = UINT64_C (0 x FFFFFFFF FFFFFFFF ) / d_i + 1, where d_i is the i-th element of the above array.
|
||||
const uint64_t hash_table_size_primes_inv[HASH_TABLE_SIZE_MAX] = {
|
||||
3689348814741910324,
|
||||
1418980313362273202,
|
||||
802032351030850071,
|
||||
392483916461905354,
|
||||
190172619316593316,
|
||||
95578984837873325,
|
||||
47420935922132524,
|
||||
23987963684927896,
|
||||
11955116055547344,
|
||||
5991147799191151,
|
||||
2998982941588287,
|
||||
1501077717772769,
|
||||
750081082979285,
|
||||
375261795343686,
|
||||
187625172388393,
|
||||
93822606204624,
|
||||
46909513691883,
|
||||
23456218233098,
|
||||
11728086747027,
|
||||
5864041509391,
|
||||
2932024948977,
|
||||
1466014921160,
|
||||
733007198436,
|
||||
366503839517,
|
||||
183251896093,
|
||||
91625960335,
|
||||
45812983922,
|
||||
22906489714,
|
||||
11453246088
|
||||
};
|
||||
|
||||
/**
|
||||
* Fastmod computes ( n mod d ) given the precomputed c much faster than n % d.
|
||||
* The implementation of fastmod is based on the following paper by Daniel Lemire et al.
|
||||
* Faster Remainder by Direct Computation: Applications to Compilers and Software Libraries
|
||||
* https://arxiv.org/abs/1902.01961
|
||||
*/
|
||||
static _FORCE_INLINE_ uint32_t fastmod(const uint32_t n, const uint64_t c, const uint32_t d) {
|
||||
#if defined(_MSC_VER)
|
||||
// Returns the upper 64 bits of the product of two 64-bit unsigned integers.
|
||||
// This intrinsic function is required since MSVC does not support unsigned 128-bit integers.
|
||||
#if defined(_M_X64) || defined(_M_ARM64)
|
||||
return __umulh(c * n, d);
|
||||
#else
|
||||
// Fallback to the slower method for 32-bit platforms.
|
||||
return n % d;
|
||||
#endif // _M_X64 || _M_ARM64
|
||||
#else
|
||||
#ifdef __SIZEOF_INT128__
|
||||
// Prevent compiler warning, because we know what we are doing.
|
||||
uint64_t lowbits = c * n;
|
||||
__extension__ typedef unsigned __int128 uint128;
|
||||
return static_cast<uint64_t>(((uint128)lowbits * d) >> 64);
|
||||
#else
|
||||
// Fallback to the slower method if no 128-bit unsigned integer type is available.
|
||||
return n % d;
|
||||
#endif // __SIZEOF_INT128__
|
||||
#endif // _MSC_VER
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_HASHFUNCS_HPP
|
||||
787
include/godot_cpp/templates/list.hpp
Normal file
787
include/godot_cpp/templates/list.hpp
Normal file
@@ -0,0 +1,787 @@
|
||||
/**************************************************************************/
|
||||
/* list.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_LIST_HPP
|
||||
#define GODOT_LIST_HPP
|
||||
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
#include <godot_cpp/templates/sort_array.hpp>
|
||||
|
||||
/**
|
||||
* Generic Templatized Linked List Implementation.
|
||||
* The implementation differs from the STL one because
|
||||
* a compatible preallocated linked list can be written
|
||||
* using the same API, or features such as erasing an element
|
||||
* from the iterator.
|
||||
*/
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <typename T, typename A = DefaultAllocator>
|
||||
class List {
|
||||
struct _Data;
|
||||
|
||||
public:
|
||||
class Element {
|
||||
private:
|
||||
friend class List<T, A>;
|
||||
|
||||
T value;
|
||||
Element *next_ptr = nullptr;
|
||||
Element *prev_ptr = nullptr;
|
||||
_Data *data = nullptr;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Get NEXT Element iterator, for constant lists.
|
||||
*/
|
||||
_FORCE_INLINE_ const Element *next() const {
|
||||
return next_ptr;
|
||||
}
|
||||
/**
|
||||
* Get NEXT Element iterator,
|
||||
*/
|
||||
_FORCE_INLINE_ Element *next() {
|
||||
return next_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get PREV Element iterator, for constant lists.
|
||||
*/
|
||||
_FORCE_INLINE_ const Element *prev() const {
|
||||
return prev_ptr;
|
||||
}
|
||||
/**
|
||||
* Get PREV Element iterator,
|
||||
*/
|
||||
_FORCE_INLINE_ Element *prev() {
|
||||
return prev_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* * operator, for using as *iterator, when iterators are defined on stack.
|
||||
*/
|
||||
_FORCE_INLINE_ const T &operator*() const {
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* operator->, for using as iterator->, when iterators are defined on stack, for constant lists.
|
||||
*/
|
||||
_FORCE_INLINE_ const T *operator->() const {
|
||||
return &value;
|
||||
}
|
||||
/**
|
||||
* * operator, for using as *iterator, when iterators are defined on stack,
|
||||
*/
|
||||
_FORCE_INLINE_ T &operator*() {
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* operator->, for using as iterator->, when iterators are defined on stack, for constant lists.
|
||||
*/
|
||||
_FORCE_INLINE_ T *operator->() {
|
||||
return &value;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the value stored in this element.
|
||||
*/
|
||||
_FORCE_INLINE_ T &get() {
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* get the value stored in this element, for constant lists
|
||||
*/
|
||||
_FORCE_INLINE_ const T &get() const {
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* set the value stored in this element.
|
||||
*/
|
||||
_FORCE_INLINE_ void set(const T &p_value) {
|
||||
value = (T &)p_value;
|
||||
}
|
||||
|
||||
void erase() {
|
||||
data->erase(this);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Element() {}
|
||||
};
|
||||
|
||||
typedef T ValueType;
|
||||
|
||||
struct ConstIterator {
|
||||
_FORCE_INLINE_ const T &operator*() const {
|
||||
return E->get();
|
||||
}
|
||||
_FORCE_INLINE_ const T *operator->() const { return &E->get(); }
|
||||
_FORCE_INLINE_ ConstIterator &operator++() {
|
||||
E = E->next();
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator &operator--() {
|
||||
E = E->prev();
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; }
|
||||
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; }
|
||||
|
||||
_FORCE_INLINE_ ConstIterator(const Element *p_E) { E = p_E; }
|
||||
_FORCE_INLINE_ ConstIterator() {}
|
||||
_FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
|
||||
|
||||
private:
|
||||
const Element *E = nullptr;
|
||||
};
|
||||
|
||||
struct Iterator {
|
||||
_FORCE_INLINE_ T &operator*() const {
|
||||
return E->get();
|
||||
}
|
||||
_FORCE_INLINE_ T *operator->() const { return &E->get(); }
|
||||
_FORCE_INLINE_ Iterator &operator++() {
|
||||
E = E->next();
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ Iterator &operator--() {
|
||||
E = E->prev();
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
|
||||
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
|
||||
|
||||
Iterator(Element *p_E) { E = p_E; }
|
||||
Iterator() {}
|
||||
Iterator(const Iterator &p_it) { E = p_it.E; }
|
||||
|
||||
operator ConstIterator() const {
|
||||
return ConstIterator(E);
|
||||
}
|
||||
|
||||
private:
|
||||
Element *E = nullptr;
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ Iterator begin() {
|
||||
return Iterator(front());
|
||||
}
|
||||
_FORCE_INLINE_ Iterator end() {
|
||||
return Iterator(nullptr);
|
||||
}
|
||||
|
||||
#if 0
|
||||
//to use when replacing find()
|
||||
_FORCE_INLINE_ Iterator find(const K &p_key) {
|
||||
return Iterator(find(p_key));
|
||||
}
|
||||
#endif
|
||||
_FORCE_INLINE_ ConstIterator begin() const {
|
||||
return ConstIterator(front());
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator end() const {
|
||||
return ConstIterator(nullptr);
|
||||
}
|
||||
#if 0
|
||||
//to use when replacing find()
|
||||
_FORCE_INLINE_ ConstIterator find(const K &p_key) const {
|
||||
return ConstIterator(find(p_key));
|
||||
}
|
||||
#endif
|
||||
private:
|
||||
struct _Data {
|
||||
Element *first = nullptr;
|
||||
Element *last = nullptr;
|
||||
int size_cache = 0;
|
||||
|
||||
bool erase(const Element *p_I) {
|
||||
ERR_FAIL_NULL_V(p_I, false);
|
||||
ERR_FAIL_COND_V(p_I->data != this, false);
|
||||
|
||||
if (first == p_I) {
|
||||
first = p_I->next_ptr;
|
||||
}
|
||||
|
||||
if (last == p_I) {
|
||||
last = p_I->prev_ptr;
|
||||
}
|
||||
|
||||
if (p_I->prev_ptr) {
|
||||
p_I->prev_ptr->next_ptr = p_I->next_ptr;
|
||||
}
|
||||
|
||||
if (p_I->next_ptr) {
|
||||
p_I->next_ptr->prev_ptr = p_I->prev_ptr;
|
||||
}
|
||||
|
||||
memdelete_allocator<Element, A>(const_cast<Element *>(p_I));
|
||||
size_cache--;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
_Data *_data = nullptr;
|
||||
|
||||
public:
|
||||
/**
|
||||
* return a const iterator to the beginning of the list.
|
||||
*/
|
||||
_FORCE_INLINE_ const Element *front() const {
|
||||
return _data ? _data->first : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* return an iterator to the beginning of the list.
|
||||
*/
|
||||
_FORCE_INLINE_ Element *front() {
|
||||
return _data ? _data->first : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* return a const iterator to the last member of the list.
|
||||
*/
|
||||
_FORCE_INLINE_ const Element *back() const {
|
||||
return _data ? _data->last : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* return an iterator to the last member of the list.
|
||||
*/
|
||||
_FORCE_INLINE_ Element *back() {
|
||||
return _data ? _data->last : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* store a new element at the end of the list
|
||||
*/
|
||||
Element *push_back(const T &value) {
|
||||
if (!_data) {
|
||||
_data = memnew_allocator(_Data, A);
|
||||
_data->first = nullptr;
|
||||
_data->last = nullptr;
|
||||
_data->size_cache = 0;
|
||||
}
|
||||
|
||||
Element *n = memnew_allocator(Element, A);
|
||||
n->value = (T &)value;
|
||||
|
||||
n->prev_ptr = _data->last;
|
||||
n->next_ptr = nullptr;
|
||||
n->data = _data;
|
||||
|
||||
if (_data->last) {
|
||||
_data->last->next_ptr = n;
|
||||
}
|
||||
|
||||
_data->last = n;
|
||||
|
||||
if (!_data->first) {
|
||||
_data->first = n;
|
||||
}
|
||||
|
||||
_data->size_cache++;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void pop_back() {
|
||||
if (_data && _data->last) {
|
||||
erase(_data->last);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* store a new element at the beginning of the list
|
||||
*/
|
||||
Element *push_front(const T &value) {
|
||||
if (!_data) {
|
||||
_data = memnew_allocator(_Data, A);
|
||||
_data->first = nullptr;
|
||||
_data->last = nullptr;
|
||||
_data->size_cache = 0;
|
||||
}
|
||||
|
||||
Element *n = memnew_allocator(Element, A);
|
||||
n->value = (T &)value;
|
||||
n->prev_ptr = nullptr;
|
||||
n->next_ptr = _data->first;
|
||||
n->data = _data;
|
||||
|
||||
if (_data->first) {
|
||||
_data->first->prev_ptr = n;
|
||||
}
|
||||
|
||||
_data->first = n;
|
||||
|
||||
if (!_data->last) {
|
||||
_data->last = n;
|
||||
}
|
||||
|
||||
_data->size_cache++;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void pop_front() {
|
||||
if (_data && _data->first) {
|
||||
erase(_data->first);
|
||||
}
|
||||
}
|
||||
|
||||
Element *insert_after(Element *p_element, const T &p_value) {
|
||||
CRASH_COND(p_element && (!_data || p_element->data != _data));
|
||||
|
||||
if (!p_element) {
|
||||
return push_back(p_value);
|
||||
}
|
||||
|
||||
Element *n = memnew_allocator(Element, A);
|
||||
n->value = (T &)p_value;
|
||||
n->prev_ptr = p_element;
|
||||
n->next_ptr = p_element->next_ptr;
|
||||
n->data = _data;
|
||||
|
||||
if (!p_element->next_ptr) {
|
||||
_data->last = n;
|
||||
} else {
|
||||
p_element->next_ptr->prev_ptr = n;
|
||||
}
|
||||
|
||||
p_element->next_ptr = n;
|
||||
|
||||
_data->size_cache++;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
Element *insert_before(Element *p_element, const T &p_value) {
|
||||
CRASH_COND(p_element && (!_data || p_element->data != _data));
|
||||
|
||||
if (!p_element) {
|
||||
return push_back(p_value);
|
||||
}
|
||||
|
||||
Element *n = memnew_allocator(Element, A);
|
||||
n->value = (T &)p_value;
|
||||
n->prev_ptr = p_element->prev_ptr;
|
||||
n->next_ptr = p_element;
|
||||
n->data = _data;
|
||||
|
||||
if (!p_element->prev_ptr) {
|
||||
_data->first = n;
|
||||
} else {
|
||||
p_element->prev_ptr->next_ptr = n;
|
||||
}
|
||||
|
||||
p_element->prev_ptr = n;
|
||||
|
||||
_data->size_cache++;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* find an element in the list,
|
||||
*/
|
||||
template <typename T_v>
|
||||
Element *find(const T_v &p_val) {
|
||||
Element *it = front();
|
||||
while (it) {
|
||||
if (it->value == p_val) {
|
||||
return it;
|
||||
}
|
||||
it = it->next();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* erase an element in the list, by iterator pointing to it. Return true if it was found/erased.
|
||||
*/
|
||||
bool erase(const Element *p_I) {
|
||||
if (_data && p_I) {
|
||||
bool ret = _data->erase(p_I);
|
||||
|
||||
if (_data->size_cache == 0) {
|
||||
memdelete_allocator<_Data, A>(_data);
|
||||
_data = nullptr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* erase the first element in the list, that contains value
|
||||
*/
|
||||
bool erase(const T &value) {
|
||||
Element *I = find(value);
|
||||
return erase(I);
|
||||
}
|
||||
|
||||
/**
|
||||
* return whether the list is empty
|
||||
*/
|
||||
_FORCE_INLINE_ bool is_empty() const {
|
||||
return (!_data || !_data->size_cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* clear the list
|
||||
*/
|
||||
void clear() {
|
||||
while (front()) {
|
||||
erase(front());
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int size() const {
|
||||
return _data ? _data->size_cache : 0;
|
||||
}
|
||||
|
||||
void swap(Element *p_A, Element *p_B) {
|
||||
ERR_FAIL_COND(!p_A || !p_B);
|
||||
ERR_FAIL_COND(p_A->data != _data);
|
||||
ERR_FAIL_COND(p_B->data != _data);
|
||||
|
||||
if (p_A == p_B) {
|
||||
return;
|
||||
}
|
||||
Element *A_prev = p_A->prev_ptr;
|
||||
Element *A_next = p_A->next_ptr;
|
||||
Element *B_prev = p_B->prev_ptr;
|
||||
Element *B_next = p_B->next_ptr;
|
||||
|
||||
if (A_prev) {
|
||||
A_prev->next_ptr = p_B;
|
||||
} else {
|
||||
_data->first = p_B;
|
||||
}
|
||||
if (B_prev) {
|
||||
B_prev->next_ptr = p_A;
|
||||
} else {
|
||||
_data->first = p_A;
|
||||
}
|
||||
if (A_next) {
|
||||
A_next->prev_ptr = p_B;
|
||||
} else {
|
||||
_data->last = p_B;
|
||||
}
|
||||
if (B_next) {
|
||||
B_next->prev_ptr = p_A;
|
||||
} else {
|
||||
_data->last = p_A;
|
||||
}
|
||||
p_A->prev_ptr = A_next == p_B ? p_B : B_prev;
|
||||
p_A->next_ptr = B_next == p_A ? p_B : B_next;
|
||||
p_B->prev_ptr = B_next == p_A ? p_A : A_prev;
|
||||
p_B->next_ptr = A_next == p_B ? p_A : A_next;
|
||||
}
|
||||
/**
|
||||
* copy the list
|
||||
*/
|
||||
void operator=(const List &p_list) {
|
||||
clear();
|
||||
const Element *it = p_list.front();
|
||||
while (it) {
|
||||
push_back(it->get());
|
||||
it = it->next();
|
||||
}
|
||||
}
|
||||
|
||||
// Index operator, kept for compatibility.
|
||||
_FORCE_INLINE_ T &operator[](int p_index) {
|
||||
return get(p_index);
|
||||
}
|
||||
|
||||
// Random access to elements, use with care,
|
||||
// do not use for iteration.
|
||||
T &get(int p_index) {
|
||||
CRASH_BAD_INDEX(p_index, size());
|
||||
|
||||
Element *I = front();
|
||||
int c = 0;
|
||||
while (c < p_index) {
|
||||
I = I->next();
|
||||
c++;
|
||||
}
|
||||
|
||||
return I->get();
|
||||
}
|
||||
|
||||
// Index operator, kept for compatibility.
|
||||
_FORCE_INLINE_ const T &operator[](int p_index) const {
|
||||
return get(p_index);
|
||||
}
|
||||
|
||||
// Random access to elements, use with care,
|
||||
// do not use for iteration.
|
||||
const T &get(int p_index) const {
|
||||
CRASH_BAD_INDEX(p_index, size());
|
||||
|
||||
const Element *I = front();
|
||||
int c = 0;
|
||||
while (c < p_index) {
|
||||
I = I->next();
|
||||
c++;
|
||||
}
|
||||
|
||||
return I->get();
|
||||
}
|
||||
|
||||
void move_to_back(Element *p_I) {
|
||||
ERR_FAIL_COND(p_I->data != _data);
|
||||
if (!p_I->next_ptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_data->first == p_I) {
|
||||
_data->first = p_I->next_ptr;
|
||||
}
|
||||
|
||||
if (_data->last == p_I) {
|
||||
_data->last = p_I->prev_ptr;
|
||||
}
|
||||
|
||||
if (p_I->prev_ptr) {
|
||||
p_I->prev_ptr->next_ptr = p_I->next_ptr;
|
||||
}
|
||||
|
||||
p_I->next_ptr->prev_ptr = p_I->prev_ptr;
|
||||
|
||||
_data->last->next_ptr = p_I;
|
||||
p_I->prev_ptr = _data->last;
|
||||
p_I->next_ptr = nullptr;
|
||||
_data->last = p_I;
|
||||
}
|
||||
|
||||
void reverse() {
|
||||
int s = size() / 2;
|
||||
Element *F = front();
|
||||
Element *B = back();
|
||||
for (int i = 0; i < s; i++) {
|
||||
SWAP(F->value, B->value);
|
||||
F = F->next();
|
||||
B = B->prev();
|
||||
}
|
||||
}
|
||||
|
||||
void move_to_front(Element *p_I) {
|
||||
ERR_FAIL_COND(p_I->data != _data);
|
||||
if (!p_I->prev_ptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_data->first == p_I) {
|
||||
_data->first = p_I->next_ptr;
|
||||
}
|
||||
|
||||
if (_data->last == p_I) {
|
||||
_data->last = p_I->prev_ptr;
|
||||
}
|
||||
|
||||
p_I->prev_ptr->next_ptr = p_I->next_ptr;
|
||||
|
||||
if (p_I->next_ptr) {
|
||||
p_I->next_ptr->prev_ptr = p_I->prev_ptr;
|
||||
}
|
||||
|
||||
_data->first->prev_ptr = p_I;
|
||||
p_I->next_ptr = _data->first;
|
||||
p_I->prev_ptr = nullptr;
|
||||
_data->first = p_I;
|
||||
}
|
||||
|
||||
void move_before(Element *value, Element *where) {
|
||||
if (value->prev_ptr) {
|
||||
value->prev_ptr->next_ptr = value->next_ptr;
|
||||
} else {
|
||||
_data->first = value->next_ptr;
|
||||
}
|
||||
if (value->next_ptr) {
|
||||
value->next_ptr->prev_ptr = value->prev_ptr;
|
||||
} else {
|
||||
_data->last = value->prev_ptr;
|
||||
}
|
||||
|
||||
value->next_ptr = where;
|
||||
if (!where) {
|
||||
value->prev_ptr = _data->last;
|
||||
_data->last = value;
|
||||
return;
|
||||
}
|
||||
|
||||
value->prev_ptr = where->prev_ptr;
|
||||
|
||||
if (where->prev_ptr) {
|
||||
where->prev_ptr->next_ptr = value;
|
||||
} else {
|
||||
_data->first = value;
|
||||
}
|
||||
|
||||
where->prev_ptr = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* simple insertion sort
|
||||
*/
|
||||
|
||||
void sort() {
|
||||
sort_custom<Comparator<T>>();
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
void sort_custom_inplace() {
|
||||
if (size() < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
Element *from = front();
|
||||
Element *current = from;
|
||||
Element *to = from;
|
||||
|
||||
while (current) {
|
||||
Element *next = current->next_ptr;
|
||||
|
||||
if (from != current) {
|
||||
current->prev_ptr = nullptr;
|
||||
current->next_ptr = from;
|
||||
|
||||
Element *find = from;
|
||||
C less;
|
||||
while (find && less(find->value, current->value)) {
|
||||
current->prev_ptr = find;
|
||||
current->next_ptr = find->next_ptr;
|
||||
find = find->next_ptr;
|
||||
}
|
||||
|
||||
if (current->prev_ptr) {
|
||||
current->prev_ptr->next_ptr = current;
|
||||
} else {
|
||||
from = current;
|
||||
}
|
||||
|
||||
if (current->next_ptr) {
|
||||
current->next_ptr->prev_ptr = current;
|
||||
} else {
|
||||
to = current;
|
||||
}
|
||||
} else {
|
||||
current->prev_ptr = nullptr;
|
||||
current->next_ptr = nullptr;
|
||||
}
|
||||
|
||||
current = next;
|
||||
}
|
||||
_data->first = from;
|
||||
_data->last = to;
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
struct AuxiliaryComparator {
|
||||
C compare;
|
||||
_FORCE_INLINE_ bool operator()(const Element *a, const Element *b) const {
|
||||
return compare(a->value, b->value);
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
int s = size();
|
||||
if (s < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
Element **aux_buffer = memnew_arr(Element *, s);
|
||||
|
||||
int idx = 0;
|
||||
for (Element *E = front(); E; E = E->next_ptr) {
|
||||
aux_buffer[idx] = E;
|
||||
idx++;
|
||||
}
|
||||
|
||||
SortArray<Element *, AuxiliaryComparator<C>> sort;
|
||||
sort.sort(aux_buffer, s);
|
||||
|
||||
_data->first = aux_buffer[0];
|
||||
aux_buffer[0]->prev_ptr = nullptr;
|
||||
aux_buffer[0]->next_ptr = aux_buffer[1];
|
||||
|
||||
_data->last = aux_buffer[s - 1];
|
||||
aux_buffer[s - 1]->prev_ptr = aux_buffer[s - 2];
|
||||
aux_buffer[s - 1]->next_ptr = nullptr;
|
||||
|
||||
for (int i = 1; i < s - 1; i++) {
|
||||
aux_buffer[i]->prev_ptr = aux_buffer[i - 1];
|
||||
aux_buffer[i]->next_ptr = aux_buffer[i + 1];
|
||||
}
|
||||
|
||||
memdelete_arr(aux_buffer);
|
||||
}
|
||||
|
||||
const void *id() const {
|
||||
return (void *)_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* copy constructor for the list
|
||||
*/
|
||||
List(const List &p_list) {
|
||||
const Element *it = p_list.front();
|
||||
while (it) {
|
||||
push_back(it->get());
|
||||
it = it->next();
|
||||
}
|
||||
}
|
||||
|
||||
List() {}
|
||||
|
||||
~List() {
|
||||
clear();
|
||||
if (_data) {
|
||||
ERR_FAIL_COND(_data->size_cache);
|
||||
memdelete_allocator<_Data, A>(_data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_LIST_HPP
|
||||
343
include/godot_cpp/templates/local_vector.hpp
Normal file
343
include/godot_cpp/templates/local_vector.hpp
Normal file
@@ -0,0 +1,343 @@
|
||||
/**************************************************************************/
|
||||
/* local_vector.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_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 <initializer_list>
|
||||
#include <type_traits>
|
||||
|
||||
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 <typename T, typename U = uint32_t, bool force_trivial = false, bool tight = false>
|
||||
class LocalVector {
|
||||
private:
|
||||
U count = 0;
|
||||
U capacity = 0;
|
||||
T *data = nullptr;
|
||||
|
||||
public:
|
||||
T *ptr() {
|
||||
return data;
|
||||
}
|
||||
|
||||
const T *ptr() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void push_back(T p_elem) {
|
||||
if (unlikely(count == capacity)) {
|
||||
if (capacity == 0) {
|
||||
capacity = 1;
|
||||
} else {
|
||||
capacity <<= 1;
|
||||
}
|
||||
data = (T *)memrealloc(data, capacity * sizeof(T));
|
||||
CRASH_COND_MSG(!data, "Out of memory");
|
||||
}
|
||||
|
||||
if constexpr (!std::is_trivially_constructible<T>::value && !force_trivial) {
|
||||
memnew_placement(&data[count++], T(p_elem));
|
||||
} else {
|
||||
data[count++] = p_elem;
|
||||
}
|
||||
}
|
||||
|
||||
void remove_at(U p_index) {
|
||||
ERR_FAIL_UNSIGNED_INDEX(p_index, count);
|
||||
count--;
|
||||
for (U i = p_index; i < count; i++) {
|
||||
data[i] = data[i + 1];
|
||||
}
|
||||
if constexpr (!std::is_trivially_destructible<T>::value && !force_trivial) {
|
||||
data[count].~T();
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the item copying the last value into the position of the one to
|
||||
/// remove. It's generally faster than `remove`.
|
||||
void remove_at_unordered(U p_index) {
|
||||
ERR_FAIL_INDEX(p_index, count);
|
||||
count--;
|
||||
if (count > p_index) {
|
||||
data[p_index] = data[count];
|
||||
}
|
||||
if constexpr (!std::is_trivially_destructible<T>::value && !force_trivial) {
|
||||
data[count].~T();
|
||||
}
|
||||
}
|
||||
|
||||
void erase(const T &p_val) {
|
||||
int64_t idx = find(p_val);
|
||||
if (idx >= 0) {
|
||||
remove_at(idx);
|
||||
}
|
||||
}
|
||||
|
||||
void invert() {
|
||||
for (U i = 0; i < count / 2; i++) {
|
||||
SWAP(data[i], data[count - i - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void clear() { resize(0); }
|
||||
_FORCE_INLINE_ void reset() {
|
||||
clear();
|
||||
if (data) {
|
||||
memfree(data);
|
||||
data = nullptr;
|
||||
capacity = 0;
|
||||
}
|
||||
}
|
||||
_FORCE_INLINE_ bool is_empty() const { return count == 0; }
|
||||
_FORCE_INLINE_ U get_capacity() const { return capacity; }
|
||||
_FORCE_INLINE_ void reserve(U p_size) {
|
||||
p_size = tight ? p_size : nearest_power_of_2_templated(p_size);
|
||||
if (p_size > capacity) {
|
||||
capacity = p_size;
|
||||
data = (T *)memrealloc(data, capacity * sizeof(T));
|
||||
CRASH_COND_MSG(!data, "Out of memory");
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ U size() const { return count; }
|
||||
void resize(U p_size) {
|
||||
if (p_size < count) {
|
||||
if constexpr (!std::is_trivially_destructible<T>::value && !force_trivial) {
|
||||
for (U i = p_size; i < count; i++) {
|
||||
data[i].~T();
|
||||
}
|
||||
}
|
||||
count = p_size;
|
||||
} else if (p_size > count) {
|
||||
if (unlikely(p_size > capacity)) {
|
||||
if (capacity == 0) {
|
||||
capacity = 1;
|
||||
}
|
||||
while (capacity < p_size) {
|
||||
capacity <<= 1;
|
||||
}
|
||||
data = (T *)memrealloc(data, capacity * sizeof(T));
|
||||
CRASH_COND_MSG(!data, "Out of memory");
|
||||
}
|
||||
if constexpr (!std::is_trivially_constructible<T>::value && !force_trivial) {
|
||||
for (U i = count; i < p_size; i++) {
|
||||
memnew_placement(&data[i], T);
|
||||
}
|
||||
}
|
||||
count = p_size;
|
||||
}
|
||||
}
|
||||
_FORCE_INLINE_ const T &operator[](U p_index) const {
|
||||
CRASH_BAD_UNSIGNED_INDEX(p_index, count);
|
||||
return data[p_index];
|
||||
}
|
||||
_FORCE_INLINE_ T &operator[](U p_index) {
|
||||
CRASH_BAD_UNSIGNED_INDEX(p_index, count);
|
||||
return data[p_index];
|
||||
}
|
||||
|
||||
struct Iterator {
|
||||
_FORCE_INLINE_ T &operator*() const {
|
||||
return *elem_ptr;
|
||||
}
|
||||
_FORCE_INLINE_ T *operator->() const { return elem_ptr; }
|
||||
_FORCE_INLINE_ Iterator &operator++() {
|
||||
elem_ptr++;
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ Iterator &operator--() {
|
||||
elem_ptr--;
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return elem_ptr == b.elem_ptr; }
|
||||
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return elem_ptr != b.elem_ptr; }
|
||||
|
||||
Iterator(T *p_ptr) { elem_ptr = p_ptr; }
|
||||
Iterator() {}
|
||||
Iterator(const Iterator &p_it) { elem_ptr = p_it.elem_ptr; }
|
||||
|
||||
private:
|
||||
T *elem_ptr = nullptr;
|
||||
};
|
||||
|
||||
struct ConstIterator {
|
||||
_FORCE_INLINE_ const T &operator*() const {
|
||||
return *elem_ptr;
|
||||
}
|
||||
_FORCE_INLINE_ const T *operator->() const { return elem_ptr; }
|
||||
_FORCE_INLINE_ ConstIterator &operator++() {
|
||||
elem_ptr++;
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator &operator--() {
|
||||
elem_ptr--;
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return elem_ptr == b.elem_ptr; }
|
||||
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return elem_ptr != b.elem_ptr; }
|
||||
|
||||
ConstIterator(const T *p_ptr) { elem_ptr = p_ptr; }
|
||||
ConstIterator() {}
|
||||
ConstIterator(const ConstIterator &p_it) { elem_ptr = p_it.elem_ptr; }
|
||||
|
||||
private:
|
||||
const T *elem_ptr = nullptr;
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ Iterator begin() {
|
||||
return Iterator(data);
|
||||
}
|
||||
_FORCE_INLINE_ Iterator end() {
|
||||
return Iterator(data + size());
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ ConstIterator begin() const {
|
||||
return ConstIterator(ptr());
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator end() const {
|
||||
return ConstIterator(ptr() + size());
|
||||
}
|
||||
|
||||
void insert(U p_pos, T p_val) {
|
||||
ERR_FAIL_UNSIGNED_INDEX(p_pos, count + 1);
|
||||
if (p_pos == count) {
|
||||
push_back(p_val);
|
||||
} else {
|
||||
resize(count + 1);
|
||||
for (U i = count - 1; i > p_pos; i--) {
|
||||
data[i] = data[i - 1];
|
||||
}
|
||||
data[p_pos] = p_val;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t find(const T &p_val, U p_from = 0) const {
|
||||
for (U i = p_from; i < count; i++) {
|
||||
if (data[i] == p_val) {
|
||||
return int64_t(i);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool has(const T &p_val) const {
|
||||
return find(p_val) != -1;
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
void sort_custom() {
|
||||
U len = count;
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
SortArray<T, C> sorter;
|
||||
sorter.sort(data, len);
|
||||
}
|
||||
|
||||
void sort() {
|
||||
sort_custom<_DefaultComparator<T>>();
|
||||
}
|
||||
|
||||
void ordered_insert(T p_val) {
|
||||
U i;
|
||||
for (i = 0; i < count; i++) {
|
||||
if (p_val < data[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
insert(i, p_val);
|
||||
}
|
||||
|
||||
operator Vector<T>() const {
|
||||
Vector<T> ret;
|
||||
ret.resize(size());
|
||||
T *w = ret.ptrw();
|
||||
memcpy(w, data, sizeof(T) * count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Vector<uint8_t> to_byte_array() const { //useful to pass stuff to gpu or variant
|
||||
Vector<uint8_t> ret;
|
||||
ret.resize(count * sizeof(T));
|
||||
uint8_t *w = ret.ptrw();
|
||||
memcpy(w, data, sizeof(T) * count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ LocalVector() {}
|
||||
_FORCE_INLINE_ LocalVector(std::initializer_list<T> p_init) {
|
||||
reserve(p_init.size());
|
||||
for (const T &element : p_init) {
|
||||
push_back(element);
|
||||
}
|
||||
}
|
||||
_FORCE_INLINE_ LocalVector(const LocalVector &p_from) {
|
||||
resize(p_from.size());
|
||||
for (U i = 0; i < p_from.count; i++) {
|
||||
data[i] = p_from.data[i];
|
||||
}
|
||||
}
|
||||
inline void operator=(const LocalVector &p_from) {
|
||||
resize(p_from.size());
|
||||
for (U i = 0; i < p_from.count; i++) {
|
||||
data[i] = p_from.data[i];
|
||||
}
|
||||
}
|
||||
inline void operator=(const Vector<T> &p_from) {
|
||||
resize(p_from.size());
|
||||
for (U i = 0; i < count; i++) {
|
||||
data[i] = p_from[i];
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ ~LocalVector() {
|
||||
if (data) {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename U = uint32_t, bool force_trivial = false>
|
||||
using TightLocalVector = LocalVector<T, U, force_trivial, true>;
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_LOCAL_VECTOR_HPP
|
||||
107
include/godot_cpp/templates/pair.hpp
Normal file
107
include/godot_cpp/templates/pair.hpp
Normal file
@@ -0,0 +1,107 @@
|
||||
/**************************************************************************/
|
||||
/* pair.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_PAIR_HPP
|
||||
#define GODOT_PAIR_HPP
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <typename F, typename S>
|
||||
struct Pair {
|
||||
F first;
|
||||
S second;
|
||||
|
||||
Pair() :
|
||||
first(),
|
||||
second() {
|
||||
}
|
||||
|
||||
Pair(F p_first, const S &p_second) :
|
||||
first(p_first),
|
||||
second(p_second) {
|
||||
}
|
||||
};
|
||||
|
||||
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 <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 <typename F, typename S>
|
||||
struct PairSort {
|
||||
bool operator()(const Pair<F, S> &A, const Pair<F, S> &B) const {
|
||||
if (A.first != B.first) {
|
||||
return A.first < B.first;
|
||||
}
|
||||
return A.second < B.second;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename K, typename V>
|
||||
struct KeyValue {
|
||||
const K key;
|
||||
V value;
|
||||
|
||||
void operator=(const KeyValue &p_kv) = delete;
|
||||
_FORCE_INLINE_ KeyValue(const KeyValue &p_kv) :
|
||||
key(p_kv.key),
|
||||
value(p_kv.value) {
|
||||
}
|
||||
_FORCE_INLINE_ KeyValue(const K &p_key, const V &p_value) :
|
||||
key(p_key),
|
||||
value(p_value) {
|
||||
}
|
||||
};
|
||||
|
||||
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 <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 <typename K, typename V>
|
||||
struct KeyValueSort {
|
||||
bool operator()(const KeyValue<K, V> &A, const KeyValue<K, V> &B) const {
|
||||
return A.key < B.key;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_PAIR_HPP
|
||||
765
include/godot_cpp/templates/rb_map.hpp
Normal file
765
include/godot_cpp/templates/rb_map.hpp
Normal file
@@ -0,0 +1,765 @@
|
||||
/**************************************************************************/
|
||||
/* rb_map.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_RB_MAP_HPP
|
||||
#define GODOT_RB_MAP_HPP
|
||||
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
#include <godot_cpp/templates/pair.hpp>
|
||||
|
||||
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 <typename K, typename V, typename C = Comparator<K>, typename A = DefaultAllocator>
|
||||
class RBMap {
|
||||
enum Color {
|
||||
RED,
|
||||
BLACK
|
||||
};
|
||||
struct _Data;
|
||||
|
||||
public:
|
||||
class Element {
|
||||
private:
|
||||
friend class RBMap<K, V, C, A>;
|
||||
int color = RED;
|
||||
Element *right = nullptr;
|
||||
Element *left = nullptr;
|
||||
Element *parent = nullptr;
|
||||
Element *_next = nullptr;
|
||||
Element *_prev = nullptr;
|
||||
KeyValue<K, V> _data;
|
||||
|
||||
public:
|
||||
KeyValue<K, V> &key_value() { return _data; }
|
||||
const KeyValue<K, V> &key_value() const { return _data; }
|
||||
|
||||
const Element *next() const {
|
||||
return _next;
|
||||
}
|
||||
Element *next() {
|
||||
return _next;
|
||||
}
|
||||
const Element *prev() const {
|
||||
return _prev;
|
||||
}
|
||||
Element *prev() {
|
||||
return _prev;
|
||||
}
|
||||
const K &key() const {
|
||||
return _data.key;
|
||||
}
|
||||
V &value() {
|
||||
return _data.value;
|
||||
}
|
||||
const V &value() const {
|
||||
return _data.value;
|
||||
}
|
||||
V &get() {
|
||||
return _data.value;
|
||||
}
|
||||
const V &get() const {
|
||||
return _data.value;
|
||||
}
|
||||
Element(const KeyValue<K, V> &p_data) :
|
||||
_data(p_data) {}
|
||||
};
|
||||
|
||||
typedef KeyValue<K, V> ValueType;
|
||||
|
||||
struct Iterator {
|
||||
_FORCE_INLINE_ KeyValue<K, V> &operator*() const {
|
||||
return E->key_value();
|
||||
}
|
||||
_FORCE_INLINE_ KeyValue<K, V> *operator->() const { return &E->key_value(); }
|
||||
_FORCE_INLINE_ Iterator &operator++() {
|
||||
E = E->next();
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ Iterator &operator--() {
|
||||
E = E->prev();
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
|
||||
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
|
||||
explicit operator bool() const {
|
||||
return E != nullptr;
|
||||
}
|
||||
Iterator(Element *p_E) { E = p_E; }
|
||||
Iterator() {}
|
||||
Iterator(const Iterator &p_it) { E = p_it.E; }
|
||||
|
||||
private:
|
||||
Element *E = nullptr;
|
||||
};
|
||||
|
||||
struct ConstIterator {
|
||||
_FORCE_INLINE_ const KeyValue<K, V> &operator*() const {
|
||||
return E->key_value();
|
||||
}
|
||||
_FORCE_INLINE_ const KeyValue<K, V> *operator->() const { return &E->key_value(); }
|
||||
_FORCE_INLINE_ ConstIterator &operator++() {
|
||||
E = E->next();
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator &operator--() {
|
||||
E = E->prev();
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; }
|
||||
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; }
|
||||
explicit operator bool() const {
|
||||
return E != nullptr;
|
||||
}
|
||||
ConstIterator(const Element *p_E) { E = p_E; }
|
||||
ConstIterator() {}
|
||||
ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
|
||||
|
||||
private:
|
||||
const Element *E = nullptr;
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ Iterator begin() {
|
||||
return Iterator(front());
|
||||
}
|
||||
_FORCE_INLINE_ Iterator end() {
|
||||
return Iterator(nullptr);
|
||||
}
|
||||
|
||||
#if 0
|
||||
//to use when replacing find()
|
||||
_FORCE_INLINE_ Iterator find(const K &p_key) {
|
||||
return Iterator(find(p_key));
|
||||
}
|
||||
#endif
|
||||
_FORCE_INLINE_ void remove(const Iterator &p_iter) {
|
||||
return erase(p_iter.E);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ ConstIterator begin() const {
|
||||
return ConstIterator(front());
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator end() const {
|
||||
return ConstIterator(nullptr);
|
||||
}
|
||||
|
||||
#if 0
|
||||
//to use when replacing find()
|
||||
_FORCE_INLINE_ ConstIterator find(const K &p_key) const {
|
||||
return ConstIterator(find(p_key));
|
||||
}
|
||||
#endif
|
||||
private:
|
||||
struct _Data {
|
||||
Element *_root = nullptr;
|
||||
Element *_nil = nullptr;
|
||||
int size_cache = 0;
|
||||
|
||||
_FORCE_INLINE_ _Data() {
|
||||
#ifdef GLOBALNIL_DISABLED
|
||||
_nil = memnew_allocator(Element, A);
|
||||
_nil->parent = _nil->left = _nil->right = _nil;
|
||||
_nil->color = BLACK;
|
||||
#else
|
||||
_nil = (Element *)&_GlobalNilClass::_nil;
|
||||
#endif
|
||||
}
|
||||
|
||||
void _create_root() {
|
||||
_root = memnew_allocator(Element(KeyValue<K, V>(K(), V())), A);
|
||||
_root->parent = _root->left = _root->right = _nil;
|
||||
_root->color = BLACK;
|
||||
}
|
||||
|
||||
void _free_root() {
|
||||
if (_root) {
|
||||
memdelete_allocator<Element, A>(_root);
|
||||
_root = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
~_Data() {
|
||||
_free_root();
|
||||
|
||||
#ifdef GLOBALNIL_DISABLED
|
||||
memdelete_allocator<Element, A>(_nil);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
_Data _data;
|
||||
|
||||
inline void _set_color(Element *p_node, int p_color) {
|
||||
ERR_FAIL_COND(p_node == _data._nil && p_color == RED);
|
||||
p_node->color = p_color;
|
||||
}
|
||||
|
||||
inline void _rotate_left(Element *p_node) {
|
||||
Element *r = p_node->right;
|
||||
p_node->right = r->left;
|
||||
if (r->left != _data._nil) {
|
||||
r->left->parent = p_node;
|
||||
}
|
||||
r->parent = p_node->parent;
|
||||
if (p_node == p_node->parent->left) {
|
||||
p_node->parent->left = r;
|
||||
} else {
|
||||
p_node->parent->right = r;
|
||||
}
|
||||
|
||||
r->left = p_node;
|
||||
p_node->parent = r;
|
||||
}
|
||||
|
||||
inline void _rotate_right(Element *p_node) {
|
||||
Element *l = p_node->left;
|
||||
p_node->left = l->right;
|
||||
if (l->right != _data._nil) {
|
||||
l->right->parent = p_node;
|
||||
}
|
||||
l->parent = p_node->parent;
|
||||
if (p_node == p_node->parent->right) {
|
||||
p_node->parent->right = l;
|
||||
} else {
|
||||
p_node->parent->left = l;
|
||||
}
|
||||
|
||||
l->right = p_node;
|
||||
p_node->parent = l;
|
||||
}
|
||||
|
||||
inline Element *_successor(Element *p_node) const {
|
||||
Element *node = p_node;
|
||||
|
||||
if (node->right != _data._nil) {
|
||||
node = node->right;
|
||||
while (node->left != _data._nil) { /* returns the minimum of the right subtree of node */
|
||||
node = node->left;
|
||||
}
|
||||
return node;
|
||||
} else {
|
||||
while (node == node->parent->right) {
|
||||
node = node->parent;
|
||||
}
|
||||
|
||||
if (node->parent == _data._root) {
|
||||
return nullptr; // No successor, as p_node = last node
|
||||
}
|
||||
return node->parent;
|
||||
}
|
||||
}
|
||||
|
||||
inline Element *_predecessor(Element *p_node) const {
|
||||
Element *node = p_node;
|
||||
|
||||
if (node->left != _data._nil) {
|
||||
node = node->left;
|
||||
while (node->right != _data._nil) { /* returns the minimum of the left subtree of node */
|
||||
node = node->right;
|
||||
}
|
||||
return node;
|
||||
} else {
|
||||
while (node == node->parent->left) {
|
||||
node = node->parent;
|
||||
}
|
||||
|
||||
if (node == _data._root) {
|
||||
return nullptr; // No predecessor, as p_node = first node
|
||||
}
|
||||
return node->parent;
|
||||
}
|
||||
}
|
||||
|
||||
Element *_find(const K &p_key) const {
|
||||
Element *node = _data._root->left;
|
||||
C less;
|
||||
|
||||
while (node != _data._nil) {
|
||||
if (less(p_key, node->_data.key)) {
|
||||
node = node->left;
|
||||
} else if (less(node->_data.key, p_key)) {
|
||||
node = node->right;
|
||||
} else {
|
||||
return node; // found
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element *_find_closest(const K &p_key) const {
|
||||
Element *node = _data._root->left;
|
||||
Element *prev = nullptr;
|
||||
C less;
|
||||
|
||||
while (node != _data._nil) {
|
||||
prev = node;
|
||||
|
||||
if (less(p_key, node->_data.key)) {
|
||||
node = node->left;
|
||||
} else if (less(node->_data.key, p_key)) {
|
||||
node = node->right;
|
||||
} else {
|
||||
return node; // found
|
||||
}
|
||||
}
|
||||
|
||||
if (prev == nullptr) {
|
||||
return nullptr; // tree empty
|
||||
}
|
||||
|
||||
if (less(p_key, prev->_data.key)) {
|
||||
prev = prev->_prev;
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
void _insert_rb_fix(Element *p_new_node) {
|
||||
Element *node = p_new_node;
|
||||
Element *nparent = node->parent;
|
||||
Element *ngrand_parent = nullptr;
|
||||
|
||||
while (nparent->color == RED) {
|
||||
ngrand_parent = nparent->parent;
|
||||
|
||||
if (nparent == ngrand_parent->left) {
|
||||
if (ngrand_parent->right->color == RED) {
|
||||
_set_color(nparent, BLACK);
|
||||
_set_color(ngrand_parent->right, BLACK);
|
||||
_set_color(ngrand_parent, RED);
|
||||
node = ngrand_parent;
|
||||
nparent = node->parent;
|
||||
} else {
|
||||
if (node == nparent->right) {
|
||||
_rotate_left(nparent);
|
||||
node = nparent;
|
||||
nparent = node->parent;
|
||||
}
|
||||
_set_color(nparent, BLACK);
|
||||
_set_color(ngrand_parent, RED);
|
||||
_rotate_right(ngrand_parent);
|
||||
}
|
||||
} else {
|
||||
if (ngrand_parent->left->color == RED) {
|
||||
_set_color(nparent, BLACK);
|
||||
_set_color(ngrand_parent->left, BLACK);
|
||||
_set_color(ngrand_parent, RED);
|
||||
node = ngrand_parent;
|
||||
nparent = node->parent;
|
||||
} else {
|
||||
if (node == nparent->left) {
|
||||
_rotate_right(nparent);
|
||||
node = nparent;
|
||||
nparent = node->parent;
|
||||
}
|
||||
_set_color(nparent, BLACK);
|
||||
_set_color(ngrand_parent, RED);
|
||||
_rotate_left(ngrand_parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_set_color(_data._root->left, BLACK);
|
||||
}
|
||||
|
||||
Element *_insert(const K &p_key, const V &p_value) {
|
||||
Element *new_parent = _data._root;
|
||||
Element *node = _data._root->left;
|
||||
C less;
|
||||
|
||||
while (node != _data._nil) {
|
||||
new_parent = node;
|
||||
|
||||
if (less(p_key, node->_data.key)) {
|
||||
node = node->left;
|
||||
} else if (less(node->_data.key, p_key)) {
|
||||
node = node->right;
|
||||
} else {
|
||||
node->_data.value = p_value;
|
||||
return node; // Return existing node with new value
|
||||
}
|
||||
}
|
||||
|
||||
typedef KeyValue<K, V> KV;
|
||||
Element *new_node = memnew_allocator(Element(KV(p_key, p_value)), A);
|
||||
new_node->parent = new_parent;
|
||||
new_node->right = _data._nil;
|
||||
new_node->left = _data._nil;
|
||||
|
||||
// new_node->data=_data;
|
||||
|
||||
if (new_parent == _data._root || less(p_key, new_parent->_data.key)) {
|
||||
new_parent->left = new_node;
|
||||
} else {
|
||||
new_parent->right = new_node;
|
||||
}
|
||||
|
||||
new_node->_next = _successor(new_node);
|
||||
new_node->_prev = _predecessor(new_node);
|
||||
if (new_node->_next) {
|
||||
new_node->_next->_prev = new_node;
|
||||
}
|
||||
if (new_node->_prev) {
|
||||
new_node->_prev->_next = new_node;
|
||||
}
|
||||
|
||||
_data.size_cache++;
|
||||
_insert_rb_fix(new_node);
|
||||
return new_node;
|
||||
}
|
||||
|
||||
void _erase_fix_rb(Element *p_node) {
|
||||
Element *root = _data._root->left;
|
||||
Element *node = _data._nil;
|
||||
Element *sibling = p_node;
|
||||
Element *parent = sibling->parent;
|
||||
|
||||
while (node != root) { // If red node found, will exit at a break
|
||||
if (sibling->color == RED) {
|
||||
_set_color(sibling, BLACK);
|
||||
_set_color(parent, RED);
|
||||
if (sibling == parent->right) {
|
||||
sibling = sibling->left;
|
||||
_rotate_left(parent);
|
||||
} else {
|
||||
sibling = sibling->right;
|
||||
_rotate_right(parent);
|
||||
}
|
||||
}
|
||||
if ((sibling->left->color == BLACK) && (sibling->right->color == BLACK)) {
|
||||
_set_color(sibling, RED);
|
||||
if (parent->color == RED) {
|
||||
_set_color(parent, BLACK);
|
||||
break;
|
||||
} else { // loop: haven't found any red nodes yet
|
||||
node = parent;
|
||||
parent = node->parent;
|
||||
sibling = (node == parent->left) ? parent->right : parent->left;
|
||||
}
|
||||
} else {
|
||||
if (sibling == parent->right) {
|
||||
if (sibling->right->color == BLACK) {
|
||||
_set_color(sibling->left, BLACK);
|
||||
_set_color(sibling, RED);
|
||||
_rotate_right(sibling);
|
||||
sibling = sibling->parent;
|
||||
}
|
||||
_set_color(sibling, parent->color);
|
||||
_set_color(parent, BLACK);
|
||||
_set_color(sibling->right, BLACK);
|
||||
_rotate_left(parent);
|
||||
break;
|
||||
} else {
|
||||
if (sibling->left->color == BLACK) {
|
||||
_set_color(sibling->right, BLACK);
|
||||
_set_color(sibling, RED);
|
||||
_rotate_left(sibling);
|
||||
sibling = sibling->parent;
|
||||
}
|
||||
|
||||
_set_color(sibling, parent->color);
|
||||
_set_color(parent, BLACK);
|
||||
_set_color(sibling->left, BLACK);
|
||||
_rotate_right(parent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(_data._nil->color != BLACK);
|
||||
}
|
||||
|
||||
void _erase(Element *p_node) {
|
||||
Element *rp = ((p_node->left == _data._nil) || (p_node->right == _data._nil)) ? p_node : p_node->_next;
|
||||
Element *node = (rp->left == _data._nil) ? rp->right : rp->left;
|
||||
|
||||
Element *sibling = nullptr;
|
||||
if (rp == rp->parent->left) {
|
||||
rp->parent->left = node;
|
||||
sibling = rp->parent->right;
|
||||
} else {
|
||||
rp->parent->right = node;
|
||||
sibling = rp->parent->left;
|
||||
}
|
||||
|
||||
if (node->color == RED) {
|
||||
node->parent = rp->parent;
|
||||
_set_color(node, BLACK);
|
||||
} else if (rp->color == BLACK && rp->parent != _data._root) {
|
||||
_erase_fix_rb(sibling);
|
||||
}
|
||||
|
||||
if (rp != p_node) {
|
||||
ERR_FAIL_COND(rp == _data._nil);
|
||||
|
||||
rp->left = p_node->left;
|
||||
rp->right = p_node->right;
|
||||
rp->parent = p_node->parent;
|
||||
rp->color = p_node->color;
|
||||
if (p_node->left != _data._nil) {
|
||||
p_node->left->parent = rp;
|
||||
}
|
||||
if (p_node->right != _data._nil) {
|
||||
p_node->right->parent = rp;
|
||||
}
|
||||
|
||||
if (p_node == p_node->parent->left) {
|
||||
p_node->parent->left = rp;
|
||||
} else {
|
||||
p_node->parent->right = rp;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_node->_next) {
|
||||
p_node->_next->_prev = p_node->_prev;
|
||||
}
|
||||
if (p_node->_prev) {
|
||||
p_node->_prev->_next = p_node->_next;
|
||||
}
|
||||
|
||||
memdelete_allocator<Element, A>(p_node);
|
||||
_data.size_cache--;
|
||||
ERR_FAIL_COND(_data._nil->color == RED);
|
||||
}
|
||||
|
||||
void _calculate_depth(Element *p_element, int &max_d, int d) const {
|
||||
if (p_element == _data._nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
_calculate_depth(p_element->left, max_d, d + 1);
|
||||
_calculate_depth(p_element->right, max_d, d + 1);
|
||||
|
||||
if (d > max_d) {
|
||||
max_d = d;
|
||||
}
|
||||
}
|
||||
|
||||
void _cleanup_tree(Element *p_element) {
|
||||
if (p_element == _data._nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
_cleanup_tree(p_element->left);
|
||||
_cleanup_tree(p_element->right);
|
||||
memdelete_allocator<Element, A>(p_element);
|
||||
}
|
||||
|
||||
void _copy_from(const RBMap &p_map) {
|
||||
clear();
|
||||
// not the fastest way, but safeset to write.
|
||||
for (Element *I = p_map.front(); I; I = I->next()) {
|
||||
insert(I->key(), I->value());
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
const Element *find(const K &p_key) const {
|
||||
if (!_data._root) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Element *res = _find(p_key);
|
||||
return res;
|
||||
}
|
||||
|
||||
Element *find(const K &p_key) {
|
||||
if (!_data._root) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element *res = _find(p_key);
|
||||
return res;
|
||||
}
|
||||
|
||||
const Element *find_closest(const K &p_key) const {
|
||||
if (!_data._root) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Element *res = _find_closest(p_key);
|
||||
return res;
|
||||
}
|
||||
|
||||
Element *find_closest(const K &p_key) {
|
||||
if (!_data._root) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element *res = _find_closest(p_key);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool has(const K &p_key) const {
|
||||
return find(p_key) != nullptr;
|
||||
}
|
||||
|
||||
Element *insert(const K &p_key, const V &p_value) {
|
||||
if (!_data._root) {
|
||||
_data._create_root();
|
||||
}
|
||||
return _insert(p_key, p_value);
|
||||
}
|
||||
|
||||
void erase(Element *p_element) {
|
||||
if (!_data._root || !p_element) {
|
||||
return;
|
||||
}
|
||||
|
||||
_erase(p_element);
|
||||
if (_data.size_cache == 0 && _data._root) {
|
||||
_data._free_root();
|
||||
}
|
||||
}
|
||||
|
||||
bool erase(const K &p_key) {
|
||||
if (!_data._root) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Element *e = find(p_key);
|
||||
if (!e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_erase(e);
|
||||
if (_data.size_cache == 0 && _data._root) {
|
||||
_data._free_root();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const V &operator[](const K &p_key) const {
|
||||
CRASH_COND(!_data._root);
|
||||
const Element *e = find(p_key);
|
||||
CRASH_COND(!e);
|
||||
return e->_data.value;
|
||||
}
|
||||
|
||||
V &operator[](const K &p_key) {
|
||||
if (!_data._root) {
|
||||
_data._create_root();
|
||||
}
|
||||
|
||||
Element *e = find(p_key);
|
||||
if (!e) {
|
||||
e = insert(p_key, V());
|
||||
}
|
||||
|
||||
return e->_data.value;
|
||||
}
|
||||
|
||||
Element *front() const {
|
||||
if (!_data._root) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element *e = _data._root->left;
|
||||
if (e == _data._nil) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
while (e->left != _data._nil) {
|
||||
e = e->left;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
Element *back() const {
|
||||
if (!_data._root) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element *e = _data._root->left;
|
||||
if (e == _data._nil) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
while (e->right != _data._nil) {
|
||||
e = e->right;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
inline bool is_empty() const {
|
||||
return _data.size_cache == 0;
|
||||
}
|
||||
inline int size() const {
|
||||
return _data.size_cache;
|
||||
}
|
||||
|
||||
int calculate_depth() const {
|
||||
// used for debug mostly
|
||||
if (!_data._root) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int max_d = 0;
|
||||
_calculate_depth(_data._root->left, max_d, 0);
|
||||
return max_d;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
if (!_data._root) {
|
||||
return;
|
||||
}
|
||||
|
||||
_cleanup_tree(_data._root->left);
|
||||
_data._root->left = _data._nil;
|
||||
_data.size_cache = 0;
|
||||
_data._free_root();
|
||||
}
|
||||
|
||||
void operator=(const RBMap &p_map) {
|
||||
_copy_from(p_map);
|
||||
}
|
||||
|
||||
RBMap(const RBMap &p_map) {
|
||||
_copy_from(p_map);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ RBMap() {}
|
||||
|
||||
~RBMap() {
|
||||
clear();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_RB_MAP_HPP
|
||||
714
include/godot_cpp/templates/rb_set.hpp
Normal file
714
include/godot_cpp/templates/rb_set.hpp
Normal file
@@ -0,0 +1,714 @@
|
||||
/**************************************************************************/
|
||||
/* rb_set.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_RB_SET_HPP
|
||||
#define GODOT_RB_SET_HPP
|
||||
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
|
||||
// based on the very nice implementation of rb-trees by:
|
||||
// https://web.archive.org/web/20120507164830/https://web.mit.edu/~emin/www/source_code/red_black_tree/index.html
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <typename T, typename C = Comparator<T>, typename A = DefaultAllocator>
|
||||
class RBSet {
|
||||
enum Color {
|
||||
RED,
|
||||
BLACK
|
||||
};
|
||||
struct _Data;
|
||||
|
||||
public:
|
||||
class Element {
|
||||
private:
|
||||
friend class RBSet<T, C, A>;
|
||||
int color = RED;
|
||||
Element *right = nullptr;
|
||||
Element *left = nullptr;
|
||||
Element *parent = nullptr;
|
||||
Element *_next = nullptr;
|
||||
Element *_prev = nullptr;
|
||||
T value;
|
||||
//_Data *data;
|
||||
|
||||
public:
|
||||
const Element *next() const {
|
||||
return _next;
|
||||
}
|
||||
Element *next() {
|
||||
return _next;
|
||||
}
|
||||
const Element *prev() const {
|
||||
return _prev;
|
||||
}
|
||||
Element *prev() {
|
||||
return _prev;
|
||||
}
|
||||
T &get() {
|
||||
return value;
|
||||
}
|
||||
const T &get() const {
|
||||
return value;
|
||||
}
|
||||
Element() {}
|
||||
};
|
||||
|
||||
typedef T ValueType;
|
||||
|
||||
struct Iterator {
|
||||
_FORCE_INLINE_ T &operator*() const {
|
||||
return E->get();
|
||||
}
|
||||
_FORCE_INLINE_ T *operator->() const { return &E->get(); }
|
||||
_FORCE_INLINE_ Iterator &operator++() {
|
||||
E = E->next();
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ Iterator &operator--() {
|
||||
E = E->prev();
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
|
||||
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
|
||||
|
||||
explicit operator bool() const { return E != nullptr; }
|
||||
Iterator(Element *p_E) { E = p_E; }
|
||||
Iterator() {}
|
||||
Iterator(const Iterator &p_it) { E = p_it.E; }
|
||||
|
||||
private:
|
||||
Element *E = nullptr;
|
||||
};
|
||||
|
||||
struct ConstIterator {
|
||||
_FORCE_INLINE_ const T &operator*() const {
|
||||
return E->get();
|
||||
}
|
||||
_FORCE_INLINE_ const T *operator->() const { return &E->get(); }
|
||||
_FORCE_INLINE_ ConstIterator &operator++() {
|
||||
E = E->next();
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator &operator--() {
|
||||
E = E->prev();
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; }
|
||||
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; }
|
||||
|
||||
_FORCE_INLINE_ ConstIterator(const Element *p_E) { E = p_E; }
|
||||
_FORCE_INLINE_ ConstIterator() {}
|
||||
_FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
|
||||
|
||||
explicit operator bool() const { return E != nullptr; }
|
||||
|
||||
private:
|
||||
const Element *E = nullptr;
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ Iterator begin() {
|
||||
return Iterator(front());
|
||||
}
|
||||
_FORCE_INLINE_ Iterator end() {
|
||||
return Iterator(nullptr);
|
||||
}
|
||||
|
||||
#if 0
|
||||
//to use when replacing find()
|
||||
_FORCE_INLINE_ Iterator find(const K &p_key) {
|
||||
return Iterator(find(p_key));
|
||||
}
|
||||
#endif
|
||||
|
||||
_FORCE_INLINE_ ConstIterator begin() const {
|
||||
return ConstIterator(front());
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator end() const {
|
||||
return ConstIterator(nullptr);
|
||||
}
|
||||
|
||||
#if 0
|
||||
//to use when replacing find()
|
||||
_FORCE_INLINE_ ConstIterator find(const K &p_key) const {
|
||||
return ConstIterator(find(p_key));
|
||||
}
|
||||
#endif
|
||||
private:
|
||||
struct _Data {
|
||||
Element *_root = nullptr;
|
||||
Element *_nil = nullptr;
|
||||
int size_cache = 0;
|
||||
|
||||
_FORCE_INLINE_ _Data() {
|
||||
#ifdef GLOBALNIL_DISABLED
|
||||
_nil = memnew_allocator(Element, A);
|
||||
_nil->parent = _nil->left = _nil->right = _nil;
|
||||
_nil->color = BLACK;
|
||||
#else
|
||||
_nil = (Element *)&_GlobalNilClass::_nil;
|
||||
#endif
|
||||
}
|
||||
|
||||
void _create_root() {
|
||||
_root = memnew_allocator(Element, A);
|
||||
_root->parent = _root->left = _root->right = _nil;
|
||||
_root->color = BLACK;
|
||||
}
|
||||
|
||||
void _free_root() {
|
||||
if (_root) {
|
||||
memdelete_allocator<Element, A>(_root);
|
||||
_root = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
~_Data() {
|
||||
_free_root();
|
||||
|
||||
#ifdef GLOBALNIL_DISABLED
|
||||
memdelete_allocator<Element, A>(_nil);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
_Data _data;
|
||||
|
||||
inline void _set_color(Element *p_node, int p_color) {
|
||||
ERR_FAIL_COND(p_node == _data._nil && p_color == RED);
|
||||
p_node->color = p_color;
|
||||
}
|
||||
|
||||
inline void _rotate_left(Element *p_node) {
|
||||
Element *r = p_node->right;
|
||||
p_node->right = r->left;
|
||||
if (r->left != _data._nil) {
|
||||
r->left->parent = p_node;
|
||||
}
|
||||
r->parent = p_node->parent;
|
||||
if (p_node == p_node->parent->left) {
|
||||
p_node->parent->left = r;
|
||||
} else {
|
||||
p_node->parent->right = r;
|
||||
}
|
||||
|
||||
r->left = p_node;
|
||||
p_node->parent = r;
|
||||
}
|
||||
|
||||
inline void _rotate_right(Element *p_node) {
|
||||
Element *l = p_node->left;
|
||||
p_node->left = l->right;
|
||||
if (l->right != _data._nil) {
|
||||
l->right->parent = p_node;
|
||||
}
|
||||
l->parent = p_node->parent;
|
||||
if (p_node == p_node->parent->right) {
|
||||
p_node->parent->right = l;
|
||||
} else {
|
||||
p_node->parent->left = l;
|
||||
}
|
||||
|
||||
l->right = p_node;
|
||||
p_node->parent = l;
|
||||
}
|
||||
|
||||
inline Element *_successor(Element *p_node) const {
|
||||
Element *node = p_node;
|
||||
|
||||
if (node->right != _data._nil) {
|
||||
node = node->right;
|
||||
while (node->left != _data._nil) { /* returns the minimum of the right subtree of node */
|
||||
node = node->left;
|
||||
}
|
||||
return node;
|
||||
} else {
|
||||
while (node == node->parent->right) {
|
||||
node = node->parent;
|
||||
}
|
||||
|
||||
if (node->parent == _data._root) {
|
||||
return nullptr; // No successor, as p_node = last node
|
||||
}
|
||||
return node->parent;
|
||||
}
|
||||
}
|
||||
|
||||
inline Element *_predecessor(Element *p_node) const {
|
||||
Element *node = p_node;
|
||||
|
||||
if (node->left != _data._nil) {
|
||||
node = node->left;
|
||||
while (node->right != _data._nil) { /* returns the minimum of the left subtree of node */
|
||||
node = node->right;
|
||||
}
|
||||
return node;
|
||||
} else {
|
||||
while (node == node->parent->left) {
|
||||
node = node->parent;
|
||||
}
|
||||
|
||||
if (node == _data._root) {
|
||||
return nullptr; // No predecessor, as p_node = first node.
|
||||
}
|
||||
return node->parent;
|
||||
}
|
||||
}
|
||||
|
||||
Element *_find(const T &p_value) const {
|
||||
Element *node = _data._root->left;
|
||||
C less;
|
||||
|
||||
while (node != _data._nil) {
|
||||
if (less(p_value, node->value)) {
|
||||
node = node->left;
|
||||
} else if (less(node->value, p_value)) {
|
||||
node = node->right;
|
||||
} else {
|
||||
return node; // found
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element *_lower_bound(const T &p_value) const {
|
||||
Element *node = _data._root->left;
|
||||
Element *prev = nullptr;
|
||||
C less;
|
||||
|
||||
while (node != _data._nil) {
|
||||
prev = node;
|
||||
|
||||
if (less(p_value, node->value)) {
|
||||
node = node->left;
|
||||
} else if (less(node->value, p_value)) {
|
||||
node = node->right;
|
||||
} else {
|
||||
return node; // found
|
||||
}
|
||||
}
|
||||
|
||||
if (prev == nullptr) {
|
||||
return nullptr; // tree empty
|
||||
}
|
||||
|
||||
if (less(prev->value, p_value)) {
|
||||
prev = prev->_next;
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
void _insert_rb_fix(Element *p_new_node) {
|
||||
Element *node = p_new_node;
|
||||
Element *nparent = node->parent;
|
||||
Element *ngrand_parent = nullptr;
|
||||
|
||||
while (nparent->color == RED) {
|
||||
ngrand_parent = nparent->parent;
|
||||
|
||||
if (nparent == ngrand_parent->left) {
|
||||
if (ngrand_parent->right->color == RED) {
|
||||
_set_color(nparent, BLACK);
|
||||
_set_color(ngrand_parent->right, BLACK);
|
||||
_set_color(ngrand_parent, RED);
|
||||
node = ngrand_parent;
|
||||
nparent = node->parent;
|
||||
} else {
|
||||
if (node == nparent->right) {
|
||||
_rotate_left(nparent);
|
||||
node = nparent;
|
||||
nparent = node->parent;
|
||||
}
|
||||
_set_color(nparent, BLACK);
|
||||
_set_color(ngrand_parent, RED);
|
||||
_rotate_right(ngrand_parent);
|
||||
}
|
||||
} else {
|
||||
if (ngrand_parent->left->color == RED) {
|
||||
_set_color(nparent, BLACK);
|
||||
_set_color(ngrand_parent->left, BLACK);
|
||||
_set_color(ngrand_parent, RED);
|
||||
node = ngrand_parent;
|
||||
nparent = node->parent;
|
||||
} else {
|
||||
if (node == nparent->left) {
|
||||
_rotate_right(nparent);
|
||||
node = nparent;
|
||||
nparent = node->parent;
|
||||
}
|
||||
_set_color(nparent, BLACK);
|
||||
_set_color(ngrand_parent, RED);
|
||||
_rotate_left(ngrand_parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_set_color(_data._root->left, BLACK);
|
||||
}
|
||||
|
||||
Element *_insert(const T &p_value) {
|
||||
Element *new_parent = _data._root;
|
||||
Element *node = _data._root->left;
|
||||
C less;
|
||||
|
||||
while (node != _data._nil) {
|
||||
new_parent = node;
|
||||
|
||||
if (less(p_value, node->value)) {
|
||||
node = node->left;
|
||||
} else if (less(node->value, p_value)) {
|
||||
node = node->right;
|
||||
} else {
|
||||
return node; // Return existing node
|
||||
}
|
||||
}
|
||||
|
||||
Element *new_node = memnew_allocator(Element, A);
|
||||
new_node->parent = new_parent;
|
||||
new_node->right = _data._nil;
|
||||
new_node->left = _data._nil;
|
||||
new_node->value = p_value;
|
||||
// new_node->data=_data;
|
||||
|
||||
if (new_parent == _data._root || less(p_value, new_parent->value)) {
|
||||
new_parent->left = new_node;
|
||||
} else {
|
||||
new_parent->right = new_node;
|
||||
}
|
||||
|
||||
new_node->_next = _successor(new_node);
|
||||
new_node->_prev = _predecessor(new_node);
|
||||
if (new_node->_next) {
|
||||
new_node->_next->_prev = new_node;
|
||||
}
|
||||
if (new_node->_prev) {
|
||||
new_node->_prev->_next = new_node;
|
||||
}
|
||||
|
||||
_data.size_cache++;
|
||||
_insert_rb_fix(new_node);
|
||||
return new_node;
|
||||
}
|
||||
|
||||
void _erase_fix_rb(Element *p_node) {
|
||||
Element *root = _data._root->left;
|
||||
Element *node = _data._nil;
|
||||
Element *sibling = p_node;
|
||||
Element *parent = sibling->parent;
|
||||
|
||||
while (node != root) { // If red node found, will exit at a break
|
||||
if (sibling->color == RED) {
|
||||
_set_color(sibling, BLACK);
|
||||
_set_color(parent, RED);
|
||||
if (sibling == parent->right) {
|
||||
sibling = sibling->left;
|
||||
_rotate_left(parent);
|
||||
} else {
|
||||
sibling = sibling->right;
|
||||
_rotate_right(parent);
|
||||
}
|
||||
}
|
||||
if ((sibling->left->color == BLACK) && (sibling->right->color == BLACK)) {
|
||||
_set_color(sibling, RED);
|
||||
if (parent->color == RED) {
|
||||
_set_color(parent, BLACK);
|
||||
break;
|
||||
} else { // loop: haven't found any red nodes yet
|
||||
node = parent;
|
||||
parent = node->parent;
|
||||
sibling = (node == parent->left) ? parent->right : parent->left;
|
||||
}
|
||||
} else {
|
||||
if (sibling == parent->right) {
|
||||
if (sibling->right->color == BLACK) {
|
||||
_set_color(sibling->left, BLACK);
|
||||
_set_color(sibling, RED);
|
||||
_rotate_right(sibling);
|
||||
sibling = sibling->parent;
|
||||
}
|
||||
_set_color(sibling, parent->color);
|
||||
_set_color(parent, BLACK);
|
||||
_set_color(sibling->right, BLACK);
|
||||
_rotate_left(parent);
|
||||
break;
|
||||
} else {
|
||||
if (sibling->left->color == BLACK) {
|
||||
_set_color(sibling->right, BLACK);
|
||||
_set_color(sibling, RED);
|
||||
_rotate_left(sibling);
|
||||
sibling = sibling->parent;
|
||||
}
|
||||
|
||||
_set_color(sibling, parent->color);
|
||||
_set_color(parent, BLACK);
|
||||
_set_color(sibling->left, BLACK);
|
||||
_rotate_right(parent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(_data._nil->color != BLACK);
|
||||
}
|
||||
|
||||
void _erase(Element *p_node) {
|
||||
Element *rp = ((p_node->left == _data._nil) || (p_node->right == _data._nil)) ? p_node : p_node->_next;
|
||||
Element *node = (rp->left == _data._nil) ? rp->right : rp->left;
|
||||
|
||||
Element *sibling = nullptr;
|
||||
if (rp == rp->parent->left) {
|
||||
rp->parent->left = node;
|
||||
sibling = rp->parent->right;
|
||||
} else {
|
||||
rp->parent->right = node;
|
||||
sibling = rp->parent->left;
|
||||
}
|
||||
|
||||
if (node->color == RED) {
|
||||
node->parent = rp->parent;
|
||||
_set_color(node, BLACK);
|
||||
} else if (rp->color == BLACK && rp->parent != _data._root) {
|
||||
_erase_fix_rb(sibling);
|
||||
}
|
||||
|
||||
if (rp != p_node) {
|
||||
ERR_FAIL_COND(rp == _data._nil);
|
||||
|
||||
rp->left = p_node->left;
|
||||
rp->right = p_node->right;
|
||||
rp->parent = p_node->parent;
|
||||
rp->color = p_node->color;
|
||||
if (p_node->left != _data._nil) {
|
||||
p_node->left->parent = rp;
|
||||
}
|
||||
if (p_node->right != _data._nil) {
|
||||
p_node->right->parent = rp;
|
||||
}
|
||||
|
||||
if (p_node == p_node->parent->left) {
|
||||
p_node->parent->left = rp;
|
||||
} else {
|
||||
p_node->parent->right = rp;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_node->_next) {
|
||||
p_node->_next->_prev = p_node->_prev;
|
||||
}
|
||||
if (p_node->_prev) {
|
||||
p_node->_prev->_next = p_node->_next;
|
||||
}
|
||||
|
||||
memdelete_allocator<Element, A>(p_node);
|
||||
_data.size_cache--;
|
||||
ERR_FAIL_COND(_data._nil->color == RED);
|
||||
}
|
||||
|
||||
void _calculate_depth(Element *p_element, int &max_d, int d) const {
|
||||
if (p_element == _data._nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
_calculate_depth(p_element->left, max_d, d + 1);
|
||||
_calculate_depth(p_element->right, max_d, d + 1);
|
||||
|
||||
if (d > max_d) {
|
||||
max_d = d;
|
||||
}
|
||||
}
|
||||
|
||||
void _cleanup_tree(Element *p_element) {
|
||||
if (p_element == _data._nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
_cleanup_tree(p_element->left);
|
||||
_cleanup_tree(p_element->right);
|
||||
memdelete_allocator<Element, A>(p_element);
|
||||
}
|
||||
|
||||
void _copy_from(const RBSet &p_set) {
|
||||
clear();
|
||||
// not the fastest way, but safeset to write.
|
||||
for (Element *I = p_set.front(); I; I = I->next()) {
|
||||
insert(I->get());
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
const Element *find(const T &p_value) const {
|
||||
if (!_data._root) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Element *res = _find(p_value);
|
||||
return res;
|
||||
}
|
||||
|
||||
Element *find(const T &p_value) {
|
||||
if (!_data._root) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element *res = _find(p_value);
|
||||
return res;
|
||||
}
|
||||
|
||||
Element *lower_bound(const T &p_value) const {
|
||||
if (!_data._root) {
|
||||
return nullptr;
|
||||
}
|
||||
return _lower_bound(p_value);
|
||||
}
|
||||
|
||||
bool has(const T &p_value) const {
|
||||
return find(p_value) != nullptr;
|
||||
}
|
||||
|
||||
Element *insert(const T &p_value) {
|
||||
if (!_data._root) {
|
||||
_data._create_root();
|
||||
}
|
||||
return _insert(p_value);
|
||||
}
|
||||
|
||||
void erase(Element *p_element) {
|
||||
if (!_data._root || !p_element) {
|
||||
return;
|
||||
}
|
||||
|
||||
_erase(p_element);
|
||||
if (_data.size_cache == 0 && _data._root) {
|
||||
_data._free_root();
|
||||
}
|
||||
}
|
||||
|
||||
bool erase(const T &p_value) {
|
||||
if (!_data._root) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Element *e = find(p_value);
|
||||
if (!e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_erase(e);
|
||||
if (_data.size_cache == 0 && _data._root) {
|
||||
_data._free_root();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Element *front() const {
|
||||
if (!_data._root) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element *e = _data._root->left;
|
||||
if (e == _data._nil) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
while (e->left != _data._nil) {
|
||||
e = e->left;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
Element *back() const {
|
||||
if (!_data._root) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element *e = _data._root->left;
|
||||
if (e == _data._nil) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
while (e->right != _data._nil) {
|
||||
e = e->right;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
inline bool is_empty() const {
|
||||
return _data.size_cache == 0;
|
||||
}
|
||||
inline int size() const {
|
||||
return _data.size_cache;
|
||||
}
|
||||
|
||||
int calculate_depth() const {
|
||||
// used for debug mostly
|
||||
if (!_data._root) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int max_d = 0;
|
||||
_calculate_depth(_data._root->left, max_d, 0);
|
||||
return max_d;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
if (!_data._root) {
|
||||
return;
|
||||
}
|
||||
|
||||
_cleanup_tree(_data._root->left);
|
||||
_data._root->left = _data._nil;
|
||||
_data.size_cache = 0;
|
||||
_data._free_root();
|
||||
}
|
||||
|
||||
void operator=(const RBSet &p_set) {
|
||||
_copy_from(p_set);
|
||||
}
|
||||
|
||||
RBSet(const RBSet &p_set) {
|
||||
_copy_from(p_set);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ RBSet() {}
|
||||
|
||||
~RBSet() {
|
||||
clear();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_RB_SET_HPP
|
||||
465
include/godot_cpp/templates/rid_owner.hpp
Normal file
465
include/godot_cpp/templates/rid_owner.hpp
Normal file
@@ -0,0 +1,465 @@
|
||||
/**************************************************************************/
|
||||
/* rid_owner.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_RID_OWNER_HPP
|
||||
#define GODOT_RID_OWNER_HPP
|
||||
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
#include <godot_cpp/godot.hpp>
|
||||
#include <godot_cpp/templates/list.hpp>
|
||||
#include <godot_cpp/templates/spin_lock.hpp>
|
||||
#include <godot_cpp/variant/utility_functions.hpp>
|
||||
|
||||
#include <cstdio>
|
||||
#include <typeinfo>
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <typename T, bool THREAD_SAFE = false>
|
||||
class RID_Alloc {
|
||||
T **chunks = nullptr;
|
||||
uint32_t **free_list_chunks = nullptr;
|
||||
uint32_t **validator_chunks = nullptr;
|
||||
|
||||
uint32_t elements_in_chunk;
|
||||
uint32_t max_alloc = 0;
|
||||
uint32_t alloc_count = 0;
|
||||
|
||||
const char *description = nullptr;
|
||||
|
||||
SpinLock spin_lock;
|
||||
|
||||
_FORCE_INLINE_ RID _allocate_rid() {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.lock();
|
||||
}
|
||||
|
||||
if (alloc_count == max_alloc) {
|
||||
// allocate a new chunk
|
||||
uint32_t chunk_count = alloc_count == 0 ? 0 : (max_alloc / elements_in_chunk);
|
||||
|
||||
// grow chunks
|
||||
chunks = (T **)memrealloc(chunks, sizeof(T *) * (chunk_count + 1));
|
||||
chunks[chunk_count] = (T *)memalloc(sizeof(T) * elements_in_chunk); // but don't initialize
|
||||
|
||||
// grow validators
|
||||
validator_chunks = (uint32_t **)memrealloc(validator_chunks, sizeof(uint32_t *) * (chunk_count + 1));
|
||||
validator_chunks[chunk_count] = (uint32_t *)memalloc(sizeof(uint32_t) * elements_in_chunk);
|
||||
// grow free lists
|
||||
free_list_chunks = (uint32_t **)memrealloc(free_list_chunks, sizeof(uint32_t *) * (chunk_count + 1));
|
||||
free_list_chunks[chunk_count] = (uint32_t *)memalloc(sizeof(uint32_t) * elements_in_chunk);
|
||||
|
||||
// initialize
|
||||
for (uint32_t i = 0; i < elements_in_chunk; i++) {
|
||||
// Don't initialize chunk.
|
||||
validator_chunks[chunk_count][i] = 0xFFFFFFFF;
|
||||
free_list_chunks[chunk_count][i] = alloc_count + i;
|
||||
}
|
||||
|
||||
max_alloc += elements_in_chunk;
|
||||
}
|
||||
|
||||
uint32_t free_index = free_list_chunks[alloc_count / elements_in_chunk][alloc_count % elements_in_chunk];
|
||||
|
||||
uint32_t free_chunk = free_index / elements_in_chunk;
|
||||
uint32_t free_element = free_index % elements_in_chunk;
|
||||
|
||||
uint32_t validator = (uint32_t)(UtilityFunctions::rid_allocate_id() & 0x7FFFFFFF);
|
||||
uint64_t id = validator;
|
||||
id <<= 32;
|
||||
id |= free_index;
|
||||
|
||||
validator_chunks[free_chunk][free_element] = validator;
|
||||
|
||||
validator_chunks[free_chunk][free_element] |= 0x80000000; // mark uninitialized bit
|
||||
|
||||
alloc_count++;
|
||||
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
|
||||
return UtilityFunctions::rid_from_int64(id);
|
||||
}
|
||||
|
||||
public:
|
||||
RID make_rid() {
|
||||
RID rid = _allocate_rid();
|
||||
initialize_rid(rid);
|
||||
return rid;
|
||||
}
|
||||
RID make_rid(const T &p_value) {
|
||||
RID rid = _allocate_rid();
|
||||
initialize_rid(rid, p_value);
|
||||
return rid;
|
||||
}
|
||||
|
||||
// allocate but don't initialize, use initialize_rid afterwards
|
||||
RID allocate_rid() {
|
||||
return _allocate_rid();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ T *get_or_null(const RID &p_rid, bool p_initialize = false) {
|
||||
if (p_rid == RID()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.lock();
|
||||
}
|
||||
|
||||
uint64_t id = p_rid.get_id();
|
||||
uint32_t idx = uint32_t(id & 0xFFFFFFFF);
|
||||
if (unlikely(idx >= max_alloc)) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t idx_chunk = idx / elements_in_chunk;
|
||||
uint32_t idx_element = idx % elements_in_chunk;
|
||||
|
||||
uint32_t validator = uint32_t(id >> 32);
|
||||
|
||||
if (unlikely(p_initialize)) {
|
||||
if (unlikely(!(validator_chunks[idx_chunk][idx_element] & 0x80000000))) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
ERR_FAIL_V_MSG(nullptr, "Initializing already initialized RID");
|
||||
}
|
||||
|
||||
if (unlikely((validator_chunks[idx_chunk][idx_element] & 0x7FFFFFFF) != validator)) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
ERR_FAIL_V_MSG(nullptr, "Attempting to initialize the wrong RID");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
validator_chunks[idx_chunk][idx_element] &= 0x7FFFFFFF; // initialized
|
||||
|
||||
} else if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
if ((validator_chunks[idx_chunk][idx_element] & 0x80000000) && validator_chunks[idx_chunk][idx_element] != 0xFFFFFFFF) {
|
||||
ERR_FAIL_V_MSG(nullptr, "Attempting to use an uninitialized RID");
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
T *ptr = &chunks[idx_chunk][idx_element];
|
||||
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
void initialize_rid(RID p_rid) {
|
||||
T *mem = get_or_null(p_rid, true);
|
||||
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_NULL(mem);
|
||||
memnew_placement(mem, T(p_value));
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool owns(const RID &p_rid) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.lock();
|
||||
}
|
||||
|
||||
uint64_t id = p_rid.get_id();
|
||||
uint32_t idx = uint32_t(id & 0xFFFFFFFF);
|
||||
if (unlikely(idx >= max_alloc)) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t idx_chunk = idx / elements_in_chunk;
|
||||
uint32_t idx_element = idx % elements_in_chunk;
|
||||
|
||||
uint32_t validator = uint32_t(id >> 32);
|
||||
|
||||
bool owned = (validator_chunks[idx_chunk][idx_element] & 0x7FFFFFFF) == validator;
|
||||
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
|
||||
return owned;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void free(const RID &p_rid) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.lock();
|
||||
}
|
||||
|
||||
uint64_t id = p_rid.get_id();
|
||||
uint32_t idx = uint32_t(id & 0xFFFFFFFF);
|
||||
if (unlikely(idx >= max_alloc)) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
ERR_FAIL();
|
||||
}
|
||||
|
||||
uint32_t idx_chunk = idx / elements_in_chunk;
|
||||
uint32_t idx_element = idx % elements_in_chunk;
|
||||
|
||||
uint32_t validator = uint32_t(id >> 32);
|
||||
if (unlikely(validator_chunks[idx_chunk][idx_element] & 0x80000000)) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
ERR_FAIL_MSG("Attempted to free an uninitialized or invalid RID");
|
||||
} else if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
ERR_FAIL();
|
||||
}
|
||||
|
||||
chunks[idx_chunk][idx_element].~T();
|
||||
validator_chunks[idx_chunk][idx_element] = 0xFFFFFFFF; // go invalid
|
||||
|
||||
alloc_count--;
|
||||
free_list_chunks[alloc_count / elements_in_chunk][alloc_count % elements_in_chunk] = idx;
|
||||
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t get_rid_count() const {
|
||||
return alloc_count;
|
||||
}
|
||||
|
||||
void get_owned_list(List<RID> *p_owned) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.lock();
|
||||
}
|
||||
for (size_t i = 0; i < max_alloc; i++) {
|
||||
uint64_t validator = validator_chunks[i / elements_in_chunk][i % elements_in_chunk];
|
||||
if (validator != 0xFFFFFFFF) {
|
||||
p_owned->push_back(UtilityFunctions::rid_from_int64((validator << 32) | i));
|
||||
}
|
||||
}
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// used for fast iteration in the elements or RIDs
|
||||
void fill_owned_buffer(RID *p_rid_buffer) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.lock();
|
||||
}
|
||||
uint32_t idx = 0;
|
||||
for (size_t i = 0; i < max_alloc; i++) {
|
||||
uint64_t validator = validator_chunks[i / elements_in_chunk][i % elements_in_chunk];
|
||||
if (validator != 0xFFFFFFFF) {
|
||||
p_rid_buffer[idx] = UtilityFunctions::rid_from_int64((validator << 32) | i);
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void set_description(const char *p_descrption) {
|
||||
description = p_descrption;
|
||||
}
|
||||
|
||||
RID_Alloc(uint32_t p_target_chunk_byte_size = 65536) {
|
||||
elements_in_chunk = sizeof(T) > p_target_chunk_byte_size ? 1 : (p_target_chunk_byte_size / sizeof(T));
|
||||
}
|
||||
|
||||
~RID_Alloc() {
|
||||
if (alloc_count) {
|
||||
if (description) {
|
||||
printf("ERROR: %d RID allocations of type '%s' were leaked at exit.", alloc_count, description);
|
||||
} else {
|
||||
#ifdef NO_SAFE_CAST
|
||||
printf("ERROR: %d RID allocations of type 'unknown' were leaked at exit.", alloc_count);
|
||||
#else
|
||||
printf("ERROR: %d RID allocations of type '%s' were leaked at exit.", alloc_count, typeid(T).name());
|
||||
#endif
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < max_alloc; i++) {
|
||||
uint64_t validator = validator_chunks[i / elements_in_chunk][i % elements_in_chunk];
|
||||
if (validator & 0x80000000) {
|
||||
continue; // uninitialized
|
||||
}
|
||||
if (validator != 0xFFFFFFFF) {
|
||||
chunks[i / elements_in_chunk][i % elements_in_chunk].~T();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t chunk_count = max_alloc / elements_in_chunk;
|
||||
for (uint32_t i = 0; i < chunk_count; i++) {
|
||||
memfree(chunks[i]);
|
||||
memfree(validator_chunks[i]);
|
||||
memfree(free_list_chunks[i]);
|
||||
}
|
||||
|
||||
if (chunks) {
|
||||
memfree(chunks);
|
||||
memfree(free_list_chunks);
|
||||
memfree(validator_chunks);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, bool THREAD_SAFE = false>
|
||||
class RID_PtrOwner {
|
||||
RID_Alloc<T *, THREAD_SAFE> alloc;
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ RID make_rid(T *p_ptr) {
|
||||
return alloc.make_rid(p_ptr);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ RID allocate_rid() {
|
||||
return alloc.allocate_rid();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void initialize_rid(RID p_rid, T *p_ptr) {
|
||||
alloc.initialize_rid(p_rid, p_ptr);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ T *get_or_null(const RID &p_rid) {
|
||||
T **ptr = alloc.get_or_null(p_rid);
|
||||
if (unlikely(!ptr)) {
|
||||
return nullptr;
|
||||
}
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void replace(const RID &p_rid, T *p_new_ptr) {
|
||||
T **ptr = alloc.get_or_null(p_rid);
|
||||
ERR_FAIL_NULL(ptr);
|
||||
*ptr = p_new_ptr;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool owns(const RID &p_rid) {
|
||||
return alloc.owns(p_rid);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void free(const RID &p_rid) {
|
||||
alloc.free(p_rid);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t get_rid_count() const {
|
||||
return alloc.get_rid_count();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void get_owned_list(List<RID> *p_owned) {
|
||||
return alloc.get_owned_list(p_owned);
|
||||
}
|
||||
|
||||
void fill_owned_buffer(RID *p_rid_buffer) {
|
||||
alloc.fill_owned_buffer(p_rid_buffer);
|
||||
}
|
||||
|
||||
void set_description(const char *p_descrption) {
|
||||
alloc.set_description(p_descrption);
|
||||
}
|
||||
|
||||
RID_PtrOwner(uint32_t p_target_chunk_byte_size = 65536) :
|
||||
alloc(p_target_chunk_byte_size) {}
|
||||
};
|
||||
|
||||
template <typename T, bool THREAD_SAFE = false>
|
||||
class RID_Owner {
|
||||
RID_Alloc<T, THREAD_SAFE> alloc;
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ RID make_rid() {
|
||||
return alloc.make_rid();
|
||||
}
|
||||
_FORCE_INLINE_ RID make_rid(const T &p_ptr) {
|
||||
return alloc.make_rid(p_ptr);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ RID allocate_rid() {
|
||||
return alloc.allocate_rid();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void initialize_rid(RID p_rid) {
|
||||
alloc.initialize_rid(p_rid);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void initialize_rid(RID p_rid, const T &p_ptr) {
|
||||
alloc.initialize_rid(p_rid, p_ptr);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ T *get_or_null(const RID &p_rid) {
|
||||
return alloc.get_or_null(p_rid);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool owns(const RID &p_rid) {
|
||||
return alloc.owns(p_rid);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void free(const RID &p_rid) {
|
||||
alloc.free(p_rid);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t get_rid_count() const {
|
||||
return alloc.get_rid_count();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void get_owned_list(List<RID> *p_owned) {
|
||||
return alloc.get_owned_list(p_owned);
|
||||
}
|
||||
void fill_owned_buffer(RID *p_rid_buffer) {
|
||||
alloc.fill_owned_buffer(p_rid_buffer);
|
||||
}
|
||||
|
||||
void set_description(const char *p_descrption) {
|
||||
alloc.set_description(p_descrption);
|
||||
}
|
||||
RID_Owner(uint32_t p_target_chunk_byte_size = 65536) :
|
||||
alloc(p_target_chunk_byte_size) {}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_RID_OWNER_HPP
|
||||
335
include/godot_cpp/templates/safe_refcount.hpp
Normal file
335
include/godot_cpp/templates/safe_refcount.hpp
Normal file
@@ -0,0 +1,335 @@
|
||||
/**************************************************************************/
|
||||
/* safe_refcount.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_SAFE_REFCOUNT_HPP
|
||||
#define GODOT_SAFE_REFCOUNT_HPP
|
||||
|
||||
#if !defined(NO_THREADS)
|
||||
|
||||
#include <atomic>
|
||||
#include <type_traits>
|
||||
|
||||
namespace godot {
|
||||
|
||||
// Design goals for these classes:
|
||||
// - No automatic conversions or arithmetic operators,
|
||||
// to keep explicit the use of atomics everywhere.
|
||||
// - Using acquire-release semantics, even to set the first value.
|
||||
// The first value may be set relaxedly in many cases, but adding the distinction
|
||||
// between relaxed and unrelaxed operation to the interface would make it needlessly
|
||||
// flexible. There's negligible waste in having release semantics for the initial
|
||||
// value and, as an important benefit, you can be sure the value is properly synchronized
|
||||
// even with threads that are already running.
|
||||
|
||||
// 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;
|
||||
|
||||
static_assert(std::atomic<T>::is_always_lock_free);
|
||||
|
||||
public:
|
||||
_ALWAYS_INLINE_ void set(T p_value) {
|
||||
value.store(p_value, std::memory_order_release);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T get() const {
|
||||
return value.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T increment() {
|
||||
return value.fetch_add(1, std::memory_order_acq_rel) + 1;
|
||||
}
|
||||
|
||||
// Returns the original value instead of the new one
|
||||
_ALWAYS_INLINE_ T postincrement() {
|
||||
return value.fetch_add(1, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T decrement() {
|
||||
return value.fetch_sub(1, std::memory_order_acq_rel) - 1;
|
||||
}
|
||||
|
||||
// Returns the original value instead of the new one
|
||||
_ALWAYS_INLINE_ T postdecrement() {
|
||||
return value.fetch_sub(1, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T add(T p_value) {
|
||||
return value.fetch_add(p_value, std::memory_order_acq_rel) + p_value;
|
||||
}
|
||||
|
||||
// Returns the original value instead of the new one
|
||||
_ALWAYS_INLINE_ T postadd(T p_value) {
|
||||
return value.fetch_add(p_value, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T sub(T p_value) {
|
||||
return value.fetch_sub(p_value, std::memory_order_acq_rel) - p_value;
|
||||
}
|
||||
|
||||
// Returns the original value instead of the new one
|
||||
_ALWAYS_INLINE_ T postsub(T p_value) {
|
||||
return value.fetch_sub(p_value, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T exchange_if_greater(T p_value) {
|
||||
while (true) {
|
||||
T tmp = value.load(std::memory_order_acquire);
|
||||
if (tmp >= p_value) {
|
||||
return tmp; // already greater, or equal
|
||||
}
|
||||
if (value.compare_exchange_weak(tmp, p_value, std::memory_order_release)) {
|
||||
return p_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T conditional_increment() {
|
||||
while (true) {
|
||||
T c = value.load(std::memory_order_acquire);
|
||||
if (c == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (value.compare_exchange_weak(c, c + 1, std::memory_order_release)) {
|
||||
return c + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ explicit SafeNumeric(T p_value = static_cast<T>(0)) {
|
||||
set(p_value);
|
||||
}
|
||||
};
|
||||
|
||||
class SafeFlag {
|
||||
std::atomic_bool flag;
|
||||
|
||||
static_assert(std::atomic_bool::is_always_lock_free);
|
||||
|
||||
public:
|
||||
_ALWAYS_INLINE_ bool is_set() const {
|
||||
return flag.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void set() {
|
||||
flag.store(true, std::memory_order_release);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void clear() {
|
||||
flag.store(false, std::memory_order_release);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void set_to(bool p_value) {
|
||||
flag.store(p_value, std::memory_order_release);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) {
|
||||
set_to(p_value);
|
||||
}
|
||||
};
|
||||
|
||||
class SafeRefCount {
|
||||
SafeNumeric<uint32_t> count;
|
||||
|
||||
public:
|
||||
_ALWAYS_INLINE_ bool ref() { // true on success
|
||||
return count.conditional_increment() != 0;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
|
||||
return count.conditional_increment();
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ bool unref() { // true if must be disposed of
|
||||
return count.decrement() == 0;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
|
||||
return count.decrement();
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t get() const {
|
||||
return count.get();
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void init(uint32_t p_value = 1) {
|
||||
count.set(p_value);
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
template <typename T>
|
||||
class SafeNumeric {
|
||||
protected:
|
||||
T value;
|
||||
|
||||
public:
|
||||
_ALWAYS_INLINE_ void set(T p_value) {
|
||||
value = p_value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T get() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T increment() {
|
||||
return ++value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T postincrement() {
|
||||
return value++;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T decrement() {
|
||||
return --value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T postdecrement() {
|
||||
return value--;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T add(T p_value) {
|
||||
return value += p_value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T postadd(T p_value) {
|
||||
T old = value;
|
||||
value += p_value;
|
||||
return old;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T sub(T p_value) {
|
||||
return value -= p_value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T postsub(T p_value) {
|
||||
T old = value;
|
||||
value -= p_value;
|
||||
return old;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T exchange_if_greater(T p_value) {
|
||||
if (value < p_value) {
|
||||
value = p_value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T conditional_increment() {
|
||||
if (value == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return ++value;
|
||||
}
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) :
|
||||
value(p_value) {
|
||||
}
|
||||
};
|
||||
|
||||
class SafeFlag {
|
||||
protected:
|
||||
bool flag;
|
||||
|
||||
public:
|
||||
_ALWAYS_INLINE_ bool is_set() const {
|
||||
return flag;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void set() {
|
||||
flag = true;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void clear() {
|
||||
flag = false;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void set_to(bool p_value) {
|
||||
flag = p_value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) :
|
||||
flag(p_value) {}
|
||||
};
|
||||
|
||||
class SafeRefCount {
|
||||
uint32_t count = 0;
|
||||
|
||||
public:
|
||||
_ALWAYS_INLINE_ bool ref() { // true on success
|
||||
if (count != 0) {
|
||||
++count;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
|
||||
if (count != 0) {
|
||||
return ++count;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ bool unref() { // true if must be disposed of
|
||||
return --count == 0;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
|
||||
return --count;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t get() const {
|
||||
return count;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void init(uint32_t p_value = 1) {
|
||||
count = p_value;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_SAFE_REFCOUNT_HPP
|
||||
71
include/godot_cpp/templates/search_array.hpp
Normal file
71
include/godot_cpp/templates/search_array.hpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/**************************************************************************/
|
||||
/* search_array.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_SEARCH_ARRAY_HPP
|
||||
#define GODOT_SEARCH_ARRAY_HPP
|
||||
|
||||
#include <godot_cpp/templates/sort_array.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <typename T, typename Comparator = _DefaultComparator<T>>
|
||||
class SearchArray {
|
||||
public:
|
||||
Comparator compare;
|
||||
|
||||
inline int bisect(const T *p_array, int p_len, const T &p_value, bool p_before) const {
|
||||
int lo = 0;
|
||||
int hi = p_len;
|
||||
if (p_before) {
|
||||
while (lo < hi) {
|
||||
const int mid = (lo + hi) / 2;
|
||||
if (compare(p_array[mid], p_value)) {
|
||||
lo = mid + 1;
|
||||
} else {
|
||||
hi = mid;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (lo < hi) {
|
||||
const int mid = (lo + hi) / 2;
|
||||
if (compare(p_value, p_array[mid])) {
|
||||
hi = mid;
|
||||
} else {
|
||||
lo = mid + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return lo;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_SEARCH_ARRAY_HPP
|
||||
143
include/godot_cpp/templates/self_list.hpp
Normal file
143
include/godot_cpp/templates/self_list.hpp
Normal file
@@ -0,0 +1,143 @@
|
||||
/**************************************************************************/
|
||||
/* self_list.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_SELF_LIST_HPP
|
||||
#define GODOT_SELF_LIST_HPP
|
||||
|
||||
#include <godot_cpp/core/defs.hpp>
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <typename T>
|
||||
class SelfList {
|
||||
public:
|
||||
class List {
|
||||
SelfList<T> *_first = nullptr;
|
||||
SelfList<T> *_last = nullptr;
|
||||
|
||||
public:
|
||||
void add(SelfList<T> *p_elem) {
|
||||
ERR_FAIL_COND(p_elem->_root);
|
||||
|
||||
p_elem->_root = this;
|
||||
p_elem->_next = _first;
|
||||
p_elem->_prev = nullptr;
|
||||
|
||||
if (_first) {
|
||||
_first->_prev = p_elem;
|
||||
|
||||
} else {
|
||||
_last = p_elem;
|
||||
}
|
||||
|
||||
_first = p_elem;
|
||||
}
|
||||
|
||||
void add_last(SelfList<T> *p_elem) {
|
||||
ERR_FAIL_COND(p_elem->_root);
|
||||
|
||||
p_elem->_root = this;
|
||||
p_elem->_next = nullptr;
|
||||
p_elem->_prev = _last;
|
||||
|
||||
if (_last) {
|
||||
_last->_next = p_elem;
|
||||
|
||||
} else {
|
||||
_first = p_elem;
|
||||
}
|
||||
|
||||
_last = p_elem;
|
||||
}
|
||||
|
||||
void remove(SelfList<T> *p_elem) {
|
||||
ERR_FAIL_COND(p_elem->_root != this);
|
||||
if (p_elem->_next) {
|
||||
p_elem->_next->_prev = p_elem->_prev;
|
||||
}
|
||||
|
||||
if (p_elem->_prev) {
|
||||
p_elem->_prev->_next = p_elem->_next;
|
||||
}
|
||||
|
||||
if (_first == p_elem) {
|
||||
_first = p_elem->_next;
|
||||
}
|
||||
|
||||
if (_last == p_elem) {
|
||||
_last = p_elem->_prev;
|
||||
}
|
||||
|
||||
p_elem->_next = nullptr;
|
||||
p_elem->_prev = nullptr;
|
||||
p_elem->_root = nullptr;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ SelfList<T> *first() { return _first; }
|
||||
_FORCE_INLINE_ const SelfList<T> *first() const { return _first; }
|
||||
|
||||
_FORCE_INLINE_ List() {}
|
||||
_FORCE_INLINE_ ~List() { ERR_FAIL_COND(_first != nullptr); }
|
||||
};
|
||||
|
||||
private:
|
||||
List *_root = nullptr;
|
||||
T *_self = nullptr;
|
||||
SelfList<T> *_next = nullptr;
|
||||
SelfList<T> *_prev = nullptr;
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ bool in_list() const { return _root; }
|
||||
_FORCE_INLINE_ void remove_from_list() {
|
||||
if (_root) {
|
||||
_root->remove(this);
|
||||
}
|
||||
}
|
||||
_FORCE_INLINE_ SelfList<T> *next() { return _next; }
|
||||
_FORCE_INLINE_ SelfList<T> *prev() { return _prev; }
|
||||
_FORCE_INLINE_ const SelfList<T> *next() const { return _next; }
|
||||
_FORCE_INLINE_ const SelfList<T> *prev() const { return _prev; }
|
||||
_FORCE_INLINE_ T *self() const { return _self; }
|
||||
|
||||
_FORCE_INLINE_ SelfList(T *p_self) {
|
||||
_self = p_self;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ ~SelfList() {
|
||||
if (_root) {
|
||||
_root->remove(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_SELF_LIST_HPP
|
||||
323
include/godot_cpp/templates/sort_array.hpp
Normal file
323
include/godot_cpp/templates/sort_array.hpp
Normal file
@@ -0,0 +1,323 @@
|
||||
/**************************************************************************/
|
||||
/* sort_array.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_SORT_ARRAY_HPP
|
||||
#define GODOT_SORT_ARRAY_HPP
|
||||
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
#define ERR_BAD_COMPARE(cond) \
|
||||
if (unlikely(cond)) { \
|
||||
ERR_PRINT("bad comparison function; sorting will be broken"); \
|
||||
break; \
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct _DefaultComparator {
|
||||
_FORCE_INLINE_ bool operator()(const T &a, const T &b) const { return (a < b); }
|
||||
};
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
#define SORT_ARRAY_VALIDATE_ENABLED true
|
||||
#else
|
||||
#define SORT_ARRAY_VALIDATE_ENABLED false
|
||||
#endif
|
||||
|
||||
template <typename T, typename Comparator = _DefaultComparator<T>, bool Validate = SORT_ARRAY_VALIDATE_ENABLED>
|
||||
class SortArray {
|
||||
enum {
|
||||
INTROSORT_THRESHOLD = 16
|
||||
};
|
||||
|
||||
public:
|
||||
Comparator compare;
|
||||
|
||||
inline const T &median_of_3(const T &a, const T &b, const T &c) const {
|
||||
if (compare(a, b)) {
|
||||
if (compare(b, c)) {
|
||||
return b;
|
||||
} else if (compare(a, c)) {
|
||||
return c;
|
||||
} else {
|
||||
return a;
|
||||
}
|
||||
} else if (compare(a, c)) {
|
||||
return a;
|
||||
} else if (compare(b, c)) {
|
||||
return c;
|
||||
} else {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
inline int bitlog(int n) const {
|
||||
int k;
|
||||
for (k = 0; n != 1; n >>= 1) {
|
||||
++k;
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
/* Heap / Heapsort functions */
|
||||
|
||||
inline void push_heap(int p_first, int p_hole_idx, int p_top_index, T p_value, T *p_array) const {
|
||||
int parent = (p_hole_idx - 1) / 2;
|
||||
while (p_hole_idx > p_top_index && compare(p_array[p_first + parent], p_value)) {
|
||||
p_array[p_first + p_hole_idx] = p_array[p_first + parent];
|
||||
p_hole_idx = parent;
|
||||
parent = (p_hole_idx - 1) / 2;
|
||||
}
|
||||
p_array[p_first + p_hole_idx] = p_value;
|
||||
}
|
||||
|
||||
inline void pop_heap(int p_first, int p_last, int p_result, T p_value, T *p_array) const {
|
||||
p_array[p_result] = p_array[p_first];
|
||||
adjust_heap(p_first, 0, p_last - p_first, p_value, p_array);
|
||||
}
|
||||
inline void pop_heap(int p_first, int p_last, T *p_array) const {
|
||||
pop_heap(p_first, p_last - 1, p_last - 1, p_array[p_last - 1], p_array);
|
||||
}
|
||||
|
||||
inline void adjust_heap(int p_first, int p_hole_idx, int p_len, T p_value, T *p_array) const {
|
||||
int top_index = p_hole_idx;
|
||||
int second_child = 2 * p_hole_idx + 2;
|
||||
|
||||
while (second_child < p_len) {
|
||||
if (compare(p_array[p_first + second_child], p_array[p_first + (second_child - 1)])) {
|
||||
second_child--;
|
||||
}
|
||||
|
||||
p_array[p_first + p_hole_idx] = p_array[p_first + second_child];
|
||||
p_hole_idx = second_child;
|
||||
second_child = 2 * (second_child + 1);
|
||||
}
|
||||
|
||||
if (second_child == p_len) {
|
||||
p_array[p_first + p_hole_idx] = p_array[p_first + (second_child - 1)];
|
||||
p_hole_idx = second_child - 1;
|
||||
}
|
||||
push_heap(p_first, p_hole_idx, top_index, p_value, p_array);
|
||||
}
|
||||
|
||||
inline void sort_heap(int p_first, int p_last, T *p_array) const {
|
||||
while (p_last - p_first > 1) {
|
||||
pop_heap(p_first, p_last--, p_array);
|
||||
}
|
||||
}
|
||||
|
||||
inline void make_heap(int p_first, int p_last, T *p_array) const {
|
||||
if (p_last - p_first < 2) {
|
||||
return;
|
||||
}
|
||||
int len = p_last - p_first;
|
||||
int parent = (len - 2) / 2;
|
||||
|
||||
while (true) {
|
||||
adjust_heap(p_first, parent, len, p_array[p_first + parent], p_array);
|
||||
if (parent == 0) {
|
||||
return;
|
||||
}
|
||||
parent--;
|
||||
}
|
||||
}
|
||||
|
||||
inline void partial_sort(int p_first, int p_last, int p_middle, T *p_array) const {
|
||||
make_heap(p_first, p_middle, p_array);
|
||||
for (int i = p_middle; i < p_last; i++) {
|
||||
if (compare(p_array[i], p_array[p_first])) {
|
||||
pop_heap(p_first, p_middle, i, p_array[i], p_array);
|
||||
}
|
||||
}
|
||||
sort_heap(p_first, p_middle, p_array);
|
||||
}
|
||||
|
||||
inline void partial_select(int p_first, int p_last, int p_middle, T *p_array) const {
|
||||
make_heap(p_first, p_middle, p_array);
|
||||
for (int i = p_middle; i < p_last; i++) {
|
||||
if (compare(p_array[i], p_array[p_first])) {
|
||||
pop_heap(p_first, p_middle, i, p_array[i], p_array);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline int partitioner(int p_first, int p_last, T p_pivot, T *p_array) const {
|
||||
const int unmodified_first = p_first;
|
||||
const int unmodified_last = p_last;
|
||||
|
||||
while (true) {
|
||||
while (compare(p_array[p_first], p_pivot)) {
|
||||
if (Validate) {
|
||||
ERR_BAD_COMPARE(p_first == unmodified_last - 1);
|
||||
}
|
||||
p_first++;
|
||||
}
|
||||
p_last--;
|
||||
while (compare(p_pivot, p_array[p_last])) {
|
||||
if (Validate) {
|
||||
ERR_BAD_COMPARE(p_last == unmodified_first);
|
||||
}
|
||||
p_last--;
|
||||
}
|
||||
|
||||
if (!(p_first < p_last)) {
|
||||
return p_first;
|
||||
}
|
||||
|
||||
SWAP(p_array[p_first], p_array[p_last]);
|
||||
p_first++;
|
||||
}
|
||||
}
|
||||
|
||||
inline void introsort(int p_first, int p_last, T *p_array, int p_max_depth) const {
|
||||
while (p_last - p_first > INTROSORT_THRESHOLD) {
|
||||
if (p_max_depth == 0) {
|
||||
partial_sort(p_first, p_last, p_last, p_array);
|
||||
return;
|
||||
}
|
||||
|
||||
p_max_depth--;
|
||||
|
||||
int cut = partitioner(
|
||||
p_first,
|
||||
p_last,
|
||||
median_of_3(
|
||||
p_array[p_first],
|
||||
p_array[p_first + (p_last - p_first) / 2],
|
||||
p_array[p_last - 1]),
|
||||
p_array);
|
||||
|
||||
introsort(cut, p_last, p_array, p_max_depth);
|
||||
p_last = cut;
|
||||
}
|
||||
}
|
||||
|
||||
inline void introselect(int p_first, int p_nth, int p_last, T *p_array, int p_max_depth) const {
|
||||
while (p_last - p_first > 3) {
|
||||
if (p_max_depth == 0) {
|
||||
partial_select(p_first, p_nth + 1, p_last, p_array);
|
||||
SWAP(p_first, p_nth);
|
||||
return;
|
||||
}
|
||||
|
||||
p_max_depth--;
|
||||
|
||||
int cut = partitioner(
|
||||
p_first,
|
||||
p_last,
|
||||
median_of_3(
|
||||
p_array[p_first],
|
||||
p_array[p_first + (p_last - p_first) / 2],
|
||||
p_array[p_last - 1]),
|
||||
p_array);
|
||||
|
||||
if (cut <= p_nth) {
|
||||
p_first = cut;
|
||||
} else {
|
||||
p_last = cut;
|
||||
}
|
||||
}
|
||||
|
||||
insertion_sort(p_first, p_last, p_array);
|
||||
}
|
||||
|
||||
inline void unguarded_linear_insert(int p_last, T p_value, T *p_array) const {
|
||||
int next = p_last - 1;
|
||||
while (compare(p_value, p_array[next])) {
|
||||
if (Validate) {
|
||||
ERR_BAD_COMPARE(next == 0);
|
||||
}
|
||||
p_array[p_last] = p_array[next];
|
||||
p_last = next;
|
||||
next--;
|
||||
}
|
||||
p_array[p_last] = p_value;
|
||||
}
|
||||
|
||||
inline void linear_insert(int p_first, int p_last, T *p_array) const {
|
||||
T val = p_array[p_last];
|
||||
if (compare(val, p_array[p_first])) {
|
||||
for (int i = p_last; i > p_first; i--) {
|
||||
p_array[i] = p_array[i - 1];
|
||||
}
|
||||
|
||||
p_array[p_first] = val;
|
||||
} else {
|
||||
unguarded_linear_insert(p_last, val, p_array);
|
||||
}
|
||||
}
|
||||
|
||||
inline void insertion_sort(int p_first, int p_last, T *p_array) const {
|
||||
if (p_first == p_last) {
|
||||
return;
|
||||
}
|
||||
for (int i = p_first + 1; i != p_last; i++) {
|
||||
linear_insert(p_first, i, p_array);
|
||||
}
|
||||
}
|
||||
|
||||
inline void unguarded_insertion_sort(int p_first, int p_last, T *p_array) const {
|
||||
for (int i = p_first; i != p_last; i++) {
|
||||
unguarded_linear_insert(i, p_array[i], p_array);
|
||||
}
|
||||
}
|
||||
|
||||
inline void final_insertion_sort(int p_first, int p_last, T *p_array) const {
|
||||
if (p_last - p_first > INTROSORT_THRESHOLD) {
|
||||
insertion_sort(p_first, p_first + INTROSORT_THRESHOLD, p_array);
|
||||
unguarded_insertion_sort(p_first + INTROSORT_THRESHOLD, p_last, p_array);
|
||||
} else {
|
||||
insertion_sort(p_first, p_last, p_array);
|
||||
}
|
||||
}
|
||||
|
||||
inline void sort_range(int p_first, int p_last, T *p_array) const {
|
||||
if (p_first != p_last) {
|
||||
introsort(p_first, p_last, p_array, bitlog(p_last - p_first) * 2);
|
||||
final_insertion_sort(p_first, p_last, p_array);
|
||||
}
|
||||
}
|
||||
|
||||
inline void sort(T *p_array, int p_len) const {
|
||||
sort_range(0, p_len, p_array);
|
||||
}
|
||||
|
||||
inline void nth_element(int p_first, int p_last, int p_nth, T *p_array) const {
|
||||
if (p_first == p_last || p_nth == p_last) {
|
||||
return;
|
||||
}
|
||||
introselect(p_first, p_nth, p_last, p_array, bitlog(p_last - p_first) * 2);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_SORT_ARRAY_HPP
|
||||
54
include/godot_cpp/templates/spin_lock.hpp
Normal file
54
include/godot_cpp/templates/spin_lock.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
/**************************************************************************/
|
||||
/* spin_lock.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_SPIN_LOCK_HPP
|
||||
#define GODOT_SPIN_LOCK_HPP
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class SpinLock {
|
||||
std::atomic_flag locked = ATOMIC_FLAG_INIT;
|
||||
|
||||
public:
|
||||
_ALWAYS_INLINE_ void lock() {
|
||||
while (locked.test_and_set(std::memory_order_acquire)) {
|
||||
;
|
||||
}
|
||||
}
|
||||
_ALWAYS_INLINE_ void unlock() {
|
||||
locked.clear(std::memory_order_release);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_SPIN_LOCK_HPP
|
||||
205
include/godot_cpp/templates/thread_work_pool.hpp
Normal file
205
include/godot_cpp/templates/thread_work_pool.hpp
Normal file
@@ -0,0 +1,205 @@
|
||||
/**************************************************************************/
|
||||
/* thread_work_pool.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_THREAD_WORK_POOL_HPP
|
||||
#define GODOT_THREAD_WORK_POOL_HPP
|
||||
|
||||
#include <godot_cpp/classes/os.hpp>
|
||||
#include <godot_cpp/classes/semaphore.hpp>
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class ThreadWorkPool {
|
||||
std::atomic<uint32_t> index;
|
||||
|
||||
struct BaseWork {
|
||||
std::atomic<uint32_t> *index = nullptr;
|
||||
uint32_t max_elements = 0;
|
||||
virtual void work() = 0;
|
||||
virtual ~BaseWork() = default;
|
||||
};
|
||||
|
||||
template <typename C, typename M, typename U>
|
||||
struct Work : public BaseWork {
|
||||
C *instance;
|
||||
M method;
|
||||
U userdata;
|
||||
virtual void work() {
|
||||
while (true) {
|
||||
uint32_t work_index = index->fetch_add(1, std::memory_order_relaxed);
|
||||
if (work_index >= max_elements) {
|
||||
break;
|
||||
}
|
||||
(instance->*method)(work_index, userdata);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct ThreadData {
|
||||
std::thread thread;
|
||||
Semaphore start;
|
||||
Semaphore completed;
|
||||
std::atomic<bool> exit;
|
||||
BaseWork *work;
|
||||
};
|
||||
|
||||
ThreadData *threads = nullptr;
|
||||
uint32_t thread_count = 0;
|
||||
uint32_t threads_working = 0;
|
||||
BaseWork *current_work = nullptr;
|
||||
|
||||
static void _thread_function(void *p_user) {
|
||||
ThreadData *thread = static_cast<ThreadData *>(p_user);
|
||||
while (true) {
|
||||
thread->start.wait();
|
||||
if (thread->exit.load()) {
|
||||
break;
|
||||
}
|
||||
thread->work->work();
|
||||
thread->completed.post();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
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_NULL(threads); // Never initialized.
|
||||
ERR_FAIL_COND(current_work != nullptr);
|
||||
|
||||
index.store(0, std::memory_order_release);
|
||||
|
||||
Work<C, M, U> *w = new (Work<C, M, U>);
|
||||
w->instance = p_instance;
|
||||
w->userdata = p_userdata;
|
||||
w->method = p_method;
|
||||
w->index = &index;
|
||||
w->max_elements = p_elements;
|
||||
|
||||
current_work = w;
|
||||
|
||||
threads_working = Math::min(p_elements, thread_count);
|
||||
|
||||
for (uint32_t i = 0; i < threads_working; i++) {
|
||||
threads[i].work = w;
|
||||
threads[i].start.post();
|
||||
}
|
||||
}
|
||||
|
||||
bool is_working() const {
|
||||
return current_work != nullptr;
|
||||
}
|
||||
|
||||
bool is_done_dispatching() const {
|
||||
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_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_NULL(current_work);
|
||||
for (uint32_t i = 0; i < threads_working; i++) {
|
||||
threads[i].completed.wait();
|
||||
threads[i].work = nullptr;
|
||||
}
|
||||
|
||||
threads_working = 0;
|
||||
delete current_work;
|
||||
current_work = nullptr;
|
||||
}
|
||||
|
||||
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:
|
||||
// Nothing to do, so do nothing.
|
||||
break;
|
||||
case 1:
|
||||
// No value in pushing the work to another thread if it's a single job
|
||||
// and we're going to wait for it to finish. Just run it right here.
|
||||
(p_instance->*p_method)(0, p_userdata);
|
||||
break;
|
||||
default:
|
||||
// Multiple jobs to do; commence threaded business.
|
||||
begin_work(p_elements, p_instance, p_method, p_userdata);
|
||||
end_work();
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int get_thread_count() const { return thread_count; }
|
||||
void init(int p_thread_count = -1) {
|
||||
ERR_FAIL_COND(threads != nullptr);
|
||||
if (p_thread_count < 0) {
|
||||
p_thread_count = OS::get_singleton()->get_processor_count();
|
||||
}
|
||||
|
||||
thread_count = p_thread_count;
|
||||
threads = new ThreadData[thread_count];
|
||||
|
||||
for (uint32_t i = 0; i < thread_count; i++) {
|
||||
threads[i].exit.store(false);
|
||||
threads[i].thread = std::thread(&ThreadWorkPool::_thread_function, &threads[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void finish() {
|
||||
if (threads == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < thread_count; i++) {
|
||||
threads[i].exit.store(true);
|
||||
threads[i].start.post();
|
||||
}
|
||||
for (uint32_t i = 0; i < thread_count; i++) {
|
||||
threads[i].thread.join();
|
||||
}
|
||||
|
||||
delete[] (threads);
|
||||
threads = nullptr;
|
||||
}
|
||||
~ThreadWorkPool() {
|
||||
finish();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_THREAD_WORK_POOL_HPP
|
||||
336
include/godot_cpp/templates/vector.hpp
Normal file
336
include/godot_cpp/templates/vector.hpp
Normal file
@@ -0,0 +1,336 @@
|
||||
/**************************************************************************/
|
||||
/* vector.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_VECTOR_HPP
|
||||
#define GODOT_VECTOR_HPP
|
||||
|
||||
/**
|
||||
* @class Vector
|
||||
* Vector container. Regular Vector Container. Use with care and for smaller arrays when possible. Use Vector for large arrays.
|
||||
*/
|
||||
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
#include <godot_cpp/templates/cowdata.hpp>
|
||||
#include <godot_cpp/templates/search_array.hpp>
|
||||
#include <godot_cpp/templates/sort_array.hpp>
|
||||
|
||||
#include <climits>
|
||||
#include <initializer_list>
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <typename T>
|
||||
class VectorWriteProxy {
|
||||
public:
|
||||
_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 <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
|
||||
void fill(T p_elem);
|
||||
|
||||
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(); }
|
||||
_FORCE_INLINE_ const T *ptr() const { return _cowdata.ptr(); }
|
||||
_FORCE_INLINE_ void clear() { resize(0); }
|
||||
_FORCE_INLINE_ bool is_empty() const { return _cowdata.is_empty(); }
|
||||
|
||||
_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; }
|
||||
|
||||
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, Comparator, Validate> sorter{ args... };
|
||||
sorter.sort(data, len);
|
||||
}
|
||||
|
||||
Size bsearch(const T &p_value, bool p_before) {
|
||||
return bsearch_custom<_DefaultComparator<T>>(p_value, p_before);
|
||||
}
|
||||
|
||||
template <typename Comparator, typename Value, typename... Args>
|
||||
Size bsearch_custom(const Value &p_value, bool p_before, Args &&...args) {
|
||||
SearchArray<T, Comparator> search{ args... };
|
||||
return search.bisect(ptrw(), size(), p_value, p_before);
|
||||
}
|
||||
|
||||
Vector<T> duplicate() {
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ordered_insert(const T &p_val) {
|
||||
Size i;
|
||||
for (i = 0; i < _cowdata.size(); i++) {
|
||||
if (p_val < operator[](i)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
insert(i, p_val);
|
||||
}
|
||||
|
||||
inline void operator=(const Vector &p_from) {
|
||||
_cowdata._ref(p_from._cowdata);
|
||||
}
|
||||
|
||||
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(Size p_begin, Size p_end = CowData<T>::MAX_INT) const {
|
||||
Vector<T> result;
|
||||
|
||||
const Size s = size();
|
||||
|
||||
Size begin = CLAMP(p_begin, -s, s);
|
||||
if (begin < 0) {
|
||||
begin += s;
|
||||
}
|
||||
Size end = CLAMP(p_end, -s, s);
|
||||
if (end < 0) {
|
||||
end += s;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V(begin > end, result);
|
||||
|
||||
Size result_size = end - begin;
|
||||
result.resize(result_size);
|
||||
|
||||
const T *const r = ptr();
|
||||
T *const w = result.ptrw();
|
||||
for (Size i = 0; i < result_size; ++i) {
|
||||
w[i] = r[begin + i];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==(const Vector<T> &p_arr) const {
|
||||
Size s = size();
|
||||
if (s != p_arr.size()) {
|
||||
return false;
|
||||
}
|
||||
for (Size i = 0; i < s; i++) {
|
||||
if (operator[](i) != p_arr[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const Vector<T> &p_arr) const {
|
||||
Size s = size();
|
||||
if (s != p_arr.size()) {
|
||||
return true;
|
||||
}
|
||||
for (Size i = 0; i < s; i++) {
|
||||
if (operator[](i) != p_arr[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct Iterator {
|
||||
_FORCE_INLINE_ T &operator*() const {
|
||||
return *elem_ptr;
|
||||
}
|
||||
_FORCE_INLINE_ T *operator->() const { return elem_ptr; }
|
||||
_FORCE_INLINE_ Iterator &operator++() {
|
||||
elem_ptr++;
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ Iterator &operator--() {
|
||||
elem_ptr--;
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return elem_ptr == b.elem_ptr; }
|
||||
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return elem_ptr != b.elem_ptr; }
|
||||
|
||||
Iterator(T *p_ptr) { elem_ptr = p_ptr; }
|
||||
Iterator() {}
|
||||
Iterator(const Iterator &p_it) { elem_ptr = p_it.elem_ptr; }
|
||||
|
||||
private:
|
||||
T *elem_ptr = nullptr;
|
||||
};
|
||||
|
||||
struct ConstIterator {
|
||||
_FORCE_INLINE_ const T &operator*() const {
|
||||
return *elem_ptr;
|
||||
}
|
||||
_FORCE_INLINE_ const T *operator->() const { return elem_ptr; }
|
||||
_FORCE_INLINE_ ConstIterator &operator++() {
|
||||
elem_ptr++;
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator &operator--() {
|
||||
elem_ptr--;
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return elem_ptr == b.elem_ptr; }
|
||||
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return elem_ptr != b.elem_ptr; }
|
||||
|
||||
ConstIterator(const T *p_ptr) { elem_ptr = p_ptr; }
|
||||
ConstIterator() {}
|
||||
ConstIterator(const ConstIterator &p_it) { elem_ptr = p_it.elem_ptr; }
|
||||
|
||||
private:
|
||||
const T *elem_ptr = nullptr;
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ Iterator begin() {
|
||||
return Iterator(ptrw());
|
||||
}
|
||||
_FORCE_INLINE_ Iterator end() {
|
||||
return Iterator(ptrw() + size());
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ ConstIterator begin() const {
|
||||
return ConstIterator(ptr());
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator end() const {
|
||||
return ConstIterator(ptr() + size());
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Vector() {}
|
||||
_FORCE_INLINE_ Vector(std::initializer_list<T> p_init) {
|
||||
Error err = _cowdata.resize(p_init.size());
|
||||
ERR_FAIL_COND(err);
|
||||
|
||||
Size i = 0;
|
||||
for (const T &element : p_init) {
|
||||
_cowdata.set(i++, element);
|
||||
}
|
||||
}
|
||||
_FORCE_INLINE_ Vector(const Vector &p_from) { _cowdata._ref(p_from._cowdata); }
|
||||
|
||||
_FORCE_INLINE_ ~Vector() {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void Vector<T>::reverse() {
|
||||
for (Size i = 0; i < size() / 2; i++) {
|
||||
T *p = ptrw();
|
||||
SWAP(p[i], p[size() - i - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Vector<T>::append_array(Vector<T> p_other) {
|
||||
const Size ds = p_other.size();
|
||||
if (ds == 0) {
|
||||
return;
|
||||
}
|
||||
const Size bs = size();
|
||||
resize(bs + ds);
|
||||
for (Size i = 0; i < ds; ++i) {
|
||||
ptrw()[bs + i] = p_other[i];
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool Vector<T>::push_back(T p_elem) {
|
||||
Error err = resize(size() + 1);
|
||||
ERR_FAIL_COND_V(err, true);
|
||||
set(size() - 1, p_elem);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Vector<T>::fill(T p_elem) {
|
||||
T *p = ptrw();
|
||||
for (Size i = 0; i < size(); i++) {
|
||||
p[i] = p_elem;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_VECTOR_HPP
|
||||
204
include/godot_cpp/templates/vmap.hpp
Normal file
204
include/godot_cpp/templates/vmap.hpp
Normal file
@@ -0,0 +1,204 @@
|
||||
/**************************************************************************/
|
||||
/* vmap.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_VMAP_HPP
|
||||
#define GODOT_VMAP_HPP
|
||||
|
||||
#include <godot_cpp/templates/cowdata.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <typename T, typename V>
|
||||
class VMap {
|
||||
public:
|
||||
struct Pair {
|
||||
T key;
|
||||
V value;
|
||||
|
||||
_FORCE_INLINE_ Pair() {}
|
||||
|
||||
_FORCE_INLINE_ Pair(const T &p_key, const V &p_value) {
|
||||
key = p_key;
|
||||
value = p_value;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
CowData<Pair> _cowdata;
|
||||
|
||||
_FORCE_INLINE_ int _find(const T &p_val, bool &r_exact) const {
|
||||
r_exact = false;
|
||||
if (_cowdata.is_empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int low = 0;
|
||||
int high = _cowdata.size() - 1;
|
||||
const Pair *a = _cowdata.ptr();
|
||||
int middle = 0;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (low > high) {
|
||||
ERR_PRINT("low > high, this may be a bug");
|
||||
}
|
||||
#endif
|
||||
while (low <= high) {
|
||||
middle = (low + high) / 2;
|
||||
|
||||
if (p_val < a[middle].key) {
|
||||
high = middle - 1; // search low end of array
|
||||
} else if (a[middle].key < p_val) {
|
||||
low = middle + 1; // search high end of array
|
||||
} else {
|
||||
r_exact = true;
|
||||
return middle;
|
||||
}
|
||||
}
|
||||
|
||||
// return the position where this would be inserted
|
||||
if (a[middle].key < p_val) {
|
||||
middle++;
|
||||
}
|
||||
return middle;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int _find_exact(const T &p_val) const {
|
||||
if (_cowdata.is_empty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int low = 0;
|
||||
int high = _cowdata.size() - 1;
|
||||
int middle;
|
||||
const Pair *a = _cowdata.ptr();
|
||||
|
||||
while (low <= high) {
|
||||
middle = (low + high) / 2;
|
||||
|
||||
if (p_val < a[middle].key) {
|
||||
high = middle - 1; // search low end of array
|
||||
} else if (a[middle].key < p_val) {
|
||||
low = middle + 1; // search high end of array
|
||||
} else {
|
||||
return middle;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public:
|
||||
int insert(const T &p_key, const V &p_val) {
|
||||
bool exact;
|
||||
int pos = _find(p_key, exact);
|
||||
if (exact) {
|
||||
_cowdata.get_m(pos).value = p_val;
|
||||
return pos;
|
||||
}
|
||||
_cowdata.insert(pos, Pair(p_key, p_val));
|
||||
return pos;
|
||||
}
|
||||
|
||||
bool has(const T &p_val) const {
|
||||
return _find_exact(p_val) != -1;
|
||||
}
|
||||
|
||||
void erase(const T &p_val) {
|
||||
int pos = _find_exact(p_val);
|
||||
if (pos < 0) {
|
||||
return;
|
||||
}
|
||||
_cowdata.remove_at(pos);
|
||||
}
|
||||
|
||||
int find(const T &p_val) const {
|
||||
return _find_exact(p_val);
|
||||
}
|
||||
|
||||
int find_nearest(const T &p_val) const {
|
||||
bool exact;
|
||||
return _find(p_val, exact);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int size() const { return _cowdata.size(); }
|
||||
_FORCE_INLINE_ bool is_empty() const { return _cowdata.is_empty(); }
|
||||
|
||||
const Pair *get_array() const {
|
||||
return _cowdata.ptr();
|
||||
}
|
||||
|
||||
Pair *get_array() {
|
||||
return _cowdata.ptrw();
|
||||
}
|
||||
|
||||
const V &getv(int p_index) const {
|
||||
return _cowdata.get(p_index).value;
|
||||
}
|
||||
|
||||
V &getv(int p_index) {
|
||||
return _cowdata.get_m(p_index).value;
|
||||
}
|
||||
|
||||
const T &getk(int p_index) const {
|
||||
return _cowdata.get(p_index).key;
|
||||
}
|
||||
|
||||
T &getk(int p_index) {
|
||||
return _cowdata.get_m(p_index).key;
|
||||
}
|
||||
|
||||
inline const V &operator[](const T &p_key) const {
|
||||
int pos = _find_exact(p_key);
|
||||
|
||||
CRASH_COND(pos < 0);
|
||||
|
||||
return _cowdata.get(pos).value;
|
||||
}
|
||||
|
||||
inline V &operator[](const T &p_key) {
|
||||
int pos = _find_exact(p_key);
|
||||
if (pos < 0) {
|
||||
pos = insert(p_key, V());
|
||||
}
|
||||
|
||||
return _cowdata.get_m(pos).value;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ VMap() {}
|
||||
_FORCE_INLINE_ VMap(const VMap &p_from) { _cowdata._ref(p_from._cowdata); }
|
||||
|
||||
inline void operator=(const VMap &p_from) {
|
||||
_cowdata._ref(p_from._cowdata);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_VMAP_HPP
|
||||
145
include/godot_cpp/templates/vset.hpp
Normal file
145
include/godot_cpp/templates/vset.hpp
Normal file
@@ -0,0 +1,145 @@
|
||||
/**************************************************************************/
|
||||
/* vset.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_VSET_HPP
|
||||
#define GODOT_VSET_HPP
|
||||
|
||||
#include <godot_cpp/templates/vector.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <typename T>
|
||||
class VSet {
|
||||
Vector<T> _data;
|
||||
|
||||
_FORCE_INLINE_ int _find(const T &p_val, bool &r_exact) const {
|
||||
r_exact = false;
|
||||
if (_data.is_empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int low = 0;
|
||||
int high = _data.size() - 1;
|
||||
const T *a = &_data[0];
|
||||
int middle = 0;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (low > high) {
|
||||
ERR_PRINT("low > high, this may be a bug");
|
||||
}
|
||||
#endif
|
||||
|
||||
while (low <= high) {
|
||||
middle = (low + high) / 2;
|
||||
|
||||
if (p_val < a[middle]) {
|
||||
high = middle - 1; // search low end of array
|
||||
} else if (a[middle] < p_val) {
|
||||
low = middle + 1; // search high end of array
|
||||
} else {
|
||||
r_exact = true;
|
||||
return middle;
|
||||
}
|
||||
}
|
||||
|
||||
// return the position where this would be inserted
|
||||
if (a[middle] < p_val) {
|
||||
middle++;
|
||||
}
|
||||
return middle;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int _find_exact(const T &p_val) const {
|
||||
if (_data.is_empty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int low = 0;
|
||||
int high = _data.size() - 1;
|
||||
int middle;
|
||||
const T *a = &_data[0];
|
||||
|
||||
while (low <= high) {
|
||||
middle = (low + high) / 2;
|
||||
|
||||
if (p_val < a[middle]) {
|
||||
high = middle - 1; // search low end of array
|
||||
} else if (a[middle] < p_val) {
|
||||
low = middle + 1; // search high end of array
|
||||
} else {
|
||||
return middle;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public:
|
||||
void insert(const T &p_val) {
|
||||
bool exact;
|
||||
int pos = _find(p_val, exact);
|
||||
if (exact) {
|
||||
return;
|
||||
}
|
||||
_data.insert(pos, p_val);
|
||||
}
|
||||
|
||||
bool has(const T &p_val) const {
|
||||
return _find_exact(p_val) != -1;
|
||||
}
|
||||
|
||||
void erase(const T &p_val) {
|
||||
int pos = _find_exact(p_val);
|
||||
if (pos < 0) {
|
||||
return;
|
||||
}
|
||||
_data.remove_at(pos);
|
||||
}
|
||||
|
||||
int find(const T &p_val) const {
|
||||
return _find_exact(p_val);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool is_empty() const { return _data.is_empty(); }
|
||||
|
||||
_FORCE_INLINE_ int size() const { return _data.size(); }
|
||||
|
||||
inline T &operator[](int p_index) {
|
||||
return _data.write[p_index];
|
||||
}
|
||||
|
||||
inline const T &operator[](int p_index) const {
|
||||
return _data[p_index];
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_VSET_HPP
|
||||
495
include/godot_cpp/variant/aabb.hpp
Normal file
495
include/godot_cpp/variant/aabb.hpp
Normal file
@@ -0,0 +1,495 @@
|
||||
/**************************************************************************/
|
||||
/* aabb.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_AABB_HPP
|
||||
#define GODOT_AABB_HPP
|
||||
|
||||
#include <godot_cpp/variant/plane.hpp>
|
||||
#include <godot_cpp/variant/vector3.hpp>
|
||||
|
||||
/**
|
||||
* AABB (Axis Aligned Bounding Box)
|
||||
* This is implemented by a point (position) and the box size.
|
||||
*/
|
||||
|
||||
namespace godot {
|
||||
|
||||
class Variant;
|
||||
|
||||
struct [[nodiscard]] AABB {
|
||||
Vector3 position;
|
||||
Vector3 size;
|
||||
|
||||
real_t get_volume() const;
|
||||
_FORCE_INLINE_ bool has_volume() const {
|
||||
return size.x > 0.0f && size.y > 0.0f && size.z > 0.0f;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool has_surface() const {
|
||||
return size.x > 0.0f || size.y > 0.0f || size.z > 0.0f;
|
||||
}
|
||||
|
||||
const Vector3 &get_position() const { return position; }
|
||||
void set_position(const Vector3 &p_pos) { position = p_pos; }
|
||||
const Vector3 &get_size() const { return size; }
|
||||
void set_size(const Vector3 &p_size) { size = p_size; }
|
||||
|
||||
bool operator==(const AABB &p_rval) const;
|
||||
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
|
||||
|
||||
AABB merge(const AABB &p_with) const;
|
||||
void merge_with(const AABB &p_aabb); ///merge with another AABB
|
||||
AABB intersection(const AABB &p_aabb) const; ///get box where two intersect, empty if no intersection occurs
|
||||
bool intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector3 *r_clip = nullptr, Vector3 *r_normal = nullptr) const;
|
||||
bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *r_clip = nullptr, Vector3 *r_normal = nullptr) const;
|
||||
_FORCE_INLINE_ bool smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t t0, real_t t1) const;
|
||||
|
||||
_FORCE_INLINE_ bool intersects_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const;
|
||||
_FORCE_INLINE_ bool inside_convex_shape(const Plane *p_planes, int p_plane_count) const;
|
||||
bool intersects_plane(const Plane &p_plane) const;
|
||||
|
||||
_FORCE_INLINE_ bool has_point(const Vector3 &p_point) const;
|
||||
_FORCE_INLINE_ Vector3 get_support(const Vector3 &p_normal) const;
|
||||
|
||||
Vector3 get_longest_axis() const;
|
||||
int get_longest_axis_index() const;
|
||||
_FORCE_INLINE_ real_t get_longest_axis_size() const;
|
||||
|
||||
Vector3 get_shortest_axis() const;
|
||||
int get_shortest_axis_index() const;
|
||||
_FORCE_INLINE_ real_t get_shortest_axis_size() const;
|
||||
|
||||
AABB grow(real_t p_by) const;
|
||||
_FORCE_INLINE_ void grow_by(real_t p_amount);
|
||||
|
||||
void get_edge(int p_edge, Vector3 &r_from, Vector3 &r_to) const;
|
||||
_FORCE_INLINE_ Vector3 get_endpoint(int p_point) const;
|
||||
|
||||
AABB expand(const Vector3 &p_vector) const;
|
||||
_FORCE_INLINE_ void project_range_in_plane(const Plane &p_plane, real_t &r_min, real_t &r_max) const;
|
||||
_FORCE_INLINE_ void expand_to(const Vector3 &p_vector); /** expand to contain a point if necessary */
|
||||
|
||||
_FORCE_INLINE_ AABB abs() const {
|
||||
return AABB(position + size.minf(0), size.abs());
|
||||
}
|
||||
|
||||
Variant intersects_segment_bind(const Vector3 &p_from, const Vector3 &p_to) const;
|
||||
Variant intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const;
|
||||
|
||||
_FORCE_INLINE_ void quantize(real_t p_unit);
|
||||
_FORCE_INLINE_ AABB quantized(real_t p_unit) const;
|
||||
|
||||
_FORCE_INLINE_ void set_end(const Vector3 &p_end) {
|
||||
size = p_end - position;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Vector3 get_end() const {
|
||||
return position + size;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Vector3 get_center() const {
|
||||
return position + (size * 0.5f);
|
||||
}
|
||||
|
||||
operator String() const;
|
||||
|
||||
_FORCE_INLINE_ AABB() {}
|
||||
inline AABB(const Vector3 &p_pos, const Vector3 &p_size) :
|
||||
position(p_pos),
|
||||
size(p_size) {
|
||||
}
|
||||
};
|
||||
|
||||
inline bool AABB::intersects(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)) {
|
||||
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
|
||||
}
|
||||
#endif
|
||||
if (position.x >= (p_aabb.position.x + p_aabb.size.x)) {
|
||||
return false;
|
||||
}
|
||||
if ((position.x + size.x) <= p_aabb.position.x) {
|
||||
return false;
|
||||
}
|
||||
if (position.y >= (p_aabb.position.y + p_aabb.size.y)) {
|
||||
return false;
|
||||
}
|
||||
if ((position.y + size.y) <= p_aabb.position.y) {
|
||||
return false;
|
||||
}
|
||||
if (position.z >= (p_aabb.position.z + p_aabb.size.z)) {
|
||||
return false;
|
||||
}
|
||||
if ((position.z + size.z) <= p_aabb.position.z) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool AABB::intersects_inclusive(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)) {
|
||||
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
|
||||
}
|
||||
#endif
|
||||
if (position.x > (p_aabb.position.x + p_aabb.size.x)) {
|
||||
return false;
|
||||
}
|
||||
if ((position.x + size.x) < p_aabb.position.x) {
|
||||
return false;
|
||||
}
|
||||
if (position.y > (p_aabb.position.y + p_aabb.size.y)) {
|
||||
return false;
|
||||
}
|
||||
if ((position.y + size.y) < p_aabb.position.y) {
|
||||
return false;
|
||||
}
|
||||
if (position.z > (p_aabb.position.z + p_aabb.size.z)) {
|
||||
return false;
|
||||
}
|
||||
if ((position.z + size.z) < p_aabb.position.z) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool AABB::encloses(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)) {
|
||||
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
|
||||
}
|
||||
#endif
|
||||
Vector3 src_min = position;
|
||||
Vector3 src_max = position + size;
|
||||
Vector3 dst_min = p_aabb.position;
|
||||
Vector3 dst_max = p_aabb.position + p_aabb.size;
|
||||
|
||||
return (
|
||||
(src_min.x <= dst_min.x) &&
|
||||
(src_max.x >= dst_max.x) &&
|
||||
(src_min.y <= dst_min.y) &&
|
||||
(src_max.y >= dst_max.y) &&
|
||||
(src_min.z <= dst_min.z) &&
|
||||
(src_max.z >= dst_max.z));
|
||||
}
|
||||
|
||||
Vector3 AABB::get_support(const Vector3 &p_normal) const {
|
||||
Vector3 half_extents = size * 0.5f;
|
||||
Vector3 ofs = position + half_extents;
|
||||
|
||||
return Vector3(
|
||||
(p_normal.x > 0) ? half_extents.x : -half_extents.x,
|
||||
(p_normal.y > 0) ? half_extents.y : -half_extents.y,
|
||||
(p_normal.z > 0) ? half_extents.z : -half_extents.z) +
|
||||
ofs;
|
||||
}
|
||||
|
||||
Vector3 AABB::get_endpoint(int p_point) const {
|
||||
switch (p_point) {
|
||||
case 0:
|
||||
return Vector3(position.x, position.y, position.z);
|
||||
case 1:
|
||||
return Vector3(position.x, position.y, position.z + size.z);
|
||||
case 2:
|
||||
return Vector3(position.x, position.y + size.y, position.z);
|
||||
case 3:
|
||||
return Vector3(position.x, position.y + size.y, position.z + size.z);
|
||||
case 4:
|
||||
return Vector3(position.x + size.x, position.y, position.z);
|
||||
case 5:
|
||||
return Vector3(position.x + size.x, position.y, position.z + size.z);
|
||||
case 6:
|
||||
return Vector3(position.x + size.x, position.y + size.y, position.z);
|
||||
case 7:
|
||||
return Vector3(position.x + size.x, position.y + size.y, position.z + size.z);
|
||||
}
|
||||
|
||||
ERR_FAIL_V(Vector3());
|
||||
}
|
||||
|
||||
bool AABB::intersects_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const {
|
||||
Vector3 half_extents = size * 0.5f;
|
||||
Vector3 ofs = position + half_extents;
|
||||
|
||||
for (int i = 0; i < p_plane_count; i++) {
|
||||
const Plane &p = p_planes[i];
|
||||
Vector3 point(
|
||||
(p.normal.x > 0) ? -half_extents.x : half_extents.x,
|
||||
(p.normal.y > 0) ? -half_extents.y : half_extents.y,
|
||||
(p.normal.z > 0) ? -half_extents.z : half_extents.z);
|
||||
point += ofs;
|
||||
if (p.is_point_over(point)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure all points in the shape aren't fully separated from the AABB on
|
||||
// each axis.
|
||||
int bad_point_counts_positive[3] = { 0 };
|
||||
int bad_point_counts_negative[3] = { 0 };
|
||||
|
||||
for (int k = 0; k < 3; k++) {
|
||||
for (int i = 0; i < p_point_count; i++) {
|
||||
if (p_points[i].coord[k] > ofs.coord[k] + half_extents.coord[k]) {
|
||||
bad_point_counts_positive[k]++;
|
||||
}
|
||||
if (p_points[i].coord[k] < ofs.coord[k] - half_extents.coord[k]) {
|
||||
bad_point_counts_negative[k]++;
|
||||
}
|
||||
}
|
||||
|
||||
if (bad_point_counts_negative[k] == p_point_count) {
|
||||
return false;
|
||||
}
|
||||
if (bad_point_counts_positive[k] == p_point_count) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AABB::inside_convex_shape(const Plane *p_planes, int p_plane_count) const {
|
||||
Vector3 half_extents = size * 0.5f;
|
||||
Vector3 ofs = position + half_extents;
|
||||
|
||||
for (int i = 0; i < p_plane_count; i++) {
|
||||
const Plane &p = p_planes[i];
|
||||
Vector3 point(
|
||||
(p.normal.x < 0) ? -half_extents.x : half_extents.x,
|
||||
(p.normal.y < 0) ? -half_extents.y : half_extents.y,
|
||||
(p.normal.z < 0) ? -half_extents.z : half_extents.z);
|
||||
point += ofs;
|
||||
if (p.is_point_over(point)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AABB::has_point(const Vector3 &p_point) const {
|
||||
#ifdef MATH_CHECKS
|
||||
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) {
|
||||
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
|
||||
}
|
||||
#endif
|
||||
if (p_point.x < position.x) {
|
||||
return false;
|
||||
}
|
||||
if (p_point.y < position.y) {
|
||||
return false;
|
||||
}
|
||||
if (p_point.z < position.z) {
|
||||
return false;
|
||||
}
|
||||
if (p_point.x > position.x + size.x) {
|
||||
return false;
|
||||
}
|
||||
if (p_point.y > position.y + size.y) {
|
||||
return false;
|
||||
}
|
||||
if (p_point.z > position.z + size.z) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void AABB::expand_to(const Vector3 &p_vector) {
|
||||
#ifdef MATH_CHECKS
|
||||
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) {
|
||||
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
|
||||
}
|
||||
#endif
|
||||
Vector3 begin = position;
|
||||
Vector3 end = position + size;
|
||||
|
||||
if (p_vector.x < begin.x) {
|
||||
begin.x = p_vector.x;
|
||||
}
|
||||
if (p_vector.y < begin.y) {
|
||||
begin.y = p_vector.y;
|
||||
}
|
||||
if (p_vector.z < begin.z) {
|
||||
begin.z = p_vector.z;
|
||||
}
|
||||
|
||||
if (p_vector.x > end.x) {
|
||||
end.x = p_vector.x;
|
||||
}
|
||||
if (p_vector.y > end.y) {
|
||||
end.y = p_vector.y;
|
||||
}
|
||||
if (p_vector.z > end.z) {
|
||||
end.z = p_vector.z;
|
||||
}
|
||||
|
||||
position = begin;
|
||||
size = end - begin;
|
||||
}
|
||||
|
||||
void AABB::project_range_in_plane(const Plane &p_plane, real_t &r_min, real_t &r_max) const {
|
||||
Vector3 half_extents(size.x * 0.5f, size.y * 0.5f, size.z * 0.5f);
|
||||
Vector3 center(position.x + half_extents.x, position.y + half_extents.y, position.z + half_extents.z);
|
||||
|
||||
real_t length = p_plane.normal.abs().dot(half_extents);
|
||||
real_t distance = p_plane.distance_to(center);
|
||||
r_min = distance - length;
|
||||
r_max = distance + length;
|
||||
}
|
||||
|
||||
inline real_t AABB::get_longest_axis_size() const {
|
||||
real_t max_size = size.x;
|
||||
|
||||
if (size.y > max_size) {
|
||||
max_size = size.y;
|
||||
}
|
||||
|
||||
if (size.z > max_size) {
|
||||
max_size = size.z;
|
||||
}
|
||||
|
||||
return max_size;
|
||||
}
|
||||
|
||||
inline real_t AABB::get_shortest_axis_size() const {
|
||||
real_t max_size = size.x;
|
||||
|
||||
if (size.y < max_size) {
|
||||
max_size = size.y;
|
||||
}
|
||||
|
||||
if (size.z < max_size) {
|
||||
max_size = size.z;
|
||||
}
|
||||
|
||||
return max_size;
|
||||
}
|
||||
|
||||
bool AABB::smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t t0, real_t t1) const {
|
||||
#ifdef MATH_CHECKS
|
||||
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) {
|
||||
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
|
||||
}
|
||||
#endif
|
||||
real_t divx = 1.0f / p_dir.x;
|
||||
real_t divy = 1.0f / p_dir.y;
|
||||
real_t divz = 1.0f / p_dir.z;
|
||||
|
||||
Vector3 upbound = position + size;
|
||||
real_t tmin, tmax, tymin, tymax, tzmin, tzmax;
|
||||
if (p_dir.x >= 0) {
|
||||
tmin = (position.x - p_from.x) * divx;
|
||||
tmax = (upbound.x - p_from.x) * divx;
|
||||
} else {
|
||||
tmin = (upbound.x - p_from.x) * divx;
|
||||
tmax = (position.x - p_from.x) * divx;
|
||||
}
|
||||
if (p_dir.y >= 0) {
|
||||
tymin = (position.y - p_from.y) * divy;
|
||||
tymax = (upbound.y - p_from.y) * divy;
|
||||
} else {
|
||||
tymin = (upbound.y - p_from.y) * divy;
|
||||
tymax = (position.y - p_from.y) * divy;
|
||||
}
|
||||
if ((tmin > tymax) || (tymin > tmax)) {
|
||||
return false;
|
||||
}
|
||||
if (tymin > tmin) {
|
||||
tmin = tymin;
|
||||
}
|
||||
if (tymax < tmax) {
|
||||
tmax = tymax;
|
||||
}
|
||||
if (p_dir.z >= 0) {
|
||||
tzmin = (position.z - p_from.z) * divz;
|
||||
tzmax = (upbound.z - p_from.z) * divz;
|
||||
} else {
|
||||
tzmin = (upbound.z - p_from.z) * divz;
|
||||
tzmax = (position.z - p_from.z) * divz;
|
||||
}
|
||||
if ((tmin > tzmax) || (tzmin > tmax)) {
|
||||
return false;
|
||||
}
|
||||
if (tzmin > tmin) {
|
||||
tmin = tzmin;
|
||||
}
|
||||
if (tzmax < tmax) {
|
||||
tmax = tzmax;
|
||||
}
|
||||
return ((tmin < t1) && (tmax > t0));
|
||||
}
|
||||
|
||||
void AABB::grow_by(real_t p_amount) {
|
||||
position.x -= p_amount;
|
||||
position.y -= p_amount;
|
||||
position.z -= p_amount;
|
||||
size.x += 2.0f * p_amount;
|
||||
size.y += 2.0f * p_amount;
|
||||
size.z += 2.0f * p_amount;
|
||||
}
|
||||
|
||||
void AABB::quantize(real_t p_unit) {
|
||||
size += position;
|
||||
|
||||
position.x -= Math::fposmodp(position.x, p_unit);
|
||||
position.y -= Math::fposmodp(position.y, p_unit);
|
||||
position.z -= Math::fposmodp(position.z, p_unit);
|
||||
|
||||
size.x -= Math::fposmodp(size.x, p_unit);
|
||||
size.y -= Math::fposmodp(size.y, p_unit);
|
||||
size.z -= Math::fposmodp(size.z, p_unit);
|
||||
|
||||
size.x += p_unit;
|
||||
size.y += p_unit;
|
||||
size.z += p_unit;
|
||||
|
||||
size -= position;
|
||||
}
|
||||
|
||||
AABB AABB::quantized(real_t p_unit) const {
|
||||
AABB ret = *this;
|
||||
ret.quantize(p_unit);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_AABB_HPP
|
||||
55
include/godot_cpp/variant/array_helpers.hpp
Normal file
55
include/godot_cpp/variant/array_helpers.hpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/**************************************************************************/
|
||||
/* array_helpers.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_ARRAY_HELPERS_HPP
|
||||
#define GODOT_ARRAY_HELPERS_HPP
|
||||
|
||||
namespace godot {
|
||||
namespace helpers {
|
||||
template <typename T, typename ValueT>
|
||||
T append_all(T appendable, ValueT value) {
|
||||
appendable.append(value);
|
||||
return appendable;
|
||||
}
|
||||
|
||||
template <typename T, typename ValueT, typename... Args>
|
||||
T append_all(T appendable, ValueT value, Args... args) {
|
||||
appendable.append(value);
|
||||
return append_all(appendable, args...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T append_all(T appendable) {
|
||||
return appendable;
|
||||
}
|
||||
} // namespace helpers
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_ARRAY_HELPERS_HPP
|
||||
319
include/godot_cpp/variant/basis.hpp
Normal file
319
include/godot_cpp/variant/basis.hpp
Normal file
@@ -0,0 +1,319 @@
|
||||
/**************************************************************************/
|
||||
/* basis.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_BASIS_HPP
|
||||
#define GODOT_BASIS_HPP
|
||||
|
||||
#include <godot_cpp/classes/global_constants.hpp>
|
||||
#include <godot_cpp/variant/quaternion.hpp>
|
||||
#include <godot_cpp/variant/vector3.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
struct [[nodiscard]] Basis {
|
||||
Vector3 rows[3] = {
|
||||
Vector3(1, 0, 0),
|
||||
Vector3(0, 1, 0),
|
||||
Vector3(0, 0, 1)
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ const Vector3 &operator[](int axis) const {
|
||||
return rows[axis];
|
||||
}
|
||||
_FORCE_INLINE_ Vector3 &operator[](int axis) {
|
||||
return rows[axis];
|
||||
}
|
||||
|
||||
void invert();
|
||||
void transpose();
|
||||
|
||||
Basis inverse() const;
|
||||
Basis transposed() const;
|
||||
|
||||
_FORCE_INLINE_ real_t determinant() const;
|
||||
|
||||
void from_z(const Vector3 &p_z);
|
||||
|
||||
void rotate(const Vector3 &p_axis, real_t p_angle);
|
||||
Basis rotated(const Vector3 &p_axis, real_t p_angle) const;
|
||||
|
||||
void rotate_local(const Vector3 &p_axis, real_t p_angle);
|
||||
Basis rotated_local(const Vector3 &p_axis, real_t p_angle) const;
|
||||
|
||||
void rotate(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ);
|
||||
Basis rotated(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ) const;
|
||||
|
||||
void rotate(const Quaternion &p_quaternion);
|
||||
Basis rotated(const Quaternion &p_quaternion) const;
|
||||
|
||||
Vector3 get_euler_normalized(EulerOrder p_order = EULER_ORDER_YXZ) const;
|
||||
void get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const;
|
||||
void get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const;
|
||||
Quaternion get_rotation_quaternion() const;
|
||||
|
||||
void rotate_to_align(Vector3 p_start_direction, Vector3 p_end_direction);
|
||||
|
||||
Vector3 rotref_posscale_decomposition(Basis &rotref) const;
|
||||
|
||||
Vector3 get_euler(EulerOrder p_order = EULER_ORDER_YXZ) const;
|
||||
void set_euler(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ);
|
||||
static Basis from_euler(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ) {
|
||||
Basis b;
|
||||
b.set_euler(p_euler, p_order);
|
||||
return b;
|
||||
}
|
||||
|
||||
Quaternion get_quaternion() const;
|
||||
void set_quaternion(const Quaternion &p_quaternion);
|
||||
|
||||
void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const;
|
||||
void set_axis_angle(const Vector3 &p_axis, real_t p_angle);
|
||||
|
||||
void scale(const Vector3 &p_scale);
|
||||
Basis scaled(const Vector3 &p_scale) const;
|
||||
|
||||
void scale_local(const Vector3 &p_scale);
|
||||
Basis scaled_local(const Vector3 &p_scale) const;
|
||||
|
||||
void scale_orthogonal(const Vector3 &p_scale);
|
||||
Basis scaled_orthogonal(const Vector3 &p_scale) const;
|
||||
|
||||
void make_scale_uniform();
|
||||
float get_uniform_scale() const;
|
||||
|
||||
Vector3 get_scale() const;
|
||||
Vector3 get_scale_abs() const;
|
||||
Vector3 get_scale_local() const;
|
||||
|
||||
void set_axis_angle_scale(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale);
|
||||
void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale, EulerOrder p_order = EULER_ORDER_YXZ);
|
||||
void set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale);
|
||||
|
||||
// transposed dot products
|
||||
_FORCE_INLINE_ real_t tdotx(const Vector3 &v) const {
|
||||
return rows[0][0] * v[0] + rows[1][0] * v[1] + rows[2][0] * v[2];
|
||||
}
|
||||
_FORCE_INLINE_ real_t tdoty(const Vector3 &v) const {
|
||||
return rows[0][1] * v[0] + rows[1][1] * v[1] + rows[2][1] * v[2];
|
||||
}
|
||||
_FORCE_INLINE_ real_t tdotz(const Vector3 &v) const {
|
||||
return rows[0][2] * v[0] + rows[1][2] * v[1] + rows[2][2] * v[2];
|
||||
}
|
||||
|
||||
bool is_equal_approx(const Basis &p_basis) const;
|
||||
bool is_finite() const;
|
||||
|
||||
bool operator==(const Basis &p_matrix) const;
|
||||
bool operator!=(const Basis &p_matrix) const;
|
||||
|
||||
_FORCE_INLINE_ Vector3 xform(const Vector3 &p_vector) const;
|
||||
_FORCE_INLINE_ Vector3 xform_inv(const Vector3 &p_vector) const;
|
||||
_FORCE_INLINE_ void operator*=(const Basis &p_matrix);
|
||||
_FORCE_INLINE_ Basis operator*(const Basis &p_matrix) const;
|
||||
_FORCE_INLINE_ void operator+=(const Basis &p_matrix);
|
||||
_FORCE_INLINE_ Basis operator+(const Basis &p_matrix) const;
|
||||
_FORCE_INLINE_ void operator-=(const Basis &p_matrix);
|
||||
_FORCE_INLINE_ Basis operator-(const Basis &p_matrix) const;
|
||||
_FORCE_INLINE_ void operator*=(const real_t p_val);
|
||||
_FORCE_INLINE_ Basis operator*(const real_t p_val) const;
|
||||
|
||||
bool is_orthogonal() const;
|
||||
bool is_diagonal() const;
|
||||
bool is_rotation() const;
|
||||
|
||||
Basis lerp(const Basis &p_to, const real_t &p_weight) const;
|
||||
Basis slerp(const Basis &p_to, const real_t &p_weight) const;
|
||||
void rotate_sh(real_t *p_values);
|
||||
|
||||
operator String() const;
|
||||
|
||||
/* create / set */
|
||||
|
||||
_FORCE_INLINE_ void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz) {
|
||||
rows[0][0] = xx;
|
||||
rows[0][1] = xy;
|
||||
rows[0][2] = xz;
|
||||
rows[1][0] = yx;
|
||||
rows[1][1] = yy;
|
||||
rows[1][2] = yz;
|
||||
rows[2][0] = zx;
|
||||
rows[2][1] = zy;
|
||||
rows[2][2] = zz;
|
||||
}
|
||||
_FORCE_INLINE_ void set_columns(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z) {
|
||||
set_column(0, p_x);
|
||||
set_column(1, p_y);
|
||||
set_column(2, p_z);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Vector3 get_column(int p_index) const {
|
||||
// Get actual basis axis column (we store transposed as rows for performance).
|
||||
return Vector3(rows[0][p_index], rows[1][p_index], rows[2][p_index]);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void set_column(int p_index, const Vector3 &p_value) {
|
||||
// Set actual basis axis column (we store transposed as rows for performance).
|
||||
rows[0][p_index] = p_value.x;
|
||||
rows[1][p_index] = p_value.y;
|
||||
rows[2][p_index] = p_value.z;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Vector3 get_main_diagonal() const {
|
||||
return Vector3(rows[0][0], rows[1][1], rows[2][2]);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void set_zero() {
|
||||
rows[0].zero();
|
||||
rows[1].zero();
|
||||
rows[2].zero();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Basis transpose_xform(const Basis &m) const {
|
||||
return Basis(
|
||||
rows[0].x * m[0].x + rows[1].x * m[1].x + rows[2].x * m[2].x,
|
||||
rows[0].x * m[0].y + rows[1].x * m[1].y + rows[2].x * m[2].y,
|
||||
rows[0].x * m[0].z + rows[1].x * m[1].z + rows[2].x * m[2].z,
|
||||
rows[0].y * m[0].x + rows[1].y * m[1].x + rows[2].y * m[2].x,
|
||||
rows[0].y * m[0].y + rows[1].y * m[1].y + rows[2].y * m[2].y,
|
||||
rows[0].y * m[0].z + rows[1].y * m[1].z + rows[2].y * m[2].z,
|
||||
rows[0].z * m[0].x + rows[1].z * m[1].x + rows[2].z * m[2].x,
|
||||
rows[0].z * m[0].y + rows[1].z * m[1].y + rows[2].z * m[2].y,
|
||||
rows[0].z * m[0].z + rows[1].z * m[1].z + rows[2].z * m[2].z);
|
||||
}
|
||||
Basis(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz) {
|
||||
set(xx, xy, xz, yx, yy, yz, zx, zy, zz);
|
||||
}
|
||||
|
||||
void orthonormalize();
|
||||
Basis orthonormalized() const;
|
||||
|
||||
void orthogonalize();
|
||||
Basis orthogonalized() const;
|
||||
|
||||
#ifdef MATH_CHECKS
|
||||
bool is_symmetric() const;
|
||||
#endif
|
||||
Basis diagonalize();
|
||||
|
||||
operator Quaternion() const { return get_quaternion(); }
|
||||
|
||||
static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false);
|
||||
|
||||
Basis(const Quaternion &p_quaternion) { set_quaternion(p_quaternion); }
|
||||
Basis(const Quaternion &p_quaternion, const Vector3 &p_scale) { set_quaternion_scale(p_quaternion, p_scale); }
|
||||
|
||||
Basis(const Vector3 &p_axis, real_t p_angle) { set_axis_angle(p_axis, p_angle); }
|
||||
Basis(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale) { set_axis_angle_scale(p_axis, p_angle, p_scale); }
|
||||
static Basis from_scale(const Vector3 &p_scale);
|
||||
|
||||
_FORCE_INLINE_ Basis(const Vector3 &p_x_axis, const Vector3 &p_y_axis, const Vector3 &p_z_axis) {
|
||||
set_columns(p_x_axis, p_y_axis, p_z_axis);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Basis() {}
|
||||
|
||||
private:
|
||||
// Helper method.
|
||||
void _set_diagonal(const Vector3 &p_diag);
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ void Basis::operator*=(const Basis &p_matrix) {
|
||||
set(
|
||||
p_matrix.tdotx(rows[0]), p_matrix.tdoty(rows[0]), p_matrix.tdotz(rows[0]),
|
||||
p_matrix.tdotx(rows[1]), p_matrix.tdoty(rows[1]), p_matrix.tdotz(rows[1]),
|
||||
p_matrix.tdotx(rows[2]), p_matrix.tdoty(rows[2]), p_matrix.tdotz(rows[2]));
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Basis Basis::operator*(const Basis &p_matrix) const {
|
||||
return Basis(
|
||||
p_matrix.tdotx(rows[0]), p_matrix.tdoty(rows[0]), p_matrix.tdotz(rows[0]),
|
||||
p_matrix.tdotx(rows[1]), p_matrix.tdoty(rows[1]), p_matrix.tdotz(rows[1]),
|
||||
p_matrix.tdotx(rows[2]), p_matrix.tdoty(rows[2]), p_matrix.tdotz(rows[2]));
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void Basis::operator+=(const Basis &p_matrix) {
|
||||
rows[0] += p_matrix.rows[0];
|
||||
rows[1] += p_matrix.rows[1];
|
||||
rows[2] += p_matrix.rows[2];
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Basis Basis::operator+(const Basis &p_matrix) const {
|
||||
Basis ret(*this);
|
||||
ret += p_matrix;
|
||||
return ret;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void Basis::operator-=(const Basis &p_matrix) {
|
||||
rows[0] -= p_matrix.rows[0];
|
||||
rows[1] -= p_matrix.rows[1];
|
||||
rows[2] -= p_matrix.rows[2];
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Basis Basis::operator-(const Basis &p_matrix) const {
|
||||
Basis ret(*this);
|
||||
ret -= p_matrix;
|
||||
return ret;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void Basis::operator*=(const real_t p_val) {
|
||||
rows[0] *= p_val;
|
||||
rows[1] *= p_val;
|
||||
rows[2] *= p_val;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Basis Basis::operator*(const real_t p_val) const {
|
||||
Basis ret(*this);
|
||||
ret *= p_val;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Vector3 Basis::xform(const Vector3 &p_vector) const {
|
||||
return Vector3(
|
||||
rows[0].dot(p_vector),
|
||||
rows[1].dot(p_vector),
|
||||
rows[2].dot(p_vector));
|
||||
}
|
||||
|
||||
Vector3 Basis::xform_inv(const Vector3 &p_vector) const {
|
||||
return Vector3(
|
||||
(rows[0][0] * p_vector.x) + (rows[1][0] * p_vector.y) + (rows[2][0] * p_vector.z),
|
||||
(rows[0][1] * p_vector.x) + (rows[1][1] * p_vector.y) + (rows[2][1] * p_vector.z),
|
||||
(rows[0][2] * p_vector.x) + (rows[1][2] * p_vector.y) + (rows[2][2] * p_vector.z));
|
||||
}
|
||||
|
||||
real_t Basis::determinant() const {
|
||||
return rows[0][0] * (rows[1][1] * rows[2][2] - rows[2][1] * rows[1][2]) -
|
||||
rows[1][0] * (rows[0][1] * rows[2][2] - rows[2][1] * rows[0][2]) +
|
||||
rows[2][0] * (rows[0][1] * rows[1][2] - rows[1][1] * rows[0][2]);
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_BASIS_HPP
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user